Skip to content

feat(star-bin): plan 03 — runtime (registry, loader, star renderer)#442

Merged
rulkens merged 61 commits into
mainfrom
feat/gaia-star-bin-03-runtime
Jul 17, 2026
Merged

feat(star-bin): plan 03 — runtime (registry, loader, star renderer)#442
rulkens merged 61 commits into
mainfrom
feat/gaia-star-bin-03-runtime

Conversation

@rulkens

@rulkens rulkens commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Executes plan 03: the starCatalog registry row + settings, tier-aware fetcher/slot, pure octree draw-cut walker + f64 origin seam, vertex-pulling WESL star renderer, and the NEAR0 HDR layer with the Milky-Way-cloud crossfade.

Tasks 1–11 form a complete mergeable unit exercised on synthetic catalogs; Task 12 (visual bring-up + budget/crossfade tuning) is gated on the real Gaia fetch + build-stars run and may land as a follow-up.

  • Task 1 — Source.StarSource.FamousStar rename (value stays 21)
  • Tasks 2–11 — see the plan

🤖 Generated with Claude Code

Names the dedup story before the Gaia starCatalog survey row lands:
famous stars are the curated overlay, the Gaia bin is the survey —
mirroring the FamousGalaxy↔survey split. Key/const/type/discriminant
rename only; the numeric code stays 21 and the body renderer path is
untouched. Files moved via npm run move-files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 15, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
skymap 8223528 Commit Preview URL

Branch Preview URL
Jul 17 2026, 12:23 AM

rulkens and others added 28 commits July 15, 2026 23:12
…plan 03 Task 2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ow (plan 03 Task 3)

Appends the code, adds the tier-aware singleton row (draw budget +
crossfade band carried in-row as Task-12 tuning starting values), and
extends galaxyType's exhaustive non-galaxy throw group — the star survey
carries stellar, not galaxy, photometry. Also sweeps two FamousStar
rename prose stragglers from the Task 1 review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (plan 03 Task 4)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… GaiaStars rename

User decisions 2026-07-15: famous stars become a second starCatalog row
(bin + labels sidecar, future plan); more catalogs coming, so settings +
entries mirror the galaxy cluster shape (starCatalogs{enabled,items} keyed
by registry-derived StarCatalogId); Source.StarCatalog renames to GaiaStars
(Gaia-the-mission also ships galaxy content). 13 tasks after renumbering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…plan 03 task 5)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sk 6)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… (amendment 2026-07-16)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…6 review fix)

The 'tiered' field is a union-wide discriminant of SOURCE_REGISTRY (volume
rows carry literal values too), so the guard-narrowed entry collapses to
never in the untiered branch without the widening.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 10)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r build

V8 caps Set and Map at 16,777,216 entries; the real Gaia catalog streams
16,844,156 rows. Invert the GCNS dedup membership (track GCNS ids seen in
main, bounded by the 331k supplement) and carry truncation tags on the
candidate rows instead of an identity-keyed per-star side Map.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…er reload, progress wake (plan 03 task 7)

Also fixes the three initGpu.destroyReachability failures introduced by the
starCatalogRenderer construction (stub renderer mock, test-file only).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sk 11)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… surface (plan 03 task 12)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e tier search

One memoized size(k) map across all three tier binary searches dedupes the
expensive high-k prefix probes; selection is provably k-identical (exact L6
probes only decide). An injected onProgress sink narrates every probe and
tier completion on stderr.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ard (final-review fix wave)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stars now fade in while the Milky-Way cloud still dominates the view
instead of only inside 5 kpc; first-pass eye-tuning from real-data
bring-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ndary

The GCNS table's dist_50 column is in kpc (verified against parallax);
consuming it as parsecs placed ~217k supplement stars 1000x too near the
Sun with absolute magnitudes clamped to the faint end of the LUT.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sSection

