Skip to content

fix(web): keep starfield centred through zoom-out#219

Merged
JustAGhosT merged 1 commit into
mainfrom
fix/starfield-zoom-out-center
Jun 23, 2026
Merged

fix(web): keep starfield centred through zoom-out#219
JustAGhosT merged 1 commit into
mainfrom
fix/starfield-zoom-out-center

Conversation

@JustAGhosT

@JustAGhosT JustAGhosT commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Problem

Zooming out from a focused sun (Return to Stars / clicking the focused sun) ends with the whole starfield snapping sideways by ~sidebarWidth/2 (≈110px on desktop) on the final frame. Zoom-in was already centred (#212); zoom-out was not.

Root cause

In animate.ts the camera transform that shifts the view right by sidebarWidth/2 — so a focused sun lands in the centre of the visible area (right of the sidebar), matching the Zoom Out button at left: calc(50% + sidebarWidth/2) (#212) — was gated on cameraValues.zoom !== 1:

if (cameraValues && cameraValues.zoom !== 1) {
  const viewportCenterX = canvas.width / 2 + (props.sidebarWidth ?? 0) / 2;
  ...
}

The zoom-out target is zoom: 1. So the full sidebar shift stays applied right up to zoom = 1, then the transform switches off entirely on the settle frame → the field jumps left by sidebarWidth/2. That discontinuity is the "off-centre" snap.

Fix

Apply the camera transform continuously and ramp the sidebar offset from 0 at zoom = 1 to full by minSunFocusZoom (1.8):

const offsetFactor = clamp((zoom - 1) / (minSunFocusZoom - 1), 0, 1);
const viewportCenterX = canvas.width / 2 + (sidebarWidth / 2) * offsetFactor;
  • At zoom = 1, cx = cy = 0.5 the transform is the identity → the default view is pixel-unchanged.
  • At any focus zoom (1.8–3.0) offsetFactor = 1full offset → fix(web): center sun zoom + track the focused sun's live orbit #212's focused-sun centring is preserved exactly.
  • In between, the offset fades smoothly, so zoom-out settles with no jump.

The matching ctx.restore() guard is updated to stay balanced with the (now unconditional) ctx.save().

Scope / risk

  • One file, animate.ts (+24/-6). CSS/render-only; no behavioural change at either rest state (default or focused) — only the transition trajectory is smoothed. Cannot introduce a new snap.

Verification

  • Bug + fix confirmed by exact code reading and continuity math (snap was sidebarWidth/2; now continuous).
  • pnpm build:web green (deploy gate).
  • Final visual confirmation best done on the running site (headless canvas-zoom interaction wasn't drivable reliably).

Summary by CodeRabbit

  • Bug Fixes
    • Improved viewport centering and camera transform behavior for more consistent visual presentation when zooming and adjusting focus within the interface.

The focused-sun framing shifts the canvas right by sidebarWidth/2 so the
target sits in the centre of the visible area (#212). That transform was
gated on `zoom !== 1`, so the full shift applied right up to zoom=1 and then
vanished on the settle frame — snapping the whole starfield left by
sidebarWidth/2 at the end of every zoom-out.

Apply the camera transform continuously and ramp the sidebar offset from 0
at zoom=1 to full by minSunFocusZoom (1.8). Every focused state still gets
the full offset (#212 centring preserved); zoom-out now settles smoothly
with no jump. At zoom=1 / cx=cy=0.5 the transform is the identity, so the
default view is pixel-unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1925dc02-3442-4e8e-9ffa-e9653ed5d355

📥 Commits

Reviewing files that changed from the base of the PR and between ad7f01f and 632bf10.

📒 Files selected for processing (1)
  • apps/web/src/features/layout/components/Starfield/hooks/animation/animate.ts

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.


📝 Walkthrough

Walkthrough

The animation loop in animate.ts is updated to import CAMERA_CONFIG and replace the cameraValues.zoom !== 1 transform guard with an if (cameraValues) existence check. A zoom-dependent horizontal offset ramp (sidebarShift + offsetFactor) is computed from CAMERA_CONFIG.minSunFocusZoom. The canvas context restore condition is similarly updated to check cameraForRestore existence.

Changes

Starfield Camera Transform Guard and Sidebar Offset Ramp

Layer / File(s) Summary
Camera transform guard, offset ramp, and context restore
apps/web/src/features/layout/components/Starfield/hooks/animation/animate.ts
Adds CAMERA_CONFIG import; replaces zoom !== 1 transform guard with if (cameraValues) check and computes sidebarShift/offsetFactor from cameraValues.zoom and CAMERA_CONFIG.minSunFocusZoom; aligns the canvas context restore to depend on cameraForRestore existence rather than zoom !== 1.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Hop hop, the camera shifts with grace,
No longer gated by zoom's single place.
A sidebar ramp now smoothly appears,
cameraForRestore restores without fears.
The starfield aligns, the sun finds its spot —
One little guard change, but what a fine plot! ✨

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/starfield-zoom-out-center

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@JustAGhosT JustAGhosT merged commit b67d12b into main Jun 23, 2026
1 of 2 checks passed
@JustAGhosT JustAGhosT deleted the fix/starfield-zoom-out-center branch June 23, 2026 02:13
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