@pascal-app/viewer 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/components/error-boundary.d.ts +7 -3
  2. package/dist/components/error-boundary.d.ts.map +1 -1
  3. package/dist/components/error-boundary.js +3 -1
  4. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +1 -1
  5. package/dist/components/renderers/ceiling/ceiling-renderer.js +19 -3
  6. package/dist/components/renderers/column/column-renderer.d.ts +5 -0
  7. package/dist/components/renderers/column/column-renderer.d.ts.map +1 -0
  8. package/dist/components/renderers/column/column-renderer.js +594 -0
  9. package/dist/components/renderers/door/door-renderer.d.ts.map +1 -1
  10. package/dist/components/renderers/door/door-renderer.js +4 -9
  11. package/dist/components/renderers/fence/fence-renderer.d.ts.map +1 -1
  12. package/dist/components/renderers/guide/guide-renderer.js +1 -1
  13. package/dist/components/renderers/item/item-renderer.d.ts.map +1 -1
  14. package/dist/components/renderers/item/item-renderer.js +2 -1
  15. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  16. package/dist/components/renderers/node-renderer.js +3 -1
  17. package/dist/components/renderers/roof/roof-renderer.d.ts.map +1 -1
  18. package/dist/components/renderers/roof/roof-renderer.js +1 -13
  19. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +1 -1
  20. package/dist/components/renderers/roof-segment/roof-segment-renderer.js +5 -20
  21. package/dist/components/renderers/slab/slab-renderer.d.ts.map +1 -1
  22. package/dist/components/renderers/slab/slab-renderer.js +39 -27
  23. package/dist/components/renderers/spawn/spawn-renderer.d.ts +5 -0
  24. package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +1 -0
  25. package/dist/components/renderers/spawn/spawn-renderer.js +32 -0
  26. package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -1
  27. package/dist/components/renderers/stair/stair-renderer.js +5 -23
  28. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -1
  29. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +5 -22
  30. package/dist/components/viewer/index.d.ts +2 -0
  31. package/dist/components/viewer/index.d.ts.map +1 -1
  32. package/dist/components/viewer/index.js +88 -18
  33. package/dist/components/viewer/post-processing.d.ts +13 -1
  34. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  35. package/dist/components/viewer/post-processing.js +71 -14
  36. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  37. package/dist/components/viewer/selection-manager.js +19 -2
  38. package/dist/hooks/use-node-events.d.ts +9 -1
  39. package/dist/hooks/use-node-events.d.ts.map +1 -1
  40. package/dist/index.d.ts +6 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +5 -2
  43. package/dist/lib/materials.d.ts +3 -0
  44. package/dist/lib/materials.d.ts.map +1 -1
  45. package/dist/lib/materials.js +14 -0
  46. package/dist/lib/merged-outline-node.d.ts +2 -0
  47. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  48. package/dist/lib/merged-outline-node.js +25 -5
  49. package/dist/store/use-viewer.d.ts +4 -4
  50. package/dist/store/use-viewer.d.ts.map +1 -1
  51. package/dist/store/use-viewer.js +2 -2
  52. package/dist/systems/ceiling/ceiling-system.d.ts +8 -0
  53. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -0
  54. package/dist/systems/ceiling/ceiling-system.js +91 -0
  55. package/dist/systems/column/column-geometry.d.ts +22 -0
  56. package/dist/systems/column/column-geometry.d.ts.map +1 -0
  57. package/dist/systems/column/column-geometry.js +108 -0
  58. package/dist/systems/door/door-animation-system.d.ts +2 -0
  59. package/dist/systems/door/door-animation-system.d.ts.map +1 -0
  60. package/dist/systems/door/door-animation-system.js +53 -0
  61. package/dist/systems/door/door-system.d.ts +2 -0
  62. package/dist/systems/door/door-system.d.ts.map +1 -0
  63. package/dist/systems/door/door-system.js +867 -0
  64. package/dist/systems/fence/fence-system.d.ts +2 -0
  65. package/dist/systems/fence/fence-system.d.ts.map +1 -0
  66. package/dist/systems/fence/fence-system.js +185 -0
  67. package/dist/systems/item/item-system.d.ts +2 -0
  68. package/dist/systems/item/item-system.d.ts.map +1 -0
  69. package/dist/systems/item/item-system.js +44 -0
  70. package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts +14 -0
  71. package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.d.ts.map +1 -0
  72. package/dist/systems/item-mesh-metadata/compute-item-mesh-metadata.js +155 -0
  73. package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts +6 -0
  74. package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.d.ts.map +1 -0
  75. package/dist/systems/item-mesh-metadata/item-mesh-metadata-system.js +75 -0
  76. package/dist/systems/item-mesh-metadata/sync-request.d.ts +7 -0
  77. package/dist/systems/item-mesh-metadata/sync-request.d.ts.map +1 -0
  78. package/dist/systems/item-mesh-metadata/sync-request.js +25 -0
  79. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  80. package/dist/systems/roof/roof-materials.js +18 -1
  81. package/dist/systems/roof/roof-system.d.ts +16 -0
  82. package/dist/systems/roof/roof-system.d.ts.map +1 -0
  83. package/dist/systems/roof/roof-system.js +797 -0
  84. package/dist/systems/slab/slab-system.d.ts +8 -0
  85. package/dist/systems/slab/slab-system.d.ts.map +1 -0
  86. package/dist/systems/slab/slab-system.js +155 -0
  87. package/dist/systems/stair/stair-materials.d.ts.map +1 -1
  88. package/dist/systems/stair/stair-materials.js +25 -2
  89. package/dist/systems/stair/stair-system.d.ts +2 -0
  90. package/dist/systems/stair/stair-system.d.ts.map +1 -0
  91. package/dist/systems/stair/stair-system.js +772 -0
  92. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  93. package/dist/systems/wall/wall-materials.js +2 -2
  94. package/dist/systems/wall/wall-system.d.ts +11 -0
  95. package/dist/systems/wall/wall-system.d.ts.map +1 -0
  96. package/dist/systems/wall/wall-system.js +592 -0
  97. package/dist/systems/window/window-animation-system.d.ts +2 -0
  98. package/dist/systems/window/window-animation-system.d.ts.map +1 -0
  99. package/dist/systems/window/window-animation-system.js +135 -0
  100. package/dist/systems/window/window-system.d.ts +12 -0
  101. package/dist/systems/window/window-system.d.ts.map +1 -0
  102. package/dist/systems/window/window-system.js +1430 -0
  103. package/package.json +4 -2
@@ -0,0 +1,594 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useLiveTransforms, useRegistry } from '@pascal-app/core';
3
+ import { createContext, useContext, useMemo, useRef } from 'react';
4
+ import { useNodeEvents } from '../../../hooks/use-node-events';
5
+ import { baseMaterial, createMaterial, createMaterialFromPresetRef } from '../../../lib/materials';
6
+ import { createColumnBoxGeometry, createColumnCylinderGeometry, createColumnSphereGeometry, createColumnTorusGeometry, } from '../../../systems/column/column-geometry';
7
+ const ColumnMaterialContext = createContext(baseMaterial);
8
+ const ColumnEdgeSoftnessContext = createContext(0.025);
9
+ function ColumnMaterial() {
10
+ const material = useContext(ColumnMaterialContext);
11
+ return _jsx("primitive", { attach: "material", object: material });
12
+ }
13
+ function createColumnMaterial({ material, materialPreset, }) {
14
+ const presetMaterial = createMaterialFromPresetRef(materialPreset);
15
+ if (presetMaterial)
16
+ return presetMaterial;
17
+ if (material)
18
+ return createMaterial(material);
19
+ return baseMaterial;
20
+ }
21
+ function getSegments(node) {
22
+ if (node.crossSection === 'octagonal')
23
+ return 8;
24
+ if (node.crossSection === 'sixteen-sided')
25
+ return 16;
26
+ return 32;
27
+ }
28
+ function getShaftProfile(node) {
29
+ return node.shaftProfile ?? (node.shaftTaper > 0 ? 'tapered' : 'straight');
30
+ }
31
+ function getShaftSegmentCount(node) {
32
+ const shaftProfile = getShaftProfile(node);
33
+ const shaftTaper = node.shaftTaper ?? 0;
34
+ const hasTwist = Math.abs(node.shaftTwistStep ?? 0) > 0.001;
35
+ return Math.max(hasTwist ? 4 : 1, shaftProfile === 'straight' && shaftTaper <= 0 && !hasTwist
36
+ ? 1
37
+ : (node.shaftSegmentCount ?? (hasTwist ? 12 : 24)));
38
+ }
39
+ function getShaftTwistRadians(node, index) {
40
+ return ((node.shaftTwistStep ?? 0) * Math.PI * index) / 180;
41
+ }
42
+ function getShaftScaleAt(node, t) {
43
+ const shaftProfile = getShaftProfile(node);
44
+ const shaftTaper = Math.min(node.shaftTaper ?? 0, 0.85);
45
+ const startScale = node.shaftStartScale ?? 0.72;
46
+ const endScale = node.shaftEndScale ?? startScale;
47
+ const shaftBulge = node.shaftBulge ??
48
+ (shaftProfile === 'bulged'
49
+ ? 0.16
50
+ : shaftProfile === 'baluster'
51
+ ? 0.2
52
+ : shaftProfile === 'hourglass'
53
+ ? 0.18
54
+ : 0);
55
+ const taperedScale = 1 - shaftTaper * t;
56
+ const linearScale = (startScale + (endScale - startScale) * t) * taperedScale;
57
+ const bulgeCurve = Math.sin(Math.PI * t);
58
+ const hourglassCurve = Math.abs(t - 0.5) * 2;
59
+ const profileScale = shaftProfile === 'bulged' || shaftProfile === 'baluster'
60
+ ? linearScale + shaftBulge * bulgeCurve
61
+ : shaftProfile === 'hourglass'
62
+ ? linearScale - shaftBulge * (1 - hourglassCurve)
63
+ : linearScale;
64
+ return Math.max(0.1, profileScale);
65
+ }
66
+ function MappedBox({ depth, height, position, rotation, softenEdges = true, width, }) {
67
+ const edgeSoftness = useContext(ColumnEdgeSoftnessContext);
68
+ const minDimension = Math.max(0, Math.min(width, height, depth));
69
+ const bevelRadius = softenEdges ? Math.min(Math.max(0, edgeSoftness), minDimension * 0.35) : 0;
70
+ const geometry = useMemo(() => {
71
+ if (height <= 0 || width <= 0 || depth <= 0)
72
+ return null;
73
+ return createColumnBoxGeometry(width, height, depth, bevelRadius);
74
+ }, [bevelRadius, depth, height, width]);
75
+ if (!geometry)
76
+ return null;
77
+ return (_jsxs("mesh", { dispose: null, position: position, rotation: rotation, children: [_jsx("primitive", { attach: "geometry", dispose: null, object: geometry }), _jsx(ColumnMaterial, {})] }));
78
+ }
79
+ function MappedCylinder({ height, position, radius, radiusBottom = radius, radiusTop = radius, radiusX = 1, radiusZ = 1, rotation, segments = 32, }) {
80
+ const geometry = useMemo(() => {
81
+ if (height <= 0 || radius <= 0 || radiusBottom < 0 || radiusTop < 0)
82
+ return null;
83
+ return createColumnCylinderGeometry({
84
+ height,
85
+ radiusBottom,
86
+ radiusTop,
87
+ radiusX,
88
+ radiusZ,
89
+ segments,
90
+ });
91
+ }, [height, radius, radiusBottom, radiusTop, radiusX, radiusZ, segments]);
92
+ if (!geometry)
93
+ return null;
94
+ return (_jsxs("mesh", { dispose: null, position: position, rotation: rotation, children: [_jsx("primitive", { attach: "geometry", dispose: null, object: geometry }), _jsx(ColumnMaterial, {})] }));
95
+ }
96
+ function MappedCone({ height, position, radiusX, radiusZ = radiusX, rotation, segments = 6, }) {
97
+ const geometry = useMemo(() => {
98
+ if (height <= 0 || radiusX <= 0 || radiusZ <= 0)
99
+ return null;
100
+ return createColumnCylinderGeometry({
101
+ height,
102
+ radiusBottom: 1,
103
+ radiusTop: 0,
104
+ radiusX,
105
+ radiusZ,
106
+ segments,
107
+ });
108
+ }, [height, radiusX, radiusZ, segments]);
109
+ if (!geometry)
110
+ return null;
111
+ return (_jsxs("mesh", { dispose: null, position: position, rotation: rotation, children: [_jsx("primitive", { attach: "geometry", dispose: null, object: geometry }), _jsx(ColumnMaterial, {})] }));
112
+ }
113
+ function MappedSphere({ position, radius, segments = 10, verticalSegments = 8, }) {
114
+ const geometry = useMemo(() => {
115
+ if (radius <= 0)
116
+ return null;
117
+ return createColumnSphereGeometry(radius, segments, verticalSegments);
118
+ }, [radius, segments, verticalSegments]);
119
+ if (!geometry)
120
+ return null;
121
+ return (_jsxs("mesh", { dispose: null, position: position, children: [_jsx("primitive", { attach: "geometry", dispose: null, object: geometry }), _jsx(ColumnMaterial, {})] }));
122
+ }
123
+ function MappedTorus({ arc, position, ringRadius, rotation, scaleX, scaleY, scaleZ, tubeRadius, }) {
124
+ const geometry = useMemo(() => {
125
+ if (ringRadius <= 0 || tubeRadius <= 0)
126
+ return null;
127
+ return createColumnTorusGeometry({ arc, ringRadius, scaleX, scaleY, scaleZ, tubeRadius });
128
+ }, [arc, ringRadius, scaleX, scaleY, scaleZ, tubeRadius]);
129
+ if (!geometry)
130
+ return null;
131
+ return (_jsxs("mesh", { dispose: null, position: position, rotation: rotation, children: [_jsx("primitive", { attach: "geometry", dispose: null, object: geometry }), _jsx(ColumnMaterial, {})] }));
132
+ }
133
+ function SquareBlock({ y, height, width, depth, softenEdges = true, }) {
134
+ return (_jsx(MappedBox, { depth: depth, height: height, position: [0, y + height / 2, 0], softenEdges: softenEdges, width: width }));
135
+ }
136
+ function RoundBlock({ x = 0, y, z = 0, height, radius, segments = 32, }) {
137
+ return (_jsx(MappedCylinder, { height: height, position: [x, y + height / 2, z], radius: radius, segments: segments }));
138
+ }
139
+ function RoundedRectangleShaftSegment({ y, height, width, depth, cornerRadius, }) {
140
+ if (height <= 0)
141
+ return null;
142
+ const radius = Math.min(Math.max(0, cornerRadius), Math.min(width, depth) * 0.45);
143
+ if (radius <= 0.001) {
144
+ return _jsx(SquareBlock, { depth: depth, height: height, width: width, y: y });
145
+ }
146
+ const innerWidth = Math.max(0, width - radius * 2);
147
+ const innerDepth = Math.max(0, depth - radius * 2);
148
+ const cornerX = width / 2 - radius;
149
+ const cornerZ = depth / 2 - radius;
150
+ return (_jsxs("group", { children: [innerWidth > 0 && (_jsx(SquareBlock, { depth: depth, height: height, softenEdges: false, width: innerWidth, y: y })), innerDepth > 0 && (_jsx(SquareBlock, { depth: innerDepth, height: height, softenEdges: false, width: width, y: y })), [
151
+ [cornerX, cornerZ],
152
+ [cornerX, -cornerZ],
153
+ [-cornerX, cornerZ],
154
+ [-cornerX, -cornerZ],
155
+ ].map(([x, z], index) => (_jsx(RoundBlock, { height: height, radius: radius, segments: 18, x: x, y: y, z: z }, index)))] }));
156
+ }
157
+ function OvalBlock({ y, height, width, depth, segments = 32, }) {
158
+ return (_jsx(MappedCylinder, { height: height, position: [0, y + height / 2, 0], radius: 1, radiusX: width / 2, radiusZ: depth / 2, segments: segments }));
159
+ }
160
+ function ColumnBlock({ node, y, height, scale = 1, }) {
161
+ if (height <= 0)
162
+ return null;
163
+ const width = node.width * scale;
164
+ const depth = node.depth * scale;
165
+ const radius = node.radius * scale;
166
+ if (node.crossSection === 'square' || node.crossSection === 'rectangular') {
167
+ return _jsx(SquareBlock, { depth: depth, height: height, width: width, y: y });
168
+ }
169
+ return _jsx(RoundBlock, { height: height, radius: radius, segments: getSegments(node), y: y });
170
+ }
171
+ function TaperedRoundShaft({ node, y, height }) {
172
+ const segmentCount = getShaftSegmentCount(node);
173
+ const segmentHeight = height / segmentCount;
174
+ return (_jsx("group", { children: Array.from({ length: segmentCount }, (_, index) => {
175
+ const t = (index + 0.5) / segmentCount;
176
+ const profileScale = getShaftScaleAt(node, t);
177
+ return (_jsx("group", { rotation: [0, getShaftTwistRadians(node, index), 0], children: _jsx(RoundBlock, { height: segmentHeight * 1.015, radius: node.radius * profileScale, segments: getSegments(node), y: y + index * segmentHeight }) }, index));
178
+ }) }));
179
+ }
180
+ function TaperedSquareShaft({ node, y, height }) {
181
+ const segmentCount = getShaftSegmentCount(node);
182
+ const segmentHeight = height / segmentCount;
183
+ return (_jsx("group", { children: Array.from({ length: segmentCount }, (_, index) => {
184
+ const t = (index + 0.5) / segmentCount;
185
+ const profileScale = getShaftScaleAt(node, t);
186
+ return (_jsx("group", { rotation: [0, getShaftTwistRadians(node, index), 0], children: _jsx(RoundedRectangleShaftSegment, { cornerRadius: (node.shaftCornerRadius ?? 0.035) * profileScale, depth: node.depth * profileScale, height: segmentHeight * 1.015, width: node.width * profileScale, y: y + index * segmentHeight }) }, index));
187
+ }) }));
188
+ }
189
+ function Shaft({ node, y, height }) {
190
+ if (height <= 0)
191
+ return null;
192
+ if (node.style === 'cluster') {
193
+ const sideRadius = Math.max(0.04, node.radius * 0.36);
194
+ const offset = Math.max(node.radius * 0.78, node.width * 0.22);
195
+ return (_jsxs("group", { children: [_jsx(RoundBlock, { height: height, radius: node.radius * 0.62, segments: 24, y: y }), [
196
+ [offset, 0],
197
+ [-offset, 0],
198
+ [0, offset],
199
+ [0, -offset],
200
+ ].map(([x, z], index) => (_jsx(RoundBlock, { height: height, radius: sideRadius, segments: 16, x: x, y: y, z: z }, `${x}-${z}-${index}`)))] }));
201
+ }
202
+ if (node.crossSection === 'round' ||
203
+ node.crossSection === 'octagonal' ||
204
+ node.crossSection === 'sixteen-sided') {
205
+ return _jsx(TaperedRoundShaft, { height: height, node: node, y: y });
206
+ }
207
+ return _jsx(TaperedSquareShaft, { height: height, node: node, y: y });
208
+ }
209
+ function Base({ node, height }) {
210
+ if (height <= 0)
211
+ return null;
212
+ const baseStyle = node.baseStyle ?? 'round-rings';
213
+ const widthScale = node.baseWidthScale ?? 1.24;
214
+ const depthScale = node.baseDepthScale ?? widthScale;
215
+ if (baseStyle === 'none')
216
+ return null;
217
+ if (baseStyle === 'simple-square') {
218
+ return (_jsx(SquareBlock, { depth: node.depth * depthScale, height: height, width: node.width * widthScale, y: 0 }));
219
+ }
220
+ if (baseStyle === 'square-plinth') {
221
+ return (_jsxs("group", { children: [_jsx(SquareBlock, { depth: node.depth * depthScale, height: height * 0.35, width: node.width * widthScale, y: 0 }), _jsx(SquareBlock, { depth: node.depth * Math.max(0.9, depthScale * 0.84), height: height * 0.65, width: node.width * Math.max(0.9, widthScale * 0.84), y: height * 0.35 })] }));
222
+ }
223
+ if (baseStyle === 'stepped-square') {
224
+ const tierCount = Math.max(3, node.baseTierCount ?? 3);
225
+ const tierHeight = height / tierCount;
226
+ const stepSpread = node.baseStepSpread ?? 0.42;
227
+ return (_jsx("group", { children: Array.from({ length: tierCount }, (_, index) => {
228
+ const t = index / Math.max(1, tierCount - 1);
229
+ const widthScaleAt = Math.max(0.5, widthScale - t * stepSpread);
230
+ const depthScaleAt = Math.max(0.5, depthScale - t * stepSpread);
231
+ return (_jsx(SquareBlock, { depth: node.depth * depthScaleAt, height: tierHeight * 1.01, width: node.width * widthScaleAt, y: index * tierHeight }, index));
232
+ }) }));
233
+ }
234
+ if (baseStyle === 'round-rings') {
235
+ const baseWidth = node.width * widthScale;
236
+ const baseDepth = node.depth * depthScale;
237
+ const plinthRatio = Math.min(0.7, Math.max(0.2, node.basePlinthHeightRatio ?? 0.44));
238
+ const plinthHeight = height * plinthRatio;
239
+ const roundedHeight = height - plinthHeight;
240
+ const bandHeight = roundedHeight * 0.57;
241
+ const neckHeight = roundedHeight - bandHeight;
242
+ const bandScale = node.baseRoundBandScale ?? 0.92;
243
+ const neckScale = node.baseNeckScale ?? 0.72;
244
+ return (_jsxs("group", { children: [_jsx(SquareBlock, { depth: baseDepth, height: plinthHeight, width: baseWidth, y: 0 }), _jsx(OvalBlock, { depth: baseDepth * bandScale, height: bandHeight, segments: 32, width: baseWidth * bandScale, y: plinthHeight }), _jsx(OvalBlock, { depth: baseDepth * neckScale, height: neckHeight, segments: 32, width: baseWidth * neckScale, y: plinthHeight + bandHeight })] }));
245
+ }
246
+ if (baseStyle === 'lotus' || baseStyle === 'ribbed-lotus') {
247
+ const ribCount = node.baseRibCount ?? (baseStyle === 'ribbed-lotus' ? 24 : 14);
248
+ const ribRadius = Math.max(0.01, node.width * 0.025);
249
+ const baseRadius = Math.max(node.radius * widthScale, node.width * widthScale * 0.5);
250
+ return (_jsxs("group", { children: [_jsx(SquareBlock, { depth: node.depth * 1.28, height: height * 0.22, width: node.width * 1.28, y: 0 }), _jsx(RoundBlock, { height: height * 0.24, radius: baseRadius * 0.86, segments: 32, y: height * 0.22 }), Array.from({ length: ribCount }, (_, index) => {
251
+ const angle = (index / ribCount) * Math.PI * 2;
252
+ return (_jsx(MappedCylinder, { height: height * 0.38, position: [
253
+ Math.cos(angle) * baseRadius * 0.86,
254
+ height * 0.58,
255
+ Math.sin(angle) * baseRadius * 0.86,
256
+ ], radius: ribRadius, rotation: [0, -angle, 0], segments: 6 }, index));
257
+ }), _jsx(RoundBlock, { height: height * 0.16, radius: baseRadius * 0.72, segments: 32, y: height * 0.82 })] }));
258
+ }
259
+ if (baseStyle === 'panelled-pedestal') {
260
+ const inset = node.basePanelInset ?? 0.02;
261
+ return (_jsxs("group", { children: [_jsx(SquareBlock, { depth: node.depth * widthScale, height: height, width: node.width * widthScale, y: 0 }), [
262
+ [0, node.depth * widthScale * 0.51, 0],
263
+ [0, -node.depth * widthScale * 0.51, 0],
264
+ [node.width * widthScale * 0.51, 0, Math.PI / 2],
265
+ [-node.width * widthScale * 0.51, 0, Math.PI / 2],
266
+ ].map(([x, z, rotation], index) => (_jsx(MappedBox, { depth: inset, height: height * 0.42, position: [x, height * 0.5, z], rotation: [0, rotation, 0], softenEdges: false, width: node.width * 0.36 }, index)))] }));
267
+ }
268
+ return _jsx(ColumnBlock, { height: height, node: node, scale: 1.12, y: 0 });
269
+ }
270
+ function BaseCarvings({ node, height }) {
271
+ const placement = node.carvingPlacement ?? 'capital';
272
+ const carvingLevel = node.baseCarvingLevel ?? 0;
273
+ if (carvingLevel <= 0 || height <= 0 || (placement !== 'base' && placement !== 'all')) {
274
+ return null;
275
+ }
276
+ const count = Math.max(8, carvingLevel * 8);
277
+ const radius = Math.max(node.radius * 1.04, Math.max(node.width, node.depth) * 0.5);
278
+ const y = height * 0.52;
279
+ return (_jsx("group", { children: Array.from({ length: count }, (_, index) => {
280
+ const angle = (index / count) * Math.PI * 2;
281
+ return (_jsx(MappedCone, { height: height * 0.28, position: [Math.cos(angle) * radius, y, Math.sin(angle) * radius], radiusX: 0.014, radiusZ: 0.01, rotation: [0.36, -angle, 0], segments: 5 }, index));
282
+ }) }));
283
+ }
284
+ function Rings({ node, shaftY, shaftHeight, }) {
285
+ if (node.ringCount <= 0 || shaftHeight <= 0)
286
+ return null;
287
+ const ringPlacement = node.ringPlacement ?? 'ends';
288
+ const ringSpread = Math.min(0.45, Math.max(0.04, node.ringSpread ?? 0.16));
289
+ const ringHeight = Math.min(node.ringThickness ?? 0.055, shaftHeight / Math.max(8, node.ringCount * 3));
290
+ const rings = Array.from({ length: node.ringCount }, (_, index) => {
291
+ const pairIndex = Math.floor(index / 2);
292
+ const nearTop = index % 2 === 1;
293
+ const pairCount = Math.ceil(node.ringCount / 2);
294
+ const pairT = pairCount <= 1 ? 0 : pairIndex / (pairCount - 1);
295
+ const offset = Math.min(0.48, 0.06 + pairT * Math.max(0, ringSpread - 0.06));
296
+ const oneSideT = 0.06 + (index / Math.max(1, node.ringCount - 1)) * Math.max(0, ringSpread - 0.06);
297
+ const t = ringPlacement === 'even'
298
+ ? (index + 1) / (node.ringCount + 1)
299
+ : ringPlacement === 'top'
300
+ ? 1 - Math.min(0.48, oneSideT)
301
+ : ringPlacement === 'bottom'
302
+ ? Math.min(0.48, oneSideT)
303
+ : nearTop
304
+ ? 1 - offset
305
+ : offset;
306
+ return {
307
+ scale: Math.min(1.4, getShaftScaleAt(node, t) + 0.12),
308
+ y: shaftY + shaftHeight * t - ringHeight / 2,
309
+ };
310
+ }).sort((a, b) => a.y - b.y);
311
+ return (_jsx("group", { children: rings.map((ring, index) => (_jsx(ColumnBlock, { height: ringHeight, node: node, scale: ring.scale, y: ring.y }, index))) }));
312
+ }
313
+ function LatheBands({ node, shaftY, shaftHeight, }) {
314
+ const latheRingCount = Math.max(node.latheRingCount ?? 0, node.shaftDetail === 'lathe-turned' ? 8 : 0);
315
+ if (latheRingCount <= 0 || shaftHeight <= 0)
316
+ return null;
317
+ const placement = node.latheRingSpacing ?? 'ends';
318
+ const bandHeight = Math.min(0.04, shaftHeight / Math.max(12, latheRingCount * 3));
319
+ const bands = Array.from({ length: latheRingCount }, (_, index) => {
320
+ const pairIndex = Math.floor(index / 2);
321
+ const nearTop = index % 2 === 1;
322
+ const offset = Math.min(0.48, 0.1 + pairIndex * 0.04);
323
+ const t = placement === 'even'
324
+ ? (index + 1) / (latheRingCount + 1)
325
+ : placement === 'top'
326
+ ? 1 - Math.min(0.48, 0.08 + index * 0.04)
327
+ : placement === 'bottom'
328
+ ? Math.min(0.48, 0.08 + index * 0.04)
329
+ : nearTop
330
+ ? 1 - offset
331
+ : offset;
332
+ return shaftY + shaftHeight * t - bandHeight / 2;
333
+ }).sort((a, b) => a - b);
334
+ return (_jsx("group", { children: bands.map((y, index) => (_jsx(ColumnBlock, { height: bandHeight, node: node, scale: 0.82 + (index % 2) * 0.08, y: y }, index))) }));
335
+ }
336
+ function Flutes({ node, shaftY, shaftHeight, }) {
337
+ const fluteCount = Math.max(node.fluteCount, node.shaftDetail === 'fluted' ? 16 : 0);
338
+ if (fluteCount <= 0 || shaftHeight <= 0 || node.crossSection !== 'round')
339
+ return null;
340
+ const fluteDepth = node.fluteDepth ?? 0.02;
341
+ const fluteWidth = node.fluteWidth ?? fluteDepth;
342
+ const fluteRadius = Math.max(0.006, fluteWidth * 0.42);
343
+ const shaftRadius = node.radius * 0.74;
344
+ return (_jsx("group", { children: Array.from({ length: fluteCount }, (_, index) => {
345
+ const angle = (index / fluteCount) * Math.PI * 2;
346
+ const x = Math.cos(angle) * shaftRadius;
347
+ const z = Math.sin(angle) * shaftRadius;
348
+ return (_jsx(MappedCylinder, { height: shaftHeight * 0.92, position: [x, shaftY + shaftHeight / 2, z], radius: fluteRadius, segments: 8 }, index));
349
+ }) }));
350
+ }
351
+ function DravidianShaftPanels({ node, shaftY, shaftHeight, }) {
352
+ const panelCount = Math.max(node.panelCount ?? 0, node.style === 'dravidian-carved' || node.shaftDetail === 'panelled' ? 3 : 0);
353
+ if (panelCount <= 0 || shaftHeight <= 0)
354
+ return null;
355
+ const shaftWidth = node.width * 0.72;
356
+ const shaftDepth = node.depth * 0.72;
357
+ const panelHeight = Math.min(0.42, shaftHeight / Math.max(4, panelCount + 2));
358
+ const panelWidth = node.width * 0.26;
359
+ const rail = Math.max(0.012, node.width * 0.028);
360
+ const reliefDepth = Math.max(0.012, node.panelInsetDepth ?? node.width * 0.025);
361
+ const rows = Array.from({ length: panelCount }, (_, index) => (index + 1) / (panelCount + 1));
362
+ const panelShape = node.panelShape ?? 'rectangle';
363
+ const PanelFace = ({ position, rotation = 0, }) => (_jsxs("group", { position: position, rotation: [0, rotation, 0], children: [_jsx(MappedBox, { depth: reliefDepth, height: rail, position: [0, panelHeight / 2, 0], softenEdges: false, width: panelWidth }), _jsx(MappedBox, { depth: reliefDepth, height: rail, position: [0, -panelHeight / 2, 0], softenEdges: false, width: panelWidth }), _jsx(MappedBox, { depth: reliefDepth, height: panelHeight, position: [panelWidth / 2, 0, 0], softenEdges: false, width: rail }), _jsx(MappedBox, { depth: reliefDepth, height: panelHeight, position: [-panelWidth / 2, 0, 0], softenEdges: false, width: rail }), panelShape === 'diamond' && (_jsx(MappedBox, { depth: reliefDepth, height: panelHeight * 0.42, position: [0, 0, 0], rotation: [0, 0, Math.PI / 4], softenEdges: false, width: rail * 1.2 })), panelShape === 'arched' && (_jsx(MappedTorus, { arc: Math.PI, position: [0, panelHeight * 0.28, 0], ringRadius: panelWidth * 0.42, scaleX: panelWidth * 0.42, scaleY: rail, scaleZ: reliefDepth, tubeRadius: Math.max(rail, reliefDepth) * 0.18 }))] }));
364
+ return (_jsx("group", { children: rows.map((t, rowIndex) => {
365
+ const y = shaftY + shaftHeight * t;
366
+ return (_jsxs("group", { children: [_jsx(PanelFace, { position: [0, y, shaftDepth / 2 + reliefDepth / 2] }), _jsx(PanelFace, { position: [0, y, -shaftDepth / 2 - reliefDepth / 2] }), _jsx(PanelFace, { position: [shaftWidth / 2 + reliefDepth / 2, y, 0], rotation: Math.PI / 2 }), _jsx(PanelFace, { position: [-shaftWidth / 2 - reliefDepth / 2, y, 0], rotation: Math.PI / 2 })] }, rowIndex));
367
+ }) }));
368
+ }
369
+ function SpiralRibs({ node, shaftY, shaftHeight, }) {
370
+ const spiralRibCount = node.spiralRibCount ?? 0;
371
+ const spiralTwist = node.spiralTwist ?? 0;
372
+ const shaftTaper = node.shaftTaper ?? 0;
373
+ const ribCountSetting = Math.max(spiralRibCount, node.shaftDetail === 'spiral' ? 12 : 0);
374
+ if (ribCountSetting <= 0 || spiralTwist === 0 || shaftHeight <= 0)
375
+ return null;
376
+ const ribCount = Math.min(ribCountSetting, 24);
377
+ const stepCount = 28;
378
+ const ribDistance = node.radius * 0.78;
379
+ const ribWidth = Math.max(0.012, node.radius * 0.06);
380
+ const segmentHeight = (shaftHeight / stepCount) * 1.18;
381
+ const lean = spiralTwist > 0 ? -0.55 : 0.55;
382
+ return (_jsx("group", { children: Array.from({ length: ribCount * stepCount }, (_, index) => {
383
+ const ribIndex = index % ribCount;
384
+ const stepIndex = Math.floor(index / ribCount);
385
+ const t = (stepIndex + 0.5) / stepCount;
386
+ const angle = (ribIndex / ribCount) * Math.PI * 2 + t * spiralTwist * Math.PI * 2;
387
+ const taperScale = 1 - Math.min(shaftTaper, 0.85) * t;
388
+ return (_jsx(MappedCylinder, { height: segmentHeight, position: [
389
+ Math.cos(angle) * ribDistance * taperScale,
390
+ shaftY + shaftHeight * t,
391
+ Math.sin(angle) * ribDistance * taperScale,
392
+ ], radius: ribWidth, rotation: [0, -angle, lean], segments: 8 }, index));
393
+ }) }));
394
+ }
395
+ function LowerCarvedBand({ node, shaftY, shaftHeight, }) {
396
+ const placement = node.carvingPlacement ?? 'capital';
397
+ if (!node.lowerBandEnabled ||
398
+ shaftHeight <= 0 ||
399
+ (placement !== 'shaft' && placement !== 'all')) {
400
+ return null;
401
+ }
402
+ const bandHeight = Math.min(node.lowerBandHeight ?? 0.24, shaftHeight * 0.35);
403
+ const y = shaftY + shaftHeight * 0.12;
404
+ const level = Math.max(1, node.lowerBandCarvingLevel ?? 1);
405
+ const count = Math.max(6, level * 6);
406
+ const distance = Math.max(node.radius * 0.82, Math.max(node.width, node.depth) * 0.36);
407
+ return (_jsxs("group", { children: [_jsx(ColumnBlock, { height: bandHeight, node: node, scale: 0.84, y: y }), Array.from({ length: count }, (_, index) => {
408
+ const angle = (index / count) * Math.PI * 2;
409
+ return (_jsx(MappedCylinder, { height: bandHeight * 0.62, position: [
410
+ Math.cos(angle) * distance,
411
+ y + bandHeight * 0.5,
412
+ Math.sin(angle) * distance,
413
+ ], radius: 0.012, rotation: [0, -angle, 0], segments: 5 }, index));
414
+ })] }));
415
+ }
416
+ function CapitalCarvings({ node, capitalY, capitalHeight, }) {
417
+ const placement = node.carvingPlacement ?? 'capital';
418
+ const carvingLevel = Math.max(node.carvingLevel ?? 0, node.capitalCarvingLevel ?? 0);
419
+ const bandSetting = node.capitalBandCount ?? 0;
420
+ if ((carvingLevel <= 0 && bandSetting <= 0) ||
421
+ capitalHeight <= 0 ||
422
+ (placement !== 'capital' && placement !== 'all')) {
423
+ return null;
424
+ }
425
+ const level = Math.min(Math.max(carvingLevel, bandSetting > 0 ? 1 : 0), 4);
426
+ const bandHeight = Math.min(0.035, capitalHeight / 8);
427
+ const bandCount = Math.min(bandSetting > 0 ? bandSetting : level + 1, 16);
428
+ const bands = Array.from({ length: bandCount }, (_, index) => {
429
+ const t = (index + 1) / (bandCount + 1);
430
+ return capitalY + capitalHeight * t - bandHeight / 2;
431
+ });
432
+ if (node.crossSection === 'square' || node.crossSection === 'rectangular') {
433
+ const dentilCount = Math.max(node.dentilCount ?? 0, level * 4, 4);
434
+ const dentilHeight = Math.min(0.08, capitalHeight * 0.28);
435
+ const dentilDepth = Math.min(0.08, Math.min(node.width, node.depth) * 0.16);
436
+ const dentilWidth = Math.max(0.025, node.width / (dentilCount * 1.75));
437
+ const halfWidth = node.width * 0.56;
438
+ const halfDepth = node.depth * 0.56;
439
+ const y = capitalY + capitalHeight * 0.28;
440
+ const xPositions = Array.from({ length: dentilCount }, (_, index) => {
441
+ const t = dentilCount === 1 ? 0.5 : index / (dentilCount - 1);
442
+ return -halfWidth + t * halfWidth * 2;
443
+ });
444
+ const zPositions = Array.from({ length: dentilCount }, (_, index) => {
445
+ const t = dentilCount === 1 ? 0.5 : index / (dentilCount - 1);
446
+ return -halfDepth + t * halfDepth * 2;
447
+ });
448
+ return (_jsxs("group", { children: [bands.map((bandY, index) => (_jsx(ColumnBlock, { height: bandHeight, node: node, scale: 1.28, y: bandY }, `band-${index}`))), xPositions.map((x, index) => (_jsxs("group", { children: [_jsx(MappedBox, { depth: dentilDepth, height: dentilHeight, position: [x, y, halfDepth], softenEdges: false, width: dentilWidth }), _jsx(MappedBox, { depth: dentilDepth, height: dentilHeight, position: [x, y, -halfDepth], softenEdges: false, width: dentilWidth })] }, `front-back-dentil-${index}`))), zPositions.map((z, index) => (_jsxs("group", { children: [_jsx(MappedBox, { depth: dentilWidth, height: dentilHeight, position: [halfWidth, y, z], softenEdges: false, width: dentilDepth }), _jsx(MappedBox, { depth: dentilWidth, height: dentilHeight, position: [-halfWidth, y, z], softenEdges: false, width: dentilDepth })] }, `side-dentil-${index}`)))] }));
449
+ }
450
+ const beadCount = Math.max(node.beadCount ?? 0, 8, level * 8);
451
+ const beadRadius = Math.max(0.012, Math.min(0.03, node.radius * 0.12));
452
+ const beadDistance = node.radius * 1.24;
453
+ const beadY = capitalY + capitalHeight * 0.24;
454
+ return (_jsxs("group", { children: [bands.map((bandY, index) => (_jsx(ColumnBlock, { height: bandHeight, node: node, scale: 1.24, y: bandY }, `band-${index}`))), Array.from({ length: beadCount }, (_, index) => {
455
+ const angle = (index / beadCount) * Math.PI * 2;
456
+ return (_jsx(MappedSphere, { position: [Math.cos(angle) * beadDistance, beadY, Math.sin(angle) * beadDistance], radius: beadRadius }, `bead-${index}`));
457
+ })] }));
458
+ }
459
+ function Volutes({ node, capitalY, capitalHeight, }) {
460
+ if (!['volute', 'ionic-volute'].includes(node.capitalStyle ?? 'simple') || capitalHeight <= 0)
461
+ return null;
462
+ const y = capitalY + capitalHeight * 0.62;
463
+ const radius = node.voluteSize ?? Math.min(0.085, Math.max(0.04, node.width * 0.12));
464
+ const x = node.width * 0.46;
465
+ const z = node.depth * 0.7;
466
+ const maxVolutes = Math.max(0, Math.min(node.voluteCount ?? 4, 8));
467
+ const volutes = [
468
+ {
469
+ position: [x, y, z],
470
+ rotation: [0, 0, 0],
471
+ },
472
+ {
473
+ position: [-x, y, z],
474
+ rotation: [0, 0, 0],
475
+ },
476
+ {
477
+ position: [x, y, -z],
478
+ rotation: [0, Math.PI, 0],
479
+ },
480
+ {
481
+ position: [-x, y, -z],
482
+ rotation: [0, Math.PI, 0],
483
+ },
484
+ {
485
+ position: [z, y, x],
486
+ rotation: [0, Math.PI / 2, 0],
487
+ },
488
+ {
489
+ position: [z, y, -x],
490
+ rotation: [0, Math.PI / 2, 0],
491
+ },
492
+ {
493
+ position: [-z, y, x],
494
+ rotation: [0, -Math.PI / 2, 0],
495
+ },
496
+ {
497
+ position: [-z, y, -x],
498
+ rotation: [0, -Math.PI / 2, 0],
499
+ },
500
+ ].slice(0, maxVolutes);
501
+ return (_jsx("group", { children: volutes.map((volute, index) => (_jsx(MappedTorus, { position: volute.position, ringRadius: radius, rotation: volute.rotation, scaleZ: radius * 0.28, tubeRadius: radius * 0.18 }, index))) }));
502
+ }
503
+ function LeafCarvings({ node, capitalY, capitalHeight, }) {
504
+ if (!['leaf-carved', 'corinthian-leaf'].includes(node.capitalStyle ?? 'simple') ||
505
+ capitalHeight <= 0) {
506
+ return null;
507
+ }
508
+ const leafCount = node.leafCount ?? (node.crossSection === 'round' ? 18 : 12);
509
+ const distance = Math.max(node.radius * 1.05, Math.max(node.width, node.depth) * 0.48);
510
+ const rowCount = Math.max(0, Math.min(node.leafRows ?? 2, 4));
511
+ const rows = Array.from({ length: rowCount }, (_, index) => ({
512
+ y: capitalY + capitalHeight * (0.3 + index * 0.16),
513
+ scale: 0.28 - index * 0.04,
514
+ offset: index % 2 === 0 ? 0 : Math.PI / leafCount,
515
+ }));
516
+ return (_jsx("group", { children: rows.flatMap((row, rowIndex) => Array.from({ length: leafCount }, (_, index) => {
517
+ const angle = (index / leafCount) * Math.PI * 2 + row.offset;
518
+ return (_jsx(MappedCone, { height: capitalHeight * row.scale, position: [Math.cos(angle) * distance, row.y, Math.sin(angle) * distance], radiusX: 0.018, radiusZ: 0.01, rotation: [0.48, -angle, 0], segments: 6 }, `${rowIndex}-${index}`));
519
+ })) }));
520
+ }
521
+ function Capital({ node, y, height }) {
522
+ if (height <= 0)
523
+ return null;
524
+ const capitalStyle = node.capitalStyle ?? 'simple';
525
+ if (capitalStyle === 'none')
526
+ return null;
527
+ if (capitalStyle === 'south-indian-bracket' || capitalStyle === 'wood-bracket') {
528
+ const tierCount = Math.max(1, node.bracketTierCount ?? 3);
529
+ const tierHeight = height / tierCount;
530
+ const bracketDepth = node.bracketDepth ?? 0.35;
531
+ return (_jsxs("group", { children: [Array.from({ length: tierCount }, (_, index) => {
532
+ const t = index / Math.max(1, tierCount - 1);
533
+ const scale = (node.capitalWidthScale ?? 1.6) + t * 0.32;
534
+ return (_jsx(SquareBlock, { depth: node.depth * scale + bracketDepth * t, height: tierHeight, width: node.width * scale + bracketDepth * t, y: y + index * tierHeight }, index));
535
+ }), Array.from({ length: node.pendantCount ?? 0 }, (_, index) => {
536
+ const count = Math.max(1, node.pendantCount ?? 0);
537
+ const angle = (index / count) * Math.PI * 2;
538
+ const distance = Math.max(node.width, node.depth) * 0.56;
539
+ return (_jsx(MappedCone, { height: height * 0.28, position: [Math.cos(angle) * distance, y - height * 0.1, Math.sin(angle) * distance], radiusX: 0.035, rotation: [0, 0, 0], segments: 6 }, index));
540
+ })] }));
541
+ }
542
+ if (capitalStyle === 'rounded' || capitalStyle === 'doric') {
543
+ const topWidth = node.width * (node.capitalWidthScale ?? 1.34);
544
+ const topDepth = node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.34);
545
+ return (_jsxs("group", { children: [_jsx(OvalBlock, { depth: topDepth * 0.72, height: height * 0.24, segments: 32, width: topWidth * 0.72, y: y }), _jsx(OvalBlock, { depth: topDepth * 0.92, height: height * 0.32, segments: 32, width: topWidth * 0.92, y: y + height * 0.24 }), _jsx(SquareBlock, { depth: topDepth, height: height * 0.44, width: topWidth, y: y + height * 0.56 })] }));
546
+ }
547
+ if (capitalStyle === 'stepped') {
548
+ const widthScale = node.capitalWidthScale ?? 1.46;
549
+ const depthScale = node.capitalDepthScale ?? widthScale;
550
+ const tierCount = Math.max(3, node.capitalTierCount ?? 3);
551
+ const tierHeight = height / tierCount;
552
+ const stepSpread = node.capitalStepSpread ?? 0.42;
553
+ return (_jsx("group", { children: Array.from({ length: tierCount }, (_, index) => {
554
+ const t = index / Math.max(1, tierCount - 1);
555
+ const widthScaleAt = Math.max(0.5, widthScale - (1 - t) * stepSpread);
556
+ const depthScaleAt = Math.max(0.5, depthScale - (1 - t) * stepSpread);
557
+ return (_jsx(SquareBlock, { depth: node.depth * depthScaleAt, height: tierHeight * 1.01, width: node.width * widthScaleAt, y: y + index * tierHeight }, index));
558
+ }) }));
559
+ }
560
+ if (capitalStyle === 'volute' ||
561
+ capitalStyle === 'ionic-volute' ||
562
+ capitalStyle === 'leaf-carved' ||
563
+ capitalStyle === 'corinthian-leaf') {
564
+ const topWidth = node.width * (node.capitalWidthScale ?? 1.46);
565
+ const topDepth = node.depth * (node.capitalDepthScale ?? node.capitalWidthScale ?? 1.46);
566
+ return (_jsxs("group", { children: [_jsx(ColumnBlock, { height: height * 0.24, node: node, scale: 0.9, y: y }), _jsx(ColumnBlock, { height: height * 0.2, node: node, scale: 1.08, y: y + height * 0.24 }), _jsx(SquareBlock, { depth: topDepth, height: height * 0.28, width: topWidth, y: y + height * 0.44 }), _jsx(Volutes, { capitalHeight: height, capitalY: y, node: node }), _jsx(LeafCarvings, { capitalHeight: height, capitalY: y, node: node })] }));
567
+ }
568
+ const widthScale = node.capitalWidthScale ?? (capitalStyle === 'simple-slab' ? 1.28 : 1.18);
569
+ const depthScale = node.capitalDepthScale ?? widthScale;
570
+ if (node.crossSection === 'square' || node.crossSection === 'rectangular') {
571
+ return (_jsx(SquareBlock, { depth: node.depth * depthScale, height: height, width: node.width * widthScale, y: y }));
572
+ }
573
+ return (_jsx(RoundBlock, { height: height, radius: Math.max(node.radius * widthScale, node.width * widthScale * 0.5), segments: getSegments(node), y: y }));
574
+ }
575
+ export const ColumnRenderer = ({ node }) => {
576
+ const ref = useRef(null);
577
+ const handlers = useNodeEvents(node, 'column');
578
+ const liveTransform = useLiveTransforms((state) => state.get(node.id));
579
+ const material = useMemo(() => createColumnMaterial({ material: node.material, materialPreset: node.materialPreset }), [
580
+ node.material,
581
+ node.material?.preset,
582
+ node.material?.properties,
583
+ node.material?.texture,
584
+ node.materialPreset,
585
+ ]);
586
+ useRegistry(node.id, node.type, ref);
587
+ const shaftLayout = useMemo(() => {
588
+ const baseHeight = node.baseStyle === 'none' ? 0 : Math.min(node.baseHeight, node.height * 0.4);
589
+ const capitalHeight = node.capitalStyle === 'none' ? 0 : Math.min(node.capitalHeight, node.height * 0.4);
590
+ const shaftHeight = Math.max(0.1, node.height - baseHeight - capitalHeight);
591
+ return { baseHeight, capitalHeight, shaftY: baseHeight, shaftHeight };
592
+ }, [node.baseHeight, node.baseStyle, node.capitalHeight, node.capitalStyle, node.height]);
593
+ return (_jsx(ColumnMaterialContext.Provider, { value: material, children: _jsx(ColumnEdgeSoftnessContext.Provider, { value: node.edgeSoftness ?? 0.025, children: _jsxs("group", { position: liveTransform?.position ?? node.position, ref: ref, rotation: [0, liveTransform?.rotation ?? node.rotation, 0], visible: node.visible, ...handlers, children: [_jsx(Base, { height: shaftLayout.baseHeight, node: node }), _jsx(BaseCarvings, { height: shaftLayout.baseHeight, node: node }), _jsx(Shaft, { height: shaftLayout.shaftHeight, node: node, y: shaftLayout.shaftY }), _jsx(Rings, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(LatheBands, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(Flutes, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(LowerCarvedBand, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(DravidianShaftPanels, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(SpiralRibs, { node: node, shaftHeight: shaftLayout.shaftHeight, shaftY: shaftLayout.shaftY }), _jsx(Capital, { height: shaftLayout.capitalHeight, node: node, y: shaftLayout.baseHeight + shaftLayout.shaftHeight }), _jsx(CapitalCarvings, { capitalHeight: shaftLayout.capitalHeight, capitalY: shaftLayout.baseHeight + shaftLayout.shaftHeight, node: node })] }) }) }));
594
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"door-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/door/door-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,kBAAkB,CAAA;AAMvE,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CA8BxD,CAAA"}
1
+ {"version":3,"file":"door-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/door/door-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAyB,MAAM,kBAAkB,CAAA;AAOvE,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAwBxD,CAAA"}
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useRegistry, useScene } from '@pascal-app/core';
3
- import { useLayoutEffect, useMemo, useRef } from 'react';
3
+ import { useLayoutEffect, useRef } from 'react';
4
+ import { MeshBasicMaterial } from 'three';
4
5
  import { useNodeEvents } from '../../../hooks/use-node-events';
5
- import { createMaterial, DEFAULT_DOOR_MATERIAL } from '../../../lib/materials';
6
+ const doorHitboxMaterial = new MeshBasicMaterial({ visible: false });
6
7
  export const DoorRenderer = ({ node }) => {
7
8
  const ref = useRef(null);
8
9
  useRegistry(node.id, 'door', ref);
@@ -11,11 +12,5 @@ export const DoorRenderer = ({ node }) => {
11
12
  }, [node.id]);
12
13
  const handlers = useNodeEvents(node, 'door');
13
14
  const isTransient = !!node.metadata?.isTransient;
14
- const material = useMemo(() => {
15
- const mat = node.material;
16
- if (!mat)
17
- return DEFAULT_DOOR_MATERIAL;
18
- return createMaterial(mat);
19
- }, [node.material, node.material?.preset, node.material?.properties, node.material?.texture]);
20
- return (_jsx("mesh", { castShadow: true, material: material, position: node.position, receiveShadow: true, ref: ref, rotation: node.rotation, visible: node.visible, ...(isTransient ? {} : handlers), children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
15
+ return (_jsx("mesh", { castShadow: true, material: doorHitboxMaterial, position: node.position, receiveShadow: true, ref: ref, rotation: node.rotation, visible: node.visible, ...(isTransient ? {} : handlers), children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
21
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"fence-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/fence/fence-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,kBAAkB,CAAA;AAUxE,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CA2B1D,CAAA"}
1
+ {"version":3,"file":"fence-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/fence/fence-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,kBAAkB,CAAA;AAUxE,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CAkC1D,CAAA"}
@@ -12,7 +12,7 @@ export const GuideRenderer = ({ node }) => {
12
12
  const ref = useRef(null);
13
13
  useRegistry(node.id, 'guide', ref);
14
14
  const resolvedUrl = useAssetUrl(node.url);
15
- return (_jsx("group", { position: node.position, ref: ref, rotation: [0, node.rotation[1], 0], visible: showGuides, children: resolvedUrl && (_jsx(Suspense, { children: _jsx(GuidePlane, { opacity: node.opacity, scale: node.scale, url: resolvedUrl }) })) }));
15
+ return (_jsx("group", { position: node.position, ref: ref, rotation: [0, node.rotation[1], 0], visible: showGuides && node.visible !== false, children: resolvedUrl && (_jsx(Suspense, { children: _jsx(GuidePlane, { opacity: node.opacity, scale: node.scale, url: resolvedUrl }) })) }));
16
16
  };
17
17
  const GuidePlane = ({ url, scale, opacity }) => {
18
18
  const tex = useLoader(TextureLoader, url);
@@ -1 +1 @@
1
- {"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAkCzB,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAiBxD,CAAA"}
1
+ {"version":3,"file":"item-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/item/item-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAKd,MAAM,kBAAkB,CAAA;AAmCzB,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAiBxD,CAAA"}