Settings/UI half of the star-size control, mirroring galaxyCatalogs.sizePx
(default 2.5 px, range 1-8). The GPU plumb reads selectStarCatalogSize in a
follow-up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… round-trip

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… vertex ramp

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Peak intensity = EXPOSURE*flux/(K_GAUSS*rPx^2) makes integrated screen
luminance proportional to flux and radius-invariant, so refine/coarsen
swaps deposit identical light. Leaves stay point sources; aggregates fill
their box footprint so the far field blends into a continuous glow. One
knob: STAR_FLUX_EXPOSURE.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…plete and gated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 0.3 edge/dist refine proxy only split octree boxes subtending ~17°,
so the far field drew one glow per box at box pitch — a visible lattice.
0.05 (~3°) refines anything big enough to read as structure; budgets
raised so small/medium tiers can afford the deeper cut.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…TAR_FLUX_EXPOSURE scale

Second advanced slider (0.2–3.0, default 1.0, mirroring the galaxy
brightness twin's range). Plumbed settings → container → draw args →
StarUniforms byte 84 → vertex peak multiplier; identity at 1.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Overlap (shader)

Two advanced sliders to dial out the aggregate-box lattice by eye:
refineThreshold (0.01-0.30) parameterizes the walk's split criterion —
lower splits boxes into real stars earlier; glowOverlap (1.0-2.5)
scales aggregate glow radius past the box footprint (StarUniforms
byte 88), peak auto-conserves flux since it divides by final rPx^2.
Leaves untouched; both identity at their defaults.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
rulkens and others added 25 commits July 16, 2026 14:01
…hold 0.16

Tuned jointly: a coarser cut (0.16 ~ 9 degrees, up from 0.05) with 4x
glow overlap gives the same smooth far field at a much lower node
count than deep refinement with tight glows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… range 0.01–4

The exposure ramp now carries the cross-scale swing, so the 0.01–100
brightness range is no longer needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…200 pc

The Milky Way cloud rendered on the COSMO slab, whose near plane is
FIXED at 10 kpc — but its approach fade only starts at 8 kpc, so a
descent hard-clipped fully-opaque clumps before the fade could touch
them (fifth layer to hit this trap; same cure as the other four).

Moving to NEAR0 required two companions: the adaptive far plane now
pulls in on deep descents, so stars.wesl + dust.wesl clamp clip.z
inside it (the starCatalog trick — both passes verified depthless);
and the pick renderer becomes the sole NEAR0 pickable, so it now
self-binds its @group(0) pick camera instead of inheriting whatever
a prior COSMO pickable left bound (a hidden order-dependence that was
fragile before this change).

The approach band deepens to { fullAt: 0.002, goneAt: 0.0002 } — the
clumps stay through the descent and hand off to the real Gaia star
catalog (fully faded in inside 8 kpc) instead of vanishing above it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gh exposure

Every tint anchor has r = 1.0, so once a glow's additive contribution
exceeded displayable range the shared per-channel tonemap saturated red
first, then green: the whole far field collapsed to yellow-white and
the data's real colour structure (blue-white halo aggregates, reddened
disc plane at BP-RP ~2) vanished. The fragment now compresses the
SCALAR intensity through an exponential knee (KNEE * (1 - exp(-I/KNEE)),
KNEE = 8.0, eye-tunable) BEFORE the tint multiply, so channel ratios --
the hue -- survive arbitrary exposure. Linear below the knee, so the
photometric LOD invariance holds exactly in the faint regime; bright
cores still whiten, but by accumulation of many compressed glows, not
per-channel clipping of one. Opacity folds into I pre-compression (a
faded bright glow is a dimmed bright glow, not a re-dimmed compressed
one). Scoped to the star pass: galaxies/volumes keep their calibrated
look through the shared tonemap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The walker rebuilt a (level,morton)->index Map over ALL catalog nodes
on every call (~268k inserts/frame on the large tier, final-review
finding N1) and computed each node's angular priority twice (m7). The
new starOctreeIndex builds once per catalog at load and memoises: flat
Int32Array child links (O(1) resolution, no hashing), SoA box geometry
(Float64Array origins/edges), scalar node fields, and the subtree star
counts folded into the same pass. The hot loop touches only typed
arrays and a reused scratch heap; priority is computed once at push
and carried through the heap. Cut output verified identical old vs new.

