@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-system.d.ts","sourceRoot":"","sources":["../../../src/systems/item/item-system.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"item-system.d.ts","sourceRoot":"","sources":["../../../src/systems/item/item-system.tsx"],"names":[],"mappings":"AAmBA;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,YAsDtB,CAAA"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { sceneRegistry, useScene, } from '@pascal-app/core';
|
|
1
|
+
import { getEffectiveNode, getWallBodyCenterOffset, getWallLocalFaceZ, sceneRegistry, useScene, } from '@pascal-app/core';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
|
+
import { useEffect } from 'react';
|
|
4
|
+
import { initializeObjectCutInvalidation } from './object-cut-invalidation';
|
|
3
5
|
// ============================================================================
|
|
4
6
|
// ITEM SYSTEM
|
|
5
7
|
// ============================================================================
|
|
@@ -11,6 +13,7 @@ import { useFrame } from '@react-three/fiber';
|
|
|
11
13
|
* mark at priority 2.
|
|
12
14
|
*/
|
|
13
15
|
export const ItemSystem = () => {
|
|
16
|
+
useEffect(initializeObjectCutInvalidation, []);
|
|
14
17
|
const dirtyNodes = useScene((state) => state.dirtyNodes);
|
|
15
18
|
const clearDirty = useScene((state) => state.clearDirty);
|
|
16
19
|
useFrame(() => {
|
|
@@ -25,6 +28,10 @@ export const ItemSystem = () => {
|
|
|
25
28
|
const mesh = sceneRegistry.nodes.get(id);
|
|
26
29
|
if (!mesh)
|
|
27
30
|
return;
|
|
31
|
+
const host = item.parentId ? nodes[item.parentId] : undefined;
|
|
32
|
+
if (item.asset.attachTo === 'wall' && host?.type === 'wall') {
|
|
33
|
+
mesh.position.z = item.position[2] + getWallBodyCenterOffset(getEffectiveNode(host));
|
|
34
|
+
}
|
|
28
35
|
if (item.asset.attachTo === 'wall-side') {
|
|
29
36
|
// Wall-attached item: offset Z by half the host wall's thickness.
|
|
30
37
|
// Roof-segment wall faces share the convention — the face frame's
|
|
@@ -37,8 +44,7 @@ export const ItemSystem = () => {
|
|
|
37
44
|
? (parent.wallThickness ?? 0.1)
|
|
38
45
|
: undefined;
|
|
39
46
|
if (thickness !== undefined) {
|
|
40
|
-
|
|
41
|
-
mesh.position.z = (thickness / 2) * side;
|
|
47
|
+
mesh.position.z = getWallLocalFaceZ(parent?.type === 'wall' ? getEffectiveNode(parent) : { thickness }, item.side === 'front' ? 'a' : 'b');
|
|
42
48
|
}
|
|
43
49
|
}
|
|
44
50
|
// Hold the mark until the model settles (loaded, terminally failed, or
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object-cut-invalidation.d.ts","sourceRoot":"","sources":["../../../src/systems/item/object-cut-invalidation.ts"],"names":[],"mappings":"AAUA,6EAA6E;AAC7E,wBAAgB,+BAA+B,eA6D9C"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { getEffectiveCutterNode, resolveCutterHost, useLiveNodeOverrides, useLiveTransforms, useScene, } from '@pascal-app/core';
|
|
2
|
+
/** Geometry remains derived; only dirty marks cross into the scene store. */
|
|
3
|
+
export function initializeObjectCutInvalidation() {
|
|
4
|
+
let previous = new Map();
|
|
5
|
+
let cutterIds = [];
|
|
6
|
+
const collect = (nodes) => {
|
|
7
|
+
cutterIds = [];
|
|
8
|
+
for (const node of Object.values(nodes)) {
|
|
9
|
+
if (node.type === 'item' && node.source?.manifest.cutters?.length)
|
|
10
|
+
cutterIds.push(node.id);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
// Drags fire every frame: a scene without cutters pays nothing here.
|
|
14
|
+
const refresh = () => {
|
|
15
|
+
if (!cutterIds.length && !previous.size)
|
|
16
|
+
return;
|
|
17
|
+
const state = useScene.getState();
|
|
18
|
+
const nodes = { ...state.nodes };
|
|
19
|
+
for (const id of new Set([
|
|
20
|
+
...useLiveNodeOverrides.getState().overrides.keys(),
|
|
21
|
+
...useLiveTransforms.getState().transforms.keys(),
|
|
22
|
+
])) {
|
|
23
|
+
if (nodes[id])
|
|
24
|
+
nodes[id] = getEffectiveCutterNode(nodes[id]);
|
|
25
|
+
}
|
|
26
|
+
const owners = new Map();
|
|
27
|
+
for (const id of cutterIds) {
|
|
28
|
+
const node = nodes[id];
|
|
29
|
+
if (node?.type !== 'item' || !node.source?.manifest.cutters?.length)
|
|
30
|
+
continue;
|
|
31
|
+
for (const cutter of node.source.manifest.cutters) {
|
|
32
|
+
const host = resolveCutterHost(node, cutter.host === 'mounted' ? 'cutout' : `cut:${cutter.host}`, nodes);
|
|
33
|
+
if (!host)
|
|
34
|
+
continue;
|
|
35
|
+
const entries = owners.get(host.id) ?? [];
|
|
36
|
+
entries.push([node.id, node.source.artifact, node.position, node.rotation, node.scale]);
|
|
37
|
+
owners.set(host.id, entries);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const next = new Map([...owners].map(([id, entries]) => [id, JSON.stringify(entries)]));
|
|
41
|
+
const changed = [...new Set([...previous.keys(), ...next.keys()])].filter((id) => previous.get(id) !== next.get(id));
|
|
42
|
+
previous = next;
|
|
43
|
+
for (const id of changed)
|
|
44
|
+
if (nodes[id])
|
|
45
|
+
state.markDirty(id);
|
|
46
|
+
};
|
|
47
|
+
collect(useScene.getState().nodes);
|
|
48
|
+
refresh();
|
|
49
|
+
const unsubscribeScene = useScene.subscribe((state, before) => {
|
|
50
|
+
if (state.nodes === before.nodes)
|
|
51
|
+
return;
|
|
52
|
+
collect(state.nodes);
|
|
53
|
+
refresh();
|
|
54
|
+
});
|
|
55
|
+
const unsubscribeLive = useLiveNodeOverrides.subscribe((state, before) => {
|
|
56
|
+
if (state.overrides !== before.overrides)
|
|
57
|
+
refresh();
|
|
58
|
+
});
|
|
59
|
+
const unsubscribeTransforms = useLiveTransforms.subscribe((state, before) => {
|
|
60
|
+
if (state.transforms !== before.transforms)
|
|
61
|
+
refresh();
|
|
62
|
+
});
|
|
63
|
+
return () => {
|
|
64
|
+
unsubscribeScene();
|
|
65
|
+
unsubscribeLive();
|
|
66
|
+
unsubscribeTransforms();
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function ItemLightSystem(): import("react").JSX.Element;
|
|
1
|
+
export declare function ItemLightSystem(): import("react").JSX.Element | null;
|
|
2
2
|
//# sourceMappingURL=item-light-system.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"item-light-system.d.ts","sourceRoot":"","sources":["../../../src/systems/item-light/item-light-system.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"item-light-system.d.ts","sourceRoot":"","sources":["../../../src/systems/item-light/item-light-system.tsx"],"names":[],"mappings":"AAgGA,wBAAgB,eAAe,uCA0M9B"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { findLevelAncestorId, sceneRegistry,
|
|
3
|
-
import { useFrame } from '@react-three/fiber';
|
|
2
|
+
import { findLevelAncestorId, sceneRegistry, useScene } from '@pascal-app/core';
|
|
3
|
+
import { useFrame, useThree } from '@react-three/fiber';
|
|
4
4
|
import { useRef } from 'react';
|
|
5
5
|
import { MathUtils, Vector3 } from 'three';
|
|
6
|
+
import { SCENE_LAYER } from '../../lib/layers';
|
|
6
7
|
import { useItemLightPool } from '../../store/use-item-light-pool';
|
|
7
8
|
import useViewer from '../../store/use-viewer';
|
|
8
9
|
const POOL_SIZE = 12;
|
|
@@ -19,22 +20,30 @@ const _dir = new Vector3();
|
|
|
19
20
|
const _camPos = new Vector3();
|
|
20
21
|
const _camFwd = new Vector3();
|
|
21
22
|
const _itemPos = new Vector3();
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!
|
|
23
|
+
function isRendered(nodeId) {
|
|
24
|
+
let object = sceneRegistry.nodes.get(nodeId);
|
|
25
|
+
if (!object?.layers.isEnabled(SCENE_LAYER))
|
|
26
|
+
return false;
|
|
27
|
+
while (object) {
|
|
28
|
+
if (!object.visible)
|
|
29
|
+
return false;
|
|
30
|
+
object = object.parent;
|
|
31
|
+
}
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
function scoreRegistration(reg, nodes, selectedLevelId, levelMode, hideAbove) {
|
|
35
|
+
if (!reg.isEligible() || !isRendered(reg.nodeId) || !reg.getWorldPosition(_itemPos))
|
|
36
|
+
return Number.POSITIVE_INFINITY;
|
|
37
|
+
const { nodeId } = reg;
|
|
38
|
+
let current = nodes[nodeId];
|
|
39
|
+
while (current) {
|
|
40
|
+
if (current.type !== 'site' && current.visible === false)
|
|
28
41
|
return Number.POSITIVE_INFINITY;
|
|
42
|
+
current = current.parentId ? nodes[current.parentId] : undefined;
|
|
29
43
|
}
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
if (!obj)
|
|
44
|
+
const itemLevelId = findLevelAncestorId(nodeId, nodes);
|
|
45
|
+
if (selectedLevelId && itemLevelId !== selectedLevelId && levelMode === 'solo')
|
|
33
46
|
return Number.POSITIVE_INFINITY;
|
|
34
|
-
obj.getWorldPosition(_itemPos);
|
|
35
|
-
_itemPos.x += effect.offset[0];
|
|
36
|
-
_itemPos.y += effect.offset[1];
|
|
37
|
-
_itemPos.z += effect.offset[2];
|
|
38
47
|
_dir.copy(_itemPos).sub(_camPos).normalize();
|
|
39
48
|
const dot = _camFwd.dot(_dir); // 1 = ahead, -1 = behind
|
|
40
49
|
// Angular component (0 = dead ahead, 2 = directly behind)
|
|
@@ -42,12 +51,15 @@ function scoreRegistration(reg, nodes, selectedLevelId, levelMode, interactiveSt
|
|
|
42
51
|
// Normalised distance component (assumes scenes < 200 units)
|
|
43
52
|
const dist = _camPos.distanceTo(_itemPos) / 200;
|
|
44
53
|
// ── Level factor ──────────────────────────────────────────────────────────
|
|
45
|
-
const itemLevelId = findLevelAncestorId(nodeId, nodes);
|
|
46
54
|
let levelPenalty = 0;
|
|
47
55
|
if (selectedLevelId) {
|
|
48
56
|
if (itemLevelId !== selectedLevelId) {
|
|
49
|
-
//
|
|
50
|
-
|
|
57
|
+
// Items on hidden levels (every other one in solo, those above the
|
|
58
|
+
// selected one while editing) are invisible — deprioritize strongly
|
|
59
|
+
const itemIndex = nodes[itemLevelId]?.level ?? 0;
|
|
60
|
+
const selectedIndex = nodes[selectedLevelId]?.level ?? 0;
|
|
61
|
+
const hidden = levelMode === 'solo' || (hideAbove && itemIndex > selectedIndex);
|
|
62
|
+
levelPenalty = hidden ? 100 : 0.8;
|
|
51
63
|
}
|
|
52
64
|
}
|
|
53
65
|
else if (itemLevelId) {
|
|
@@ -60,6 +72,8 @@ function scoreRegistration(reg, nodes, selectedLevelId, levelMode, interactiveSt
|
|
|
60
72
|
return angular * 0.7 + dist * 0.3 + levelPenalty;
|
|
61
73
|
}
|
|
62
74
|
export function ItemLightSystem() {
|
|
75
|
+
const scene = useThree((state) => state.scene);
|
|
76
|
+
const bakedOwner = useItemLightPool((state) => state.bakedCanvases.has(scene));
|
|
63
77
|
const lightRefs = useRef(Array.from({ length: POOL_SIZE }, () => null));
|
|
64
78
|
const slots = useRef(Array.from({ length: POOL_SIZE }, () => ({ key: null, pendingKey: null, isFadingOut: false })));
|
|
65
79
|
const reassignTimer = useRef(0);
|
|
@@ -67,9 +81,10 @@ export function ItemLightSystem() {
|
|
|
67
81
|
const prevReassignCamPos = useRef(new Vector3());
|
|
68
82
|
const prevReassignCamFwd = useRef(new Vector3(0, 0, -1));
|
|
69
83
|
useFrame(({ camera }, delta) => {
|
|
84
|
+
if (bakedOwner)
|
|
85
|
+
return;
|
|
70
86
|
const dt = Math.min(delta, 0.1);
|
|
71
87
|
const { registrations } = useItemLightPool.getState();
|
|
72
|
-
const interactiveState = useInteractive.getState();
|
|
73
88
|
// ── 1. Throttled priority reassignment ──────────────────────────────────
|
|
74
89
|
camera.getWorldPosition(_camPos);
|
|
75
90
|
camera.getWorldDirection(_camFwd);
|
|
@@ -86,12 +101,13 @@ export function ItemLightSystem() {
|
|
|
86
101
|
const viewerState = useViewer.getState();
|
|
87
102
|
const selectedLevelId = viewerState.selection.levelId;
|
|
88
103
|
const levelMode = viewerState.levelMode;
|
|
104
|
+
const hideAbove = viewerState.hideLevelsAboveSelection;
|
|
89
105
|
// Score every registration
|
|
90
106
|
const scored = [];
|
|
91
107
|
for (const [key, reg] of registrations) {
|
|
92
108
|
scored.push({
|
|
93
109
|
key,
|
|
94
|
-
score: scoreRegistration(reg, nodes, selectedLevelId, levelMode,
|
|
110
|
+
score: scoreRegistration(reg, nodes, selectedLevelId, levelMode, hideAbove),
|
|
95
111
|
});
|
|
96
112
|
}
|
|
97
113
|
scored.sort((a, b) => a.score - b.score);
|
|
@@ -155,8 +171,8 @@ export function ItemLightSystem() {
|
|
|
155
171
|
const light = lightRefs.current[freeSlot];
|
|
156
172
|
const reg = registrations.get(key);
|
|
157
173
|
if (light && reg) {
|
|
158
|
-
light.color.set(reg.
|
|
159
|
-
light.distance = reg.
|
|
174
|
+
light.color.set(reg.color);
|
|
175
|
+
light.distance = reg.distance;
|
|
160
176
|
}
|
|
161
177
|
}
|
|
162
178
|
}
|
|
@@ -183,19 +199,17 @@ export function ItemLightSystem() {
|
|
|
183
199
|
continue;
|
|
184
200
|
// Fade-out phase: lerp intensity → 0, then complete the transition
|
|
185
201
|
if (slot.isFadingOut) {
|
|
186
|
-
light.visible = true;
|
|
187
202
|
light.intensity = MathUtils.lerp(light.intensity, 0, dt * 12);
|
|
188
203
|
if (light.intensity < 0.01) {
|
|
189
204
|
light.intensity = 0;
|
|
190
|
-
light.visible = false;
|
|
191
205
|
slot.isFadingOut = false;
|
|
192
206
|
slot.key = slot.pendingKey;
|
|
193
207
|
slot.pendingKey = null;
|
|
194
208
|
if (slot.key) {
|
|
195
209
|
const reg = registrations.get(slot.key);
|
|
196
210
|
if (reg) {
|
|
197
|
-
light.color.set(reg.
|
|
198
|
-
light.distance = reg.
|
|
211
|
+
light.color.set(reg.color);
|
|
212
|
+
light.distance = reg.distance;
|
|
199
213
|
}
|
|
200
214
|
}
|
|
201
215
|
}
|
|
@@ -204,45 +218,26 @@ export function ItemLightSystem() {
|
|
|
204
218
|
if (!slot.key) {
|
|
205
219
|
// Idle slot — keep dark
|
|
206
220
|
light.intensity = 0;
|
|
207
|
-
light.visible = false;
|
|
208
221
|
continue;
|
|
209
222
|
}
|
|
210
223
|
const reg = registrations.get(slot.key);
|
|
211
224
|
if (!reg) {
|
|
212
225
|
slot.key = null;
|
|
213
226
|
light.intensity = 0;
|
|
214
|
-
light.visible = false;
|
|
215
227
|
continue;
|
|
216
228
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
obj.getWorldPosition(_itemPos);
|
|
221
|
-
const [ox, oy, oz] = reg.effect.offset;
|
|
222
|
-
light.position.set(_itemPos.x + ox, _itemPos.y + oy, _itemPos.z + oz);
|
|
223
|
-
}
|
|
224
|
-
// Compute target intensity
|
|
225
|
-
const values = interactiveState.items[reg.nodeId]?.controlValues;
|
|
226
|
-
const isOn = reg.toggleIndex >= 0 ? Boolean(values?.[reg.toggleIndex]) : true;
|
|
227
|
-
let t = 1;
|
|
228
|
-
if (reg.hasSlider) {
|
|
229
|
-
const raw = values?.[reg.sliderIndex] ?? reg.sliderMin;
|
|
230
|
-
t = (raw - reg.sliderMin) / (reg.sliderMax - reg.sliderMin);
|
|
231
|
-
}
|
|
232
|
-
const targetIntensity = isOn
|
|
233
|
-
? MathUtils.lerp(reg.effect.intensityRange[0], reg.effect.intensityRange[1], t)
|
|
234
|
-
: reg.effect.intensityRange[0];
|
|
235
|
-
if (targetIntensity > 0) {
|
|
236
|
-
light.visible = true;
|
|
237
|
-
}
|
|
229
|
+
if (reg.getWorldPosition(_itemPos))
|
|
230
|
+
light.position.copy(_itemPos);
|
|
231
|
+
const targetIntensity = reg.isEligible() && isRendered(reg.nodeId) ? reg.getIntensity() : 0;
|
|
238
232
|
light.intensity = MathUtils.lerp(light.intensity, targetIntensity, dt * 12);
|
|
239
233
|
if (targetIntensity <= 0 && light.intensity < 0.01) {
|
|
240
234
|
light.intensity = 0;
|
|
241
|
-
light.visible = false;
|
|
242
235
|
}
|
|
243
236
|
}
|
|
244
|
-
});
|
|
245
|
-
|
|
237
|
+
}, 6);
|
|
238
|
+
if (bakedOwner)
|
|
239
|
+
return null;
|
|
240
|
+
return (_jsx(_Fragment, { children: Array.from({ length: POOL_SIZE }, (_, i) => (_jsx("pointLight", { castShadow: false, intensity: 0, visible: true, ref: (el) => {
|
|
246
241
|
lightRefs.current[i] = el;
|
|
247
242
|
} }, i))) }));
|
|
248
243
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"level-system.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-system.tsx"],"names":[],"mappings":"AAQA,eAAO,MAAM,WAAW,YA+DvB,CAAA"}
|
|
@@ -3,16 +3,13 @@ import { useFrame } from '@react-three/fiber';
|
|
|
3
3
|
import { lerp } from 'three/src/math/MathUtils.js';
|
|
4
4
|
import { applyShadowOnly, clearShadowOnly } from '../../lib/shadow-only';
|
|
5
5
|
import useViewer from '../../store/use-viewer';
|
|
6
|
-
import { EXPLODED_GAP } from './level-utils';
|
|
7
|
-
|
|
8
|
-
// passes but keeps their sun shadows). Tracked so we can restore layer masks
|
|
9
|
-
// exactly once on transition; apply re-runs every frame so meshes rebuilt
|
|
10
|
-
// while hidden (theme/texture changes) get re-hidden.
|
|
11
|
-
const shadowOnlyLevels = new WeakSet();
|
|
6
|
+
import { EXPLODED_GAP, resolveLevelVisibility } from './level-utils';
|
|
7
|
+
import { shadowOnlyLevels } from './shadow-only-levels';
|
|
12
8
|
export const LevelSystem = () => {
|
|
13
9
|
useFrame((_, delta) => {
|
|
14
10
|
const nodes = useScene.getState().nodes;
|
|
15
11
|
const levelMode = useViewer.getState().levelMode;
|
|
12
|
+
const hideAbove = useViewer.getState().hideLevelsAboveSelection;
|
|
16
13
|
const selectedLevel = useViewer.getState().selection.levelId;
|
|
17
14
|
const levelElevations = getLevelElevations(nodes);
|
|
18
15
|
const entries = [];
|
|
@@ -42,23 +39,24 @@ export const LevelSystem = () => {
|
|
|
42
39
|
// (blank viewport). Clamping keeps every step a contraction: identical
|
|
43
40
|
// feel at 60 fps, exact snap instead of overshoot on slow frames.
|
|
44
41
|
obj.position.y = lerp(obj.position.y, targetY, Math.min(1, delta * 12));
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
42
|
+
const { visible, shadowOnly } = resolveLevelVisibility({
|
|
43
|
+
levelMode,
|
|
44
|
+
hideAbove,
|
|
45
|
+
hasSelectedLevel: Boolean(selectedLevel),
|
|
46
|
+
isSelected: level?.id === selectedLevel,
|
|
47
|
+
index,
|
|
48
|
+
selectedIndex,
|
|
49
|
+
nodeVisible: level?.visible !== false,
|
|
50
|
+
});
|
|
51
|
+
if (shadowOnly) {
|
|
51
52
|
applyShadowOnly(obj);
|
|
52
53
|
shadowOnlyLevels.add(obj);
|
|
53
|
-
obj.visible = true;
|
|
54
54
|
}
|
|
55
|
-
else {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
shadowOnlyLevels.delete(obj);
|
|
59
|
-
}
|
|
60
|
-
obj.visible = !hidden;
|
|
55
|
+
else if (shadowOnlyLevels.has(obj)) {
|
|
56
|
+
clearShadowOnly(obj);
|
|
57
|
+
shadowOnlyLevels.delete(obj);
|
|
61
58
|
}
|
|
59
|
+
obj.visible = visible;
|
|
62
60
|
}
|
|
63
61
|
}, 5); // Using a lower priority so it runs after transforms from other systems have settled
|
|
64
62
|
return null;
|
|
@@ -7,9 +7,36 @@ export declare const EXPLODED_GAP = 5;
|
|
|
7
7
|
* code framing a level must aim at the destination, not the moving target.
|
|
8
8
|
*/
|
|
9
9
|
export declare function getLevelPresentationY(levelId: string, nodes: Record<string, unknown>, levelMode: 'stacked' | 'exploded' | 'solo' | 'manual'): number;
|
|
10
|
+
/**
|
|
11
|
+
* Whether a level renders this frame, and whether it renders as a
|
|
12
|
+
* shadow-caster only.
|
|
13
|
+
*
|
|
14
|
+
* Two unrelated things hide a level and they do not compose: the author's own
|
|
15
|
+
* `visible` flag (the sidebar eye), which hides the floor outright, and
|
|
16
|
+
* presentation hiding — solo mode hides every level but the soloed one, and
|
|
17
|
+
* the editor's level display (`hideAbove`) hides the levels above the
|
|
18
|
+
* selected one. Presentation-hidden levels ABOVE the selected one stay in the
|
|
19
|
+
* shadow map so the sun still shadows the selected floor through them.
|
|
20
|
+
* A level the author hid never enters that shadow-caster branch: its shadows
|
|
21
|
+
* on the floor below would be exactly what hiding it was meant to remove.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveLevelVisibility({ levelMode, hideAbove, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, }: {
|
|
24
|
+
levelMode: 'stacked' | 'exploded' | 'solo' | 'manual';
|
|
25
|
+
hideAbove: boolean;
|
|
26
|
+
hasSelectedLevel: boolean;
|
|
27
|
+
isSelected: boolean;
|
|
28
|
+
index: number;
|
|
29
|
+
selectedIndex: number | undefined;
|
|
30
|
+
nodeVisible: boolean;
|
|
31
|
+
}): {
|
|
32
|
+
visible: boolean;
|
|
33
|
+
shadowOnly: boolean;
|
|
34
|
+
};
|
|
10
35
|
/**
|
|
11
36
|
* Instantly snaps all level Objects3D to their true stacked Y positions
|
|
12
|
-
* (ignores levelMode — always uses stacked, no exploded gap).
|
|
37
|
+
* (ignores levelMode — always uses stacked, no exploded gap). Presentation
|
|
38
|
+
* hiding is undone with it, but a level the author hid stays hidden: the
|
|
39
|
+
* capture has to match the export, which prunes it.
|
|
13
40
|
*
|
|
14
41
|
* Returns a restore function that reverts each level's Y to what it was
|
|
15
42
|
* before the snap, so lerp animations in LevelSystem can continue undisturbed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"level-utils.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"level-utils.d.ts","sourceRoot":"","sources":["../../../src/systems/level/level-utils.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY,IAAI,CAAA;AAE7B;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GACpD,MAAM,CAKR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,KAAK,EACL,aAAa,EACb,WAAW,GACZ,EAAE;IACD,SAAS,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAA;IACrD,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,EAAE,OAAO,CAAA;IACzB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,aAAa,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,WAAW,EAAE,OAAO,CAAA;CACrB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAQ5C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,IAAI,CA+CtD"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { getLevelElevations, sceneRegistry, useScene } from '@pascal-app/core';
|
|
2
|
+
import { applyShadowOnly, clearShadowOnly } from '../../lib/shadow-only';
|
|
3
|
+
import { shadowOnlyLevels } from './shadow-only-levels';
|
|
2
4
|
export const EXPLODED_GAP = 5;
|
|
3
5
|
/**
|
|
4
6
|
* The Y a level settles at under the given presentation mode — its stacked
|
|
@@ -13,9 +15,32 @@ export function getLevelPresentationY(levelId, nodes, levelMode) {
|
|
|
13
15
|
const explodedExtra = levelMode === 'exploded' && level ? level.level * EXPLODED_GAP : 0;
|
|
14
16
|
return baseY + explodedExtra;
|
|
15
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether a level renders this frame, and whether it renders as a
|
|
20
|
+
* shadow-caster only.
|
|
21
|
+
*
|
|
22
|
+
* Two unrelated things hide a level and they do not compose: the author's own
|
|
23
|
+
* `visible` flag (the sidebar eye), which hides the floor outright, and
|
|
24
|
+
* presentation hiding — solo mode hides every level but the soloed one, and
|
|
25
|
+
* the editor's level display (`hideAbove`) hides the levels above the
|
|
26
|
+
* selected one. Presentation-hidden levels ABOVE the selected one stay in the
|
|
27
|
+
* shadow map so the sun still shadows the selected floor through them.
|
|
28
|
+
* A level the author hid never enters that shadow-caster branch: its shadows
|
|
29
|
+
* on the floor below would be exactly what hiding it was meant to remove.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveLevelVisibility({ levelMode, hideAbove, hasSelectedLevel, isSelected, index, selectedIndex, nodeVisible, }) {
|
|
32
|
+
if (!nodeVisible)
|
|
33
|
+
return { visible: false, shadowOnly: false };
|
|
34
|
+
const hidden = (levelMode === 'solo' && hasSelectedLevel && !isSelected) ||
|
|
35
|
+
(hideAbove && selectedIndex !== undefined && index > selectedIndex);
|
|
36
|
+
const shadowOnly = hidden && selectedIndex !== undefined && index > selectedIndex;
|
|
37
|
+
return { visible: shadowOnly || !hidden, shadowOnly };
|
|
38
|
+
}
|
|
16
39
|
/**
|
|
17
40
|
* Instantly snaps all level Objects3D to their true stacked Y positions
|
|
18
|
-
* (ignores levelMode — always uses stacked, no exploded gap).
|
|
41
|
+
* (ignores levelMode — always uses stacked, no exploded gap). Presentation
|
|
42
|
+
* hiding is undone with it, but a level the author hid stays hidden: the
|
|
43
|
+
* capture has to match the export, which prunes it.
|
|
19
44
|
*
|
|
20
45
|
* Returns a restore function that reverts each level's Y to what it was
|
|
21
46
|
* before the snap, so lerp animations in LevelSystem can continue undisturbed.
|
|
@@ -35,17 +60,22 @@ export function snapLevelsToTruePositions() {
|
|
|
35
60
|
entries.push({
|
|
36
61
|
levelId,
|
|
37
62
|
obj,
|
|
63
|
+
nodeVisible: level.visible !== false,
|
|
38
64
|
});
|
|
39
65
|
}
|
|
40
66
|
});
|
|
41
67
|
const levelElevations = getLevelElevations(nodes);
|
|
42
68
|
// Snapshot current Y and visibility so we can restore them after the render
|
|
43
69
|
const snapshot = new Map(entries.map(({ levelId, obj }) => [levelId, { y: obj.position.y, visible: obj.visible }]));
|
|
44
|
-
// Snap to true stacked positions and
|
|
45
|
-
|
|
70
|
+
// Snap to true stacked positions and undo presentation hiding — including
|
|
71
|
+
// the levels kept shadow-caster-only above the selected level.
|
|
72
|
+
const shadowOnly = entries.filter(({ obj }) => shadowOnlyLevels.has(obj));
|
|
73
|
+
for (const { levelId, obj, nodeVisible } of entries) {
|
|
46
74
|
obj.position.y = levelElevations.get(levelId)?.baseY ?? 0;
|
|
47
|
-
obj.visible =
|
|
75
|
+
obj.visible = nodeVisible;
|
|
48
76
|
}
|
|
77
|
+
for (const { obj } of shadowOnly)
|
|
78
|
+
clearShadowOnly(obj);
|
|
49
79
|
return () => {
|
|
50
80
|
for (const { levelId, obj } of entries) {
|
|
51
81
|
const saved = snapshot.get(levelId);
|
|
@@ -54,5 +84,7 @@ export function snapLevelsToTruePositions() {
|
|
|
54
84
|
obj.visible = saved.visible;
|
|
55
85
|
}
|
|
56
86
|
}
|
|
87
|
+
for (const { obj } of shadowOnly)
|
|
88
|
+
applyShadowOnly(obj);
|
|
57
89
|
};
|
|
58
90
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Object3D } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Levels currently in shadow-caster-only mode (hidden above the selected level
|
|
4
|
+
* by solo or by the editor's level display). Tracked so layer masks are
|
|
5
|
+
* restored exactly once on transition, and so a full-building capture can
|
|
6
|
+
* show them for its one render.
|
|
7
|
+
*/
|
|
8
|
+
export declare const shadowOnlyLevels: WeakSet<Object3D<import("three").Object3DEventMap>>;
|
|
9
|
+
//# sourceMappingURL=shadow-only-levels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shadow-only-levels.d.ts","sourceRoot":"","sources":["../../../src/systems/level/shadow-only-levels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAErC;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,qDAA0B,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Levels currently in shadow-caster-only mode (hidden above the selected level
|
|
3
|
+
* by solo or by the editor's level display). Tracked so layer masks are
|
|
4
|
+
* restored exactly once on transition, and so a full-building capture can
|
|
5
|
+
* show them for its one render.
|
|
6
|
+
*/
|
|
7
|
+
export const shadowOnlyLevels = new WeakSet();
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import { type RoofNode } from '@pascal-app/core';
|
|
1
|
+
import { type AnyNode, type RoofNode, type SceneMaterial, type SceneMaterialId } from '@pascal-app/core';
|
|
2
2
|
import type * as THREE from 'three';
|
|
3
3
|
import { type ColorPreset, type RenderShading } from '../../lib/materials';
|
|
4
|
+
type SceneMaterials = Record<SceneMaterialId, SceneMaterial> | undefined;
|
|
4
5
|
export type RoofMaterialArray = [THREE.Material, THREE.Material, THREE.Material, THREE.Material];
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* The cladding the walls under a roof declare through their ASSEMBLIES
|
|
8
|
+
* (`wall.assembly.exterior.finish` → catalog ref), so the roof's gable band —
|
|
9
|
+
* the triangle of wall above the plate that the roof kind builds — is skinned
|
|
10
|
+
* like the walls it sits on instead of the bare drywall default. The most
|
|
11
|
+
* common ref among the level's walls wins; null when none declares one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function levelWallCladdingRef(nodes: Readonly<Record<string, AnyNode | undefined>>, roof: Pick<RoofNode, 'parentId'>): string | null;
|
|
14
|
+
export declare function getRoofMaterialArray(node: RoofNode, shading?: RenderShading, textures?: boolean, colorPreset?: ColorPreset, sceneTheme?: string,
|
|
15
|
+
/** Catalog ref for the gable/trim band when unpainted — see `levelWallCladdingRef`. */
|
|
16
|
+
wallCladdingRef?: string | null, sceneMaterials?: SceneMaterials): RoofMaterialArray | null;
|
|
17
|
+
export {};
|
|
6
18
|
//# sourceMappingURL=roof-materials.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"roof-materials.d.ts","sourceRoot":"","sources":["../../../src/systems/roof/roof-materials.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGZ,KAAK,QAAQ,EAEb,KAAK,aAAa,EAClB,KAAK,eAAe,EAErB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAA;AACnC,OAAO,EACL,KAAK,WAAW,EAGhB,KAAK,aAAa,EAGnB,MAAM,qBAAqB,CAAA;AAE5B,KAAK,cAAc,GAAG,MAAM,CAAC,eAAe,EAAE,aAAa,CAAC,GAAG,SAAS,CAAA;AAaxE,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAA;AAqChG;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC,EACpD,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,GAC/B,MAAM,GAAG,IAAI,CAkBf;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,QAAQ,EACd,OAAO,GAAE,aAA0B,EACnC,QAAQ,UAAO,EACf,WAAW,GAAE,WAAoB,EACjC,UAAU,CAAC,EAAE,MAAM;AACnB,uFAAuF;AACvF,eAAe,GAAE,MAAM,GAAG,IAAW,EACrC,cAAc,CAAC,EAAE,cAAc,GAC9B,iBAAiB,GAAG,IAAI,CAyE1B"}
|