@pascal-app/viewer 1.0.1 → 1.0.4
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.
- package/dist/components/renderers/node-renderer.d.ts.map +1 -1
- package/dist/components/renderers/node-renderer.js +8 -3
- package/dist/components/viewer/frame-limiter.d.ts +1 -0
- package/dist/components/viewer/frame-limiter.d.ts.map +1 -1
- package/dist/components/viewer/frame-limiter.js +22 -3
- package/dist/components/viewer/glb-interactive.d.ts +25 -1
- package/dist/components/viewer/glb-interactive.d.ts.map +1 -1
- package/dist/components/viewer/glb-interactive.js +252 -85
- package/dist/components/viewer/glb-mechanisms.d.ts +10 -0
- package/dist/components/viewer/glb-mechanisms.d.ts.map +1 -0
- package/dist/components/viewer/glb-mechanisms.js +19 -0
- package/dist/components/viewer/glb-scene.d.ts +45 -27
- package/dist/components/viewer/glb-scene.d.ts.map +1 -1
- package/dist/components/viewer/glb-scene.js +420 -506
- package/dist/components/viewer/glb-walkthrough-controller.d.ts +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.d.ts.map +1 -1
- package/dist/components/viewer/glb-walkthrough-controller.js +12 -1
- package/dist/components/viewer/index.d.ts +26 -0
- package/dist/components/viewer/index.d.ts.map +1 -1
- package/dist/components/viewer/index.js +108 -29
- package/dist/components/viewer/lights.d.ts.map +1 -1
- package/dist/components/viewer/lights.js +6 -1
- package/dist/components/viewer/perf-monitor.d.ts.map +1 -1
- package/dist/components/viewer/perf-monitor.js +6 -0
- package/dist/components/viewer/post-processing.d.ts.map +1 -1
- package/dist/components/viewer/post-processing.js +8 -3
- package/dist/components/viewer/registered-systems.d.ts.map +1 -1
- package/dist/components/viewer/registered-systems.js +16 -2
- package/dist/components/viewer/render-error.d.ts +18 -0
- package/dist/components/viewer/render-error.d.ts.map +1 -0
- package/dist/components/viewer/render-error.js +29 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts +6 -0
- package/dist/components/viewer/scene-ground-replacement.d.ts.map +1 -1
- package/dist/components/viewer/scene-ground-replacement.js +15 -0
- package/dist/components/viewer/selection-manager.d.ts.map +1 -1
- package/dist/components/viewer/selection-manager.js +10 -0
- package/dist/components/viewer/viewer-camera.d.ts +19 -1
- package/dist/components/viewer/viewer-camera.d.ts.map +1 -1
- package/dist/components/viewer/viewer-camera.js +53 -5
- package/dist/index.d.ts +28 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -18
- package/dist/lib/asset-url.d.ts.map +1 -1
- package/dist/lib/asset-url.js +7 -1
- package/dist/lib/csg-utils.d.ts +1 -1
- package/dist/lib/csg-utils.d.ts.map +1 -1
- package/dist/lib/csg-utils.js +1 -1
- package/dist/lib/display-state.d.ts +25 -0
- package/dist/lib/display-state.d.ts.map +1 -0
- package/dist/lib/display-state.js +1 -0
- package/dist/lib/hero-pose.d.ts +12 -2
- package/dist/lib/hero-pose.d.ts.map +1 -1
- package/dist/lib/hero-pose.js +72 -5
- package/dist/lib/ink-edges.d.ts +4 -2
- package/dist/lib/ink-edges.d.ts.map +1 -1
- package/dist/lib/ink-edges.js +17 -7
- package/dist/lib/key-light-override.d.ts +11 -0
- package/dist/lib/key-light-override.d.ts.map +1 -0
- package/dist/lib/key-light-override.js +14 -0
- package/dist/lib/live-frame-hold.d.ts +14 -0
- package/dist/lib/live-frame-hold.d.ts.map +1 -0
- package/dist/lib/live-frame-hold.js +28 -0
- package/dist/lib/materials.d.ts +14 -7
- package/dist/lib/materials.d.ts.map +1 -1
- package/dist/lib/materials.js +31 -5
- package/dist/lib/node-top-surface-height.d.ts +6 -0
- package/dist/lib/node-top-surface-height.d.ts.map +1 -0
- package/dist/lib/node-top-surface-height.js +74 -0
- package/dist/lib/perf-probe-state.d.ts +39 -0
- package/dist/lib/perf-probe-state.d.ts.map +1 -0
- package/dist/lib/perf-probe-state.js +17 -0
- package/dist/lib/pointer-events.d.ts +8 -0
- package/dist/lib/pointer-events.d.ts.map +1 -1
- package/dist/lib/pointer-events.js +27 -4
- package/dist/lib/procedural-emission.d.ts +7 -0
- package/dist/lib/procedural-emission.d.ts.map +1 -0
- package/dist/lib/procedural-emission.js +54 -0
- package/dist/lib/renderer-capability.d.ts +2 -1
- package/dist/lib/renderer-capability.d.ts.map +1 -1
- package/dist/lib/renderer-capability.js +2 -2
- package/dist/lib/scene-support-height.d.ts +4 -0
- package/dist/lib/scene-support-height.d.ts.map +1 -0
- package/dist/lib/scene-support-height.js +34 -0
- package/dist/lib/scene-visibility.d.ts +6 -0
- package/dist/lib/scene-visibility.d.ts.map +1 -1
- package/dist/lib/scene-visibility.js +15 -3
- package/dist/lib/scripted-opening.d.ts +11 -0
- package/dist/lib/scripted-opening.d.ts.map +1 -0
- package/dist/lib/scripted-opening.js +20 -0
- package/dist/lib/snapshot-pipeline.d.ts +32 -2
- package/dist/lib/snapshot-pipeline.d.ts.map +1 -1
- package/dist/lib/snapshot-pipeline.js +215 -105
- package/dist/lib/terrain-perimeter-fill.d.ts.map +1 -1
- package/dist/lib/terrain-perimeter-fill.js +22 -14
- package/dist/lib/zone-geometry.d.ts +11 -0
- package/dist/lib/zone-geometry.d.ts.map +1 -0
- package/dist/lib/zone-geometry.js +46 -0
- package/dist/store/use-item-light-pool.d.ts +14 -10
- package/dist/store/use-item-light-pool.d.ts.map +1 -1
- package/dist/store/use-item-light-pool.js +52 -26
- package/dist/store/use-viewer.d.ts +11 -0
- package/dist/store/use-viewer.d.ts.map +1 -1
- package/dist/store/use-viewer.js +13 -6
- package/dist/systems/ceiling/ceiling-system.d.ts +15 -1
- package/dist/systems/ceiling/ceiling-system.d.ts.map +1 -1
- package/dist/systems/ceiling/ceiling-system.js +86 -6
- package/dist/systems/door/door-system.d.ts.map +1 -1
- package/dist/systems/door/door-system.js +73 -22
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts +3 -1
- package/dist/systems/floor-elevation/floor-elevation-system.d.ts.map +1 -1
- package/dist/systems/floor-elevation/floor-elevation-system.js +148 -5
- package/dist/systems/geometry/geometry-system.d.ts.map +1 -1
- package/dist/systems/geometry/geometry-system.js +71 -11
- package/dist/systems/interactive/interactive-system.d.ts.map +1 -1
- package/dist/systems/interactive/interactive-system.js +40 -15
- package/dist/systems/interactive/procedural-controls.d.ts +13 -0
- package/dist/systems/interactive/procedural-controls.d.ts.map +1 -0
- package/dist/systems/interactive/procedural-controls.js +17 -0
- package/dist/systems/interactive/scripted-clips.d.ts +19 -0
- package/dist/systems/interactive/scripted-clips.d.ts.map +1 -0
- package/dist/systems/interactive/scripted-clips.js +134 -0
- package/dist/systems/item/item-system.d.ts.map +1 -1
- package/dist/systems/item/item-system.js +9 -3
- package/dist/systems/item/object-cut-invalidation.d.ts +3 -0
- package/dist/systems/item/object-cut-invalidation.d.ts.map +1 -0
- package/dist/systems/item/object-cut-invalidation.js +68 -0
- package/dist/systems/item-light/item-light-system.d.ts +1 -1
- package/dist/systems/item-light/item-light-system.d.ts.map +1 -1
- package/dist/systems/item-light/item-light-system.js +47 -52
- package/dist/systems/level/level-system.d.ts.map +1 -1
- package/dist/systems/level/level-system.js +17 -19
- package/dist/systems/level/level-utils.d.ts +28 -1
- package/dist/systems/level/level-utils.d.ts.map +1 -1
- package/dist/systems/level/level-utils.js +36 -4
- package/dist/systems/level/shadow-only-levels.d.ts +9 -0
- package/dist/systems/level/shadow-only-levels.d.ts.map +1 -0
- package/dist/systems/level/shadow-only-levels.js +7 -0
- package/dist/systems/roof/roof-materials.d.ts +14 -2
- package/dist/systems/roof/roof-materials.d.ts.map +1 -1
- package/dist/systems/roof/roof-materials.js +54 -15
- package/dist/systems/roof/roof-system.d.ts +13 -3
- package/dist/systems/roof/roof-system.d.ts.map +1 -1
- package/dist/systems/roof/roof-system.js +188 -13
- package/dist/systems/slab/slab-system.d.ts +1 -1
- package/dist/systems/slab/slab-system.d.ts.map +1 -1
- package/dist/systems/slab/slab-system.js +49 -19
- package/dist/systems/stair/stair-system.d.ts.map +1 -1
- package/dist/systems/stair/stair-system.js +133 -354
- package/dist/systems/wall/wall-cutout-cache.d.ts +11 -1
- package/dist/systems/wall/wall-cutout-cache.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout-cache.js +58 -20
- package/dist/systems/wall/wall-cutout.d.ts +9 -1
- package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
- package/dist/systems/wall/wall-cutout.js +46 -32
- package/dist/systems/wall/wall-finish-data.d.ts +22 -0
- package/dist/systems/wall/wall-finish-data.d.ts.map +1 -0
- package/dist/systems/wall/wall-finish-data.js +17 -0
- package/dist/systems/wall/wall-materials.d.ts +17 -3
- package/dist/systems/wall/wall-materials.d.ts.map +1 -1
- package/dist/systems/wall/wall-materials.js +109 -156
- package/dist/systems/wall/wall-system.d.ts +43 -4
- package/dist/systems/wall/wall-system.d.ts.map +1 -1
- package/dist/systems/wall/wall-system.js +601 -163
- package/dist/systems/window/window-system.d.ts +1 -1
- package/dist/systems/window/window-system.d.ts.map +1 -1
- package/dist/systems/window/window-system.js +44 -24
- package/dist/xr/presentation-context.d.ts +7 -0
- package/dist/xr/presentation-context.d.ts.map +1 -0
- package/dist/xr/presentation-context.js +10 -0
- package/package.json +6 -6
- package/dist/systems/fence/fence-system.d.ts +0 -22
- package/dist/systems/fence/fence-system.d.ts.map +0 -1
- package/dist/systems/fence/fence-system.js +0 -357
|
@@ -32,7 +32,12 @@ type ViewerState = {
|
|
|
32
32
|
cameraMode: 'perspective' | 'orthographic';
|
|
33
33
|
setCameraMode: (mode: 'perspective' | 'orthographic') => void;
|
|
34
34
|
sceneTheme: string;
|
|
35
|
+
/** The user's own pick, and the only theme that persists. */
|
|
36
|
+
savedSceneTheme: string;
|
|
35
37
|
setSceneTheme: (id: string) => void;
|
|
38
|
+
/** Show a theme without saving it (e.g. a project's own mood); `null`
|
|
39
|
+
* returns to the saved one. */
|
|
40
|
+
showSceneTheme: (id: string | null) => void;
|
|
36
41
|
renderContext: RenderContext;
|
|
37
42
|
setRenderContext: (context: RenderContext) => void;
|
|
38
43
|
/** True during a GLB bake/export pass. Renderers that normally draw via a
|
|
@@ -73,6 +78,12 @@ type ViewerState = {
|
|
|
73
78
|
unitExplicit: boolean;
|
|
74
79
|
levelMode: 'stacked' | 'exploded' | 'solo' | 'manual';
|
|
75
80
|
setLevelMode: (mode: 'stacked' | 'exploded' | 'solo' | 'manual') => void;
|
|
81
|
+
/**
|
|
82
|
+
* The editor's level display: stacked, with every level above the selected
|
|
83
|
+
* one hidden (the selected level and those below stay). Set by the host
|
|
84
|
+
* while editing; never persisted, so the viewer app keeps its own mode.
|
|
85
|
+
*/
|
|
86
|
+
hideLevelsAboveSelection: boolean;
|
|
76
87
|
wallMode: WallMode;
|
|
77
88
|
setWallMode: (mode: WallMode) => void;
|
|
78
89
|
showScans: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,QAAQ,EACR,QAAQ,EACT,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAIrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAGlE,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAC/C,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,aAAa,CAAA;AACrD,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,CAAA;AAEhE,KAAK,aAAa,GAAG;IACnB,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrC,OAAO,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC/B,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC7B,WAAW,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;CAC9B,CAAA;AAED,KAAK,QAAQ,GAAG;IACd,eAAe,EAAE,QAAQ,EAAE,CAAA;IAC3B,cAAc,EAAE,QAAQ,EAAE,CAAA;CAC3B,CAAA;AAED,KAAK,WAAW,GAAG;IACjB,SAAS,EAAE,aAAa,CAAA;IACxB,aAAa,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACpC,cAAc,EAAE,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IACnD,kBAAkB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;IACpC,qBAAqB,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAA;IACtD;+EAC2E;IAC3E,mBAAmB,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAA;IACrC,sBAAsB,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAA;IACvD,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC7C,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAChD,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,CAAA;IAEjE,UAAU,EAAE,aAAa,GAAG,cAAc,CAAA;IAC1C,aAAa,EAAE,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,KAAK,IAAI,CAAA;IAE7D,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"use-viewer.d.ts","sourceRoot":"","sources":["../../src/store/use-viewer.ts"],"names":[],"mappings":"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"}
|
package/dist/store/use-viewer.js
CHANGED
|
@@ -141,7 +141,9 @@ const useViewer = create()(persist((set) => ({
|
|
|
141
141
|
cameraMode: 'perspective',
|
|
142
142
|
setCameraMode: (mode) => set({ cameraMode: mode }),
|
|
143
143
|
sceneTheme: 'studio',
|
|
144
|
-
|
|
144
|
+
savedSceneTheme: 'studio',
|
|
145
|
+
setSceneTheme: (id) => set({ sceneTheme: id, savedSceneTheme: id }),
|
|
146
|
+
showSceneTheme: (id) => set((state) => ({ sceneTheme: id ?? state.savedSceneTheme })),
|
|
145
147
|
renderContext: 'editor',
|
|
146
148
|
setRenderContext: (context) => set({ renderContext: context }),
|
|
147
149
|
isExporting: false,
|
|
@@ -180,6 +182,7 @@ const useViewer = create()(persist((set) => ({
|
|
|
180
182
|
setMetricNotation: (metricNotation) => set({ unit: 'metric', metricNotation, unitExplicit: true }),
|
|
181
183
|
levelMode: 'stacked',
|
|
182
184
|
setLevelMode: (mode) => set({ levelMode: mode }),
|
|
185
|
+
hideLevelsAboveSelection: false,
|
|
183
186
|
wallMode: 'up',
|
|
184
187
|
setWallMode: (mode) => set({ wallMode: mode }),
|
|
185
188
|
showScans: true,
|
|
@@ -295,13 +298,17 @@ const useViewer = create()(persist((set) => ({
|
|
|
295
298
|
setInputDragging: (dragging) => set({ inputDragging: dragging }),
|
|
296
299
|
}), {
|
|
297
300
|
name: 'viewer-preferences',
|
|
298
|
-
merge: (persistedState, currentState) =>
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
merge: (persistedState, currentState) => {
|
|
302
|
+
const persisted = normalizePersistedViewerState(persistedState);
|
|
303
|
+
return {
|
|
304
|
+
...currentState,
|
|
305
|
+
...persisted,
|
|
306
|
+
savedSceneTheme: persisted.sceneTheme ?? currentState.savedSceneTheme,
|
|
307
|
+
};
|
|
308
|
+
},
|
|
302
309
|
partialize: (state) => ({
|
|
303
310
|
cameraMode: state.cameraMode,
|
|
304
|
-
sceneTheme: state.
|
|
311
|
+
sceneTheme: state.savedSceneTheme,
|
|
305
312
|
shadingByContext: state.shadingByContext,
|
|
306
313
|
textures: state.textures,
|
|
307
314
|
colorPreset: state.colorPreset,
|
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { type CeilingNode } from '@pascal-app/core';
|
|
1
|
+
import { type CeilingNode, type CeilingSurfaceCell, useScene } from '@pascal-app/core';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
/** Name of the meshes a ceiling draws its paint regions with, one per region. */
|
|
4
|
+
export declare const CEILING_REGION_MESH = "ceiling-region";
|
|
5
|
+
/**
|
|
6
|
+
* The material a ceiling draws a region finish with. The ceiling's renderer
|
|
7
|
+
* owns materials (theme, textures, scene materials) and leaves this on the
|
|
8
|
+
* registered mesh; the system builds geometry and asks it.
|
|
9
|
+
*/
|
|
10
|
+
export type CeilingRegionMaterial = (finish: CeilingSurfaceCell['finish']) => THREE.Material;
|
|
11
|
+
type SceneNodes = ReturnType<typeof useScene.getState>['nodes'];
|
|
3
12
|
export declare const CeilingSystem: () => null;
|
|
13
|
+
/**
|
|
14
|
+
* Updates the geometry for a single ceiling
|
|
15
|
+
*/
|
|
16
|
+
export declare function updateCeilingGeometry(node: CeilingNode, mesh: THREE.Mesh, extraHoles?: Array<Array<[number, number]>>, nodes?: SceneNodes): void;
|
|
4
17
|
/**
|
|
5
18
|
* Generates flat ceiling geometry from polygon (no extrusion).
|
|
6
19
|
*
|
|
@@ -9,4 +22,5 @@ export declare const CeilingSystem: () => null;
|
|
|
9
22
|
* stored on the node — they are recomputed on every rebuild.
|
|
10
23
|
*/
|
|
11
24
|
export declare function generateCeilingGeometry(ceilingNode: CeilingNode, extraHoles?: Array<Array<[number, number]>>): THREE.BufferGeometry;
|
|
25
|
+
export {};
|
|
12
26
|
//# sourceMappingURL=ceiling-system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ceiling-system.d.ts","sourceRoot":"","sources":["../../../src/systems/ceiling/ceiling-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EAYvB,QAAQ,EACT,MAAM,kBAAkB,CAAA;AAEzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,iFAAiF;AACjF,eAAO,MAAM,mBAAmB,mBAAmB,CAAA;AAEnD;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,QAAQ,CAAA;AAE5F,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAA;AAa/D,eAAO,MAAM,aAAa,YA4BzB,CAAA;AAsCD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EACjB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,UAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM,EAC/C,KAAK,GAAE,UAAsC,QA8C9C;AAqDD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,WAAW,EACxB,UAAU,GAAE,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAM,GAC9C,KAAK,CAAC,cAAc,CA6DtB"}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import { getEffectiveNode, nodeRegistry, resolveCeilingHeight, sceneRegistry, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { CEILING_DRAW_OFFSET, CEILING_SURFACE_ROLE, ceilingPaintRegions, computeCeilingSurfaceCells, getEffectiveCutterNode, getEffectiveNode, hostedCutterHoles, isScriptedNode, nodeRegistry, resolveCeilingHeight, sceneRegistry, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
|
+
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
|
|
4
5
|
import { mergeSurfaceHolePolygons } from '../surface-hole-geometry';
|
|
6
|
+
/** Name of the meshes a ceiling draws its paint regions with, one per region. */
|
|
7
|
+
export const CEILING_REGION_MESH = 'ceiling-region';
|
|
5
8
|
function ensureUv2Attribute(geometry) {
|
|
6
9
|
const uv = geometry.getAttribute('uv');
|
|
7
10
|
if (!uv)
|
|
@@ -49,29 +52,53 @@ export const CeilingSystem = () => {
|
|
|
49
52
|
* participate just by declaring `capabilities.ceilingCut` on its definition.
|
|
50
53
|
*/
|
|
51
54
|
function collectCeilingHoles(ceiling, nodes) {
|
|
52
|
-
|
|
55
|
+
// Only the ceiling's own children can bind to it.
|
|
56
|
+
const hosted = { [ceiling.id]: ceiling };
|
|
57
|
+
for (const childId of ceiling.children ?? []) {
|
|
58
|
+
const child = nodes[childId];
|
|
59
|
+
if (child)
|
|
60
|
+
hosted[child.id] = getEffectiveCutterNode(child);
|
|
61
|
+
}
|
|
62
|
+
const holes = hostedCutterHoles(ceiling, hosted);
|
|
53
63
|
for (const childId of ceiling.children ?? []) {
|
|
54
64
|
const child = nodes[childId];
|
|
55
65
|
if (!child)
|
|
56
66
|
continue;
|
|
67
|
+
if (isScriptedNode(child) && child.source.manifest.cutters?.length)
|
|
68
|
+
continue;
|
|
57
69
|
const def = nodeRegistry.get(child.type);
|
|
58
70
|
const hole = def?.capabilities?.ceilingCut?.buildCeilingHole(child);
|
|
59
71
|
if (hole)
|
|
60
72
|
holes.push(hole);
|
|
61
73
|
}
|
|
74
|
+
for (const [, def] of nodeRegistry.entries())
|
|
75
|
+
holes.push(...(def.capabilities?.ceilingCut?.holesFor?.(ceiling) ?? []));
|
|
62
76
|
return holes;
|
|
63
77
|
}
|
|
64
78
|
/**
|
|
65
79
|
* Updates the geometry for a single ceiling
|
|
66
80
|
*/
|
|
67
|
-
function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.getState().nodes) {
|
|
81
|
+
export function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.getState().nodes) {
|
|
68
82
|
const newGeo = generateCeilingGeometry(node, extraHoles);
|
|
83
|
+
// Painted regions partition the underside: the ceiling's own mesh keeps what
|
|
84
|
+
// no region covers, and each region draws as its own single-material mesh,
|
|
85
|
+
// so batching buckets them by material like any other surface.
|
|
86
|
+
const regions = node.polygon.length >= 3 ? ceilingPaintRegions(node, nodes) : [];
|
|
87
|
+
const cells = regions.length
|
|
88
|
+
? computeCeilingSurfaceCells(node.polygon, [...mergeSurfaceHolePolygons(node.holes || []), ...extraHoles], regions)
|
|
89
|
+
: null;
|
|
90
|
+
const surface = cells?.find((cell) => cell.role === CEILING_SURFACE_ROLE);
|
|
69
91
|
mesh.geometry.dispose();
|
|
70
|
-
mesh.geometry = newGeo;
|
|
92
|
+
mesh.geometry = cells ? flatCeilingGeometry(surface?.polygons ?? []) : newGeo;
|
|
93
|
+
mesh.userData.paintRole = CEILING_SURFACE_ROLE;
|
|
94
|
+
syncCeilingRegionMeshes(mesh, (cells ?? []).filter((cell) => cell.role !== CEILING_SURFACE_ROLE));
|
|
71
95
|
const gridMesh = mesh.getObjectByName('ceiling-grid');
|
|
72
96
|
if (gridMesh) {
|
|
73
97
|
gridMesh.geometry.dispose();
|
|
74
|
-
gridMesh.geometry = newGeo.clone();
|
|
98
|
+
gridMesh.geometry = cells ? newGeo : newGeo.clone();
|
|
99
|
+
}
|
|
100
|
+
else if (cells) {
|
|
101
|
+
newGeo.dispose();
|
|
75
102
|
}
|
|
76
103
|
// Position at the ceiling height and reset X/Z so live-drag mesh
|
|
77
104
|
// offsets (set by move tools during the drag) don't leak into the
|
|
@@ -85,7 +112,60 @@ function updateCeilingGeometry(node, mesh, extraHoles = [], nodes = useScene.get
|
|
|
85
112
|
// follows-mode ceiling re-parks under the current plane on every rebuild
|
|
86
113
|
// (level-height edits / covering-slab changes dirty-mark ceilings).
|
|
87
114
|
// Slight offset to avoid z-fighting with upper-level slabs.
|
|
88
|
-
mesh.position.y =
|
|
115
|
+
mesh.position.y =
|
|
116
|
+
resolveCeilingHeight(node, nodes) - CEILING_DRAW_OFFSET + (liveTransform?.position[1] ?? 0);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* One child mesh per region cell, reused by position so a repaint keeps its
|
|
120
|
+
* mesh; surplus meshes go. The material comes from the renderer's resolver.
|
|
121
|
+
*/
|
|
122
|
+
function syncCeilingRegionMeshes(mesh, cells) {
|
|
123
|
+
const existing = mesh.children.filter((child) => child.isMesh && child.name === CEILING_REGION_MESH);
|
|
124
|
+
const resolve = mesh.userData.ceilingRegionMaterial;
|
|
125
|
+
cells.forEach((cell, index) => {
|
|
126
|
+
let region = existing[index];
|
|
127
|
+
if (!region) {
|
|
128
|
+
region = new THREE.Mesh();
|
|
129
|
+
region.name = CEILING_REGION_MESH;
|
|
130
|
+
mesh.add(region);
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
region.geometry.dispose();
|
|
134
|
+
region.geometry = flatCeilingGeometry(cell.polygons);
|
|
135
|
+
region.userData.paintRole = cell.role;
|
|
136
|
+
region.userData.finish = cell.finish;
|
|
137
|
+
region.userData.__fromGeometry = true;
|
|
138
|
+
region.material = resolve?.(cell.finish) ?? mesh.material;
|
|
139
|
+
});
|
|
140
|
+
for (const surplus of existing.slice(cells.length)) {
|
|
141
|
+
surplus.geometry.dispose();
|
|
142
|
+
surplus.removeFromParent();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/** Flat geometry for level-XZ pieces, laid out the way `generateCeilingGeometry` lays a ceiling. */
|
|
146
|
+
function flatCeilingGeometry(pieces) {
|
|
147
|
+
const parts = pieces
|
|
148
|
+
.filter((piece) => piece.outer.length >= 3)
|
|
149
|
+
.map((piece) => {
|
|
150
|
+
const shape = new THREE.Shape(piece.outer.map(([x, z]) => new THREE.Vector2(x, -z)));
|
|
151
|
+
for (const hole of piece.holes)
|
|
152
|
+
if (hole.length >= 3)
|
|
153
|
+
shape.holes.push(new THREE.Path(hole.map(([x, z]) => new THREE.Vector2(x, -z))));
|
|
154
|
+
const geometry = new THREE.ShapeGeometry(shape);
|
|
155
|
+
geometry.rotateX(-Math.PI / 2);
|
|
156
|
+
geometry.computeVertexNormals();
|
|
157
|
+
ensureUv2Attribute(geometry);
|
|
158
|
+
return geometry;
|
|
159
|
+
});
|
|
160
|
+
if (parts.length === 0)
|
|
161
|
+
return generateCeilingGeometry({ polygon: [] });
|
|
162
|
+
if (parts.length === 1)
|
|
163
|
+
return parts[0];
|
|
164
|
+
const merged = mergeGeometries(parts) ?? parts[0];
|
|
165
|
+
for (const part of parts)
|
|
166
|
+
if (part !== merged)
|
|
167
|
+
part.dispose();
|
|
168
|
+
return merged;
|
|
89
169
|
}
|
|
90
170
|
/**
|
|
91
171
|
* Generates flat ceiling geometry from polygon (no extrusion).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,
|
|
1
|
+
{"version":3,"file":"door-system.d.ts","sourceRoot":"","sources":["../../../src/systems/door/door-system.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,QAAQ,EAcd,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA6D9B,eAAO,MAAM,UAAU,YAyHtB,CAAA;AAiqCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,EAChC,KAAK,EAAE,MAAM,GACZ,OAAO,CA6GT;AA6wCD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,CAAC,IAAI,CAI/D"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { clampDoorOperationState, DEFAULT_WALL_THICKNESS, DoorNode as DoorNodeSchema, getDoorRenderOpenAmount, getEffectiveNode, getWallThickness, sceneRegistry, useInteractive, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { clampDoorOperationState, DEFAULT_WALL_THICKNESS, DoorNode as DoorNodeSchema, getDoorRenderOpenAmount, getEffectiveNode, getOpeningWallPlacement, getWallThickness, sceneRegistry, scriptedSize, useInteractive, useLiveNodeOverrides, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
3
|
import { useEffect, useRef } from 'react';
|
|
4
4
|
import * as THREE from 'three';
|
|
5
5
|
import { applyWorldScaleBoxUVs } from '../../lib/box-uv';
|
|
6
|
-
import { createDefaultMaterial, createSurfaceRoleMaterial, glassMaterial as defaultGlassMaterial, baseMaterial as getBaseMaterial, resolveMaterialRef, } from '../../lib/materials';
|
|
6
|
+
import { createDefaultMaterial, createMaterial, createSurfaceRoleMaterial, glassMaterial as defaultGlassMaterial, baseMaterial as getBaseMaterial, resolveMaterialRef, } from '../../lib/materials';
|
|
7
7
|
import { timeSpan } from '../../lib/perf-tracks';
|
|
8
|
+
import { settleScriptedOpening } from '../../lib/scripted-opening';
|
|
8
9
|
import useViewer from '../../store/use-viewer';
|
|
9
10
|
import { getOpeningCutoutProxyDepth } from '../wall/opening-cutout-geometry';
|
|
10
11
|
// Invisible material for root mesh — used as selection hitbox only
|
|
@@ -146,16 +147,20 @@ export const DoorSystem = () => {
|
|
|
146
147
|
// rebuild reflects the in-flight drag without zustand churn. When
|
|
147
148
|
// no override is set this returns the scene node unchanged.
|
|
148
149
|
const effectiveNode = getEffectiveNode(node);
|
|
149
|
-
timeSpan('door', () => updateDoorMesh(effectiveNode, mesh), {
|
|
150
|
+
const built = timeSpan('door', () => updateDoorMesh(effectiveNode, mesh), {
|
|
150
151
|
properties: [['node', id]],
|
|
151
152
|
});
|
|
153
|
+
// A scripted opening stays dirty until its artifact has loaded.
|
|
154
|
+
if (!built)
|
|
155
|
+
continue;
|
|
152
156
|
clearDirty(id);
|
|
153
157
|
rebuiltDoorsThisFrame += 1;
|
|
154
158
|
// Rebuild the parent wall so its cutout reflects the updated door geometry
|
|
155
159
|
// Avoid triggering expensive wall CSG rebuilds while the door is being interactively moved/duplicated.
|
|
156
160
|
// The editor tools will request a final wall rebuild on commit.
|
|
157
|
-
const
|
|
158
|
-
|
|
161
|
+
const metadata = effectiveNode.metadata;
|
|
162
|
+
const deferParentRebuild = !!metadata?.isTransient || !!metadata?.deferParentRebuild;
|
|
163
|
+
if (!deferParentRebuild && effectiveNode.parentId) {
|
|
159
164
|
useScene.getState().dirtyNodes.add(effectiveNode.parentId);
|
|
160
165
|
}
|
|
161
166
|
}
|
|
@@ -207,16 +212,21 @@ function doorSlotDefault(slotId) {
|
|
|
207
212
|
getBaseMaterial(currentShading));
|
|
208
213
|
}
|
|
209
214
|
// Resolve a door's slot to a material: the `node.slots` override (colored mode
|
|
210
|
-
// only) → the body
|
|
211
|
-
//
|
|
215
|
+
// only) → the door-wide `material` for the body (panel and frame; glass and
|
|
216
|
+
// hardware keep their own finish) → the body/glass/hardware default.
|
|
217
|
+
// Textures-off ignores overrides — the monochrome escape hatch.
|
|
212
218
|
function resolveDoorSlotMaterial(node, slotId) {
|
|
213
219
|
const fallback = doorSlotDefault(slotId);
|
|
214
220
|
if (!currentTextures)
|
|
215
221
|
return fallback;
|
|
216
222
|
const ref = node.slots?.[slotId];
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
223
|
+
const painted = ref ? resolveMaterialRef(ref, currentSceneMaterials, currentShading) : null;
|
|
224
|
+
if (painted)
|
|
225
|
+
return painted;
|
|
226
|
+
if (node.material && (slotId === 'panel' || slotId === 'frame')) {
|
|
227
|
+
return createMaterial(node.material, currentShading);
|
|
228
|
+
}
|
|
229
|
+
return fallback;
|
|
220
230
|
}
|
|
221
231
|
function addBox(parent, material, w, h, d, x, y, z) {
|
|
222
232
|
const geometry = new THREE.BoxGeometry(w, h, d);
|
|
@@ -675,7 +685,9 @@ function addLeafSegmentContent({ addLeafBox, addLeafShape, leafWidth, leafHeight
|
|
|
675
685
|
addLeafShape(baseMaterial, innerPanelShape, effectiveDepth);
|
|
676
686
|
}
|
|
677
687
|
else {
|
|
688
|
+
// A leaf is paneled on both faces, so the person sees the style from either side.
|
|
678
689
|
addLeafBox(baseMaterial, panelW, panelH, effectiveDepth, colX, segCenterY, panelZ);
|
|
690
|
+
addLeafBox(baseMaterial, panelW, panelH, effectiveDepth, colX, segCenterY, -panelZ);
|
|
679
691
|
}
|
|
680
692
|
}
|
|
681
693
|
}
|
|
@@ -777,9 +789,21 @@ function addDoorLeaf(mesh, { leafWidth, leafHeight, leafCenterX, leafCenterY, le
|
|
|
777
789
|
const hingeH = 0.1;
|
|
778
790
|
const hingeW = 0.024;
|
|
779
791
|
const hingeD = leafDepth + 0.016;
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
792
|
+
const hingeRadii = roundedBoundary?.radii ?? openingTopRadii;
|
|
793
|
+
const cornerDrop = openingShape === 'rounded'
|
|
794
|
+
? hingeSide === 'left'
|
|
795
|
+
? hingeRadii.topLeft
|
|
796
|
+
: hingeRadii.topRight
|
|
797
|
+
: openingShape === 'arch'
|
|
798
|
+
? getClampedArchHeight(leafWidth, leafHeight, archHeight)
|
|
799
|
+
: 0;
|
|
800
|
+
// Hinges need their full height supported by the straight jamb below the curve.
|
|
801
|
+
const straightEdgeTop = leafTop - cornerDrop;
|
|
802
|
+
for (const hingeY of [leafBottom + 0.25, (leafBottom + leafTop) / 2, leafTop - 0.25]) {
|
|
803
|
+
if (hingeY + hingeH / 2 > straightEdgeTop + 1e-6)
|
|
804
|
+
continue;
|
|
805
|
+
addBox(mesh, hardwareMaterial, hingeW, hingeH, hingeD, hingeMarkerX, hingeY, 0);
|
|
806
|
+
}
|
|
783
807
|
}
|
|
784
808
|
// When the leaf is swung open it projects into the room and would otherwise
|
|
785
809
|
// win a top-down selection click over the floor beneath it. Drop only the
|
|
@@ -1226,8 +1250,19 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1226
1250
|
mesh.geometry = new THREE.BoxGeometry(node.width, node.height, node.frameDepth);
|
|
1227
1251
|
mesh.material = hitboxMaterial;
|
|
1228
1252
|
// Sync transform from node (React may lag behind the system by a frame during drag)
|
|
1229
|
-
|
|
1230
|
-
|
|
1253
|
+
const parent = node.parentId ? useScene.getState().nodes[node.parentId] : undefined;
|
|
1254
|
+
const placement = parent?.type === 'wall' && !node.roofSegmentId
|
|
1255
|
+
? getOpeningWallPlacement(getEffectiveNode(parent), node, useScene.getState().nodes)
|
|
1256
|
+
: node;
|
|
1257
|
+
mesh.position.set(...placement.position);
|
|
1258
|
+
mesh.rotation.set(...placement.rotation);
|
|
1259
|
+
// Built from a script: the renderer shows its artifact, not the parametric
|
|
1260
|
+
// frame, and the hit box is what the script built.
|
|
1261
|
+
if (node.source) {
|
|
1262
|
+
mesh.geometry.dispose();
|
|
1263
|
+
mesh.geometry = new THREE.BoxGeometry(...scriptedSize(node.source.manifest));
|
|
1264
|
+
return settleScriptedOpening(mesh);
|
|
1265
|
+
}
|
|
1231
1266
|
// Dispose and remove all old visual children; preserve 'cutout'
|
|
1232
1267
|
for (const child of [...mesh.children]) {
|
|
1233
1268
|
if (child.name === 'cutout')
|
|
@@ -1250,7 +1285,7 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1250
1285
|
const clampedSwingAngle = Math.max(0, Math.min(Math.PI / 2, swingAngle));
|
|
1251
1286
|
if (openingKind === 'opening') {
|
|
1252
1287
|
syncDoorCutout(node, mesh);
|
|
1253
|
-
return;
|
|
1288
|
+
return true;
|
|
1254
1289
|
}
|
|
1255
1290
|
const insideWidth = width - 2 * frameThickness;
|
|
1256
1291
|
const leafH = height - frameThickness; // only top frame
|
|
@@ -1492,11 +1527,12 @@ function updateDoorMesh(rawNode, mesh) {
|
|
|
1492
1527
|
// … was not set" on a Draw(0, …)). Hide any empty mesh so it is never
|
|
1493
1528
|
// drawn (it would render nothing anyway).
|
|
1494
1529
|
hideEmptyGeometryMeshes(mesh);
|
|
1530
|
+
return true;
|
|
1495
1531
|
}
|
|
1496
1532
|
function hideEmptyGeometryMeshes(root) {
|
|
1497
1533
|
root.traverse((obj) => {
|
|
1498
1534
|
const child = obj;
|
|
1499
|
-
if (!child.isMesh
|
|
1535
|
+
if (!(child.isMesh && child.geometry))
|
|
1500
1536
|
return;
|
|
1501
1537
|
const position = child.geometry.getAttribute('position');
|
|
1502
1538
|
if (!position || position.count === 0)
|
|
@@ -1518,7 +1554,15 @@ function syncDoorCutout(node, mesh) {
|
|
|
1518
1554
|
mesh.add(cutout);
|
|
1519
1555
|
}
|
|
1520
1556
|
cutout.geometry.dispose();
|
|
1521
|
-
const depth =
|
|
1557
|
+
const { depth, center } = resolveOpeningCutoutProxy(node);
|
|
1558
|
+
cutout.position.set(0, 0, 0);
|
|
1559
|
+
if (center) {
|
|
1560
|
+
// Curved and justified walls place openings off the reference line. Remove
|
|
1561
|
+
// only the visual plane offset, preserving the frame's resolved floor datum.
|
|
1562
|
+
cutout.position
|
|
1563
|
+
.set(center[0] - mesh.position.x, 0, center[2] - mesh.position.z)
|
|
1564
|
+
.applyQuaternion(mesh.quaternion.clone().invert());
|
|
1565
|
+
}
|
|
1522
1566
|
const openingShape = getEffectiveOpeningShape(node);
|
|
1523
1567
|
if (openingShape === 'arch') {
|
|
1524
1568
|
cutout.geometry = new THREE.ExtrudeGeometry(createArchShape(-node.width / 2, node.width / 2, -node.height / 2, node.height / 2, getClampedArchHeight(node.width, node.height, node.archHeight)), {
|
|
@@ -1545,11 +1589,18 @@ function syncDoorCutout(node, mesh) {
|
|
|
1545
1589
|
// the proxy stays proud of both wall faces (front/back selection) without the
|
|
1546
1590
|
// old 1m depth that blanketed the floor. Falls back to the default thickness
|
|
1547
1591
|
// when the parent wall isn't a resolvable wall node.
|
|
1548
|
-
function
|
|
1592
|
+
function resolveOpeningCutoutProxy(node) {
|
|
1549
1593
|
const parentId = node.parentId;
|
|
1550
|
-
const
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1594
|
+
const nodes = useScene.getState().nodes;
|
|
1595
|
+
const parent = parentId ? nodes[parentId] : undefined;
|
|
1596
|
+
const wall = parent?.type === 'wall' ? getEffectiveNode(parent) : undefined;
|
|
1597
|
+
const wallThickness = wall ? getWallThickness(wall) : DEFAULT_WALL_THICKNESS;
|
|
1598
|
+
return {
|
|
1599
|
+
depth: getOpeningCutoutProxyDepth(wallThickness),
|
|
1600
|
+
center: wall && !node.roofSegmentId && node.position[2] !== 0
|
|
1601
|
+
? getOpeningWallPlacement(wall, { ...node, position: [node.position[0], node.position[1], 0] }, nodes).position
|
|
1602
|
+
: undefined,
|
|
1603
|
+
};
|
|
1553
1604
|
}
|
|
1554
1605
|
/**
|
|
1555
1606
|
* Build a fresh door mesh for preview/ghost rendering.
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* Runs at priority 1 — before the priority-2 systems (`GeometrySystem`,
|
|
15
15
|
* `ItemSystem`) so the dirty mark survives long enough for those to do
|
|
16
16
|
* their own work. Kinds with no geometry/system have no downstream dirty
|
|
17
|
-
* consumer, so this system clears their dirty mark after applying the lift
|
|
17
|
+
* consumer, so this system clears their dirty mark after applying the lift,
|
|
18
|
+
* at priority 2 like every other consumer: the node batch snapshots marks at
|
|
19
|
+
* priority 1, and a mark cleared there could run before that snapshot.
|
|
18
20
|
*/
|
|
19
21
|
export declare const FloorElevationSystem: () => null;
|
|
20
22
|
//# sourceMappingURL=floor-elevation-system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"floor-elevation-system.d.ts","sourceRoot":"","sources":["../../../src/systems/floor-elevation/floor-elevation-system.tsx"],"names":[],"mappings":"AA8DA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,oBAAoB,YAoNhC,CAAA"}
|