editor: improve roof materials, drawing, and intersections - #690
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
Clip entering roof segments against their host without removing host surfaces.
| if (plan.slope) { | ||
| const { tail, head } = plan.slope | ||
| const visibleSlope = clipLineByCutters([tail, head], cutters).at(-1) | ||
| if (!visibleSlope) continue |
There was a problem hiding this comment.
Shed slope keeps last fragment only
Medium Severity
After clipping a shed slope against overlapping roofs, the plan draws only the last remaining segment via .at(-1). When a host cuts through the middle of a shed, the other visible run and its arrow are dropped, so the 2D plan no longer matches the trimmed 3D roof.
Reviewed by Cursor Bugbot for commit 9d72e22. Configure here.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
There are 3 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 11878fa. Configure here.
| ) | ||
| } | ||
| label={showTrimPlanes ? 'Done editing' : 'Edit footprint'} | ||
| onClick={() => (showTrimPlanes ? handleBack() : handleTrimEditing(true))} |
There was a problem hiding this comment.
Done editing leaves the segment
Medium Severity
The Done editing control calls handleBack, which deselects the segment and selects the parent roof. Turning off trim-plane editing therefore exits the segment inspector instead of just clearing showTrimPlanes.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 11878fa. Configure here.
| ? new THREE.Matrix4().multiplyMatrices(targetSegmentInverse, siblingInTargetRoof) | ||
| : siblingInTargetRoof | ||
| csgGeometry(siblingBrushes.innerBrush).applyMatrix4(relativeMatrix) | ||
| siblingBrushes.innerBrush.updateMatrixWorld() |
There was a problem hiding this comment.
Cutter BVH not rebuilt
Medium Severity
After baking a sibling interior into the target roof with applyMatrix4, the cutter is not run through prepareBrushForCSG. Intersection CSG can keep using a bounds tree built in the sibling’s original space, so clipping fails or is incomplete once roofs are offset or rotated.
Reviewed by Cursor Bugbot for commit 11878fa. Configure here.


What does this PR do?
How to test
bun dev, create each supported roof accessory, and use Painting to apply different materials to its separate parts; confirm texture scale remains consistent.Screenshots / screen recording
A screen recording will be added for the visual and interactive changes.
Checklist
bun devbun checkto verify)mainbranchNote
Medium Risk
Broad changes to roof plan intersection rules, merged-roof visibility during edits, and material migration affect core authoring and rendering paths, though covered by new unit tests.
Overview
Adds per-part material slots for gutters, downspouts, and several roof vents (base/top, body/roof, hood/front, etc.), with scene migration from legacy
*MaterialPresetfields and renderers resolvingnode.slotsviaslot-paint. Accessories get geometry material groups and metre-scale UVs (primitive-uv,uv2) so presets tile at consistent real-world size.Roof authoring: pressing R while drawing rotates footprint width/depth 90° (2D direction line + 3D ghost); global R/T defers to the roof tool. Eave logic is centralized in
getRoofShapeEaveSides(e.g. mansard uses four eaves for gutter snap/defaults). Segment trim in the inspector is an explicit edit/reset flow instead of a simple “show planes” toggle; adding a roof segment launches the draw segment tool.Plans & overlap: new
roof-overlaphelpers andsubtractPolygonsFromPolygonin core drive 2D roof plans that clip the smaller/overlapping segment footprint and linework against larger “owning” neighbors (area + stable ID tie-break). Open-valley generation on the merged outline is removed in favor of this clipping model.Rendering/editing: during segment moves the merged roof stays visible and rebuilds from live overrides instead of revealing per-segment meshes. Dormer preview/fallback shells use the same
getRoofModuleFacespath as real roof types.unionPolygonsis consumed from core where appropriate (e.g. site).Reviewed by Cursor Bugbot for commit 9d72e22. Bugbot is set up for automated code reviews on this repo. Configure here.