Skip to content

fix: restore wall plane-bound defaults (draft, panel, self-heal) - #630

Merged
wass08 merged 6 commits into
mainfrom
fix/wall-plane-bound-defaults
Aug 11, 2026
Merged

fix: restore wall plane-bound defaults (draft, panel, self-heal)#630
wass08 merged 6 commits into
mainfrom
fix/wall-plane-bound-defaults

Conversation

@wass08

@wass08 wass08 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes the fallout of the terrain-sculpt regression (#564-era) that detached walls from the plane-bound vertical model, across three layers:

  • DraftingcreateWallOnCurrentLevel no longer stamps the draft ghost's height/supportOffset/ground host onto walls drawn on flat ground or on slabs. Stamping is gated on drafted ground intent with sculpted terrain actually present (the terrain exception), so every other wall commits plane-bound: no stored height, top at the storey plane, base re-elected from slab support. Non-ground chains re-resolve the pointed surface per commit for supportCap.
  • Wall panel — the inspector is reworked around the vertical model: Top is "Follows level" (plane-bound, shows the resolved height) vs "Custom height" (slider, seeded from the effective height so geometry doesn't jump on detach); Bottom is "Auto" vs "Fill to terrain", and the infill toggle no longer materializes an explicit height. Both "Follows level" and "Auto" perform a one-click repair of regression-era walls: they drop the stamped draft offset and a ground host that no sculpted terrain supports. "Auto" fires even when already selected, so walls that display Auto while secretly ground-pinned heal in place, keeping their custom height.
  • Self-heal on load — the shared vertical canonicalization strips a terrain-less ground host (plus draft offset) when the un-pinned election would land the wall on a slab its base is currently embedded in — the buried state that z-fights the slab's side faces. Deliberately narrow: a wall intentionally grounded under a hovering deck is not buried and keeps its pin, and scenes with sculpted terrain are skipped wholesale (the pin is load-bearing there, and the live terrain field isn't visible to this pure, authority-shared pass).

Includes 2 drafting regression tests and 5 canonicalization tests. Suites: core 1004, nodes 944, editor 600 — green; turbo check-types 10/10.

How to test

  1. bun dev, open a project, draw a slab, then draw a wall on it with the 3D wall tool. Select the wall: Top should read "Follows level" and the persisted node should have no height/supportOffset/supportSlabId.
  2. Draw a closed room on flat ground (auto slab forms). The wall bases should land on the slab top — no striped z-fighting band at the base.
  3. Load a scene containing a regression-era wall (supportSlabId: "ground" + stamped height, buried in a room slab). On load the pin is stripped and the base lands on the slab, keeping the custom height.
  4. In the wall panel, toggle Top → "Custom height" (slider appears seeded with current height) → back to "Follows level" (height clears, base re-elects). Toggle Bottom → "Fill to terrain" and back to "Auto" on a flat scene: geometry is identical (infill is terrain-only).
  5. On a sculpted-terrain scene, confirm terrain-drafted walls still freeze their construction plane and "Fill to terrain" still fills down to the sculpted ground.

Screenshots / screen recording

N/A — validated via before/after base close-ups during development (z-fight band at the wall base gone once the ground pin is stripped); happy to attach a clip on request.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Medium Risk
Changes serialized wall vertical fields, load-time migration shared by editor and authority, and commit-time drafting behavior—high user visibility but narrow rules and solid test coverage.

Overview
Restores the plane-bound wall vertical model after terrain-sculpt-era regressions that stamped draft ghost data (height, supportOffset, supportSlabId: 'ground') onto walls that should stay storey-bound.

DraftingcreateWallOnCurrentLevel only freezes construction plane/height when the chain is a ground draft on sculpted terrain; flat ground and slab starts commit without stored height, offset, or ground host. The 3D wall tool re-resolves the pointed support surface on each segment commit except ground-hosted chains.

Load migrationmigrateVerticalSceneNodes strips terrain-less ground pins (and draft offsets) when slab election would bury the wall base in a floor slab; skips sculpted-terrain sites and preserves pins under hovering decks.

Wall panelTop is “Follows level” vs “Custom height”; Bottom is “Auto” vs “Fill to terrain”. Toggling back to storey/auto applies wallBaseRepairPatch to clear bogus offsets and ground hosts without terrain support.

Reviewed by Cursor Bugbot for commit 85c9229. Bugbot is set up for automated code reviews on this repo. Configure here.

wass08 and others added 6 commits August 11, 2026 11:03
The terrain drafting flow stamped the ghost's explicit height and a
supportOffset onto every wall whose frozen construction plane sat above
y=0 — i.e. any wall started on a slab or deck, not just ground-hosted
terrain chains. Such walls stopped following the level height and no
longer re-elected their base from slab support.

Gate the stamping on a ground-drafted plane (the terrain exception), and
re-resolve the aimed support surface per commit for non-ground chains so
a later segment still elects the slab it visibly crosses instead of
being capped at the first click's elevation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Top: "Follows level" (no explicit height, shows the resolved height) vs
"Custom height" (seeded from the effective height so geometry doesn't
jump on detach). Bottom: the terrain infill toggle no longer materializes
an explicit height, so toggling it can't silently detach the wall top
from the storey plane.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pointing at bare ground freezes a GROUND construction plane, and the
commit path treated every ground-preferred draft as a terrain chain:
stamped ghost height, persisted ground host, election capped at the
draft plane. On flat ground (no sculpted terrain) all three are wrong —
the wall showed "Custom height 2.50" instead of following the level,
and a slab drawn later could never lift it, leaving the wall buried in
the slab (z-fighting band at the base).

Gate the terrain exception on terrainSupportLift(): ground-preferred
drafts with no terrain support drop their draft options entirely and
commit plane-bound. The terrain-freeze test now seeds a real terrain
field; a new regression test pins the flat-ground shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…toggle

Switching Top back to "Follows level" only cleared the stored height,
so regression-era walls (stamped ground host + draft offset) kept their
base pinned at the level floor, still buried in any slab. The toggle now
also drops the draft offset, and drops a ground host when no sculpted
terrain supports it — giving existing broken walls a one-click repair.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The follows-level toggle repairs regression-era walls, but walls whose
Bottom already displays "Auto" while secretly ground-pinned had no
clickable path that kept their custom height — the pin isn't reflected
in the control, and the base stayed buried in the slab (z-fighting its
side faces). "Auto" now performs the same re-election repair (drop the
draft offset, drop a terrain-less ground host), and the segmented
control fires on already-selected clicks, so clicking "Auto" itself
heals the wall.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Regression-era walls carry supportSlabId 'ground', which short-circuits
slab election: the base stays at the level floor, buried in the room
slab and z-fighting its side faces, while the panel truthfully-but-
uselessly displays the base as automatic. Users shouldn't have to click
anything: the load-time canonicalization now strips the pin (and draft
offset) when the un-pinned election would land the wall on a slab its
base is currently embedded in.

Deliberately narrow so the one legitimate flat-scene ground pin
survives: a wall kept on the ground under a hovering deck is not buried
(the deck's occupied interval sits above the base) and keeps its pin,
and scenes with sculpted terrain are skipped wholesale — the pin is
load-bearing there and the live terrain field isn't visible to this
pure, authority-shared pass.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@wass08
wass08 merged commit f90c741 into main Aug 11, 2026
4 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 85c9229. Configure here.

? { supportSlabId: undefined }
: {}),
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repair clears terrain wall offsets

Medium Severity

wallBaseRepairPatch always clears supportOffset, even when it keeps a terrain-backed supportSlabId of ground. Clicking already-selected Bottom Auto (or Top Follows level) therefore drops the frozen construction offset on legitimate terrain-drafted walls, so the base jumps while the ground host remains.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 85c9229. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant