Skip to content

viewer: Fix Dutch roof trim artifacts#452

Open
sudhir9297 wants to merge 57 commits into
pascalorg:mainfrom
sudhir9297:fix/tue-jun-23
Open

viewer: Fix Dutch roof trim artifacts#452
sudhir9297 wants to merge 57 commits into
pascalorg:mainfrom
sudhir9297:fix/tue-jun-23

Conversation

@sudhir9297

@sudhir9297 sudhir9297 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

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

  1. Run bun install, then bun dev, and open http://127.0.0.1:3002.
  2. Create or load a Dutch roof, start a trim drag near the gable/rake area, and verify the red trim preview hugs the roof shape without phantom triangles, spikes, or gaps in empty space.
  3. Verify the rake/top roof pieces keep the existing roof material while trimming instead of switching to white.
  4. Add roof accessories/ridge vents, trim through the roof, and verify the trim preview clips the roof/accessories consistently.
  5. Run bun run check-types, bun run check, and bun run build.

Screenshots / screen recording

Visual change; recording will be added separately.

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
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 trim schema (side and diagonal cuts) with normalizeRoofSegmentTrim and getRoofSegmentVisibleTopBounds, plus Dutch-specific fields (dutchWaistLengthRatio, dutchGabletRake, dutchTopRakeThickness) and shared face building in roof-segment-shape.ts (including planar Dutch end slopes and optional excludeDutchEndSlopes). 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 force preset-white; unpainted vents inherit roof top material.

Fences support optional path + tangents for Catmull-Rom/Bézier centerlines, with core spline helpers, registry handle APIs (engageControlPointMove, engageTangentMove, round corner 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 Next next-env.d.ts path tweak; Biome drops nursery/noShadow.

Reviewed by Cursor Bugbot for commit c8339cd. 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>
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>
sudhir9297 and others added 19 commits June 26, 2026 23:41
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
Comment thread packages/core/src/store/actions/node-actions.ts
Comment thread packages/core/src/schema/nodes/roof-segment.ts
Comment thread packages/core/src/schema/nodes/ridge-vent.ts
Comment thread packages/core/src/schema/nodes/roof-segment-shape.ts Outdated
Comment thread packages/editor/src/components/editor/floorplan-panel.tsx
Comment thread packages/editor/src/components/systems/roof/roof-edit-system.tsx

@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 1 potential issue.

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 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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c8339cd. Configure here.

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.

1 participant