Building SkyMoment: A 4K Personalized Star Map Generator with Python, Skyfield and Real Astronomical Data
I recently shipped a small side project called SkyMoment โ a generator that creates personalized 4K star map posters using real astronomical data.
You enter a date, time, and location.
SkyMoment recreates the exact night sky for that moment and renders it as a minimalist, print-ready 4000ร4000 poster.
๐ Live demo: https://skymoment.art/
This post is a breakdown of how the system works โ from astronomical calculations to rendering and backend automation.
๐ The idea
Most โstar map postersโ online arenโt actually based on real sky data.
Many use approximations, fake constellations, or pre-rendered visuals.
I wanted something more accurate and scientific:
- real positions of stars,
- real coordinate transforms,
- proper field of view,
- natural-looking Milky Way,
- clean and minimal layout.
And I wanted to turn this into a small automated product:
enter a moment โ get a PDF/PNG โ done.
๐ฐ Tech stack overview
Python โ main rendering pipeline
Skyfield โ planetary ephemeris & star calculations
Hipparcos catalog โ star positions & magnitudes
Astropy โ coordinate transforms
Matplotlib โ final 4K rendering
Django โ backend & API
Lemon Squeezy โ payments + webhooks
SMTP โ email delivery of the final poster
The frontend is intentionally minimal. The โmagicโ happens in the rendering pipeline.
๐ญ Astronomical calculations step-by-step
When a user enters:
- date
- time
- location (lat/lon)
the pipeline does:
1. Convert local time to UTC
Skyfield requires accurate UTC timestamps.
2. Load planetary ephemeris
Using DE421 / DE422 depending on the build.
3. Load Hipparcos star catalog
This gives:
- RA/Dec
- magnitude
- proper motion
4. Transform everything into the user's sky coordinates
Using Astropy AltAz transforms based on the observerโs position.
5. Filter stars
Only stars above a certain brightness threshold are rendered.
6. Split bright/faint stars
Bright stars use a stylized 8-point marker.
Faint stars use simple dots.
7. Render the Milky Way
A custom multi-noise layer:
- low-frequency shapes
- medium cloud structure
- smooth alpha falloff
- suppression of โsand grainโ artifacts
This part took the longest to tune.
8. Render at 4000ร4000 resolution
Matplotlib actually does a great job when used carefully.
Total render time: ~35โ40 seconds on server hardware.
๐ฅ Rendering performance challenges
4K resolution + thousands of stars + Milky Way noise layers = heavy.
Some optimizations:
- preload catalogs once per worker
- reuse figure objects
- avoid expensive Python loops
- limit use of transparency
- skip stars below a certain magnitude
- cache static layers when possible
Even small changes can save 10โ20% time.
๐งฉ Backend architecture (Django)
SkyMoment uses a simple pipeline:
1. User configures their moment
Chooses date/time/location and sees a preview.
2. User is redirected to Lemon Squeezy checkout
3. After payment, LS sends a webhook to Django
The webhook contains:
- the order ID
- the custom fields (title, location, datetime)
- the product variant
4. Django creates a generation job
Status: pending โ generating โ ready
5. A worker process runs the Python renderer
6. The final 4K poster is saved to disk
7. Django sends an email with a download link
Important detail:
the webhook responds immediately โ rendering happens asynchronously to avoid LS timeouts.
๐งช Example of what the system produces
Here is a reduced-size preview of a generated poster:
(Insert image URL here if you want)
The 4K version includes:
- precise star positions
- constellation lines
- minimal typography
- custom title & subtitle
- a clean dark theme
๐ Whatโs next
On the roadmap:
- multiple poster templates
- faster rendering (possibly caching or partial reuse)
- more curated landing pages
- detailed generational logs and analytics
If you want to try generating a star map for your own moment:
Happy to answer any technical questions about astronomical data, rendering, or backend architecture!
Top comments (1)
Cool idea!