Panel-owned X-ray wall-mode takeover; export the headless engine surface - #2
Open
JonathanNus wants to merge 1 commit into
Open
Panel-owned X-ray wall-mode takeover; export the headless engine surface#2JonathanNus wants to merge 1 commit into
JonathanNus wants to merge 1 commit into
Conversation
…ss engine
Two changes a host needs:
1. The wall-mode takeover ('down' while X-raying) moves from the 3D
renderer to the panel. The renderer lives as long as the bones:framing
node does, so leaving the Bones tab kept the host's walls hidden — and
because wallMode is a persisted viewer preference, the stuck view
survived reloads, and merely OPENING a scene that contained an X-ray
node blanked the walls. The panel unmounts exactly when the user
leaves, which is the lifetime this intent actually has. The state
machine lives in view-takeover.ts (viewer-import-free, unit tested:
restore on leave, never stomp a user-picked mode, no ownership when
walls were already down). Also aligns with the plugin appearance
contract (#625): the renderer no longer writes host presentation state.
2. index.ts exports the pure derivation surface — computeLevel,
computeLevelUncached, computeTakeoff, cutList, the row/member types,
extractLevels/extractRoofs — so a host estimator can compute the same
quantities the panel shows without mounting anything.
computeLevelUncached is exported because a whole-building rollup loop
would otherwise thrash the 1-deep memo the panel and renderer share.
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.
The bug
Leaving the Bones panel keeps the host stuck in the X-ray view. The wall-mode takeover in
framing/renderer.tsxwritesuseViewer.setWallMode('down')from an effect whose cleanup is tied to the node's lifetime, but the intent ("get the walls out of the way while I'm looking at the X-ray") is tied to the panel's. Sidebar tab switches unmount the panel, not the renderer, so nothing restores — and sincewallModeis a persisted viewer preference, the stuck view survives page reloads. The sharpest edge: merely opening a saved scene that contains abones:framingnode blanks the host's walls before the user touches anything.This also runs against the plugin appearance contract (#625): the renderer was writing host presentation state, which the contract says plugins subscribe to read-only.
The fix
src/view-takeover.ts, viewer-import-free so it tests headlessly. Behaviours pinned by unit tests: restores the previous mode on release; takes no ownership when the user already had walls down; never stomps a mode the user picked while the panel was open; double-engage keeps the original mode.panel.tsxengages it while a live X-ray exists (seeThrough !== false) and releases on unmount — i.e. exactly when the user leaves.framing/renderer.tsxno longer touches host state; it only draws.Long term, a scoped, owner-tokened presentation override on
useViewer(push/pop) would be the contract-sanctioned way to do this — happy to discuss; this PR just makes the current behaviour match the current contract.Also: headless engine exports
index.tsnow exports the pure derivation surface (computeLevel,computeLevelUncached,computeTakeoff,cutList, row/member types,extractLevels,extractRoofs). The pipeline is already pure and fully tested headlessly; the exports let a host estimator compute the same quantities the panel shows — per level, without mounting anything.computeLevelUncachedis exported so a whole-building rollup loop doesn't thrash the 1-deep memo the panel and 3D renderer share. No behaviour change for existing consumers.Tests
499 pass, 0 fail (
bun test);tsc --noEmitclean. New:src/view-takeover.test.ts(6 tests).