viewer: Fix Dutch roof trim artifacts#452
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>
Remove Dutch ridge axis abstraction and rework roof edit system, ridge vent clipping geometry, and roof surface placement. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Track ridge vent auto-generation via an `autoRidgeVent` metadata flag so geometry changes only regenerate default vents when enabled, treating legacy segments with generated vents as auto-enabled for back-compat. Expose a panel toggle to opt in/out per segment. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Seed the Dutch shape parameters (waist width/height/length, top rake thickness/length) with sensible defaults whenever a segment is created as or switched to Dutch, so the gablet is well-formed regardless of leftover values from the previous roof type. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Color the corner/endpoint snap markers and the vertical cursor pillar green across the 2D floorplan beacon, the 3D alignment guide dots, and the wall snap beacon so snap targets read as a consistent accent. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Snap roof draft corners onto wall corners, midpoints, crossings, and bodies on the active level and the floor below, reusing the wall tool's snap pipeline so the beacon and coloring match. The cursor's ground dot/ring is hidden while a wall snap is active to avoid overlapping the beacon glyph. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Regenerated next-env.d.ts now references ./.next/dev/types/routes.d.ts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Slice an untrimmed segment volume generated from the live node instead of the registry mesh, whose CSG rebuild lags a few frames behind the drag and may still hold placeholder geometry — so the section outline now renders deterministically. Use LineBasicNodeMaterial so the outline draws under the WebGPU pipeline, and export generateRoofSegmentGeometry for the slice source. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a violet silhouette fill behind the cutaway outline, extend the section slicing to angled diagonal/corner trims via a generic vertical cut plane, and clip each slice to its footprint span so the infinite plane no longer sprouts stray lines across the rest of the roof. The cutaway now renders only while a trim handle is being dragged. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pull the Dutch hip end slopes out of the watertight shingle shell into their own slab wedge so they can be reshaped independently, and extend each end slope inward up its own hip plane until the top edge meets the gablet's inner triangle. Refactor roof-segment shape geometry into a shared roof-segment-shape module. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the triangle-mesh slicer with a CSG intersection of a thin slab against the untrimmed roof shell, so the cutaway shows red only on real material (wall + deck bands) and leaves the hollow attic empty. Add an analytic surface-edge outline, style both solid red like a SketchUp section, and make the cutaway persist whenever a segment is trimmed. Keep the merged roof shell visible during trim editing (re-trimmed live from each segment's drag override) instead of swapping in the per-segment meshes, whose abutting end-cap faces showed as stray white planes the commit never had. Extend each slab past free cut-line ends only — trimmed ends clamp to the cut line — so the red section stays inside the trim box. Re-export INTERSECTION from the viewer CSG surface for the editor.
Derive the section-cut outline from the fill geometry's edges (EdgesGeometry) so it traces the real cut shape — wall/deck band boundaries and the hollow-attic edge — instead of just the top surface line. Drop the fill to 85% opacity and recolor both fill and outline to the app's destructive red, matching the delete/destructive UI.
Roof accessories (chimney, vents, skylight, dormer, gutter, downspout, solar-panel, cupola) now slice at the trim plane like the roof shell and appear in the red section-cut while dragging a trim handle: - Export clipGeometryBySegmentTrim from the viewer as a reusable segment-local trim-clip primitive. - Add a shared useSegmentTrimClippedGeometry hook + TrimClippedMesh wrapper (nodes) that slice accessory geometry by the host segment's live trim override, so the cut tracks the drag. - Wire the clip into all 11 accessory renderers, including skylight glass panes and dormer window glass/frame/sill. - Feed every hosted accessory mesh into the editor's red cutaway, welding triangle-soup geometry (e.g. ridge vent) so CSG INTERSECTION yields a cross-section. - Register skylight in the scene-graph tree-node map so it shows in the outliner when placed on a roof. Co-Authored-By: Claude <noreply@anthropic.com>
Fences can now be drawn as one continuous Catmull-Rom/Bezier curve via an optional `path` (+ per-point `tangents`), selectable in a Straight/Curved mode toggle. Selected spline fences expose draggable control-point dots (hexagon) and symmetric tangent handles (circle) joined by a violet line, editable in both 2D plan and 3D. Side-move arrows are dropped for splines. Co-Authored-By: Claude <noreply@anthropic.com>
Child meshes relied on a parent group's layer, which three.js does not propagate, so the trim section/rail/plane overlays rendered on the scene layer — getting inked/SSGI-darkened and leaking into thumbnail exports. Co-Authored-By: Claude <noreply@anthropic.com>
# Conflicts: # packages/editor/src/components/editor/floorplan-panel.tsx # packages/editor/src/components/tools/roof/roof-tool.tsx # packages/editor/src/components/tools/tool-manager.tsx # packages/editor/src/components/ui/helpers/helper-manager.tsx # packages/editor/src/index.tsx # packages/editor/src/store/use-editor.tsx # packages/nodes/src/fence/definition.ts # packages/nodes/src/wall/tool.tsx
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c8339cd. Configure here.
| const cos = Math.cos(angle) | ||
| const sin = Math.sin(angle) | ||
| extendByLocal(box, stair, cos * innerRadius, sin * innerRadius) | ||
| extendByLocal(box, stair, cos * outerRadius, sin * outerRadius) |
There was a problem hiding this comment.
Spiral landing uses unclamped sweep
Low Severity
Integrated spiral top-landing samples in the footprint AABB start at rawSweep / 2, but the main annular arc is sampled with clamped sweep when |sweepAngle| ≥ 2π. The landing extension can begin at a different angle than the main stair ends, so footprint bounds (and anything derived from them) can miss or mis-size the landing for extreme sweep values.
Reviewed by Cursor Bugbot for commit c8339cd. Configure here.


