Open comments for this post
Devlog #7
Another Day to feel demotivated because your ship got rejected… there was another recommendation they made to me (following up from the fact they thought my project was AI but sure), that was to add new features that would make it more cool to use! Kinda agree tho it does need more QOL features. That is why after the Hide UI (which was also added because of this suggestion btw) I added 2 new features!!!
- Camera Lock: This button allows you to lock your camera to the satellite, and the camera just follows the satellite, its useful if you just want it to sit in the background or smthing or just dont want to rotate the globe constantly in-between a Pass to see the satellite angle.
- Notifications!!!: This button allows you to enable notifications and the web-app will remind you 2 minutes before a pass using the alert() function in JS. pretty simpleOff topic: for 1080p monitors or low-end setups, the first load might be very fiddly and maybe the orbit path or the satellite or something can break, reloading fixes this mostly.
These features are really simple lol and I was planning on adding more but I think its enough for now, I plan to integrate E-mails so it can remind you through Email or smthing but that will take HOURS! anyways, this sums it up to a total of 3 features. I also FINALLY completed the readme, and yes I know I said I had exams but all the more reason to finish it right here and right now, because if I hadn’t done it now, then I would have kept thinking about it lol, it might have even hindered my exam performance (yes its that serious for me). Anyways, I completely deleted the entire readme which AI made, and I tried my best when writing it manually, I don;t know what you include in a readme because I havent made it before this but I tried my best, I also added a picture of a photo I took using orbital-eye!!!
Open comments for this post
Welp, My Ship got rejected, hahahahha, not rejected but there were some changes requested and they were entirely reasonable and actually I’m amazed how much the shipwrights actually care about the people who are making these project. The main reason was because my ENTIRE CSS was just AI slop, and I know that we all hate AI but trust me, CSS is the bane of my existence, even though it is now I had to manually revamp the entire CSS and it looks sooo muchhh better, Istg if this gets flagged as AI I might actually quit lol. Anyways, the second change they suggested was updating the README, which I havent done yet but I will do soon (my exams are in 2 days, I have to study lol) and I guess because I didnt commit until like 50% of the project they thought my entire project was AI or something? In my defence it was my first time using github codespaces and since the code was saved I thought it must have magically synced with my repo or smthing lol. Anyways, the reasons were completely valid and let me list out the changes I made:
-Changed font from the generic typewriter to the Inter font, and sans-serif.
-Made HUD Panels almost invisible (they were protruding too much and felt distracting, I wanted to make the Globe the visual centre of the site so yea).
-Changed the Globe skin to blue marble, the NASA skin wasn’t very detailed it just had a higher resolution, the current one looks very good.
-Added a background image URL so that there is a starry sky in the background not a plain black void.
-Changed the top left HUD, did many changes, I found inspiration from stellarium, its basically a star tracking astrophotgraphy software, but its UI is like way too detail intensive, I took the transparent design philosophy from there and the rest I just fiddled with it until I liked it lol.
-Changed the 100 accents of blues I used, to a single steel blue #5D88AA4D, I decreased the opacity for borders to around 30% ish.
-I also reduced the size of the actually pass table to about 70% of its current size, it was wayyy too dominant on the UI, and I also added the accent colour there too. I completely removed green (except for the user dot).
-I made the satellite path thickness less because it was tooo thick, it didn’t look like an orbit, so I made it thinner and also made the satellite sphere smaller as well from 8 : 5 to 5 : 4, I dont know the units I just turned the number smaller lol.
-Next, I added a Hide UI button, the UI was very prominent on PC itself and on mobile it was just unbearable so I thought I should add a HIDE UI button so that users can focus on the globe (tho that’s not the point of this website but sure, it serves as a simulation too lol). I put it on the top right edge. On click, it just makes all the HUD elements transparent and set their pointer events to none so they can’t interact. That is basically it. I will be sure to completely remake the README I guess when I will get some time, right now, I gotta study.
Open comments for this post
Devlog 5 - FOV Rings & Custom Satellites!
Overview
This session was mostly spent adding QOL updates. I made a section for custom TLE data so that you can just drop the TLE for ANY asset you want to track and the app will display it. I also added a ground station field-of-view (FOV) overlay so users can see the exact area of the Earth they can realistically observe from their specific location.
What’s New!
- Added a ground station FOV ring with a ~1500 km visibility radius.
- Implemented accurate spherical projection for the FOV overlay.
- Added support for custom TLE injection.
- Created a new backend API endpoint for custom satellites.
- Enabled live orbit updates without needing full page reloads.
- Added pass predictions for custom satellites.
- Improved overlay rendering and stability.
- Fixed several major performance bottlenecks.
Challenges
- Globe.gl’s built-in rings system turned out to be designed for animated ripple effects rather than static geometry, making it incredibly frustrating to work with.
- Spent a good chunk of time tracking down rendering bugs, massive performance drops, and objects annoyingly drawing right through the Earth.
- Page load times were atrocious—taking at least 50 seconds because my code organization sucked, causing the app to repeatedly load timescales and rerun complex calculations instead of doing them globally.
Solutions
- Scrapped the built-in Globe.gl rings API entirely and custom-built the FOV ring myself using a canvas overlay and spherical geometry calculations.
- Implemented a mix of occlusion culling, render-loop optimization, and smarter canvas handling to fix the visual bugs and clipping issues.
- Moved repetitive calculations and timescale loading into global instances, which absolutely crushed the performance bottleneck. Page load times dropped from 50+ seconds down to a smooth 5-10 seconds!
I am super proud of how the performance changes turned out (though they were mostly caused because of my stupidity).
Also, this is going to be the final development blog for Orbital Eye because I’m finally preparing to ship it! This has somehow turned into a full satellite tracking platform with visibility forecasting, live telemetry, custom TLE support, and a 3D globe. There’s still a lot I want to add in the future, but for now I think it’s time for me to fix the last few little bugs and ship it!
Open comments for this post
Devlog 4 - 3D GLOBE!?!
Overview
ITS LIVE FOR DEMO!, avishgoyal.pythonanywhere.com
This session was all about finally implementing the 3D globe for the Satellite Pass Predictor. The goal was to create an interactive Earth that users can rotate around while viewing satellites orbiting in real time, kind of like a mini Google Earth for satellite tracking. To make this work, I used Globe.gl for visualization and Skyfield on the backend to generate future orbital positions from TLE data. Instead of constantly requesting new coordinates from the server, the backend pre-calculates future positions and sends them to the client, which then smoothly animates the satellite between those points.
What’s New!
- Added an interactive 3D Earth using Globe.gl.
- Implemented future trajectory generation using Skyfield and TLE data.
- Added a new Flask API endpoint for orbit predictions.
- Generated 2 hours of future satellite positions at 1-minute intervals.
- Added real-time satellite animation using interpolation.
- Implemented automatic trajectory refreshes every 2 hours.
- Added orbit path visualization around the Earth.
- Fixed International Date Line wrap-around issues.
- Improved rendering performance by reducing unnecessary updates.
- Fixed Celestrak parsing issues caused by hidden characters.
Challenges
- The globe rendered perfectly, the backend returned valid coordinates, and the animation logic was running, yet the satellite simply refused to appear. There were no useful errors either, which made debugging much more painful.
- Whenever the satellite crossed ±180° longitude, the orbit path would suddenly draw giant lines across the globe, making the orbit look completely broken.
- Valid satellites occasionally weren’t being found despite existing in the TLE files.
- Performance became a problem because I was accidentally rebuilding parts of the globe every frame.
Approach
- My first assumption was that the rendering system itself was broken. I experimented with custom Three.js objects, custom spheres, imported raw Three.js alongside Globe.gl, and tried multiple rendering approaches.
- When none of those worked, I traced the entire pipeline, checking API responses, coordinate generation, interpolation calculations, altitude scaling, and orbit path generation.
- For the orbit issue, I compared coordinate transitions between consecutive points and investigated what happened when satellites crossed specific regions of the globe.
- For performance issues, I profiled the update loop and monitored how often rendering updates were occurring.
Solutions
- The rendering issue turned out to be much simpler than expected. I was fighting Globe.gl instead of using the tools it already provided. Once I switched to its built-in object plotting system, the satellite immediately appeared.
- The orbit path issue was caused by longitude wrap-around at the International Date Line. Adding logic to detect large longitude jumps and split orbit segments fixed the problem.
- The backend lookup issue was traced back to hidden non-breaking spaces (\xa0) inside Celestrak TLE files. Sanitizing satellite names fixed the issue.
- Performance improved significantly after I stopped rebuilding globe geometry every frame and throttled rendering updates.
Next Steps
- Add support for multiple satellites.
- Improve orbit path visualization.
- Add satellite labels and information overlays.
- Improve camera controls and globe interaction.
- Display upcoming passes directly on the globe.
- Continue optimizing animation performance.
Overall, despite the suffering involved, this was one of the biggest milestones in the project so far. The globe is rendering, satellites are moving around the Earth, orbit paths are displaying correctly, and the project is finally starting to look like the thing I originally imagined instead of a collection of APIs and tables stitched together. See you in Devlog #5!
Open comments for this post
DEVLOG 3
Day 3 was an absolute sprint to turn raw orbital math into something I could actually use without gaslighting myself over cloud cover. I started the day with a cup of chai and a mission to fix our directional tracking, which quickly snowballed into a massive overhaul of the entire real-time calculation chain… So instead of drowning the codebase in technical jargon, I tried to focus on human-readable data, AND try to make this hour-long loading time a snappy asynchronous platform, (also hyper-local conditions to keep the frontend running smoothly.) Here is the core of what went down: Compass & Routing: Added a degrees_to_cardinal helper that slices the 360° horizon into 8 neat cardinal directions, refactored find_events to log satellite positions at rise, peak, and set, and squashed a dictionary reference bug preventing set_dir from saving to memory—all bundled into a clean frontend payload string via app. py. Live Telemetry Engine: Implemented get_live_telemetry() in predictor.py to pull coordinates instantly from our local stations.txt TLE cache without network lag, translated orbital positions into altitude/azimuth degrees using ts.now(), and added an above-horizon state gatekeeper. Async & Lifecycle Management: Locked the telemetry rendering logic safely inside the frontend. then() promise block to stop the DOM from breaking on undefined data, and built a self-termination loop that fires clearInterval() and refreshes the browser after 3 seconds when a pass ends. Weather & Geometry Matrix: Integrated an async nearest-neighbor matcher to map Open-Meteo hourly cloud cover to the exact minute of the pass peak while using the de421. bsp planetary model to run double-agent geometry checks, ensuring the local sky is dark (sun altitude below -6°) but the asset itself is . is_sunlit(). Visibility Sorting Pipeline: Aligned app.py to route tracking payloads into a rigid 5-tier classification matrix ranging from EXCELLENT (clear overhead passes) down to INVISIBLE (lost in daylight glare or Earth’s shadow) so I never accidentally watch water vapor for 15 minutes again. With the math finally behaving and the data flowing cleanly between files without throwing runtime attribute errors, the tracking engine is officially locked, loaded, and ready for real sky-gazing mischief.
Open comments for this post
DEVLOG 2
Building software always starts with a beautiful delusion. You think you’re just taking a neat little script that prints satellite passes to a terminal and giving it a pretty web face. But the second you try to turn it into a real app, the code fights back. You modularize the math, build a safety net so the app doesn’t crash if the external tracking servers go down, and think you’re golden. Then you try to make it smart enough to track things based on where a user is actually standing, and you accidentally unleash an infinite reload nightmare that traps your browser in a loop, forcing you to write a literal memory-check in JavaScript just to stop the page from having a total meltdown. Once you break out of that loop, you realize tracking things in space means dealing with the absolute chaos of time itself. Space math lives in UTC, which is completely useless to a human looking out a window. So you find yourself wrestling with system timezone databases just to translate those raw numbers into normal, local clock times. At the same time, you build a massive, beautifully categorized dropdown menu to track everything from the ISS to random space junk—only to watch the interface develop instant amnesia, resetting itself back to the default option every single time the page refreshes. Fixing it requires writing a client-side script that acts like a digital detective, checking the web address to force the menu to remember what you clicked. But the absolute worst part? The ghosts in the machine. You try to track specific ships, and the app just returns a blank screen. You spend hours digging through raw text lines only to find out the tracking database is silently laced with hidden, non-breaking space characters. They look identical to normal spaces to a human eye, but to a computer, they break strict string matching entirely. After aggressively scrubbing those invisible characters out of the memory loops, you finally cross the finish line by hooking up a live countdown timer that ticks down to the exact second a satellite crosses your sky. You started with a text printout; you ended up surviving a relentless gauntlet of infrastructure fires.
Open comments for this post
DEVLOG 1
Building a reliable ISS pass predictor has been a lesson in balancing ambition and my own consistent ability to break perfectly good code. I started by moving my entire development workflow to GitHub Codespaces, which has been a lifesaver; it provides a clean, cloud-based environment that keeps my local machine safe from the digital clutter and potential malware risks I encountered during my previous projects. Seriously, I’m pretty sure my machine still has the digital equivalent of an STD from that dock project I made a while ago. I tackled the core prediction engine using the Skyfield and Requests libraries, which allow me to pull live Two-Line Element (TLE) data directly from CelesTrak (which is a website that basically contains all the TLE for almost every satellite), ensuring that every calculation is based on the most recent orbital telemetry. The most significant hurdle I faced was refining the state machine logic within my prediction loop. Without a proper tracker, my initial script would suffer from an existential crisis, mistakenly logging “Set” events before “Rise” events or failing to account for passes that were already in progress when the script began (Please dont judge me, I’m a beginner and tho I have completed half of CS50, it has been a while since I have coded anything…). I solved this by implementing a persistent tracking dictionary that survives outside the loop iterations, allowing the program to safely identify and group the three distinct phases of an ISS pass: the Rise, the Peak, and the Set. Along the way, I navigated some predictable debugging hurdles, such as TypeErrors caused by me trying to force-format a Skyfield Time object as a simple float—which is a fantastic way to make your terminal scream at you—before I finally realized I needed to use proper UTC string formatting. The project is now at a point where it successfully processes raw orbital geometry for my specific coordinates in Greater Noida and exports clean, actionable data. With the backend logic stabilized, my next steps involve refactoring the code into a modular utility for my Flask API and building. Once my exams are finished, I intend to dedicate full-time focus to this project and my upcoming plans for a personal homelab setup, provided I don’t accidentally join a botnet in the meantime.