Skip to main content

Overview

The DoorSystem is a React component that processes dirty door nodes and generates 3D door geometry. It supports:
  • Parametric door geometry with configurable segments (panels, glass, empty)
  • CSG cutouts in parent walls for door openings
  • Commercial hardware (door closers, panic bars)
  • Multi-segment layouts with independent column divisions per segment
  • Threshold, handle, and hinge customization
The system runs in a useFrame hook at priority 3, ensuring doors update after items and slabs but before wall CSG operations.

Location

How It Works

Processing Pipeline

1

Monitor dirty nodes

The system watches the dirtyNodes set for nodes with type === 'door'.
2

Update door geometry

For each dirty door:
  • Generate new geometry from door parameters
  • Create frame members (left post, right post, head)
  • Build leaf segments (panels, glass, or empty)
  • Add hardware (handle, hinges, closer, panic bar)
  • Update the invisible cutout mesh for wall CSG
3

Mark parent wall dirty

Trigger parent wall rebuild so its CSG cutout reflects the updated door geometry.
4

Clear dirty flag

Once the mesh is updated, the node is removed from dirtyNodes.

Geometry Generation

The updateDoorMesh() function builds door geometry in these steps:
  1. Create invisible hitbox (root mesh for selection)
  2. Build frame members (left post, right post, head)
  3. Add threshold if enabled
  4. Build leaf segments with content padding border strips
  5. Generate segment content (panels with raised details, glass panes, or empty fill)
  6. Add hardware (handle, door closer, panic bar, hinges)
  7. Update cutout mesh (always full door dimensions, 1m deep for wall CSG)

Props

The DoorSystem component has no props. It reads state from the Zustand store:
Set<AnyNodeId>
Set of node IDs that need geometry updates
Record<AnyNodeId, AnyNode>
All nodes in the scene graph

Dependencies

DoorNode Schema

The system processes DoorNode objects with these properties:
string
required
Unique door identifier
[number, number, number]
default:"[0, 0, 0]"
Center of the door in wall-local coordinates [x, y, z]
[number, number, number]
default:"[0, 0, 0]"
Euler rotation in radians [x, y, z]
number
default:"0.9"
Overall door width in meters
number
default:"2.1"
Overall door height in meters
number
default:"0.05"
Width of frame members in meters
number
default:"0.07"
Depth of frame in meters (perpendicular to wall)
boolean
default:"true"
Whether to show threshold at door base
number
default:"0.02"
Height of threshold in meters
'left' | 'right'
default:"'left'"
Which side the hinges are on
'inward' | 'outward'
default:"'inward'"
Direction the door swings
DoorSegment[]
required
Array of segments stacked top to bottom, each defining its own column layout
boolean
default:"true"
Whether to show door handle
number
default:"1.05"
Height of handle from floor in meters
'left' | 'right'
default:"'right'"
Which side the handle is on
[number, number]
default:"[0.04, 0.04]"
Leaf inner margin [x, y] in meters
boolean
default:"false"
Whether to show commercial door closer hardware
boolean
default:"false"
Whether to show panic bar (emergency exit hardware)
number
default:"1.0"
Height of panic bar from floor in meters
string
Parent wall ID

DoorSegment Schema

Each segment in the segments array has:
'panel' | 'glass' | 'empty'
required
  • 'panel': Opaque with raised/recessed panel detail
  • 'glass': Transparent glazed pane
  • 'empty': Flat opaque fill
number
required
Relative height proportion (segments are stacked top to bottom)
number[]
default:"[1]"
Relative width proportions for columns within this segment
number
default:"0.03"
Thickness of column dividers in meters
number
default:"0.01"
Depth of raised panel (positive = raised, negative = recessed)
number
default:"0.04"
Inset from segment edges to panel detail in meters

External Systems

  • Scene Registry (sceneRegistry.nodes): Maps node IDs to THREE.js meshes
  • Wall System (WallSystem): Applies CSG subtraction using door’s cutout mesh

Door Geometry Details

Frame Construction

The frame consists of three members:
  1. Left post: Full height, frameThickness wide
  2. Right post: Full height, frameThickness wide
  3. Head (top bar): Full width, frameThickness tall
No bottom frame bar exists — doors open to the floor.

Leaf Layout

The leaf occupies the full opening with no bottom frame:
Content padding creates border strips, and segments fill the remaining area.

Segment Processing

Segments are stacked top to bottom:
1

Calculate segment heights

Divide content area by heightRatio proportions.
2

Divide into columns

For each segment, split width by columnRatios with dividerThickness spacing.
3

Generate content per column

  • Panel: Opaque backing + raised panel detail
  • Glass: Thin transparent pane (no opaque backing)
  • Empty: Opaque backing only

Hardware

Hinges (door-system.tsx:227-241)

Three knuckle-style hinges positioned:
  • Bottom: 0.25m from floor
  • Middle: Centered vertically
  • Top: 0.25m from top

Handle (door-system.tsx:194-209)

Lever-style handle with backplate and grip, positioned on front face at handleHeight.

Door Closer (door-system.tsx:211-218)

Commercial closer with body and arm, mounted at top of leaf.

Panic Bar (door-system.tsx:220-224)

Horizontal push bar at panicBarHeight, spanning 72% of leaf width.

CSG Cutouts

The door creates a cutout in its parent wall using Constructive Solid Geometry:
1

Create cutout mesh

Invisible mesh named 'cutout' with full door dimensions (width × height × 1.0m deep).
2

Wall CSG subtraction

Parent wall system subtracts the cutout brush from wall geometry using three-bvh-csg.
3

Rebuild wall on door changes

Whenever a door is updated, its parent wall is marked dirty to trigger CSG recalculation.

Usage in Viewer

The system automatically:
  • Monitors the dirtyNodes store
  • Updates doors when they’re marked dirty
  • Triggers parent wall CSG updates

Multi-Column Segments

Each segment can have independent column divisions:

Materials

The system uses three materials:

Performance Notes

  • Only updates dirty doors (not all doors every frame)
  • Reuses shared material instances across all doors
  • Disposes old geometries to prevent memory leaks
  • Root mesh is invisible hitbox; all visuals are child meshes
  • Runs at priority 3 (after items, before wall CSG)

Coordinate System

Doors use wall-local coordinates:
  • X-axis: Along wall length
  • Y-axis: Height (up)
  • Z-axis: Perpendicular to wall (through thickness)
The door’s position is its center, with Y = height/2 so the base sits at floor level.