@pascal-app/viewer 0.8.0 → 0.9.1

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 (194) hide show
  1. package/dist/components/renderers/node-renderer.d.ts +1 -1
  2. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  3. package/dist/components/renderers/node-renderer.js +38 -22
  4. package/dist/components/renderers/parametric-node-renderer.d.ts +5 -0
  5. package/dist/components/renderers/parametric-node-renderer.d.ts.map +1 -0
  6. package/dist/components/renderers/parametric-node-renderer.js +34 -0
  7. package/dist/components/renderers/scene-renderer.d.ts +1 -1
  8. package/dist/components/renderers/scene-renderer.d.ts.map +1 -1
  9. package/dist/components/viewer/ground-occluder.d.ts +1 -1
  10. package/dist/components/viewer/ground-occluder.d.ts.map +1 -1
  11. package/dist/components/viewer/ground-occluder.js +12 -24
  12. package/dist/components/viewer/index.d.ts +37 -1
  13. package/dist/components/viewer/index.d.ts.map +1 -1
  14. package/dist/components/viewer/index.js +186 -63
  15. package/dist/components/viewer/lights.d.ts +1 -1
  16. package/dist/components/viewer/lights.d.ts.map +1 -1
  17. package/dist/components/viewer/lights.js +170 -43
  18. package/dist/components/viewer/perf-monitor.d.ts +1 -1
  19. package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
  20. package/dist/components/viewer/perf-monitor.js +99 -11
  21. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  22. package/dist/components/viewer/post-processing.js +231 -54
  23. package/dist/components/viewer/registered-systems.d.ts +12 -0
  24. package/dist/components/viewer/registered-systems.d.ts.map +1 -0
  25. package/dist/components/viewer/registered-systems.js +47 -0
  26. package/dist/components/viewer/scene-bvh.d.ts +17 -0
  27. package/dist/components/viewer/scene-bvh.d.ts.map +1 -0
  28. package/dist/components/viewer/scene-bvh.js +94 -0
  29. package/dist/components/viewer/selection-manager.d.ts +1 -1
  30. package/dist/components/viewer/selection-manager.d.ts.map +1 -1
  31. package/dist/components/viewer/selection-manager.js +20 -5
  32. package/dist/components/viewer/viewer-camera.d.ts +1 -1
  33. package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
  34. package/dist/components/viewer/walkthrough-controls.d.ts +1 -1
  35. package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -1
  36. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  37. package/dist/hooks/use-node-events.d.ts +5 -73
  38. package/dist/hooks/use-node-events.d.ts.map +1 -1
  39. package/dist/hooks/use-node-events.js +19 -7
  40. package/dist/index.d.ts +36 -4
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +67 -3
  43. package/dist/lib/csg-utils.d.ts +16 -0
  44. package/dist/lib/csg-utils.d.ts.map +1 -0
  45. package/dist/lib/csg-utils.js +33 -0
  46. package/dist/lib/drawable-geometry.d.ts +21 -0
  47. package/dist/lib/drawable-geometry.d.ts.map +1 -0
  48. package/dist/lib/drawable-geometry.js +22 -0
  49. package/dist/lib/edge-style.d.ts +3 -0
  50. package/dist/lib/edge-style.d.ts.map +1 -0
  51. package/dist/lib/edge-style.js +11 -0
  52. package/dist/lib/gpu-perf.d.ts +4 -0
  53. package/dist/lib/gpu-perf.d.ts.map +1 -0
  54. package/dist/lib/gpu-perf.js +23 -0
  55. package/dist/lib/ink-edges.d.ts +9 -0
  56. package/dist/lib/ink-edges.d.ts.map +1 -0
  57. package/dist/lib/ink-edges.js +43 -0
  58. package/dist/lib/isolation.d.ts +39 -0
  59. package/dist/lib/isolation.d.ts.map +1 -0
  60. package/dist/lib/isolation.js +103 -0
  61. package/dist/lib/layers.d.ts +18 -0
  62. package/dist/lib/layers.d.ts.map +1 -1
  63. package/dist/lib/layers.js +18 -0
  64. package/dist/lib/materials.d.ts +25 -15
  65. package/dist/lib/materials.d.ts.map +1 -1
  66. package/dist/lib/materials.js +277 -62
  67. package/dist/lib/merged-outline-node.d.ts.map +1 -1
  68. package/dist/lib/merged-outline-node.js +7 -0
  69. package/dist/lib/polygon-union.d.ts +4 -0
  70. package/dist/lib/polygon-union.d.ts.map +1 -0
  71. package/dist/lib/polygon-union.js +289 -0
  72. package/dist/lib/polygon-union.test.d.ts +2 -0
  73. package/dist/lib/polygon-union.test.d.ts.map +1 -0
  74. package/dist/lib/polygon-union.test.js +105 -0
  75. package/dist/lib/scene-themes.d.ts +29 -0
  76. package/dist/lib/scene-themes.d.ts.map +1 -0
  77. package/dist/lib/scene-themes.js +193 -0
  78. package/dist/store/use-viewer.d.ts +42 -4
  79. package/dist/store/use-viewer.d.ts.map +1 -1
  80. package/dist/store/use-viewer.js +26 -3
  81. package/dist/systems/ceiling/ceiling-system.d.ts +6 -2
  82. package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
  83. package/dist/systems/ceiling/ceiling-system.js +62 -12
  84. package/dist/systems/door/door-system.d.ts.map +1 -1
  85. package/dist/systems/door/door-system.js +373 -22
  86. package/dist/systems/elevator/elevator-interaction-system.d.ts +2 -0
  87. package/dist/systems/elevator/elevator-interaction-system.d.ts.map +1 -0
  88. package/dist/systems/elevator/elevator-interaction-system.js +62 -0
  89. package/dist/systems/fence/fence-system.d.ts +3 -0
  90. package/dist/systems/fence/fence-system.d.ts.map +1 -1
  91. package/dist/systems/fence/fence-system.js +9 -5
  92. package/dist/systems/floor-elevation/floor-elevation-system.d.ts +20 -0
  93. package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -0
  94. package/dist/systems/floor-elevation/floor-elevation-system.js +78 -0
  95. package/dist/systems/geometry/geometry-system.d.ts +34 -0
  96. package/dist/systems/geometry/geometry-system.d.ts.map +1 -0
  97. package/dist/systems/geometry/geometry-system.js +279 -0
  98. package/dist/systems/interactive/interactive-system.d.ts +1 -1
  99. package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
  100. package/dist/systems/item/item-system.d.ts +7 -0
  101. package/dist/systems/item/item-system.d.ts.map +1 -1
  102. package/dist/systems/item/item-system.js +8 -11
  103. package/dist/systems/item-light/item-light-system.d.ts +1 -1
  104. package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
  105. package/dist/systems/item-light/item-light-system.js +18 -5
  106. package/dist/systems/roof/roof-materials.d.ts +3 -2
  107. package/dist/systems/roof/roof-materials.d.ts.map +1 -1
  108. package/dist/systems/roof/roof-materials.js +38 -14
  109. package/dist/systems/roof/roof-system.d.ts +27 -0
  110. package/dist/systems/roof/roof-system.d.ts.map +1 -1
  111. package/dist/systems/roof/roof-system.js +396 -59
  112. package/dist/systems/slab/slab-system.d.ts.map +1 -1
  113. package/dist/systems/slab/slab-system.js +167 -49
  114. package/dist/systems/slab/slab-system.test.d.ts +2 -0
  115. package/dist/systems/slab/slab-system.test.d.ts.map +1 -0
  116. package/dist/systems/slab/slab-system.test.js +62 -0
  117. package/dist/systems/stair/stair-materials.d.ts +4 -3
  118. package/dist/systems/stair/stair-materials.d.ts.map +1 -1
  119. package/dist/systems/stair/stair-materials.js +30 -15
  120. package/dist/systems/stair/stair-system.d.ts.map +1 -1
  121. package/dist/systems/stair/stair-system.js +50 -61
  122. package/dist/systems/surface-hole-geometry.d.ts +3 -0
  123. package/dist/systems/surface-hole-geometry.d.ts.map +1 -0
  124. package/dist/systems/surface-hole-geometry.js +4 -0
  125. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  126. package/dist/systems/wall/wall-cutout.js +18 -2
  127. package/dist/systems/wall/wall-materials.d.ts +4 -3
  128. package/dist/systems/wall/wall-materials.d.ts.map +1 -1
  129. package/dist/systems/wall/wall-materials.js +52 -28
  130. package/dist/systems/wall/wall-system.d.ts.map +1 -1
  131. package/dist/systems/wall/wall-system.js +171 -26
  132. package/dist/systems/window/window-system.d.ts.map +1 -1
  133. package/dist/systems/window/window-system.js +71 -7
  134. package/package.json +3 -4
  135. package/dist/components/renderers/building/building-renderer.d.ts +0 -5
  136. package/dist/components/renderers/building/building-renderer.d.ts.map +0 -1
  137. package/dist/components/renderers/building/building-renderer.js +0 -11
  138. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts +0 -5
  139. package/dist/components/renderers/ceiling/ceiling-renderer.d.ts.map +0 -1
  140. package/dist/components/renderers/ceiling/ceiling-renderer.js +0 -58
  141. package/dist/components/renderers/column/column-renderer.d.ts +0 -5
  142. package/dist/components/renderers/column/column-renderer.d.ts.map +0 -1
  143. package/dist/components/renderers/column/column-renderer.js +0 -597
  144. package/dist/components/renderers/door/door-renderer.d.ts +0 -5
  145. package/dist/components/renderers/door/door-renderer.d.ts.map +0 -1
  146. package/dist/components/renderers/door/door-renderer.js +0 -16
  147. package/dist/components/renderers/fence/fence-renderer.d.ts +0 -5
  148. package/dist/components/renderers/fence/fence-renderer.d.ts.map +0 -1
  149. package/dist/components/renderers/fence/fence-renderer.js +0 -15
  150. package/dist/components/renderers/guide/guide-renderer.d.ts +0 -5
  151. package/dist/components/renderers/guide/guide-renderer.d.ts.map +0 -1
  152. package/dist/components/renderers/guide/guide-renderer.js +0 -38
  153. package/dist/components/renderers/item/item-renderer.d.ts +0 -5
  154. package/dist/components/renderers/item/item-renderer.d.ts.map +0 -1
  155. package/dist/components/renderers/item/item-renderer.js +0 -172
  156. package/dist/components/renderers/level/level-renderer.d.ts +0 -5
  157. package/dist/components/renderers/level/level-renderer.d.ts.map +0 -1
  158. package/dist/components/renderers/level/level-renderer.js +0 -11
  159. package/dist/components/renderers/roof/roof-materials.d.ts +0 -4
  160. package/dist/components/renderers/roof/roof-materials.d.ts.map +0 -1
  161. package/dist/components/renderers/roof/roof-materials.js +0 -16
  162. package/dist/components/renderers/roof/roof-renderer.d.ts +0 -5
  163. package/dist/components/renderers/roof/roof-renderer.d.ts.map +0 -1
  164. package/dist/components/renderers/roof/roof-renderer.js +0 -32
  165. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts +0 -5
  166. package/dist/components/renderers/roof-segment/roof-segment-renderer.d.ts.map +0 -1
  167. package/dist/components/renderers/roof-segment/roof-segment-renderer.js +0 -40
  168. package/dist/components/renderers/scan/scan-renderer.d.ts +0 -5
  169. package/dist/components/renderers/scan/scan-renderer.d.ts.map +0 -1
  170. package/dist/components/renderers/scan/scan-renderer.js +0 -54
  171. package/dist/components/renderers/site/site-renderer.d.ts +0 -5
  172. package/dist/components/renderers/site/site-renderer.d.ts.map +0 -1
  173. package/dist/components/renderers/site/site-renderer.js +0 -106
  174. package/dist/components/renderers/slab/slab-renderer.d.ts +0 -5
  175. package/dist/components/renderers/slab/slab-renderer.d.ts.map +0 -1
  176. package/dist/components/renderers/slab/slab-renderer.js +0 -58
  177. package/dist/components/renderers/spawn/spawn-renderer.d.ts +0 -5
  178. package/dist/components/renderers/spawn/spawn-renderer.d.ts.map +0 -1
  179. package/dist/components/renderers/spawn/spawn-renderer.js +0 -32
  180. package/dist/components/renderers/stair/stair-renderer.d.ts +0 -5
  181. package/dist/components/renderers/stair/stair-renderer.d.ts.map +0 -1
  182. package/dist/components/renderers/stair/stair-renderer.js +0 -603
  183. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +0 -5
  184. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +0 -1
  185. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +0 -51
  186. package/dist/components/renderers/wall/wall-renderer.d.ts +0 -5
  187. package/dist/components/renderers/wall/wall-renderer.d.ts.map +0 -1
  188. package/dist/components/renderers/wall/wall-renderer.js +0 -16
  189. package/dist/components/renderers/window/window-renderer.d.ts +0 -5
  190. package/dist/components/renderers/window/window-renderer.d.ts.map +0 -1
  191. package/dist/components/renderers/window/window-renderer.js +0 -21
  192. package/dist/components/renderers/zone/zone-renderer.d.ts +0 -5
  193. package/dist/components/renderers/zone/zone-renderer.d.ts.map +0 -1
  194. package/dist/components/renderers/zone/zone-renderer.js +0 -181