Bench (stars-large, 268k nodes): 23-26 ms/call -> 0.008-0.019 ms near,
0.79 ms worst-case far camera.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User reports the loop keeps running after auto-rotate stops. Dev-only,
rate-limited: the frame tail logs which shouldKeepTicking arm is true,
and the scheduler tallies requestRender reasons per frame, logged when
the camera is inactive (catches wake paths that bypass the predicate).
Greppable marker: TODO(wake-probe) — remove after T13.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t kept RAF loop awake forever

The thumbnail PriorityQueue frees its in-flight slot in a .finally on
the fetcher promise, and fetchGalaxyBitmap ran bare fetch() calls with
no signal from the engine path — so one stalled cutout request (SDSS
ImgCutout / CDS hips2fits) never settled, the in-flight count never
returned to zero, and hasInFlightWork kept render-on-demand ticking
indefinitely (found via the T13 wake probe: thumbs=true, all else
false). Every tryFetch now runs under AbortSignal.timeout(30s) composed
with the caller's signal via AbortSignal.any; a timeout collapses to
the existing null/failure-memoisation path, and LRU eviction already
un-memoises for a later retry. The deadline lives in the fetcher, not
the generic queue: settlement is the fetcher's contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…abels toggle

The Labels section's tri-state master summed only LABEL_CATEGORIES, so it
never touched the Star names row; the Earth/planet captions had no toggle
at all (hardcoded always-on in foregroundLabelsLayer). The master now
counts every row the section renders, and a new labels.planetLabelsEnabled
(default on) gates the 'earth'/'planet' caption kinds exactly as
starLabelsEnabled gates 'star'/'sun' — through the temporal envelope, so
flipping either fades rather than pops. The foreground captions stay out
of SOURCE_ENTRIES: they are seeded scene bodies, not catalog sources.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The RAF-loop-won't-sleep bug is fixed (thumbnail fetch deadline in
fetchGalaxyBitmap) and confirmed; the dev-only reason tally in the
scheduler, the [wake] console probes in runFrame, and the string-reason
requestRender arguments they fed all come back out, restoring the
scheduler's no-argument contract.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The quantization grid divided the population bounding box — 98 kpc, set
entirely by LMC/SMC members and bad-parallax outliers while p99.9 of the
star-weighted mass sits within 11 kpc — into 512 cells, giving 192 pc
leaves and a 228k-star cell at the Sun whose LOD flip was a visible pop.
Dropping stars past 12 kpc and deepening the grid to 1024^3 (still within
the uint32 Morton field, no format bump) brings leaves to 23 pc and the
fattest cell to ~1.3k stars. Rust builder mirrored in its worktree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fixed-finest-grid octree made every occupied 23-pc cell a node, so
sparse regions minted millions of 1-2-star leaves: 4.37M nodes whose
16-byte table entries evicted ~5M stars from the gzip-budgeted large
tier. Subtrees holding <=64 stars now collapse into a childless fat
leaf at their level, records re-expressed in the coarser cell; dense
cells keep full 23-pc resolution. Large tier: 623k nodes, 12.85M stars
at G<=13.66.

Leaf-vs-aggregate therefore stops being 'level 0' and becomes
'childMask == 0' everywhere it was encoded: the subtree-count seed, the
layer's flux-multiplier push, and NodeParams.level -> isAggregate (the
glow-overlap and box-extent selects in the vertex stage). No format
bump: childMask, level, recordCount were already on disk. Rust builder
mirrored in its worktree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The leaf-capacity cut commits ~40k draws to fill the 1.5M-instance
budget, and both CPU costs scaled with that count: the walker round-
tripped every committed node through the best-first heap (7.2 ms), and
the renderer paid setBindGroup+draw per node (~9 ms encode).

