test+docs(nav): characterise cursor-anchored LB pan (KD-38) + rotate sky-grab guard - #1881
Merged
kfarr merged 1 commit intoJul 24, 2026
Conversation
…y-grab asymmetry LB pan is cursor-anchored (keeps the grabbed world point under the cursor), so its rate scales with the anchor's depth and it needs a valid on-cursor-ray anchor — the model behind the 3DStreet#1867 cursor-ray fallback, TH-80 zoom floor, and TH-81 reach cap, but never stated in the docs. Add KD-38 characterising it explicitly, plus the pan-vs-rotate degenerate-cursor asymmetry: on a sky grab (source==='fallback') pan uses the fallback POINT while rotate branches on source and orbits the screen-centre GROUND pivot, ignoring the point. Add a rotation regression test: Shift+LB over sky orbits fallbackCentre (y approximately 0), never the cursor-ray fallback point (y>1) — the rotate side of the sky grab; the pan side is already covered in the lbPan suite. - 02-key-decisions.md: KD-38 - 04-glossary.md: cursor-anchored-pan note pointing to KD-38 - ExperimentalControls.rotation.test.js: sky-grab asymmetry guard
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.
Follow-up to the recent navigation regression fixes (#1855 / #1859 / #1868). No runtime change — docs + one test only.
Why
Tracing #1867 (sky-grab pan lurch) back, the root is that LB pan is cursor-anchored: it grabs the world point under the cursor at mouse-down and keeps that point under the cursor for the whole drag (unlike legacy
EditorControls, whose pan rate was cursor-independent). That model was carried over from the original controls but was never written down as a decision — so its consequences (rate scales with anchor depth; a sky grab needs a synthetic anchor on the cursor ray; a near-zero-distance anchor degenerates) only surfaced as the #1867 / TH-80 / TH-81 fixes. This PR states the model explicitly and closes a test-coverage gap on the rotate side.Changes
docs/02-key-decisions.md— new KD-38. Characterises cursor-anchored LB pan and, crucially, the pan-vs-rotate asymmetry: on asource === 'fallback'(sky) grab, pan uses the fallback point (why it must lie on the cursor ray, regression: cannot pan up while looking out at the horizon and grabbing top half of screen #1867), while Shift+LB rotate branches onsourceand orbits the screen-centre ground pivot (_mapModePivot'sfallbackCentre), ignoring the point. So the two gestures degenerate differently at the same cursor position — a degenerate-cursor change must be checked against both.docs/04-glossary.md— a note on the LB "pan" terms flagging the cursor-anchored dependence, pointing to KD-38.test/.../ExperimentalControls.rotation.test.js— a regression guard for the rotate side of the sky grab: Shift+LB over sky orbitsfallbackCentre(y ≈ 0), never the cursor-ray fallback point (y > 1). The pan side is already covered by theExperimentalControls.lbPansky-grab tests (regression: cannot pan up while looking out at the horizon and grabbing top half of screen #1867); this guards the branch that keeps rotate immune to the same fault.Testing
ExperimentalControls.rotation.test.js: 3/3 green (2 existing + the new guard).pivot.y42.7 vs the< 0.5assertion), confirming the guard bites.srcchanges, so lint is unaffected.🤖 Generated with Claude Code