every frame is reproducible from a single integer. no noise lottery. no cloud. no GPU. no luck.
starforge --seed 260613 --preset neon-collapse — and it will look exactly like this on your machine too
most procedural art demos stop right before they become an artifact. and the "seed" is usually just noise: change it and you get a different smear of the same thing.
starforge is the opposite bet. the seed drives real structure — position, tilt, banding, horizon size, lensing strength, palette temperature — and the lensing is real closed-form physics, not a hand-drawn ring. it sweeps seeds and presets, scores each one with inspectable composition metrics, keeps the best, and renders a final poster plus a seamless animation.
then it does the thing nobody bothers with: a good render is reproducible from its seed, down to the byte. same seed, same preset, same size → the same pixels, every run, forever. that property is tested, locked, and treated as sacred.
it's a 1,900-line python lab. numpy does the math, pillow writes the frames. that's the whole stack.
pick with --subject. all four run on the same deterministic single-center lensing math.
each new subject draws its structure from a separate RNG stream, so adding one never shifts the locked black-hole genome. the black-hole path is byte-identical to v4.
the black hole genuinely bends light. closed-form, frame-invariant, precomputed once per render — no ray tracer, no GPU.
| piece | what it does |
|---|---|
build_deflection_lut |
tabulates the bending angle vs impact parameter — a strong-deflection log divergence at the photon sphere blended into the weak-field tail |
sample_emergent_ring |
the photon ring emerges from that divergence piling up at the photon sphere, instead of being drawn by hand |
build_disk_fold_map |
the gravitational fold that lays the disk's far side as a bright arc over the top of the shadow and curls a dimmer copy beneath |
build_einstein_lens_map |
a singular-isothermal-sphere lens (β = θ − θ_E · θ̂) — the same gather powers the galaxy's Einstein rings and the wormhole's throat |
the disk's secondary arc is the disk's own emission, re-gathered through the fold. the colour and texture stay consistent because it's the same light, bent.
this is the flex, and it's enforced, not claimed:
- one entropy source. a single integer seed. no global RNG anywhere — three explicit, non-overlapping streams (genome, subject structure, per-frame grain).
- a locked draw order. the genome's RNG sequence is pinned by a golden test. any new field must be drawn after the existing sequence, or CI catches the re-roll instantly.
- a pixel golden. small renders for every subject are hashed and pinned, so a deterministic-but-wrong visual change can't sneak through.
- a stable-hash salt. the preset salt is hand-rolled, not python's
hash(), becausehash()is randomized per process and would break reproducibility across machines.
seed ──▶ genome (locked draws) ──▶ renderer (LUTs + fold, built once) ──▶ frames
│
scoring ◀── curator ranks ◀──────────────────────────────────────┘
│
└──▶ best seed + preset ──▶ poster · gif · mp4 · webm · gallery · manifest
generation is the single source of truth. the curator only ranks — so a smarter ranker can drop in without ever touching how a render is made.
here's the honest problem: "the lab picks the best" only ever meant "best by one hand-weighted number." and that number is mostly a contrast meter — so on a cross-subject sweep it ranks every black hole above every galaxy, because black holes have bright braids on a black shadow and galaxies are soft glows. it's a black-hole-picker wearing a quality costume.
v7 fixes that. --studio writes a self-contained studio.html you open in any browser, offline:
- per-subject de-biased ranking — every candidate is scored against others of its own subject, so the standout wormhole stops losing to a mediocre black hole.
- the Pareto frontier — the non-dominated set across every metric. no single scalar can surface this; it's "the best of each kind, on its own terms."
- the metrics, exposed — a bar per metric, a "leads on ring · color" tag, and a toggle between the de-biased view and the raw v6 scalar so you can see exactly where they disagree.
- pin what your eye likes — pin or reject candidates and export a manifest. the machine sorts the frontier; you make the call.
it's a read-only pass over the rendered artifacts, so it changes nothing about how a render is made. determinism stays sacred.
# the black-hole release: sweep, score, pick the best, render the poster + loop
starforge \
--output release \
--width 1600 --height 2200 \
--frames 48 --seed 260613 \
--preset neon-collapse \
--batch 10 --top-k 6 \
--supersample 2 \
--video --scale-preview# a wormhole, ranked by the focal-subject curator
starforge --output release-wh --seed 909 --preset solar-wound --subject wormhole --batch 10 --curator studio
# sweep EVERY subject and rank a mixed gallery
starforge --output release-mix --seed 260613 --batch 12 --top-k 6 --cross-subjectno install needed — run it straight from the source tree:
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. python3 -m starforge.cli --output release --seed 260613 --batch 10| preset | feel |
|---|---|
event-horizon |
classic gold-black gravity well |
neon-collapse |
magenta, cyan, and hot accretion streaks |
cold-singularity |
blue-white, colder and sharper |
solar-wound |
aggressive orange solar tear |
deep-field |
purple deep-space survey plate |
| flag | effect |
|---|---|
--seed |
the starting point for the seed sweep |
--subject |
black-hole (default), lensed-galaxy, neutron-star, or wormhole |
--preset |
the visual colour system and rendering weights |
--seed-gallery |
candidates to score before the final render (single preset) |
--batch / --top-k |
sweep across all presets, keep the best k |
--cross-subject |
sweep every subject too and rank a mixed collection |
--studio |
write studio.html — the offline compare grid with the Pareto frontier and de-biased ranking |
--curator |
heuristic (contrast-led) or studio (rewards a clear focal subject) |
--width, --height |
poster dimensions |
--frames |
animation length |
--supersample |
poster supersampling, 1-3 (poster only) |
--video |
write mp4 + webm loops when ffmpeg is available |
--scale-preview |
keep the animation small while the poster stays full size |
a complete, self-contained release directory:
| file | what |
|---|---|
index.html |
a local lab page for the finished release |
studio.html |
the offline selection studio — frontier, de-biased ranking, pinning (with --studio) |
starforge_poster.png |
the high-resolution poster |
starforge.gif |
the animated loop preview |
starforge.mp4 / .webm |
cinematic loops, written through ffmpeg |
seed_gallery.png |
the scored candidate sweep |
collection_gallery.png |
the ranked top-k across every preset (and subject) |
manifest.json |
seed, selected genome, dimensions, curator, dependency versions, provenance |
# run the full regression suite (69 tests, determinism locked)
PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=. pytest -p no:cacheprovider -v
# validate a generated release
python3 tools/inspect_outputs.py releaseafter an intended visual change, re-bless the pixel golden:
PYTHONPATH=. python3 tools/regen_pixel_golden.pybuilt on numpy + pillow. runs on your machine, offline, every time.
architecture in ARCHITECTURE.md · where it's headed in ROADMAP.md · history in CHANGELOG.md