Walker: children that cannot refine (childless or below threshold)
commit at the push site and never enter the heap — only refine
candidates get ordered, which preserves the cut exactly (once a parent
refines, every child draws regardless of budget). Priorities compare as
squared ratios (no per-node sqrt), and the output is a reused SoA
snapshot instead of 40k allocated objects. 7.2 ms -> 1.9 ms.

Renderer: NodeParams moves from a per-draw dynamic-offset uniform to a
per-source read-only storage array plus an exclusive prefix sum of
record counts; the vertex stage binary-searches the prefix by
instance_index to route itself to its node, and the whole cut draws as
one draw(3, totalInstances). Per-source buffers keep the
writeBuffer/submit ordering landmine at bay; the bind group is rebuilt
with the frame's exact size so arrayLength carries the draw count.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
toFixed(2) in Mpc units rounds every position inside ~5 kpc to 0, which
made the 'l'-key printout useless for communicating deep-zoom camera
poses. Target + distance now format with toPrecision(8) — significant
figures survive the full 1e-17..1e2 Mpc scale range and still paste as
plain numeric literals. Yaw/pitch/fov stay at 4 decimals (radians).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The supplement (faint nearby stars exempt from the tier apparent-mag
cut) all sits inside 100 pc, so the built bins carried a measured 2.2x
flux-density step at exactly that radius — a bright ball around the Sun
with a hard shell edge. Supplement rows now drop probabilistically from
full inclusion at 70 pc to none at 100 pc; the keep decision hashes the
star's Gaia DR3 source_id through splitmix64 (bit-identical in the TS
and Rust builders, top-53-bit float convention) so builds stay
deterministic and record-for-record comparable. Main-catalog rows are
untouched at any distance.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 15x/70x near/far exposure anchors were eye-tuned against older,
dimmer bins; the current bins carry far more local flux and need a live
retune. starExposureRamp is parameterized by (nearX, farX) — bit-
identical at the 15/70 defaults — and the two anchors become
settings.starCatalogs.exposureNearX/FarX with 'Exposure (near)' (1-60)
and 'Exposure (far)' (5-300) sliders in the Stars Advanced group. The
shader-baked near exposure (STAR_FLUX_EXPOSURE = 6000 = 400 x 15) is
named and handed back out by the CPU ramp, so the shader is untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Star catalogs now report their decoded starCount through the same
engineSourceCountReported -> sourceCounts path the galaxy surveys use
(fired on the slot's ready transition, so tier switches re-report), and
StarsSection renders the same formatted count span per catalog row —
absent entries render no chip rather than a misleading 0. Keyed per
catalog id, so future star bins inherit the chip automatically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two deep-zoom costs, one root cause each:

- STAR_GLOW_MAX_PX=384 caps the final glow radius (after sizeScale and
  overlap), bounding per-star additive fill at pi*MAX^2. Flux-conserving:
  the peak divides by the same clamped rPx^2, so total luminance is
  invariant — a compact bright core instead of a huge dim halo.

- produceMilkyWayLabel now rides the surveyDeepZoom fade band on the near
  side. The origin-anchored "You are here" stem is COSMO-slab content that
  cannot project once the camera descends inside the 10 kpc near plane;
  left emitting, it expanded into a near-degenerate screen-filling quad
  and kept the whole marker-lines pass alive at solar-system zoom. Culling
  it (gone by 2 kpc) empties the director's line set so the pass skips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mposite

The star-catalog pass was fill-bound: thousands of aggregate glow quads
(box footprint x glowOverlap 4.7, clamped at 384 px) additively summed to
78-139 full screens of overdraw at kpc-scale zoom — 12-20 ms GPU.

Split the cut into two streams sharing one memoised CPU walk
(prepareStarCut: walk + fade advance + childMask partition, once per
frame):

- Leaf stars (childMask == 0): unchanged — full-res into HDR, per-glow
  hue-preserving knee.
- Aggregates: LINEAR (fsLinear, no knee) into a new half-res rgba16float
  'star-aggregates' offscreen, alpha carrying the summed raw scalar; a
  fullscreen 'star-upsample' composite in the HDR step applies starKnee
  to the SUMMED field and adds the result.

Half-res per axis quarters the aggregate fill. Kneeing the summed field
also fixes the LOD compression asymmetry behind the overblown clump at
intermediate zoom: stacked sub-knee aggregate quads previously escaped
the compression that tames concentrated bright leaves (flux itself was
verified conserved — cut/truth 0.99 refined, 0.58 coarse). The knee
curve now lives in one WESL module (knee.wesl) imported by both the leaf
fragment and the composite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
starExposureRamp becomes a piecewise log-linear curve through three
anchors: near (1 pc, nearX), NEW mid (3 kpc, midX), far (10 kpc, farX).
The default midX = 57 sits on the old two-point curve at the 3 kpc knot
(15*(70/15)^(log10(3000)/4) = 57.23), so defaults reproduce the previous
look; pulling the new 'Exposure (mid)' slider (5-150) bends only the
middle segment.

Rationale: farX must stay high (~70) for whole-galaxy legibility at
>= 10 kpc, but a single near->far ramp forced by that value over-exposes
the dense central clump in the intermediate 1-6 kpc zone, which had no
lever of its own.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Foreground-body picking: blocked -> ready, both blockers shipped; stars
  first per user priority.
- New: improve planet rendering (needs-design), lower-res star-aggregate
  offscreen experiment (ready), bright clump at 5.9 kpc (deferred, with
  full diagnostic detail file).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wheel-zoom floor is now unconditionally 1e-17 Mpc (Earth-surface
scale) and the command palette's foreground-body rows (Earth, planets,
stars) always surface. The 0.05 Mpc releasable envelope and its
hasUrlGate('deepZoom') read are deleted; hasUrlGate itself stays for the
tour and gpuTimings flags. Stale gate mentions pruned from comments in
seven source files; surveyDeepZoom (the unrelated scale-fade band) is
untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The fetcher-written gaia.sha256 (gcns_main.csv + hip2.dat checksums,
written only after all count assertions pass) and the 2026-07-15 fetch
completion date — the committed post-fetch registry record, per the
DESI Task 11 precedent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DoD audit 2026-07-17: tests 4,124 PASS, typecheck PASS, all checkboxes
resolved (plan-01 Task 11 human attestations recorded inline; plan-02
real-data build satisfied via the byte-verified Rust pipeline, PR #443;
plan-03 small-tier mobile cap deferred to a backlog entry). R2 sync of
stars-{small,medium,large}.bin ran as part of the same gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rulkens
rulkens marked this pull request as ready for review July 17, 2026 00:28
@rulkens
rulkens merged commit 3c5ad44 into main Jul 17, 2026
2 checks passed
@rulkens
rulkens deleted the feat/gaia-star-bin-03-runtime branch July 17, 2026 00:28
rulkens added a commit that referenced this pull request Jul 18, 2026
Eight rungs flipped to "Built in skymap" now that their subsystems
landed on main since #401 opened:

- 10^21 Milky Way    → GPU star + dust point cloud (#408, impostor gone)
- 10^20 Orion Arm    → true-position Gaia star bin (#442)
- 10^17 nearest stars → Sun + Proxima at true parallax (#444)
- 10^12/10^11/10^10/10^8 planets, solar system, Earth+Moon → planet rendering (#445)
- 10^9  the Sun      → emissive scene-star sphere (#444)

10^19 Local Bubble downgraded research → buildable (star field renders;
the local dust volume is the remaining wiring). 10^7 Earth stays built
but its viz no longer claims the geolocation pin / atmosphere, neither
of which is rendered yet.

Each newly-built rung carries a `ref` link to the PR that shipped it,
rendered next to the badge — making the footer's "'Built in skymap'
links point at the subsystem" promise real.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant