Astrophotography

Tenrankai has first-class support for astrophotography galleries, powered by the seiza plate-solving library. Point it at a few catalog files and your images gain an exact sky solution: labeled deep-sky objects, named stars, live supernova markers, and comets and asteroids placed where they actually were on the night you pressed the shutter.

Everything here is optional. Without an [astro] section, Tenrankai behaves exactly as it always has.

What You Get

  • Plate solving — a real WCS is fitted from the star field itself, not guessed from metadata. Solutions are persisted next to the image.
  • Blind solving — images with no coordinates at all are solved from the star field alone, using a whole-sky pattern index.
  • Object overlays — labeled ellipses for deep-sky objects (NGC/IC/Messier, Sharpless, Barnard) and tick marks for named stars, oriented to the object’s true position angle, with per-catalog visibility toggles.
  • Transient markers — supernovae from a catalog you refresh on a cron, scoped to each image’s capture date.
  • Comets and asteroids — positions propagated to the moment of capture, drawn with oriented tails and motion trails.
  • Sky maps — an all-sky chart with a crosshair on the target, which works from RA/Dec alone and needs no plate solution.

Overlays appear on the image detail page, inside zoomed and pinch-zoomed views, on gallery images embedded in posts, and on post hero images.

Getting the Catalogs

Tenrankai ships no catalogs and calls no external service at runtime — you supply the data files. The easy path is to fetch the prebuilt ones:

seiza download-data prebuilt --output /var/lib/tenrankai/astro

They’re also published directly at downloads.seiza.fyi. If you’d rather build your own from source catalogs, each file has a corresponding seiza build-* command:

FileBuilt withPurpose
Star tilesseiza build-dataRequired. The reference star field everything is solved against.
Blind pattern indexseiza build-blind-indexWhole-sky patterns for solving images that carry no coordinates.
Object catalogseiza build-data objectsDeep-sky objects and named stars to overlay.
Transient catalogseiza build-data transientsActive supernovae (Rochester list).
Minor bodiesseiza build-data minor-bodiesComet and asteroid orbital elements.

No astrometry.net index files are involved, and there’s nothing to install at runtime — seiza is a library compiled into the binary.

The [astro] Block

Astro data files are configured once, in the bootstrap config.toml — not per-gallery and not per-site. All sites share the catalogs.

[astro]
star_data = "/var/lib/tenrankai/astro/stars-deep-gaia17.bin"  # Required
blind_index = "/var/lib/tenrankai/astro/blind-gaia16.idx"     # Optional
object_data = "/var/lib/tenrankai/astro/objects.bin"          # Optional
transient_data = "/var/lib/tenrankai/astro/transients.bin"    # Optional
minor_body_data = "/var/lib/tenrankai/astro/minor-bodies.bin" # Optional

Every key is a filesystem path. star_data is the only required one — the rest each switch on a capability, and omitting one simply means you don’t get it.

KeyRequiredFormatPurpose and behavior
star_dataYesSEIZAST1The reference star tiles. If the file can’t be opened, plate solving is disabled entirely and the server logs a warning — the site still starts and serves normally.
blind_indexNoSEIZABI1Prebuilt whole-sky pattern index for blind solving. Memory-mapped on first use. Without it, an index is built on demand from star_data covering only the bright tiers. See below.
object_dataNoSEIZAOB1The objects to overlay. Without it, images still solve but nothing is drawn. Loaded once at startup — changing it needs a restart.
transient_dataNoSupernovae and other transients. Reloaded automatically whenever the file’s mtime changes, so a cron can refresh it with no restart.
minor_body_dataNoComet and asteroid orbital elements. Also reloaded on mtime change.

Omit the whole [astro] table and none of this exists: the astro API returns 404 and no toggles appear.

Unknown keys are rejected at startup, so a typo fails loudly rather than being silently ignored.

The Blind Pattern Index

blind_index is what lets Tenrankai solve an image that carries no coordinates at all. It’s worth understanding the trade-off, because the fallback is quietly limited.

With blind_index set, the file is memory-mapped on first use — a fraction of a second, regardless of size. The index carries its own magnitude limit and pattern extent, and the solver honors them, so a deep index can solve small, fine-scale fields.

Without it, seiza builds an index from star_data on the first blind solve. That runtime build only ever covers the bright tiers (roughly G ≤ 11.8), because building the deep tiers over a large catalog costs minutes and gigabytes. The practical consequence: wide fields still blind-solve, but small, fine-scale fields never will. If blind solving mysteriously fails on your longer focal lengths, this is why.

The index must be built from the same catalog as star_data. Tenrankai checks this at load and logs a warning when the two are far apart:

astro: blind index blind-gaia16.idx was built from 4200000 stars
but star_data has 91000000; blind solves may fail

If the file is missing or unreadable, Tenrankai warns and falls back to the on-demand build rather than failing — so a bad path degrades blind solving instead of taking the site down.

There are no solver tuning knobs. The scale ladder (roughly 0.11–5.6 arcsec/pixel), search radius, detection limits, and magnitude cutoffs are internal constants chosen to cover typical amateur setups.

Marking Astronomical Folders

Add astro = true to a folder’s _folder.md to declare that everything in it is an astronomical image. Subfolders inherit the flag.

+++
title = "Deep Sky"
description = "Narrowband and broadband deep-sky imaging"
astro = true
+++

This is what permits blind solving — solving an image that carries no coordinates at all. Without the flag, Tenrankai will not blind-solve arbitrary photos.

How an Image Gets Solved

An image is eligible for solving when either:

  1. It has an RA/Dec hint. The ra and dec fields in the image’s markdown sidecar give the solver a starting point. Coordinates parse from sexagesimal hour or degree forms as well as plain decimal degrees:

    +++
    title = "Orion Nebula"
    telescope = "Celestron NexStar 8SE"
    mount = "EQ6-R Pro"
    filters = "Ha, OIII, SII"
    total_exposure_time = 12.5
    ra = "05h 34m 32s"
    dec = "+22° 00' 52\""
    +++
    

    Note that RA/Dec come from the sidecar, not from EXIF.

  2. It has no hint, but it’s clearly an astro image — either the sidecar has a telescope field, or the folder (or an ancestor) is marked astro = true. Tenrankai then falls back to a blind solve, searching the star field without a starting position.

Anything else is skipped. Your landscape photos will never be blind-solved.

Solving happens on demand, once per image. The first hinted solve typically takes a few seconds. Blind solves additionally need a pattern index: with blind_index configured it’s memory-mapped almost instantly, and without it one is built from star_data on first use — a slower path that only covers bright stars, and won’t solve small fields. Either way the index is loaded once per process and reused.

Failed solves are remembered only in memory, so restarting the server gives them another chance — useful after you improve a catalog.

Persisted Solutions

A successful solution is written to the app-managed TOML sidecar beside the image — beach.jpg gets beach.toml. Your hand-written beach.jpg.md is never rewritten.

The sidecar stores the fitted WCS (crval, crpix, cd), quality metrics (matched_stars, rms_arcsec), the overlay objects with their pixel positions and ellipse geometry, and an objects_version stamp identifying the catalog that produced them.

Because the WCS is persisted, later work is cheap: when the object catalog changes, objects are reprojected through the stored solution in milliseconds rather than re-solved.

Transients, comets, and asteroids are never persisted. They’re projected live on every request, because discoveries keep arriving and minor bodies keep moving.

Keeping Catalogs Fresh

The transient and minor-body files are re-read whenever their mtime changes, so a cron job can keep them current without restarting the server:

# Refresh nightly
0 4 * * * seiza build-data transients -o /var/lib/tenrankai/astro/transients.seiza
30 4 * * * seiza build-data minor-bodies -o /var/lib/tenrankai/astro/minor-bodies.seiza

The star and object catalogs are loaded once at startup. After replacing an object catalog, restart Tenrankai — then either let overlays reproject lazily on first view, or regenerate them in bulk.

Regenerating Overlays

When the object catalog changes, persisted overlays can be reprojected in one pass:

# Reproject a gallery's overlays against the current object catalog
tenrankai astro regen -g main

# A specific site (defaults to "default")
tenrankai astro regen -g main -s clients

# Report what would change without writing anything
tenrankai astro regen -g main --dry-run

This walks the gallery’s persisted sidecars, skips any whose objects_version already matches the loaded catalog, and reprojects the rest through their stored WCS — no re-solving. It prints the object-count change per image and a summary of how many solutions were refreshed versus already current.

The same reprojection happens lazily whenever a stale image is viewed, so astro regen is a convenience, not a requirement.

Capture Dates and Transients

The capture date is what makes transients and minor bodies meaningful. Tenrankai takes it from EXIF, falling back to a capture_date field in the sidecar.

Transients are marked near capture when their discovery date falls between 365 days before and 30 days after the image was taken — a window wide enough to cover a supernova that was already up when you shot, and one discovered shortly after. Markers outside that window are hidden behind a “+N old transients” toggle, so a five-year-old image doesn’t get littered with today’s discoveries.

Comets and asteroids are only drawn when a capture date exists. Their positions are propagated to that exact moment, down to a magnitude limit of 18, and labeled with brightness and distance (V~11.4, 1.83 AU).

Reading the Overlay

ObjectMarker
Deep-sky objectCyan ellipse, oriented to its position angle
Named starYellow tick marks
Transient (supernova)Magenta diamond
CometTeal diamond with a dash pointing along the anti-solar tail
AsteroidOrange diamond with a dash along its motion trail

Labels combine catalog and common name (NGC 1976 · Orion Nebula) and nudge themselves to avoid collisions. An object whose ellipse swallows the entire frame isn’t drawn as an ellipse — it’s listed in a “Field within: …” note in the corner, so a wide-field shot inside a large nebula still tells you where you are.

Toggle overlays with the Objects (N) control beneath the image. The toggle state follows you into the desktop loupe and the mobile pinch-zoom view, and the controls are placed so they don’t fight with touch gestures.

Choosing Catalogs

A rich field can carry hundreds of catalogued objects, and labeling all of them at once is unreadable. Next to the Objects toggle is a Catalogs menu that turns individual catalogs on and off:

GroupContains
NGC / IC / MessierThe main deep-sky catalogs
Sharpless / vdBSh2- emission and vdB reflection nebulae
Dark nebulae (B / LDN)Barnard and Lynds dark nebulae
Supernova remnantsSNR entries
Wolf-Rayet starsWR entries
Stars (HD / named)Named and catalogued stars
UGC galaxiesUGC entries
PGC galaxiesPGC entries
Comets / asteroidsSolar-system bodies

The menu only lists the groups actually present in the image, so it stays short. Choices are remembered in your browser and carry across images and pages — turn off PGC galaxies once and they stay off while you browse. This is a viewer-side preference; there’s nothing for the operator to configure.

Overlays in Posts

Gallery images embedded in a post carry overlays too, as a compact Objects (N) pill over the embed, with the same Catalogs menu and the same remembered catalog choices as the detail page. This also works for a post’s hero image, provided the hero is referenced as a gallery image rather than a plain URL:

+++
title = "A Supernova in NGC 3310"
hero_image = "gallery:main:astro/ngc3310.jpg"
+++

Old transients are always hidden in post embeds — the pill shows the objects that matter for the image.

If you maintain custom post templates, note that the post-detail context now carries hero_image_gallery and hero_image_path; the hero overlay depends on them.

Permissions

The astro API and every overlay are gated by can_see_technical_details, the same permission that governs the rest of the technical metadata. Viewers without it simply see the image, with no toggle and no sky map.

API

GET /api/gallery/{name}/astro/{path}

Returns the solution and overlay as JSON: the WCS, scale_arcsec_px, rms_arcsec, matched_stars, and the object list with pixel coordinates, ellipse geometry, kinds, and a near_capture flag on each transient. An image that can’t be solved returns {"solved": false}.

Requires can_see_technical_details; returns 403 otherwise, and 404 when [astro] isn’t configured.

Sky Maps

Separately from plate solving, any image with ra and dec in its sidecar gets a Sky Position card on its detail page: an all-sky chart with the brightest stars and a crosshair at the target, plus links that open Aladin Lite and SIMBAD at those coordinates. This needs no catalogs and no solution — just the coordinates.

Troubleshooting

SymptomLikely cause
No Objects toggle anywhere[astro] missing, or star_data failed to load — check the startup log for a warning
Toggle appears, but no objectsobject_data not configured; solving works but there’s nothing to overlay
Image never solvesNo ra/dec in the sidecar, no telescope field, and the folder isn’t marked astro = true
Blind solving works on wide fields but never on narrow onesNo blind_index — the on-demand fallback only covers bright stars. Configure a prebuilt index
Log warns the blind index “was built from N stars”blind_index and star_data come from different catalogs; rebuild or re-download them as a matched pair
Blind solve is slow the first timeThe index loads once per process. Memory-mapping a prebuilt blind_index is near-instant; building the fallback is not
Server refuses to start with a config error[astro] rejects unknown keys — check for a typo’d key name
No supernova markerstransient_data not set, or the discovery falls outside the capture window — check the “+N old transients” toggle
No comets or asteroidsminor_body_data not set, or the image has no capture date in EXIF or sidecar
Overlays look stale after a catalog updateRestart (object catalogs load at startup), then run tenrankai astro regen -g <gallery>
Viewer sees no overlay at allMissing can_see_technical_details permission

Upgrading

Tenrankai currently builds against seiza 0.3.0. Existing catalog files keep working — the star, object, transient, and minor-body formats are unchanged from 0.2.x, so there’s nothing to rebuild. The blind pattern index is a new, additional file: if you want blind solving on narrow fields, fetch or build one and add blind_index to your [astro] block.

Next Steps