spike(camera): video-recording showcase drivers (cosmic-flows + named cosmic web)#354
Draft
rulkens wants to merge 16 commits into
Draft
spike(camera): video-recording showcase drivers (cosmic-flows + named cosmic web)#354rulkens wants to merge 16 commits into
rulkens wants to merge 16 commits into
Conversation
Three priority-80 CameraDriver spikes for recording promo clips of the
renderer, gated behind URL flags and toggled with `g`:
- ?flyout log-dolly pull-back MW -> horizon shell (~29500 Mpc)
- ?floworbit seamless orbit + gentle pitch-bob
- ?flowshow choreographed multi-beat "cosmic flows" hero clip that
owns both the camera and the scene/layer state
These also scout the parked guided-tour feature. Findings written up in
docs/research/2026-06-19-camera-animation-spike-findings.md (driver owns
choreography, fade-through-FadeRegistry to dodge the settings-store
staleness bug, log-space dolly, storyboard grammar). Label-declutter
flicker under camera motion captured in BACKLOG.
THROWAWAY: the driver code + the settingsStore threading through
BootstrapDeps/engine.ts/startLoop and the ?nodeclutter gate are not meant
for main; this branch is kept only as a reference capture. The doc + the
BACKLOG note are the parts worth carrying forward.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#345) The zustand settings store was migrated to Redux Toolkit, injected at the app root and reachable as `cb.store` (AppStore). That deletes the spike's whole BootstrapDeps.settingsStore thread: - drop the `settingsStore?` field + its (now-moved) import from BootstrapDeps - drop the `settingsStore` entry from engine.ts's bootstrapDeps literal - startLoop reaches the store via `deps.cb.store` instead - retype the flowshow driver's `store` param zustand SettingsStore -> AppStore - guard `window` in startLoop's optional `?flyout`/`?floworbit`/`?flowshow` value reads so the node-env phase unit tests stop throwing The handle setters (setFlow/setVolumes/…) still take `(state, store, patch)`, so the driver's scene-setup calls are unchanged. Typecheck + tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PR #352 dissolved the engine `handles/setX` setters into reconcile sagas. The flowShowcaseDriver still imported the deleted `setFlow` / `setVolumesEnabled` / `setFilamentsEnabled` / `setGalaxyCatalogLabelEnabled` handles, which broke the dev bundle after merging main. Dispatch the equivalent settingsSlice actions instead — the reconcile sagas now fire the side effects (requestRender, syncVisibilityFades, flow reseed) the old setters used to. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
skymap | 081b6ef | Commit Preview URL Branch Preview URL |
Jun 20 2026, 10:43 PM |
A second throwaway recording driver for the "named cosmic web" social clip: slow-orbit the local structure neighbourhood while cluster/SC/void rings + labels sweep through, ease the camera out to Virgo, then fire structure focus (the double-click gesture) to isolate Virgo's members — non-members fade to ~8% via the existing GPU cone-search. Gated on ?webshow (=<panMpc> overrides the opening orbit distance); press g in-app to run a take. Isolation is triggered through the current selection seam (state.subsystems.selection.setFocused); a one-line retarget when PR #350 folds selection into the Intent store. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The structure store keys anchors as `${category}-${seed.id}`, so Virgo is
`cluster-virgo-m87`, not `virgo-m87`. The wrong id resolved to null, which
(both the target-lerp and the dolly being null-guarded) froze the camera at
the pan distance — no approach, no isolate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The findIndex-by-id + buildGalaxyInfo lookup that turns a famous id into a resolved GalaxyInfo was hand-rolled inside selectFamous; the recording drivers want the same resolve. Pull it into one helper (null guards — cloud not loaded, unknown id — in a single place) and route selectFamous through it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
After isolating Virgo's members, the clip now log-dollies from the cluster framing down to M87's focus distance so its curated thumbnail resolves — the "named web → one real galaxy" payoff. Virgo stays focused (a galaxy focus would cancel the isolation), so M87, a member, holds bright while the rest of the sky stays dimmed. Resolves M87 via the shared resolveFamousGalaxy helper. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Focus isolates a structure's members (non-members dim to ~8%) but a galaxy focus dims nothing. Captured as a surfaced issue with the essential-vs- accidental question to resolve before acting, noted while the webshow spike worked around it (M87 dive keeps Virgo focused). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…spike # Conflicts: # src/services/engine/engine.ts
Three tuning changes to the ?webshow named-cosmic-web driver: - Fire the Virgo focus the instant the approach settles (CLICK_DELAY_SEC 0.8 -> 0), so the isolation lands on the same beat as the camera arriving rather than after a pause. - Collapse the two cluster framings into one. The approach landed at ring framing (1.8x) but the dwell then dollied past it to close framing (0.9x), so the click's resting spot never matched where the approach arrived. The dwell now HOLDS the ring framing the approach landed on; the M87 dive starts from there. - Lift the isolation at the end of a take: after a 4 s wait orbiting M87, dispatch updateSelectionFocus(null) so the dimmed background fades back in, then release. A full take now self-cleans, so no reload is needed between takes (an aborted take still latches). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…spike Brings in the camera-pose-as-derived-state refactor (#357) + the focus-tween fold into watchFocusTween (#358). The CameraDriver contract changed from a mutating apply(cam, nowMs) to a pure pose(s, cam, elapsedMs) that RETURNS a CameraPose; assembleOrbitCamera derives position from it. Migrated the four throwaway spike drivers (webshow / flowshow / flyout / floworbit) to the new contract: - apply(cam) mutation -> pose() returning a fresh CameraPose; no more updatePosition (the resolver derives position via assembleOrbitCamera). - Self-clock via performance.now(): the driver-table elapsed clock (elapsedForWinner) only serves the 'tween'/'autoRotate' ids, so any other driver id receives elapsedMs === 0. - Self-sustain the loop: shouldKeepTicking reads camera liveness off the store (drag/tween/autoRotate), so a spike driver gating on local phase is invisible to it; each driver now pokes requestRender() per frame or the take freezes after one tick. - priority 80 -> 90: orbitDrag now occupies 80, so the takes move above the store movers to keep owning the camera. - Drop the fovYRad set (CameraPose carries no FOV); framing reads the live projection FOV off the forwarded cam. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tRender After the pose-as-derived-state merge, each throwaway spike driver had to poke requestRender() every frame to stay alive, because shouldKeepTicking derives camera liveness from STORE flags (selectCameraActive) and a spike driver moves the camera without touching the store — so it was invisible to the keep-tick gate. Move that responsibility to runFrame, which already resolves `activeId`: keep ticking whenever a non-`resting` driver owns the frame. For the built-in drivers this coincides with selectCameraActive (behaviour preserved); it ALSO covers any driver that animates the camera outside the store — today's recording spikes, the tour driver later. The drivers go back to being pure pose producers; the per-frame requestRender is gone (the `g`-keypress wake stays — that's a real input channel). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…r requestRender" This reverts commit b6aa945.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Throwaway camera spike (
worktree-fly-to-edge-spike) for recording skymap hero clips. Opened as a draft — it carries spike-only camera drivers and is not meant to land as-is. Branch is caught up withmain.Recording drivers (URL-gated in
startLoop.ts)?flowshow— choreographed "cosmic flows" hero clip (24 s;?flowshow=<mpc>sets the pull-back distance).?webshow— named cosmic web clip (this round): slow-orbit the local structure neighbourhood while cluster/SC/void rings + labels sweep through, ease the camera out to Virgo, then fire structure focus (the double-click gesture) to isolate Virgo's members — non-members fade to ~8% via the existing GPU cone-search.?webshow=<mpc>overrides the opening orbit distance.?flyout=<sec>,?floworbit— earlier camera drivers.For both showcase drivers:
hto home, ensure the scene is framed,Tabto hide UI,gto start (2 s static pre-roll to hit record). Reload between takes.Also in this branch
main(reconcile-sagas +uiroot slice, PRs docs(spec): fold app-level UI state into auiroot slice #348–refactor(engine): dissolve settings handle setters into reconcile sagas #352).flowShowcaseDriver+ newwebShowcaseDriverscene toggles tosettingsSliceactions (PR refactor(engine): dissolve settings handle setters into reconcile sagas #352 dissolved thehandles/setXsetters into reconcile sagas).state.subsystems.selection.setFocused); a one-line retarget when PR Fold galaxy selection into the RTK Intent store (ADR 0007 first fold) #350 folds selection into the Intent store.🤖 Generated with Claude Code