fix(editor): scope slab room paint to the clicked slab's level - #592
Merged
Conversation
Space polygons are per-level footprints and stacked storeys share a footprint, so the upper slab's centroid sits inside the ground floor's space polygon. Room-scope paint on a ground-floor slab therefore also repainted the slab directly above it. Every other branch in resolvePaintScopeTargets already gates on space.levelId (resolveWallPaintSpace, connectedExteriorBoundaries, wallTargetsForBoundaries); the slab branch was the one that did not. Gate both the space lookup and the fan-out, matching how space-detection itself defines level membership (node.parentId === levelId). The existing slab fixture omitted parentId, which is why no test caught this — real slabs always have one, from both the slab tool and reconciliation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Room-scope paint on a slab spreads to slabs on other levels. In a two-storey building — where stacked floors share a footprint by definition — painting a ground-floor slab also repaints the slab directly above it.
Found while reviewing #554; this one is on
maintoday and unrelated to that PR.Cause
resolvePaintScopeTargetsgates onspace.levelIdin every wall path —resolveWallPaintSpace(paint-scope.ts:169),connectedExteriorBoundaries(:205),wallTargetsForBoundaries(:276). The slab path gated on nothing: it picked the first space whose polygon contains the slab's centroid, then fanned out to every slab whose centroid falls in that polygon, regardless of level.Since space polygons are per-level footprints and storeys stack, both lookups match the wrong level as readily as the right one.
Fix
Gate both the space lookup and the fan-out on the clicked slab's level, using
node.parentId ?? resolveLevelId(...)— the same definition of level membership space-detection uses (space-detection.ts:1532filters a level's slabs bynode.parentId === levelId).Why no test caught it
The existing
slab()fixture built nodes withoutparentId:So the level dimension was invisible to the whole slab suite. Real slabs always carry a parent —
packages/nodes/src/slab/tool.tsx:72callscreateNode(slab, levelId), and reconciliation creates them with{ node, parentId: levelId }. The fixture now takes a level (defaulting to'l1', so existing cases are unaffected).Added
slab room stops at the level boundary: two slabs with identical polygons onl1andl2, one space per level. Verified it fails against unpatchedpaint-scope.ts(["ground:surface", "upstairs:surface"]) and passes with it.Only
wallandslabdeclarecapabilities.paint.roomScope, and walls were already correct — so this was the only affected kind.Gates
check1600 files clean ·check-types9/9 ·test12/12, paint-scope 27 pass🤖 Generated with Claude Code
Note
Low Risk
Localized fix to paint target resolution with a regression test; no auth, data, or API surface changes.
Overview
Room-scope slab painting no longer bleeds onto slabs on other storeys when floors share the same footprint.
resolvePaintScopeTargetsnow resolves the clicked slab’s level (parentId ?? resolveLevelId) and uses it for both the space polygon lookup and the fan-out to other slabs—matching how wall room paint already gates onlevelId.Tests: the
slab()helper setsparentId(defaultl1), andslab room stops at the level boundaryasserts stackedl1/l2slabs with identical polygons only paint the ground slab.Reviewed by Cursor Bugbot for commit cd7f703. Bugbot is set up for automated code reviews on this repo. Configure here.