What does this PR do?
Fixes the roof trim workflow around Dutch roof geometry: the trim cutaway now follows the actual roof shell instead of projecting into empty space, Dutch rake/trim materials preserve the roof material during trimming, ridge vent placement and clipping behavior is cleaned up, and roof accessories participate correctly in trim clipping. This branch also includes related roof shape/default updates, floorplan trim helpers, snapping improvements, spline fence work, and Biome cleanup after the main-branch merge.
How to test
bun install, thenbun dev, and openhttp://127.0.0.1:3002.bun run check-types,bun run check, andbun run build.Screenshots / screen recording
Visual change; recording will be added separately.
Checklist
bun devbun checkto verify)mainbranchNote
Medium Risk
Large changes to roof segment schema, geometry, and scene graph updates for ridge vents affect rendering and saved scenes; fence spline and trim normalization are new data paths but are covered by new tests.
Overview
Roof segments gain a
trimschema (side and diagonal cuts) withnormalizeRoofSegmentTrimandgetRoofSegmentVisibleTopBounds, plus Dutch-specific fields (dutchWaistLengthRatio,dutchGabletRake,dutchTopRakeThickness) and shared face building inroof-segment-shape.ts(including planar Dutch end slopes and optionalexcludeDutchEndSlopes). Dutch surface height, wall gable profiles, and ridge vent line placement use expanded overhang bounds so hips/rakes stay on the rendered arris.Ridge vents are generated per roof type (gable, hip, Dutch, mansard) via
getRidgeVentLinesForSegment/createDefaultRidgeVentsForSegment, with auto-enable metadata and store refresh when segment geometry changes (not on trim-only edits). Default vents no longer forcepreset-white; unpainted vents inherit roof top material.Fences support optional
path+tangentsfor Catmull-Rom/Bézier centerlines, with core spline helpers, registry handle APIs (engageControlPointMove,engageTangentMove,roundcorner pickers), and editor tangent-line overlay plus floorplan control/tangent reshape scopes.Stairs: integrated spiral top landings use angular annular extension for footprint and slab openings (no extra rectangular landing hole).
Editor: alignment guide endpoint dots and wall-snap endpoint markers are green; floorplan alignment goes through
resolveAlignmentForFloorplanView; 2D polyline move excludes 2D fence paths; minor hook/deps and Nextnext-env.d.tspath tweak; Biome dropsnursery/noShadow.Reviewed by Cursor Bugbot for commit c8339cd. Bugbot is set up for automated code reviews on this repo. Configure here.