Skip to content

editor: improve roof materials, drawing, and intersections - #690

Merged
wass08 merged 43 commits into
pascalorg:mainfrom
sudhir9297:t3code/enable-gutter-painting
Aug 20, 2026
Merged

editor: improve roof materials, drawing, and intersections#690
wass08 merged 43 commits into
pascalorg:mainfrom
sudhir9297:t3code/enable-gutter-painting

Conversation

@sudhir9297

@sudhir9297 sudhir9297 commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

  • Adds independently paintable material sections for gutters, downspouts, box vents, cupolas, eyebrow vents, and turbine vents, with improved texture sizing and legacy-scene migration.
  • Adds 90-degree roof rotation while drawing and improves roof face detection, editing visibility, gutter snapping, dormer connections, and 2D roof plans.
  • Completes automatic trimming between intersecting Mansard, gable, lean-to, multi-segment, and separate roofs while preserving the host roof.
  • Removes the unreliable open-valley feature and consolidates shared roof geometry logic into the correct architecture layers.

How to test

  1. Run bun dev, create each supported roof accessory, and use Painting to apply different materials to its separate parts; confirm texture scale remains consistent.
  2. Draw roofs in 2D and 3D, trigger the 90-degree rotation, and confirm width/depth and the preview rotate together.
  3. Overlap a gable roof with a Mansard roof and confirm the entering roof is trimmed inside the attic without removing the Mansard surface.
  4. Repeat with separate roofs, a lean-to, and a multi-segment roof; confirm the 2D plan matches the visible 3D trimming.

Screenshots / screen recording

A screen recording will be added for the visual and interactive changes.

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
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 *MaterialPreset fields and renderers resolving node.slots via slot-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-overlap helpers and subtractPolygonsFromPolygon in 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 getRoofModuleFaces path as real roof types. unionPolygons is 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.

sudhir9297 and others added 30 commits May 19, 2026 02:59
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>
Comment thread packages/nodes/src/gutter/definition.test.ts
if (plan.slope) {
const { tail, head } = plan.slope
const visibleSlope = clipLineByCutters([tail, head], cutters).at(-1)
if (!visibleSlope) continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 9d72e22. Configure here.

@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 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

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 11878fa. Configure here.

)
}
label={showTrimPlanes ? 'Done editing' : 'Edit footprint'}
onClick={() => (showTrimPlanes ? handleBack() : handleTrimEditing(true))}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 11878fa. Configure here.

? new THREE.Matrix4().multiplyMatrices(targetSegmentInverse, siblingInTargetRoof)
: siblingInTargetRoof
csgGeometry(siblingBrushes.innerBrush).applyMatrix4(relativeMatrix)
siblingBrushes.innerBrush.updateMatrixWorld()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 11878fa. Configure here.

@wass08
wass08 merged commit 889144d into pascalorg:main Aug 20, 2026
4 checks passed
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.

2 participants