@@ -1,5 +0,0 @@
1
- import { type GuideNode } from '@pascal-app/core';
2
- export declare const GuideRenderer: ({ node }: {
3
- node: GuideNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=guide-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"guide-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/guide/guide-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAe,MAAM,kBAAkB,CAAA;AAS9D,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CAqB1D,CAAA"}
@@ -1,38 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRegistry } from '@pascal-app/core';
3
- import { useLoader } from '@react-three/fiber';
4
- import { Suspense, useMemo, useRef } from 'react';
5
- import { DoubleSide, TextureLoader } from 'three';
6
- import { float, texture } from 'three/tsl';
7
- import { MeshBasicNodeMaterial } from 'three/webgpu';
8
- import { useAssetUrl } from '../../../hooks/use-asset-url';
9
- import useViewer from '../../../store/use-viewer';
10
- export const GuideRenderer = ({ node }) => {
11
- const showGuides = useViewer((s) => s.showGuides);
12
- const ref = useRef(null);
13
- useRegistry(node.id, 'guide', ref);
14
- const resolvedUrl = useAssetUrl(node.url);
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
- };
17
- const GuidePlane = ({ url, scale, opacity }) => {
18
- const tex = useLoader(TextureLoader, url);
19
- const { width, height, material } = useMemo(() => {
20
- const img = tex.image;
21
- const w = img.width || 1;
22
- const h = img.height || 1;
23
- const aspect = w / h;
24
- // Default: 10 meters wide, height from aspect ratio
25
- const planeWidth = 10 * scale;
26
- const planeHeight = (10 / aspect) * scale;
27
- const normalizedOpacity = opacity / 100;
28
- const mat = new MeshBasicNodeMaterial({
29
- transparent: true,
30
- colorNode: texture(tex),
31
- opacityNode: float(normalizedOpacity),
32
- side: DoubleSide,
33
- depthWrite: false,
34
- });
35
- return { width: planeWidth, height: planeHeight, material: mat };
36
- }, [tex, scale, opacity]);
37
- return (_jsx("mesh", { frustumCulled: false, material: material, raycast: () => { }, rotation: [-Math.PI / 2, 0, 0], children: _jsx("planeGeometry", { args: [width, height], boundingBox: null, boundingSphere: null }) }));
38
- };
@@ -1,5 +0,0 @@
1
- import { type ItemNode } from '@pascal-app/core';
2
- export declare const ItemRenderer: ({ node }: {
3
- node: ItemNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=item-renderer.d.ts.map
@@ -1 +0,0 @@
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"}
@@ -1,172 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useInteractive, useRegistry, useScene, } from '@pascal-app/core';
3
- import { useAnimations } from '@react-three/drei';
4
- import { Clone } from '@react-three/drei/core/Clone';
5
- import { useGLTF } from '@react-three/drei/core/Gltf';
6
- import { useFrame } from '@react-three/fiber';
7
- import { Suspense, useEffect, useMemo, useRef } from 'react';
8
- import { MathUtils } from 'three';
9
- import { positionLocal, smoothstep, time } from 'three/tsl';
10
- import { MeshStandardNodeMaterial } from 'three/webgpu';
11
- import { useNodeEvents } from '../../../hooks/use-node-events';
12
- import { resolveCdnUrl } from '../../../lib/asset-url';
13
- import { baseMaterial, glassMaterial } from '../../../lib/materials';
14
- import { useItemLightPool } from '../../../store/use-item-light-pool';
15
- import { ErrorBoundary } from '../../error-boundary';
16
- import { NodeRenderer } from '../node-renderer';
17
- const getMaterialForOriginal = (original) => {
18
- if (original.name.toLowerCase() === 'glass') {
19
- return glassMaterial;
20
- }
21
- return baseMaterial;
22
- };
23
- const BrokenItemFallback = ({ node }) => {
24
- const handlers = useNodeEvents(node, 'item');
25
- const [w, h, d] = node.asset.dimensions;
26
- return (_jsxs("mesh", { "position-y": h / 2, ...handlers, children: [_jsx("boxGeometry", { args: [w, h, d] }), _jsx("meshStandardMaterial", { color: "#ef4444", opacity: 0.6, transparent: true, wireframe: true })] }));
27
- };
28
- export const ItemRenderer = ({ node }) => {
29
- const ref = useRef(null);
30
- useRegistry(node.id, node.type, ref);
31
- return (_jsxs("group", { position: node.position, ref: ref, rotation: node.rotation, visible: node.visible, children: [_jsx(ErrorBoundary, { fallback: _jsx(BrokenItemFallback, { node: node }), children: _jsx(Suspense, { fallback: _jsx(PreviewModel, { node: node }), children: _jsx(ModelRenderer, { node: node }) }) }), node.children?.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId)))] }));
32
- };
33
- const previewMaterial = new MeshStandardNodeMaterial({
34
- color: '#cccccc',
35
- roughness: 1,
36
- metalness: 0,
37
- depthTest: false,
38
- });
39
- const previewOpacity = smoothstep(0.42, 0.55, positionLocal.y.add(time.mul(-0.2)).mul(10).fract());
40
- previewMaterial.opacityNode = previewOpacity;
41
- previewMaterial.transparent = true;
42
- const PreviewModel = ({ node }) => {
43
- return (_jsx("mesh", { material: previewMaterial, "position-y": node.asset.dimensions[1] / 2, children: _jsx("boxGeometry", { args: [node.asset.dimensions[0], node.asset.dimensions[1], node.asset.dimensions[2]] }) }));
44
- };
45
- const multiplyScales = (a, b) => [a[0] * b[0], a[1] * b[1], a[2] * b[2]];
46
- const ModelRenderer = ({ node }) => {
47
- const { scene, nodes, animations } = useGLTF(resolveCdnUrl(node.asset.src) || '');
48
- const ref = useRef(null);
49
- const { actions } = useAnimations(animations, ref);
50
- // Freeze the interactive definition at mount — asset schemas don't change at runtime
51
- const interactiveRef = useRef(node.asset.interactive);
52
- if (nodes.cutout) {
53
- nodes.cutout.visible = false;
54
- }
55
- const handlers = useNodeEvents(node, 'item');
56
- useEffect(() => {
57
- if (!node.parentId)
58
- return;
59
- useScene.getState().dirtyNodes.add(node.parentId);
60
- }, [node.parentId]);
61
- useEffect(() => {
62
- const interactive = interactiveRef.current;
63
- if (!interactive)
64
- return;
65
- useInteractive.getState().initItem(node.id, interactive);
66
- return () => useInteractive.getState().removeItem(node.id);
67
- }, [node.id]);
68
- useMemo(() => {
69
- scene.traverse((child) => {
70
- if (child.isMesh) {
71
- const mesh = child;
72
- if (mesh.name === 'cutout') {
73
- child.visible = false;
74
- return;
75
- }
76
- let hasGlass = false;
77
- // Handle both single material and material array cases
78
- if (Array.isArray(mesh.material)) {
79
- mesh.material = mesh.material.map((mat) => getMaterialForOriginal(mat));
80
- hasGlass = mesh.material.some((mat) => mat.name === 'glass');
81
- // Fix geometry groups that reference materialIndex beyond the material
82
- // array length — this causes three-mesh-bvh to crash with
83
- // "Cannot read properties of undefined (reading 'side')"
84
- const matCount = mesh.material.length;
85
- if (mesh.geometry.groups.length > 0) {
86
- for (const group of mesh.geometry.groups) {
87
- if (group.materialIndex !== undefined && group.materialIndex >= matCount) {
88
- group.materialIndex = 0;
89
- }
90
- }
91
- }
92
- }
93
- else {
94
- mesh.material = getMaterialForOriginal(mesh.material);
95
- hasGlass = mesh.material.name === 'glass';
96
- }
97
- mesh.castShadow = !hasGlass;
98
- mesh.receiveShadow = !hasGlass;
99
- }
100
- });
101
- }, [scene]);
102
- const interactive = interactiveRef.current;
103
- const animEffect = interactive?.effects.find((e) => e.kind === 'animation') ?? null;
104
- const lightEffects = interactive?.effects.filter((e) => e.kind === 'light') ?? [];
105
- return (_jsxs(_Fragment, { children: [_jsx(Clone, { object: scene, position: node.asset.offset, ref: ref, rotation: node.asset.rotation, scale: multiplyScales(node.asset.scale || [1, 1, 1], node.scale || [1, 1, 1]), ...handlers }), animations.length > 0 && (_jsx(ItemAnimation, { actions: actions, animations: animations, animEffect: animEffect, interactive: interactive ?? null, nodeId: node.id })), lightEffects.map((effect, i) => (_jsx(ItemLightRegistrar, { effect: effect, index: i, interactive: interactive, nodeId: node.id }, i)))] }));
106
- };
107
- const ItemAnimation = ({ nodeId, animEffect, interactive, actions, animations, }) => {
108
- const activeClipRef = useRef(null);
109
- const fadingOutRef = useRef(null);
110
- // Reactive: derive target clip name — only re-renders when the clip name itself changes
111
- const targetClip = useInteractive((s) => {
112
- const values = s.items[nodeId]?.controlValues;
113
- if (!animEffect)
114
- return animations[0]?.name ?? null;
115
- const toggleIndex = interactive.controls.findIndex((c) => c.kind === 'toggle');
116
- const isOn = toggleIndex >= 0 ? Boolean(values?.[toggleIndex]) : false;
117
- return isOn
118
- ? (animEffect.clips.on ?? null)
119
- : (animEffect.clips.off ?? animEffect.clips.loop ?? null);
120
- });
121
- // When target clip changes: kick off the transition
122
- useEffect(() => {
123
- // Cancel any ongoing fade-out immediately
124
- if (fadingOutRef.current) {
125
- fadingOutRef.current.timeScale = 0;
126
- fadingOutRef.current = null;
127
- }
128
- // Move current clip to fade-out
129
- if (activeClipRef.current && activeClipRef.current !== targetClip) {
130
- const old = actions[activeClipRef.current];
131
- if (old?.isRunning())
132
- fadingOutRef.current = old;
133
- }
134
- // Start new clip at timeScale 0.01 (as 0 would cause isRunning to be false and thus not play at all), then fade in to 1
135
- activeClipRef.current = targetClip;
136
- if (targetClip) {
137
- const next = actions[targetClip];
138
- if (next) {
139
- next.timeScale = 0.01;
140
- next.play();
141
- }
142
- }
143
- }, [targetClip, actions]);
144
- // useFrame: only lerping — no logic
145
- useFrame((_, delta) => {
146
- if (fadingOutRef.current) {
147
- const action = fadingOutRef.current;
148
- action.timeScale = MathUtils.lerp(action.timeScale, 0, Math.min(delta * 5, 1));
149
- if (action.timeScale < 0.01) {
150
- action.timeScale = 0;
151
- fadingOutRef.current = null;
152
- }
153
- }
154
- if (activeClipRef.current) {
155
- const action = actions[activeClipRef.current];
156
- if (action?.isRunning() && action.timeScale < 1) {
157
- action.timeScale = MathUtils.lerp(action.timeScale, 1, Math.min(delta * 5, 1));
158
- if (1 - action.timeScale < 0.01)
159
- action.timeScale = 1;
160
- }
161
- }
162
- });
163
- return null;
164
- };
165
- const ItemLightRegistrar = ({ nodeId, effect, interactive, index, }) => {
166
- useEffect(() => {
167
- const key = `${nodeId}:${index}`;
168
- useItemLightPool.getState().register(key, nodeId, effect, interactive);
169
- return () => useItemLightPool.getState().unregister(key);
170
- }, [nodeId, index, effect, interactive]);
171
- return null;
172
- };
@@ -1,5 +0,0 @@
1
- import { type LevelNode } from '@pascal-app/core';
2
- export declare const LevelRenderer: ({ node }: {
3
- node: LevelNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=level-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"level-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/level/level-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAe,MAAM,kBAAkB,CAAA;AAM9D,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CAa1D,CAAA"}
@@ -1,11 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRegistry } from '@pascal-app/core';
3
- import { useRef } from 'react';
4
- import { useNodeEvents } from '../../../hooks/use-node-events';
5
- import { NodeRenderer } from '../node-renderer';
6
- export const LevelRenderer = ({ node }) => {
7
- const ref = useRef(null);
8
- useRegistry(node.id, node.type, ref);
9
- const handlers = useNodeEvents(node, 'level');
10
- return (_jsx("group", { ref: ref, ...handlers, children: node.children.map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) }));
11
- };
@@ -1,4 +0,0 @@
1
- import * as THREE from 'three';
2
- export declare const roofMaterials: THREE.Material[];
3
- export declare const roofDebugMaterials: THREE.Material[];
4
- //# sourceMappingURL=roof-materials.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,QAAQ,EAKzC,CAAA;AAGD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,QAAQ,EAK9C,CAAA"}
@@ -1,16 +0,0 @@
1
- import * as THREE from 'three';
2
- // Production materials — match the rest of the scene (white walls, light-gray slabs).
3
- // Indices: 0 = Wall/Trim, 1 = Deck, 2 = Interior, 3 = Shingle
4
- export const roofMaterials = [
5
- new THREE.MeshStandardMaterial({ color: 'white', roughness: 1, side: THREE.DoubleSide }), // 0: Wall/Trim
6
- new THREE.MeshStandardMaterial({ color: '#e5e5e5', roughness: 1, side: THREE.FrontSide }), // 1: Deck
7
- new THREE.MeshStandardMaterial({ color: 'white', roughness: 1, side: THREE.DoubleSide }), // 2: Interior
8
- new THREE.MeshStandardMaterial({ color: '#e5e5e5', roughness: 0.9, side: THREE.FrontSide }), // 3: Shingle
9
- ];
10
- // Debug materials — vivid, distinct colours to identify each surface group.
11
- export const roofDebugMaterials = [
12
- new THREE.MeshStandardMaterial({ color: '#eaeaea', roughness: 0.8, side: THREE.DoubleSide }), // 0: Wall
13
- new THREE.MeshStandardMaterial({ color: '#000000', roughness: 0.9, side: THREE.FrontSide }), // 1: Deck
14
- new THREE.MeshStandardMaterial({ color: '#dddddd', roughness: 0.9, side: THREE.DoubleSide }), // 2: Interior
15
- new THREE.MeshStandardMaterial({ color: '#4ade80', roughness: 0.9, side: THREE.FrontSide }), // 3: Shingle
16
- ];
@@ -1,5 +0,0 @@
1
- import { type RoofNode } from '@pascal-app/core';
2
- export declare const RoofRenderer: ({ node }: {
3
- node: RoofNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=roof-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"roof-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/roof/roof-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,kBAAkB,CAAA;AAS7D,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAiDxD,CAAA"}
@@ -1,32 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRegistry } from '@pascal-app/core';
3
- import { useEffect, useMemo, useRef } from 'react';
4
- import * as THREE from 'three';
5
- import { useNodeEvents } from '../../../hooks/use-node-events';
6
- import useViewer from '../../../store/use-viewer';
7
- import { getRoofMaterialArray } from '../../../systems/roof/roof-materials';
8
- import { NodeRenderer } from '../node-renderer';
9
- import { roofDebugMaterials, roofMaterials } from './roof-materials';
10
- export const RoofRenderer = ({ node }) => {
11
- const ref = useRef(null);
12
- useRegistry(node.id, 'roof', ref);
13
- const handlers = useNodeEvents(node, 'roof');
14
- const debugColors = useViewer((s) => s.debugColors);
15
- const placeholderGeometry = useMemo(() => {
16
- const geometry = new THREE.BufferGeometry();
17
- geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
18
- geometry.addGroup(0, 0, 0);
19
- geometry.addGroup(0, 0, 1);
20
- geometry.addGroup(0, 0, 2);
21
- geometry.addGroup(0, 0, 3);
22
- return geometry;
23
- }, []);
24
- const customMaterial = useMemo(() => getRoofMaterialArray(node), [node]);
25
- const material = debugColors ? roofDebugMaterials : customMaterial || roofMaterials;
26
- useEffect(() => {
27
- return () => {
28
- placeholderGeometry.dispose();
29
- };
30
- }, [placeholderGeometry]);
31
- return (_jsxs("group", { position: node.position, ref: ref, "rotation-y": node.rotation, visible: node.visible, ...handlers, children: [_jsx("mesh", { castShadow: true, geometry: placeholderGeometry, material: material, name: "merged-roof", receiveShadow: true }), _jsx("group", { name: "segments-wrapper", visible: false, children: (node.children ?? []).map((childId) => (_jsx(NodeRenderer, { nodeId: childId }, childId))) })] }));
32
- };
@@ -1,5 +0,0 @@
1
- import { type RoofSegmentNode } from '@pascal-app/core';
2
- export declare const RoofSegmentRenderer: ({ node }: {
3
- node: RoofSegmentNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=roof-segment-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"roof-segment-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/roof-segment/roof-segment-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EAGrB,MAAM,kBAAkB,CAAA;AAQzB,eAAO,MAAM,mBAAmB,GAAI,UAAU;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,4CAgDtE,CAAA"}
@@ -1,40 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRegistry, useScene, } from '@pascal-app/core';
3
- import { useEffect, useMemo, useRef } from 'react';
4
- import * as THREE from 'three';
5
- import { useNodeEvents } from '../../../hooks/use-node-events';
6
- import useViewer from '../../../store/use-viewer';
7
- import { getRoofMaterialArray } from '../../../systems/roof/roof-materials';
8
- import { roofDebugMaterials, roofMaterials } from '../roof/roof-materials';
9
- export const RoofSegmentRenderer = ({ node }) => {
10
- const ref = useRef(null);
11
- const nodes = useScene((state) => state.nodes);
12
- useRegistry(node.id, 'roof-segment', ref);
13
- const handlers = useNodeEvents(node, 'roof-segment');
14
- const debugColors = useViewer((s) => s.debugColors);
15
- const parentNode = node.parentId
16
- ? nodes[node.parentId]
17
- : undefined;
18
- const placeholderGeometry = useMemo(() => {
19
- const geometry = new THREE.BufferGeometry();
20
- geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3));
21
- geometry.addGroup(0, 0, 0);
22
- geometry.addGroup(0, 0, 1);
23
- geometry.addGroup(0, 0, 2);
24
- geometry.addGroup(0, 0, 3);
25
- return geometry;
26
- }, []);
27
- const customMaterial = useMemo(() => {
28
- if (node.material !== undefined || typeof node.materialPreset === 'string') {
29
- return null;
30
- }
31
- return parentNode ? getRoofMaterialArray(parentNode) : null;
32
- }, [node, parentNode]);
33
- const material = debugColors ? roofDebugMaterials : customMaterial || roofMaterials;
34
- useEffect(() => {
35
- return () => {
36
- placeholderGeometry.dispose();
37
- };
38
- }, [placeholderGeometry]);
39
- return (_jsx("mesh", { geometry: placeholderGeometry, material: material, position: node.position, ref: ref, "rotation-y": node.rotation, visible: node.visible, ...handlers }));
40
- };
@@ -1,5 +0,0 @@
1
- import { type ScanNode } from '@pascal-app/core';
2
- export declare const ScanRenderer: ({ node }: {
3
- node: ScanNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=scan-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scan-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/scan/scan-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAe,MAAM,kBAAkB,CAAA;AAO7D,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAsBxD,CAAA"}
@@ -1,54 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRegistry } from '@pascal-app/core';
3
- import { Suspense, useMemo, useRef } from 'react';
4
- import { useAssetUrl } from '../../../hooks/use-asset-url';
5
- import { useGLTFKTX2 } from '../../../hooks/use-gltf-ktx2';
6
- import useViewer from '../../../store/use-viewer';
7
- export const ScanRenderer = ({ node }) => {
8
- const showScans = useViewer((s) => s.showScans);
9
- const ref = useRef(null);
10
- useRegistry(node.id, 'scan', ref);
11
- const resolvedUrl = useAssetUrl(node.url);
12
- return (_jsx("group", { position: node.position, ref: ref, rotation: node.rotation, scale: [node.scale, node.scale, node.scale], visible: showScans, children: resolvedUrl && (_jsx(Suspense, { children: _jsx(ScanModel, { opacity: node.opacity, url: resolvedUrl }) })) }));
13
- };
14
- const ScanModel = ({ url, opacity }) => {
15
- const gltf = useGLTFKTX2(url);
16
- const scene = gltf.scene;
17
- useMemo(() => {
18
- const normalizedOpacity = opacity / 100;
19
- const isTransparent = normalizedOpacity < 1;
20
- const updateMaterial = (material) => {
21
- if (isTransparent) {
22
- material.transparent = true;
23
- material.opacity = normalizedOpacity;
24
- material.depthWrite = false;
25
- }
26
- else {
27
- material.transparent = false;
28
- material.opacity = 1;
29
- material.depthWrite = true;
30
- }
31
- material.needsUpdate = true;
32
- };
33
- scene.traverse((child) => {
34
- if (child.isMesh) {
35
- const mesh = child;
36
- // Disable raycasting
37
- mesh.raycast = () => { };
38
- // Exclude from bounding box calculations
39
- mesh.geometry.boundingBox = null;
40
- mesh.geometry.boundingSphere = null;
41
- mesh.frustumCulled = false;
42
- if (Array.isArray(mesh.material)) {
43
- mesh.material.forEach((material) => {
44
- updateMaterial(material);
45
- });
46
- }
47
- else {
48
- updateMaterial(mesh.material);
49
- }
50
- }
51
- });
52
- }, [scene, opacity]);
53
- return _jsx("primitive", { object: scene });
54
- };
@@ -1,5 +0,0 @@
1
- import { type SiteNode } from '@pascal-app/core';
2
- export declare const SiteRenderer: ({ node }: {
3
- node: SiteNode;
4
- }) => import("react/jsx-runtime").JSX.Element | null;
5
- //# sourceMappingURL=site-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"site-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/site/site-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAwC,MAAM,kBAAkB,CAAA;AAmCtF,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,mDAyHxD,CAAA"}
@@ -1,106 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useRegistry, useScene } from '@pascal-app/core';
3
- import polygonClipping from 'polygon-clipping';
4
- import { useMemo, useRef } from 'react';
5
- import { BufferGeometry, Float32BufferAttribute, Path, Shape } from 'three';
6
- import { useNodeEvents } from '../../../hooks/use-node-events';
7
- import useViewer from '../../../store/use-viewer';
8
- import { NodeRenderer } from '../node-renderer';
9
- const Y_OFFSET = 0.01;
10
- /**
11
- * Creates simple line geometry for site boundary
12
- * Single horizontal line at ground level
13
- */
14
- const createBoundaryLineGeometry = (points) => {
15
- const geometry = new BufferGeometry();
16
- if (points.length < 2)
17
- return geometry;
18
- const positions = [];
19
- // Create a simple line loop at ground level
20
- for (const [x, z] of points) {
21
- positions.push(x ?? 0, Y_OFFSET, z ?? 0);
22
- }
23
- // Close the loop
24
- positions.push(points[0]?.[0] ?? 0, Y_OFFSET, points[0]?.[1] ?? 0);
25
- geometry.setAttribute('position', new Float32BufferAttribute(positions, 3));
26
- return geometry;
27
- };
28
- export const SiteRenderer = ({ node }) => {
29
- const ref = useRef(null);
30
- useRegistry(node.id, 'site', ref);
31
- const theme = useViewer((state) => state.theme);
32
- const bgColor = theme === 'dark' ? '#1f2433' : '#fafafa';
33
- // Cache slab polygon references to keep the selector stable across unrelated store updates
34
- const slabPolygonsCache = useRef([]);
35
- const slabPolygons = useScene((state) => {
36
- const nodeList = Object.values(state.nodes);
37
- const levelIndexById = new Map();
38
- let lowestLevelIndex = Number.POSITIVE_INFINITY;
39
- nodeList.forEach((n) => {
40
- if (n.type !== 'level')
41
- return;
42
- levelIndexById.set(n.id, n.level);
43
- lowestLevelIndex = Math.min(lowestLevelIndex, n.level);
44
- });
45
- const next = nodeList
46
- .filter((n) => n.type === 'slab' &&
47
- n.visible &&
48
- n.polygon.length >= 3 &&
49
- // Only recessed slabs should punch through the site ground.
50
- // Positive slabs are real floor geometry and should not create a
51
- // ghost footprint in the background ground fill.
52
- (n.elevation ?? 0.05) < 0)
53
- .filter((n) => {
54
- if (!Number.isFinite(lowestLevelIndex))
55
- return true;
56
- const parentLevel = n.parentId ? levelIndexById.get(n.parentId) : undefined;
57
- return parentLevel === lowestLevelIndex;
58
- })
59
- .map((n) => n.polygon);
60
- const prev = slabPolygonsCache.current;
61
- if (next.length === prev.length && next.every((p, i) => p === prev[i]))
62
- return prev;
63
- slabPolygonsCache.current = next;
64
- return next;
65
- });
66
- // Ground shape: site polygon with slab footprints punched as holes
67
- const groundShape = useMemo(() => {
68
- if (!node?.polygon?.points || node.polygon.points.length < 3)
69
- return null;
70
- const pts = node.polygon.points;
71
- const shape = new Shape();
72
- shape.moveTo(pts[0][0], -pts[0][1]);
73
- for (let i = 1; i < pts.length; i++)
74
- shape.lineTo(pts[i][0], -pts[i][1]);
75
- shape.closePath();
76
- if (slabPolygons.length > 0) {
77
- const multiPolygons = slabPolygons.map((p) => [
78
- p.map((pt) => [pt[0], -pt[1]]),
79
- ]);
80
- const unioned = polygonClipping.union(multiPolygons[0], ...multiPolygons.slice(1));
81
- for (const geom of unioned) {
82
- const ring = geom[0];
83
- if (ring && ring.length > 0) {
84
- const hole = new Path();
85
- hole.moveTo(ring[0][0], ring[0][1]);
86
- for (let i = 1; i < ring.length; i++)
87
- hole.lineTo(ring[i][0], ring[i][1]);
88
- hole.closePath();
89
- shape.holes.push(hole);
90
- }
91
- }
92
- }
93
- return shape;
94
- }, [node?.polygon?.points, slabPolygons]);
95
- // Create boundary line geometry
96
- const lineGeometry = useMemo(() => {
97
- if (!node?.polygon?.points || node.polygon.points.length < 2)
98
- return null;
99
- return createBoundaryLineGeometry(node.polygon.points);
100
- }, [node?.polygon?.points]);
101
- const handlers = useNodeEvents(node, 'site');
102
- if (!(node && lineGeometry)) {
103
- return null;
104
- }
105
- return (_jsxs("group", { ref: ref, ...handlers, children: [node.children.map((child) => (_jsx(NodeRenderer, { nodeId: typeof child === 'string' ? child : child.id }, typeof child === 'string' ? child : child.id))), groundShape && (_jsxs("mesh", { position: [0, -0.05, 0], receiveShadow: true, rotation: [-Math.PI / 2, 0, 0], children: [_jsx("shapeGeometry", { args: [groundShape] }), _jsx("meshStandardMaterial", { color: bgColor, depthWrite: true, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1 })] })), _jsx("line", { frustumCulled: false, geometry: lineGeometry, renderOrder: 9, children: _jsx("lineBasicMaterial", { color: "#f59e0b", linewidth: 2, opacity: 0.6, transparent: true }) })] }));
106
- };
@@ -1,5 +0,0 @@
1
- import { type SlabNode } from '@pascal-app/core';
2
- export declare const SlabRenderer: ({ node }: {
3
- node: SlabNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=slab-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slab-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/slab/slab-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,QAAQ,EAAe,MAAM,kBAAkB,CAAA;AA+CrF,eAAO,MAAM,YAAY,GAAI,UAAU;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,4CAuCxD,CAAA"}
@@ -1,58 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getMaterialPresetByRef, useRegistry } from '@pascal-app/core';
3
- import { useEffect, useMemo, useRef } from 'react';
4
- import * as THREE from 'three';
5
- import { useNodeEvents } from '../../../hooks/use-node-events';
6
- import { applyMaterialPresetToMaterials, createMaterial, DEFAULT_SLAB_MATERIAL, } from '../../../lib/materials';
7
- const slabMaterialCache = new Map();
8
- function getSlabMaterial(cacheKey, params) {
9
- const cached = slabMaterialCache.get(cacheKey);
10
- if (cached)
11
- return cached;
12
- const preset = getMaterialPresetByRef(params.materialPreset);
13
- const slabMaterial = preset
14
- ? new THREE.MeshStandardMaterial()
15
- : params.material
16
- ? createMaterial(params.material).clone()
17
- : DEFAULT_SLAB_MATERIAL.clone();
18
- if (preset) {
19
- // Apply the preset to the slab-owned material so async texture loads update
20
- // the instance we actually render after refresh as well.
21
- applyMaterialPresetToMaterials(slabMaterial, preset);
22
- }
23
- // Slabs participate in the WebGPU MRT scene pass. Keeping them opaque avoids
24
- // pipeline variants that can fail when geometry is regenerated while a
25
- // transparent/custom material is attached.
26
- slabMaterial.transparent = false;
27
- slabMaterial.opacity = 1;
28
- slabMaterial.alphaMap = null;
29
- slabMaterial.side = THREE.DoubleSide;
30
- slabMaterial.depthWrite = true;
31
- slabMaterial.needsUpdate = true;
32
- slabMaterialCache.set(cacheKey, slabMaterial);
33
- return slabMaterial;
34
- }
35
- export const SlabRenderer = ({ node }) => {
36
- const ref = useRef(null);
37
- useRegistry(node.id, 'slab', ref);
38
- const handlers = useNodeEvents(node, 'slab');
39
- const material = useMemo(() => {
40
- const resolvedMaterial = node.material;
41
- const resolvedMaterialPreset = node.materialPreset;
42
- const cacheKey = JSON.stringify({
43
- material: resolvedMaterial ?? null,
44
- materialPreset: resolvedMaterialPreset ?? null,
45
- });
46
- return getSlabMaterial(cacheKey, {
47
- material: resolvedMaterial,
48
- materialPreset: resolvedMaterialPreset,
49
- });
50
- }, [
51
- node.material,
52
- node.material?.preset,
53
- node.material?.properties,
54
- node.material?.texture,
55
- node.materialPreset,
56
- ]);
57
- return (_jsx("mesh", { castShadow: true, receiveShadow: true, ref: ref, ...handlers, material: material, visible: node.visible, children: _jsx("boxGeometry", { args: [0, 0, 0] }) }));
58
- };
@@ -1,5 +0,0 @@
1
- import { type SpawnNode } from '@pascal-app/core';
2
- export declare const SpawnRenderer: ({ node }: {
3
- node: SpawnNode;
4
- }) => import("react/jsx-runtime").JSX.Element;
5
- //# sourceMappingURL=spawn-renderer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"spawn-renderer.d.ts","sourceRoot":"","sources":["../../../../src/components/renderers/spawn/spawn-renderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAkC,MAAM,kBAAkB,CAAA;AASjF,eAAO,MAAM,aAAa,GAAI,UAAU;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,4CA0D1D,CAAA"}