Feat/stairs fence update (#226)
* feat: railing on the straight stairs and new fence * feat: added spiral and curved stairs with bug fix for fence * feat:fence are linked to each other ... so moving one move the other sharing the same coordinate * fix: update stair railing logic to include front-side attachments for terminal landings * Integrate fence rendering into the fence system * fix: pass nodeId instead of undefined node to WallTreeNode and FenceTreeNode TreeNode was passing `node` (undefined variable) instead of `nodeId` to WallTreeNode and FenceTreeNode, causing a runtime ReferenceError. Updated FenceTreeNode to accept nodeId and look up the node from the scene store internally, consistent with all other tree node components. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: update fence icon with new isometric design Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Aymeric Rabot <aymeric@pascal.app> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
Aymeric Rabot
parent
682e2a1a12
commit
a205e4f778
@@ -15,6 +15,7 @@ export {
|
||||
export { BuildingNode } from './nodes/building'
|
||||
export { CeilingNode } from './nodes/ceiling'
|
||||
export { DoorNode, DoorSegment } from './nodes/door'
|
||||
export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence'
|
||||
export { GuideNode } from './nodes/guide'
|
||||
export type {
|
||||
AnimationEffect,
|
||||
@@ -36,7 +37,7 @@ export { ScanNode } from './nodes/scan'
|
||||
// Nodes
|
||||
export { SiteNode } from './nodes/site'
|
||||
export { SlabNode } from './nodes/slab'
|
||||
export { StairNode } from './nodes/stair'
|
||||
export { StairNode, StairRailingMode, StairTopLandingMode, StairType } from './nodes/stair'
|
||||
export { AttachmentSide, StairSegmentNode, StairSegmentType } from './nodes/stair-segment'
|
||||
export { WallNode } from './nodes/wall'
|
||||
export { WindowNode } from './nodes/window'
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import dedent from 'dedent'
|
||||
import { z } from 'zod'
|
||||
import { BaseNode, nodeType, objectId } from '../base'
|
||||
|
||||
export const FenceStyle = z.enum(['slat', 'rail', 'privacy'])
|
||||
export const FenceBaseStyle = z.enum(['floating', 'grounded'])
|
||||
|
||||
export const FenceNode = BaseNode.extend({
|
||||
id: objectId('fence'),
|
||||
type: nodeType('fence'),
|
||||
start: z.tuple([z.number(), z.number()]),
|
||||
end: z.tuple([z.number(), z.number()]),
|
||||
height: z.number().default(1.8),
|
||||
thickness: z.number().default(0.08),
|
||||
baseHeight: z.number().default(0.22),
|
||||
postSpacing: z.number().default(2),
|
||||
postSize: z.number().default(0.1),
|
||||
topRailHeight: z.number().default(0.04),
|
||||
groundClearance: z.number().default(0),
|
||||
edgeInset: z.number().default(0.015),
|
||||
baseStyle: FenceBaseStyle.default('grounded'),
|
||||
color: z.string().default('#ffffff'),
|
||||
style: FenceStyle.default('slat'),
|
||||
}).describe(
|
||||
dedent`
|
||||
Fence node - used to represent a fence segment in the building/site level coordinate system
|
||||
- start/end: fence endpoints in level coordinate system
|
||||
- height/thickness: overall fence dimensions in meters
|
||||
- baseHeight/postSpacing/postSize/topRailHeight: exact geometric controls from the plan3D fence model
|
||||
- groundClearance/edgeInset/baseStyle: fence support and inset configuration
|
||||
- color/style: visual appearance options
|
||||
`,
|
||||
)
|
||||
|
||||
export type FenceNode = z.infer<typeof FenceNode>
|
||||
@@ -2,6 +2,7 @@ import dedent from 'dedent'
|
||||
import { z } from 'zod'
|
||||
import { BaseNode, nodeType, objectId } from '../base'
|
||||
import { CeilingNode } from './ceiling'
|
||||
import { FenceNode } from './fence'
|
||||
import { GuideNode } from './guide'
|
||||
import { RoofNode } from './roof'
|
||||
import { ScanNode } from './scan'
|
||||
@@ -17,6 +18,7 @@ export const LevelNode = BaseNode.extend({
|
||||
.array(
|
||||
z.union([
|
||||
WallNode.shape.id,
|
||||
FenceNode.shape.id,
|
||||
ZoneNode.shape.id,
|
||||
SlabNode.shape.id,
|
||||
CeilingNode.shape.id,
|
||||
|
||||
@@ -4,6 +4,14 @@ import { BaseNode, nodeType, objectId } from '../base'
|
||||
import { MaterialSchema } from '../material'
|
||||
import { StairSegmentNode } from './stair-segment'
|
||||
|
||||
export const StairRailingMode = z.enum(['none', 'left', 'right', 'both'])
|
||||
export const StairType = z.enum(['straight', 'curved', 'spiral'])
|
||||
export const StairTopLandingMode = z.enum(['none', 'integrated'])
|
||||
|
||||
export type StairRailingMode = z.infer<typeof StairRailingMode>
|
||||
export type StairType = z.infer<typeof StairType>
|
||||
export type StairTopLandingMode = z.infer<typeof StairTopLandingMode>
|
||||
|
||||
export const StairNode = BaseNode.extend({
|
||||
id: objectId('stair'),
|
||||
type: nodeType('stair'),
|
||||
@@ -11,16 +19,44 @@ export const StairNode = BaseNode.extend({
|
||||
position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
|
||||
// Rotation around Y axis in radians
|
||||
rotation: z.number().default(0),
|
||||
stairType: StairType.default('straight'),
|
||||
width: z.number().default(1.0),
|
||||
totalRise: z.number().default(2.5),
|
||||
stepCount: z.number().default(10),
|
||||
thickness: z.number().default(0.25),
|
||||
fillToFloor: z.boolean().default(true),
|
||||
innerRadius: z.number().default(0.9),
|
||||
sweepAngle: z.number().default(Math.PI / 2),
|
||||
topLandingMode: StairTopLandingMode.default('none'),
|
||||
topLandingDepth: z.number().default(0.9),
|
||||
showCenterColumn: z.boolean().default(true),
|
||||
showStepSupports: z.boolean().default(true),
|
||||
railingMode: StairRailingMode.default('none'),
|
||||
railingHeight: z.number().default(0.92),
|
||||
// Child stair segment IDs
|
||||
children: z.array(StairSegmentNode.shape.id).default([]),
|
||||
}).describe(
|
||||
dedent`
|
||||
Stair node - a container for stair segments.
|
||||
Acts as a group that holds one or more StairSegmentNodes (flights and landings).
|
||||
Segments chain together based on their attachmentSide to form complex staircase shapes.
|
||||
Acts as a group that either holds one or more StairSegmentNodes (straight stairs)
|
||||
or stores stair-level geometry properties for curved stairs.
|
||||
- position: center position of the stair group
|
||||
- rotation: rotation around Y axis
|
||||
- children: array of StairSegmentNode IDs
|
||||
- stairType: straight (segment-based), curved (arc-based), or spiral
|
||||
- width: stair width
|
||||
- totalRise: total stair height
|
||||
- stepCount: number of visible steps
|
||||
- thickness: stair slab / tread thickness
|
||||
- fillToFloor: whether the stair mass fills down to the floor or uses tread thickness only
|
||||
- innerRadius: inner curve radius for curved stairs
|
||||
- sweepAngle: total curved stair sweep in radians
|
||||
- topLandingMode: optional integrated top landing for spiral stairs
|
||||
- topLandingDepth: depth used to size the integrated spiral top landing
|
||||
- showCenterColumn: whether spiral stairs render a center column
|
||||
- showStepSupports: whether spiral stairs render step support brackets
|
||||
- railingMode: whether to render railings and on which side(s)
|
||||
- railingHeight: top height of the railing above the stair surface
|
||||
- children: array of StairSegmentNode IDs for straight stairs
|
||||
`,
|
||||
)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import z from 'zod'
|
||||
import { BuildingNode } from './nodes/building'
|
||||
import { CeilingNode } from './nodes/ceiling'
|
||||
import { DoorNode } from './nodes/door'
|
||||
import { FenceNode } from './nodes/fence'
|
||||
import { GuideNode } from './nodes/guide'
|
||||
import { ItemNode } from './nodes/item'
|
||||
import { LevelNode } from './nodes/level'
|
||||
@@ -21,6 +22,7 @@ export const AnyNode = z.discriminatedUnion('type', [
|
||||
BuildingNode,
|
||||
LevelNode,
|
||||
WallNode,
|
||||
FenceNode,
|
||||
ItemNode,
|
||||
ZoneNode,
|
||||
SlabNode,
|
||||
|
||||
Reference in New Issue
Block a user