editor: add lean-to roof extensions and automatic drainage - #651
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>
Represent the host wall's curve as a true-arc descriptor (center + radius) in each managed node's local frame, replacing the scalar sagitta that was re-derived through three synthetic chords and ballooned the deck into a filled disc. Every consumer — deck, gutter, downspout outlet, posts/beam/ rafters, and the 2D floorplan — now sweeps one shared concentric circle, so the canopy hugs the arc as a thin band for any extent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| if (parametrics?.derive && node) { | ||
| const next = { ...node, ...patch } as AnyNode | ||
| patch = { ...patch, ...parametrics.derive(next, patch) } | ||
| patch = { ...patch, ...parametrics.derive(next, patch, node as AnyNode) } |
There was a problem hiding this comment.
Multi-edit skips derive previous
Medium Severity
derive now takes a previous node so resize locks can compare pre-edit values, and the single-node inspector passes it, but buildMultiNodePatches still calls derive(next, patch) only. Lean-to derive defaults previous to next, so multi-select projection/pitch/height edits apply locks against already-patched values and can preserve the wrong edge.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 732accb. Configure here.
Bend the shared corner post and corner rafter onto the wall arc like every other member, instead of placing them at raw flat arc-length coordinates. Identity for straight walls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address Cursor Bugbot findings: curved-gutter downspout mapping and prescribed eave-Y, nearest-gutter reuse on segment refresh, asymmetric overhang reach in roof-edge attachment, manual-mode no longer silently reattaches, terrain/slab changes now re-trigger lean-to reconcile, and multi-node patches derive from the pre-patch node. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| (prescribedGutterEaveY(gutter) ?? computeGutterEaveY(segment)) - | ||
| Math.max(0.04, gutter.size) | ||
|
|
||
| return Math.max(0.1, outletWorldY - groundY) |
There was a problem hiding this comment.
Downspouts ignore slab ground
High Severity
Automatic downspout length samples only persisted terrain (or 0) and never the slab under the drop. Posts already resolve slab support and level-base elevation, so pipes keep falling through decks and patios, and later slab moves are not treated as length dependencies.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit baaa4f2. Configure here.
Resolve the quality CI failure: apply Biome formatter to the downspout and gutter-refresh edits and sort the lean-to system imports. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The test assembles and renders a full gutter joint across ~127 angles, running ~5s and tripping bun's 5000ms default per-test timeout on slower CI hardware. Give it an explicit 30s budget; assertions are unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0c7eb6a. Configure here.
| leftMitre = mitreBetween(subj.minus, otherEnd) | ||
| } | ||
| if (rightMitre === 0 && planDistSq(subj.plus.pos, corner) <= CORNER_EPSILON_SQ) { | ||
| if (planDistSq(subj.plus.pos, corner) <= CORNER_EPSILON_SQ) { |
There was a problem hiding this comment.
Prescribed gutter mitres exit too early
High Severity
computeGutterMitres now seeds both ends from prescribed lean-to mitres and still breaks once both values are nonzero. Adjacent lean-to runs therefore stop scanning after the first sibling, overwrite a prescribed corner with a geometric hit inside the 10 cm epsilon, or skip the true mate. Joined eaves can get the wrong cut or keep a cap.
Reviewed by Cursor Bugbot for commit 0c7eb6a. Configure here.


What does this PR do?
How to test
bun dev, open the editor, create a building, and place lean-to extensions from the Build panel on both faces of a straight wall; verify previews snap correctly and the extension is selected after placement.bun run lint,bun run check,bun run check-types,bun run test, andbun run build.Screenshots / screen recording
Recording to be added — this is a visual and interactive change.
Checklist
bun devbun checkto verify)mainbranchNote
High Risk
Large cross-cutting change to scene mutations, roof drainage generation, and new lean-to assembly sync; bugs could corrupt child trees, duplicate/delete gutters incorrectly, or desync 2D/3D edits.
Overview
Introduces a
lean-to-extensionnode (wall child, clone remap for host roof refs, canvas selection proxy to the extension) and surfaces it under Build → Roof Features & extensions viapresentation.paletteGroup: 'roof-features'.Automatic drainage on roof segments:
autoGuttermetadata drives generated gutter runs (roof-type sides, trim/sibling clipping, lean-to edge exclusions),planAutomaticDownspoutsplacement, and default downspouts withlengthMode: 'to-ground'and terrain-aware length resolution. Store create/update/delete paths refresh gutters and downspouts while preserving manual gutters and nearest-run ID stability.Gutter/downspout modeling gains concentric
arcruns (geometry bend, outlet lookup, corner mitres), lean-to-prescribed eave height/mitres metadata, grid/magnetic length handles, and a downspout system that keeps automatic lengths in sync viaSceneApi.subscribeNodes/applyChanges.SceneApiexpands withcreateMany,applyChanges, andsubscribeNodes; floorplan affordances/move targets and registry move tools receivesceneApi. Parametricderivecan takeprevious; lean-to managed columns hide layout edits and trim handles.Roof segments add optional arc and shed infill fields; accessory kinds get dedicated palette icons. Editor polish: resize snap non-finite fallback, contextual helpers during arrow resize, disabled segmented controls.
Reviewed by Cursor Bugbot for commit 0c7eb6a. Bugbot is set up for automated code reviews on this repo. Configure here.