editor: add lean-to roof extensions and automatic drainage - #651
editor: add lean-to roof extensions and automatic drainage#651sudhir9297 wants to merge 44 commits into
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>
… github.com:pascalorg/editor
| : wallSpanningLeanTo | ||
| : attachment | ||
| ? applyLeanToRoofAttachment(leanTo, attachment) | ||
| : clearLeanToRoofAttachment(wallSpanningLeanTo) |
There was a problem hiding this comment.
Manual mode reattaches automatically
High Severity
In resolveEffectiveLeanTo, a lean-to left in connectionMode: 'manual' is still magnetically reattached whenever a nearby roof edge is within ROOF_EDGE_REATTACH_TOLERANCE. That path calls applyLeanToRoofAttachment, which forces connectionMode back to auto and restores host roof fields. Inspector-driven manual mode therefore cannot stick under a typical eave, so host gutter suppression and attachment locks flip back on after the next sync.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit b840058. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9709342. Configure here.
| const levelElevations = getLevelElevations(nodes) | ||
| const wallLevel = wall.parentId ? levelElevations.get(wall.parentId) : undefined | ||
| const halfSpan = | ||
| leanTo.span / 2 + Math.max(Math.max(0, leanTo.leftOverhang), Math.max(0, leanTo.rightOverhang)) |
There was a problem hiding this comment.
Asymmetric overhangs skew edge exclusion
Low Severity
Attachment overlap and hostRoofEdgeRange are computed with a symmetric halfSpan that uses the larger of leftOverhang and rightOverhang on both sides, while layout offsets the roof with roofCenterX for true asymmetric overhangs. Uneven side overhangs therefore claim the wrong portion of the host eave and can suppress or keep host gutters incorrectly.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 9709342. Configure here.


What does this PR do?
How to test
bun dev, open the editor, create a building, and place a lean-to extension from the Build panel against a straight exterior wall; verify the preview snaps to the wall and the extension is selected after placement.bun run check-types,bun run check,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 (automatic child create/delete on roof/lean-to edits) and derived geometry; bugs could corrupt drainage graphs or orphan nodes, though coverage includes extensive tests.
Overview
Adds wall-hosted lean-to extensions as a first-class structure kind: placement and move on walls (3D + floorplan), managed child assembly (shed roof segment, columns, gutter/downspout), roof-edge attachment, and exposure under Build → Roof Features & extensions via
paletteGroup: 'roof-features'.Introduces automatic gutters and downspouts for roof segments (
autoGuttermetadata): eave runs derived from roof type/trim/sibling segments, split around intersecting geometry and lean-to host-edge exclusions, withplanAutomaticDownspoutsplacing outlets and terrain-awareto-groundlengths. Store create/update/delete paths reconcile generated gutter/downspout nodes while preserving manual edits and IDs where possible.Platform/editor wiring:
SceneApigains batchedcreateMany/applyChanges/subscribeNodes; registry tools receivesceneApi+activeLevelId; floorplan affordances/move targets can mutate viasceneApi; parametricderivemay receiveprevious; clone remapshostRoofId/hostRoofSegmentId. Gutter/downspout handles add grid/magnetic snap; a downspout system keeps automatic lengths in sync after scene changes.Reviewed by Cursor Bugbot for commit 9709342. Bugbot is set up for automated code reviews on this repo. Configure here.