editor: keep room surfaces in sync with wall topology - #554
Conversation
Items (e.g. solar panels) can now be placed on sloped roof surfaces. The placement system computes euler rotation from the roof surface normal so items sit flush on the slope instead of going inside. - Add roofStrategy to placement-strategies with enter/move/click/leave - Wire roof:enter/move/click/leave events in the placement coordinator - Add calculateRoofRotation in placement-math using surface normals - Support full 3D cursor rotation for sloped surfaces - Items on roofs are parented to the level with world-space rotation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7e6bd1d. Configure here.
| beforeNode?.type === 'wall' && beforeNode.parentId === levelId ? beforeNode : null | ||
| if (!sameIndexedWall(cached.walls.get(wallId), beforeWall)) { | ||
| return { level: this.rebuildLevel(levelId, beforeNodes), fallback: true } | ||
| } |
There was a problem hiding this comment.
Index treats new walls as stale
Medium Severity
sameIndexedWall compares missing walls with left === right, but the cache lookup returns undefined while the before-state path normalizes absence to null. For any newly created wall ID, that mismatch makes ensureBeforeLevel discard the spatial index and rebuild the whole level, so divider inserts take the fallback path instead of the indexed reconcile the PR is built around.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7e6bd1d. Configure here.
|
Thanks for the depth here — the topology-delta approach is the right idea, and I can't merge it as it stands. There's one blocking correctness problem, and the shape of the PR makes it hard to land even once that's fixed. Both are addressable. Blocker: reconciliation writes are invisible to collaboration
const unsubscribeCommits = subscribeSceneCommits(processCommit)and isProcessing = true
pauseSceneHistory(sceneStore)
try {
for (const [levelId, wallIds] of changedWalls) {
const topologyDelta = topologyIndex.applyWallDelta(…)
const spaces = reconcileWallTopologyDelta(levelId, topologyDelta, commit.current.nodes, sceneStore)Commits originate from zundo's // packages/core/src/store/use-scene.ts:1605
onSave: (pastState, currentState) => {
notifySceneCommit({
origin: 'local',
before: sceneHistorySnapshotFromState(pastState),
current: sceneHistorySnapshotFromState(currentState),
})
},So reconciliation's writes land after // apps/community — use-project-scene-collaboration.ts:552
const diff = deriveSceneOperationChanges(commit.before, commit.current)Anything reconciliation mints is therefore never transmitted. I measured it rather than inferring it. Same harness — four walls closing a room, capture every commit, compare against the live store: On On this branch:
Worth being explicit: this is a regression the PR introduces, not a pre-existing gap it happens to expose. The store-subscription approach on The fix is structural, not a patch: reconciliation either has to write inside the same commit that triggered it, or emit its own commit that collaboration can pick up. Either is a real design decision, which is why I'd rather it not ride along inside a 4,700-line change. Why I'd like this splitSetting the blocker aside, the branch is hard to review or land as one unit:
Concretely, what I'd merge quickly:
I've opened #586 for the collaboration-visibility contract so the design discussion has a home and isn't a review thread on a large PR — reconciliation-generated nodes needing to be transmittable is a constraint that applies to anything in that path, not just this branch. It also proposes the regression test that would have caught this automatically, since right now the invariant is enforced only by call ordering. Closing for now to keep the queue honest about what's actionable, not as a rejection of the work. Open #1 as a fresh PR and I'll review it promptly — a focused |
|
Following up because I owe you a correction on the advice I closed this with. I said part 1 — Framing first, because it affects how urgent any of this is: none of this code is on Method, so you can weigh each claim: every defect below was reproduced by executing code at 1. Draft subdivision has no per-span minimum length —
|


What does this PR do?
Keeps room walls, generated slabs, and generated ceilings aligned as wall topology changes.
Wall topology
Slabs and ceilings
Scoped reconciliation
Editor behavior
@pascal-app/core; editor tools only apply the resulting atomic scene changes.How to test
bun run check,bun run lint, andbun run check-types.Validation
bun run check,bun run lint, andbun run check-typespass.Checklist
mainNote
High Risk
Touches core wall topology, scene history commits, and automatic slab/ceiling reconciliation—behavior that affects every floorplan edit, undo/redo, and load path.
Overview
Adds
wall-topologyplanning in core so wall inserts/splits (straight or curved, including crossings) land as one atomic scene change, with doors/windows/items kept on the right segment and duplicate/covered segments rejected.Space detection no longer keys off coarse level structure hashes; it listens to scene commits (with
changedNodeIds) and reconciles only rooms near edited walls via an in-memoryRoomTopologyIndex. Auto slabs/ceilings split and merge with rooms—carrying materials, heights, and openings (including clipped stair/elevator holes)—while incompatible merged surfaces are demoted to manual instead of forced union. User-deleted generated surfaces stay gone across later edits, reload, and undo/redo; load does not backfill missing auto surfaces.The editor wires
onSpacesChangedinto space sync, aligns 2D wall-chain stop/continue with the mounted tool (including rejected commits), and exports topology helpers pluscreateDefaultSceneSnapshotfrom core.Reviewed by Cursor Bugbot for commit f018494. Bugbot is set up for automated code reviews on this repo. Configure here.