fix(viewer): clear pendingCameraRotation on a session reset - #3375
fix(viewer): clear pendingCameraRotation on a session reset#3375BIMvoice wants to merge 1 commit into
Conversation
resetViewerState reset cameraRotation to its default but left pendingCameraRotation holding the outgoing model's value. If the next model's Viewport then calls setCameraCallbacks before any new rotation is set, cameraSlice's existing replay path (setCameraCallbacks reads pendingCameraRotation and calls setCameraRotation with it) applies the outgoing model's stale rotation onto the freshly reset camera. Add pendingCameraRotation to cameraTeardown's owns array and its session-reset patch, alongside cameraRotation. Update the doc comment above cameraTeardown, which claimed pendingCameraRotation was deliberately unowned "renderer/host wiring that outlives a file swap" — that was true before this fix and is false after it. Fixes #3364. Note for whoever merges next: PR #3367 (branch fix-2934-embed-controls) touches the same four spots — cameraTeardown's owns array and reset patch in cameraSlice.ts, and PINNED_SESSION_RESET_KEYS / PINNED_OWNED_KEYS in teardown-registry.test.ts — adding interactionMode and pendingInteractionMode. The correct merge resolution keeps all three fields (interactionMode, pendingInteractionMode, pendingCameraRotation), never one side taken wholesale. Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
|
Warning Review limit reached
This review includes 3 billable files and costs up to $0.75. Or wait 17 minutes for your next included review. View limit detailsLimit details: You’ve used all 2 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Comment |
Viewer benchmark⚠ 1 metric(s) exceeded the regression threshold (advisory only, not blocking). 01_Snowdon_Towers_Sample_Structural(1).ifcBaseline recorded 2026-07-01T20:31:05.538Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.
AC20-FZK-Haus.ifcBaseline recorded 2026-07-01T20:30:59.972Z on github-actions ubuntu-latest, viewer-benchmark-ci (headless Chrome, SwiftShader ANGLE), production build.
Refresh the baseline from a CI run: dispatch the Benchmark workflow with |
Summary
resetViewerStateresetcameraRotationto its default but leftpendingCameraRotationholding the outgoing model's value.cameraSlice's existing replay path (setCameraCallbacksreadspendingCameraRotationand, if set, callssetCameraRotationwith it — meant for a rotation set before the renderer registered) then applies the outgoing model's stale rotation onto the freshly reset camera, if the next model'sViewportcallssetCameraCallbacksbefore any new rotation is set.cameraTeardown'sownsarray and session-reset patch never includedpendingCameraRotation, so a session reset couldn't clear it.Fixes #3364.
Family context
This is the fourth instance of "model-relative state survives a teardown because a field is missing from the slice's clear-list" (after #3367, #3371, #3372).
Overlap with PR #3367 (
fix-2934-embed-controls, still open): it edits the same four spots this PR does —cameraTeardown'sownsarray and reset patch inapps/viewer/src/store/slices/cameraSlice.ts, andPINNED_SESSION_RESET_KEYS/PINNED_OWNED_KEYSinapps/viewer/src/store/teardown-registry.test.ts— addinginteractionModeandpendingInteractionMode. Whichever of these two PRs merges second will conflict on those four spots. The correct resolution keeps all three fields —interactionMode,pendingInteractionMode, andpendingCameraRotation— never one side taken wholesale.This PR also updates the doc comment above
cameraTeardown, which claimedpendingCameraRotationwas deliberately unowned ("renderer/host wiring that outlives a file swap"). That was true before this fix and false after it, so the comment is corrected rather than left contradicting the code.Test plan
cameraSlice.ts(source, not the test files) viagit stash push --keep-index -- apps/viewer/src/store/slices/cameraSlice.ts, ran the newcameraSlice.test.tscases — 2 fail / 5 pass — then restored by exact stash SHA (git stash apply <sha>+git stash drop, never a bare pop).npx tsx --import ./src/test/vite-module-hooks.mjs --test --test-timeout=120000 --test-concurrency=1 src/store/slices/cameraSlice.test.ts src/store/teardown-registry.test.ts src/store/teardown.idempotence.test.tsfromapps/viewer— 14/14 pass.node scripts/check-module-size.mjsexits 0.PINNED_SESSION_RESET_KEYSandPINNED_OWNED_KEYSinteardown-registry.test.tsupdated in the same commit (alphabetically,pendingCameraRotationbeforependingColorUpdates).git status --porcelainclean before pushing.🤖 Generated with Claude Code
https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436