Skip to content

Showcase camera: a ground-level orbit around the gem, tunable from Settings - #159

Merged
thalida merged 4 commits into
mainfrom
feat/showcase-ground-level-orbit
Aug 10, 2026
Merged

Showcase camera: a ground-level orbit around the gem, tunable from Settings#159
thalida merged 4 commits into
mainfrom
feat/showcase-ground-level-orbit

Conversation

@thalida

@thalida thalida commented Aug 10, 2026

Copy link
Copy Markdown
Owner

The project switcher's hero shot used to fit the whole city into the viewport from 20° up. Now it circles the root gem at street level, at a radius held constant across projects: a big repo just puts more city between you and the gem. The radius pulls in to the island's shorter half-extent so the orbit never swings the camera out past the edge.

The four knobs (elevation, azimuth, orbit radius, rotation speed) live in a new Showcase section under World, replacing five hardcoded SHOWCASE_* constants. Saving a change re-frames a running turntable in place, so you don't have to close and reopen the switcher to see it. Rotation speed is kept off that path: changing the speed should change the speed, not yank the orbit back to its starting azimuth.

Two things picked up along the way

Every World setting now stages into the footer. Camera and Showcase were the only write-through stores on a draft-backed tab, so their sliders applied on drag while every neighbor waited for Save, and Reset all skipped them outright (stageResetAll and anyResettable both bow out of autosave stores). They stage like the rest now, so the tab behaves one way throughout. The cost is the live drag preview those two had. A test over the World section list guards it.

Collapsed sections no longer build their controls. A collapsed section's body is display:none, so the ~150 sliders and pickers behind the World tab were being built on every pane open for nobody to see. The body mounts on first open and stays mounted. Mounting the World tab went from 1127ms to 16ms and the ControlsPane axe audit from 4.2s to 2.9s; both had started timing out in the pre-push container, where an a11y timeout also wedges axe-core for every surface after it.

Testing

3012 passing, plus tsc/eslint/prettier, on the host and in the pre-push container. Five new cases cover the orbit: pose from the store, the island clamp, re-framing on save, no movement outside the showcase, and speed-without-yank. Each was verified to fail when the behavior it covers is broken.

Worth a second look

The radius clamps to min(halfWidth, halfDepth) of the island, but the orbit is centered on the gem, which sits near the bbox edge rather than the island's center, so a circle of that radius can still leave the island on the far side. A center-aware clamp would shrink the orbit hard on big repos, so I left it as is.

🤖 Generated with Claude Code

thalida and others added 4 commits August 9, 2026 23:13
The switcher's hero shot used to fit the whole city into the viewport from
20° up. Now it circles the root gem at street level, at a fixed radius that
holds across projects: a big repo just puts more city between you and the
gem. The radius pulls in to the island's shorter half-extent so the orbit
never swings the camera out over open water.

The four knobs live in a new Showcase section under World. SHOWCASE is
autosave, so dragging one with the switcher open re-frames the backdrop as
you drag. Rotation speed is kept out of the re-frame path: changing it
should change the speed, not yank the orbit back to its starting azimuth.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The dialed-in values. The clamp test's fixture grows to match: its deep axis
has to stay clear of the default radius for the assertion to mean anything.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A collapsed section's body is display:none, so the ~150 sliders and pickers
behind the World tab were built on every pane open for nobody to see. Mount
the body on first open instead, and keep it mounted so reopening is free.

Mounting the World tab drops from 1127ms to 16ms, and the ControlsPane axe
audit from 4.2s to 2.9s. Both were timing out in the pre-push container,
where the a11y timeout also wedges axe-core for every surface after it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ncluded

Camera and Showcase were the only write-through stores on a draft-backed
tab. That meant their sliders applied on drag while every neighbor waited
for Save, and Reset all skipped them entirely: stageResetAll and
anyResettable both bow out of autosave stores.

They now stage like the rest, so the whole tab behaves one way. The cost is
the live drag preview those two had; the rig re-frames when the draft is
saved. A test over the World section list guards the invariant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thalida
thalida force-pushed the feat/showcase-ground-level-orbit branch from e2cd9f6 to b71c2ac Compare August 10, 2026 03:13
@thalida
thalida merged commit cf58b30 into main Aug 10, 2026
1 check passed
@thalida
thalida deleted the feat/showcase-ground-level-orbit branch August 10, 2026 03:18
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