@pascal-app/viewer 0.3.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/components/renderers/item/item-renderer.d.ts.map +1 -1
  2. package/dist/components/renderers/item/item-renderer.js +14 -19
  3. package/dist/components/renderers/node-renderer.d.ts.map +1 -1
  4. package/dist/components/renderers/node-renderer.js +3 -1
  5. package/dist/components/renderers/site/site-renderer.d.ts.map +1 -1
  6. package/dist/components/renderers/site/site-renderer.js +59 -15
  7. package/dist/components/renderers/slab/slab-renderer.js +1 -1
  8. package/dist/components/renderers/stair/stair-renderer.d.ts +5 -0
  9. package/dist/components/renderers/stair/stair-renderer.d.ts.map +1 -0
  10. package/dist/components/renderers/stair/stair-renderer.js +21 -0
  11. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts +5 -0
  12. package/dist/components/renderers/stair-segment/stair-segment-renderer.d.ts.map +1 -0
  13. package/dist/components/renderers/stair-segment/stair-segment-renderer.js +20 -0
  14. package/dist/components/renderers/wall/wall-renderer.js +1 -1
  15. package/dist/components/viewer/index.d.ts.map +1 -1
  16. package/dist/components/viewer/index.js +2 -3
  17. package/dist/components/viewer/post-processing.d.ts.map +1 -1
  18. package/dist/components/viewer/post-processing.js +33 -45
  19. package/dist/components/viewer/walkthrough-controls.d.ts +2 -0
  20. package/dist/components/viewer/walkthrough-controls.d.ts.map +1 -0
  21. package/dist/components/viewer/walkthrough-controls.js +131 -0
  22. package/dist/hooks/use-gltf-ktx2.d.ts.map +1 -1
  23. package/dist/hooks/use-node-events.d.ts +9 -1
  24. package/dist/hooks/use-node-events.d.ts.map +1 -1
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +2 -1
  28. package/dist/lib/materials.d.ts +1 -0
  29. package/dist/lib/materials.d.ts.map +1 -1
  30. package/dist/lib/materials.js +1 -0
  31. package/dist/lib/merged-outline-node.d.ts +88 -0
  32. package/dist/lib/merged-outline-node.d.ts.map +1 -0
  33. package/dist/lib/merged-outline-node.js +450 -0
  34. package/dist/lib/suppress-three-clock-warning.d.ts +25 -0
  35. package/dist/lib/suppress-three-clock-warning.d.ts.map +1 -0
  36. package/dist/lib/suppress-three-clock-warning.js +51 -0
  37. package/dist/store/use-viewer.d.ts +6 -0
  38. package/dist/store/use-viewer.d.ts.map +1 -1
  39. package/dist/store/use-viewer.js +8 -1
  40. package/dist/systems/wall/wall-cutout.d.ts.map +1 -1
  41. package/dist/systems/wall/wall-cutout.js +110 -61
  42. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAA;AAC9E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAChF,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,wBAAwB,EACxB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,eAAe,GAChB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAA"}
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  export { default as Viewer } from './components/viewer';
2
+ export { WalkthroughControls } from './components/viewer/walkthrough-controls';
2
3
  export { ASSETS_CDN_URL, resolveAssetUrl, resolveCdnUrl } from './lib/asset-url';
3
4
  export { SCENE_LAYER, ZONE_LAYER } from './lib/layers';
4
5
  export { clearMaterialCache, createDefaultMaterial, createMaterial, DEFAULT_CEILING_MATERIAL, DEFAULT_DOOR_MATERIAL, DEFAULT_ROOF_MATERIAL, DEFAULT_SLAB_MATERIAL, DEFAULT_WALL_MATERIAL, DEFAULT_WINDOW_MATERIAL, disposeMaterial, } from './lib/materials';
6
+ export { mergedOutline } from './lib/merged-outline-node';
5
7
  export { default as useViewer } from './store/use-viewer';
6
- export { ExportSystem } from './systems/export/export-system';
7
8
  export { InteractiveSystem } from './systems/interactive/interactive-system';
8
9
  export { snapLevelsToTruePositions } from './systems/level/level-utils';
@@ -8,6 +8,7 @@ export declare const DEFAULT_DOOR_MATERIAL: THREE.MeshStandardMaterial;
8
8
  export declare const DEFAULT_WINDOW_MATERIAL: THREE.MeshStandardMaterial;
9
9
  export declare const DEFAULT_CEILING_MATERIAL: THREE.MeshStandardMaterial;
10
10
  export declare const DEFAULT_ROOF_MATERIAL: THREE.MeshStandardMaterial;
11
+ export declare const DEFAULT_STAIR_MATERIAL: THREE.MeshStandardMaterial;
11
12
  export declare function disposeMaterial(material: THREE.Material): void;
12
13
  export declare function clearMaterialCache(): void;
13
14
  //# sourceMappingURL=materials.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,cAAc,EAAmB,MAAM,kBAAkB,CAAA;AAChG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAc9B,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC,oBAAoB,CAmBpF;AAED,wBAAgB,qBAAqB,CACnC,KAAK,GAAE,MAAkB,EACzB,SAAS,GAAE,MAAY,GACtB,KAAK,CAAC,oBAAoB,CAO5B;AAED,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,uBAAuB,4BAOlC,CAAA;AACF,eAAO,MAAM,wBAAwB,4BAAyC,CAAA;AAC9E,eAAO,MAAM,qBAAqB,4BAAyC,CAAA;AAE3E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
1
+ {"version":3,"file":"materials.d.ts","sourceRoot":"","sources":["../../src/lib/materials.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,cAAc,EAAmB,MAAM,kBAAkB,CAAA;AAChG,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAc9B,wBAAgB,cAAc,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,KAAK,CAAC,oBAAoB,CAmBpF;AAED,wBAAgB,qBAAqB,CACnC,KAAK,SAAY,EACjB,SAAS,SAAM,GACd,KAAK,CAAC,oBAAoB,CAO5B;AAED,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,qBAAqB,4BAAwC,CAAA;AAC1E,eAAO,MAAM,uBAAuB,4BAOlC,CAAA;AACF,eAAO,MAAM,wBAAwB,4BAAyC,CAAA;AAC9E,eAAO,MAAM,qBAAqB,4BAAyC,CAAA;AAC3E,eAAO,MAAM,sBAAsB,4BAAwC,CAAA;AAE3E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAE9D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAKzC"}
@@ -47,6 +47,7 @@ export const DEFAULT_WINDOW_MATERIAL = new THREE.MeshStandardMaterial({
47
47
  });
48
48
  export const DEFAULT_CEILING_MATERIAL = createDefaultMaterial('#f5f5dc', 0.95);
49
49
  export const DEFAULT_ROOF_MATERIAL = createDefaultMaterial('#808080', 0.85);
50
+ export const DEFAULT_STAIR_MATERIAL = createDefaultMaterial('#ffffff', 0.9);
50
51
  export function disposeMaterial(material) {
51
52
  material.dispose();
52
53
  }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * MergedOutlineNode — a fork of Three.js OutlineNode that processes two object
3
+ * groups (primary = selected, secondary = hovered) in a single pass, sharing the
4
+ * expensive non-selected depth pre-render between both groups.
5
+ *
6
+ * Cost comparison vs two separate OutlineNode instances:
7
+ * Before: depth_A + mask_A + edge_A×6 + depth_B + mask_B + edge_B×6 = 2 depth passes
8
+ * After: depth_AB (shared) + mask_A + edge_A×6 + mask_B + edge_B×6 = 1 depth pass
9
+ *
10
+ * Additional early-outs:
11
+ * - Both empty → skip everything (0 passes)
12
+ * - Only primary → skip secondary mask/edge/blur
13
+ * - Only secondary → skip primary mask/edge/blur
14
+ */
15
+ import { type Object3D } from 'three';
16
+ import { TempNode } from 'three/webgpu';
17
+ export declare class MergedOutlineNode extends TempNode {
18
+ static get type(): string;
19
+ scene: any;
20
+ camera: any;
21
+ primaryObjects: Object3D[];
22
+ secondaryObjects: Object3D[];
23
+ primaryEdgeThicknessNode: any;
24
+ secondaryEdgeThicknessNode: any;
25
+ primaryEdgeGlowNode: any;
26
+ secondaryEdgeGlowNode: any;
27
+ downSampleRatio: number;
28
+ updateBeforeType: string;
29
+ private readonly _depthRT;
30
+ private readonly _depthTexUniform;
31
+ private readonly _groupA;
32
+ private readonly _groupB;
33
+ private readonly _maskTexA;
34
+ private readonly _maskDownTexA;
35
+ private readonly _edge1TexA;
36
+ private readonly _edge2TexA;
37
+ private readonly _blurColorTexA;
38
+ private readonly _maskTexB;
39
+ private readonly _maskDownTexB;
40
+ private readonly _edge1TexB;
41
+ private readonly _edge2TexB;
42
+ private readonly _blurColorTexB;
43
+ private readonly _blurDirectionA;
44
+ private readonly _blurDirectionB;
45
+ private readonly _cameraNear;
46
+ private readonly _cameraFar;
47
+ private readonly _depthMaterial;
48
+ private readonly _depthSpriteMaterial;
49
+ private readonly _prepareMaskMatA;
50
+ private readonly _prepareMaskSpriteMatA;
51
+ private readonly _copyMatA;
52
+ private readonly _edgeDetectMatA;
53
+ private readonly _blurMat1A;
54
+ private readonly _blurMat2A;
55
+ private readonly _compositeMatA;
56
+ private readonly _prepareMaskMatB;
57
+ private readonly _prepareMaskSpriteMatB;
58
+ private readonly _copyMatB;
59
+ private readonly _edgeDetectMatB;
60
+ private readonly _blurMat1B;
61
+ private readonly _blurMat2B;
62
+ private readonly _compositeMatB;
63
+ private readonly _cacheA;
64
+ private readonly _cacheB;
65
+ private readonly _textureNodeA;
66
+ private readonly _textureNodeB;
67
+ constructor(scene: any, camera: any, params?: {
68
+ primaryObjects?: Object3D[];
69
+ secondaryObjects?: Object3D[];
70
+ primaryEdgeThickness?: any;
71
+ secondaryEdgeThickness?: any;
72
+ primaryEdgeGlow?: any;
73
+ secondaryEdgeGlow?: any;
74
+ downSampleRatio?: number;
75
+ });
76
+ get primaryVisibleEdge(): any;
77
+ get primaryHiddenEdge(): any;
78
+ get secondaryVisibleEdge(): any;
79
+ get secondaryHiddenEdge(): any;
80
+ setSize(width: number, height: number): void;
81
+ updateBefore(frame: any): void;
82
+ private _runEdgePipeline;
83
+ setup(_builder: any): any;
84
+ dispose(): void;
85
+ private _buildCache;
86
+ }
87
+ export declare const mergedOutline: (scene: any, camera: any, params?: ConstructorParameters<typeof MergedOutlineNode>[2]) => MergedOutlineNode;
88
+ //# sourceMappingURL=merged-outline-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merged-outline-node.d.ts","sourceRoot":"","sources":["../../src/lib/merged-outline-node.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,450 @@
1
+ // @ts-nocheck — Three.js TSL/WebGPU internal APIs have incomplete type definitions;
2
+ // this file is a fork of OutlineNode and is intentionally exempt from strict TS checking.
3
+ /**
4
+ * MergedOutlineNode — a fork of Three.js OutlineNode that processes two object
5
+ * groups (primary = selected, secondary = hovered) in a single pass, sharing the
6
+ * expensive non-selected depth pre-render between both groups.
7
+ *
8
+ * Cost comparison vs two separate OutlineNode instances:
9
+ * Before: depth_A + mask_A + edge_A×6 + depth_B + mask_B + edge_B×6 = 2 depth passes
10
+ * After: depth_AB (shared) + mask_A + edge_A×6 + mask_B + edge_B×6 = 1 depth pass
11
+ *
12
+ * Additional early-outs:
13
+ * - Both empty → skip everything (0 passes)
14
+ * - Only primary → skip secondary mask/edge/blur
15
+ * - Only secondary → skip primary mask/edge/blur
16
+ */
17
+ import { DepthTexture, FloatType, RenderTarget, Vector2 } from 'three';
18
+ import { color, exp, Fn, float, int, Loop, min, mul, nodeObject, orthographicDepthToViewZ, passTexture, perspectiveDepthToViewZ, positionView, reference, screenUV, texture, textureSize, uniform, uv, vec2, vec3, vec4, } from 'three/tsl';
19
+ import { NodeMaterial, NodeUpdateType, QuadMesh, RendererUtils, SpriteNodeMaterial, TempNode, } from 'three/webgpu';
20
+ const _quadMesh = new QuadMesh();
21
+ const _size = new Vector2();
22
+ const _BLUR_X = new Vector2(1.0, 0.0);
23
+ const _BLUR_Y = new Vector2(0.0, 1.0);
24
+ let _rendererState; // eslint-disable-line @typescript-eslint/no-explicit-any
25
+ // ---------------------------------------------------------------------------
26
+ // Helper: render targets for one outline group
27
+ // ---------------------------------------------------------------------------
28
+ function makeGroupTargets(downSampleRatio) {
29
+ const maskBuffer = new RenderTarget();
30
+ const maskDownSample = new RenderTarget(1, 1, { depthBuffer: false });
31
+ const edgeBuffer1 = new RenderTarget(1, 1, { depthBuffer: false });
32
+ const edgeBuffer2 = new RenderTarget(1, 1, { depthBuffer: false });
33
+ const blurBuffer1 = new RenderTarget(1, 1, { depthBuffer: false });
34
+ const blurBuffer2 = new RenderTarget(1, 1, { depthBuffer: false });
35
+ const composite = new RenderTarget(1, 1, { depthBuffer: false });
36
+ function setSize(w, h) {
37
+ maskBuffer.setSize(w, h);
38
+ composite.setSize(w, h);
39
+ let rx = Math.round(w / downSampleRatio);
40
+ let ry = Math.round(h / downSampleRatio);
41
+ maskDownSample.setSize(rx, ry);
42
+ edgeBuffer1.setSize(rx, ry);
43
+ blurBuffer1.setSize(rx, ry);
44
+ rx = Math.round(rx / 2);
45
+ ry = Math.round(ry / 2);
46
+ edgeBuffer2.setSize(rx, ry);
47
+ blurBuffer2.setSize(rx, ry);
48
+ }
49
+ function dispose() {
50
+ maskBuffer.dispose();
51
+ maskDownSample.dispose();
52
+ edgeBuffer1.dispose();
53
+ edgeBuffer2.dispose();
54
+ blurBuffer1.dispose();
55
+ blurBuffer2.dispose();
56
+ composite.dispose();
57
+ }
58
+ return {
59
+ maskBuffer,
60
+ maskDownSample,
61
+ edgeBuffer1,
62
+ edgeBuffer2,
63
+ blurBuffer1,
64
+ blurBuffer2,
65
+ composite,
66
+ setSize,
67
+ dispose,
68
+ };
69
+ }
70
+ // ---------------------------------------------------------------------------
71
+ // MergedOutlineNode
72
+ // ---------------------------------------------------------------------------
73
+ export class MergedOutlineNode extends TempNode {
74
+ static get type() {
75
+ return 'MergedOutlineNode';
76
+ }
77
+ scene;
78
+ camera;
79
+ primaryObjects;
80
+ secondaryObjects;
81
+ primaryEdgeThicknessNode;
82
+ secondaryEdgeThicknessNode;
83
+ primaryEdgeGlowNode;
84
+ secondaryEdgeGlowNode;
85
+ downSampleRatio;
86
+ updateBeforeType;
87
+ _depthRT;
88
+ _depthTexUniform;
89
+ _groupA;
90
+ _groupB;
91
+ _maskTexA;
92
+ _maskDownTexA;
93
+ _edge1TexA;
94
+ _edge2TexA;
95
+ _blurColorTexA;
96
+ _maskTexB;
97
+ _maskDownTexB;
98
+ _edge1TexB;
99
+ _edge2TexB;
100
+ _blurColorTexB;
101
+ _blurDirectionA;
102
+ _blurDirectionB;
103
+ _cameraNear;
104
+ _cameraFar;
105
+ _depthMaterial;
106
+ _depthSpriteMaterial;
107
+ _prepareMaskMatA;
108
+ _prepareMaskSpriteMatA;
109
+ _copyMatA;
110
+ _edgeDetectMatA;
111
+ _blurMat1A;
112
+ _blurMat2A;
113
+ _compositeMatA;
114
+ _prepareMaskMatB;
115
+ _prepareMaskSpriteMatB;
116
+ _copyMatB;
117
+ _edgeDetectMatB;
118
+ _blurMat1B;
119
+ _blurMat2B;
120
+ _compositeMatB;
121
+ _cacheA = new Set();
122
+ _cacheB = new Set();
123
+ _textureNodeA;
124
+ _textureNodeB;
125
+ constructor(scene, camera, params = {}) {
126
+ super('vec4');
127
+ const { primaryObjects = [], secondaryObjects = [], primaryEdgeThickness = float(1), secondaryEdgeThickness = float(1), primaryEdgeGlow = float(0), secondaryEdgeGlow = float(0), downSampleRatio = 2, } = params;
128
+ this.scene = scene;
129
+ this.camera = camera;
130
+ this.primaryObjects = primaryObjects;
131
+ this.secondaryObjects = secondaryObjects;
132
+ this.primaryEdgeThicknessNode = nodeObject(primaryEdgeThickness);
133
+ this.secondaryEdgeThicknessNode = nodeObject(secondaryEdgeThickness);
134
+ this.primaryEdgeGlowNode = nodeObject(primaryEdgeGlow);
135
+ this.secondaryEdgeGlowNode = nodeObject(secondaryEdgeGlow);
136
+ this.downSampleRatio = downSampleRatio;
137
+ this.updateBeforeType = NodeUpdateType.FRAME;
138
+ this._depthRT = new RenderTarget();
139
+ this._depthRT.depthTexture = new DepthTexture();
140
+ this._depthRT.depthTexture.type = FloatType;
141
+ this._groupA = makeGroupTargets(downSampleRatio);
142
+ this._groupB = makeGroupTargets(downSampleRatio);
143
+ this._cameraNear = reference('near', 'float', camera);
144
+ this._cameraFar = reference('far', 'float', camera);
145
+ this._blurDirectionA = uniform(new Vector2());
146
+ this._blurDirectionB = uniform(new Vector2());
147
+ this._depthTexUniform = texture(this._depthRT.depthTexture);
148
+ this._maskTexA = texture(this._groupA.maskBuffer.texture);
149
+ this._maskDownTexA = texture(this._groupA.maskDownSample.texture);
150
+ this._edge1TexA = texture(this._groupA.edgeBuffer1.texture);
151
+ this._edge2TexA = texture(this._groupA.edgeBuffer2.texture);
152
+ this._blurColorTexA = texture(this._groupA.edgeBuffer1.texture);
153
+ this._maskTexB = texture(this._groupB.maskBuffer.texture);
154
+ this._maskDownTexB = texture(this._groupB.maskDownSample.texture);
155
+ this._edge1TexB = texture(this._groupB.edgeBuffer1.texture);
156
+ this._edge2TexB = texture(this._groupB.edgeBuffer2.texture);
157
+ this._blurColorTexB = texture(this._groupB.edgeBuffer1.texture);
158
+ this._depthMaterial = new NodeMaterial();
159
+ this._depthMaterial.colorNode = color(0, 0, 0);
160
+ this._depthMaterial.name = 'MergedOutline.depth';
161
+ this._depthSpriteMaterial = new SpriteNodeMaterial();
162
+ this._depthSpriteMaterial.colorNode = color(0, 0, 0);
163
+ this._depthSpriteMaterial.name = 'MergedOutline.depthSprite';
164
+ this._prepareMaskMatA = new NodeMaterial();
165
+ this._prepareMaskMatA.name = 'MergedOutline.maskA';
166
+ this._prepareMaskSpriteMatA = new SpriteNodeMaterial();
167
+ this._prepareMaskSpriteMatA.name = 'MergedOutline.maskSpriteA';
168
+ this._copyMatA = new NodeMaterial();
169
+ this._copyMatA.name = 'MergedOutline.copyA';
170
+ this._edgeDetectMatA = new NodeMaterial();
171
+ this._edgeDetectMatA.name = 'MergedOutline.edgeA';
172
+ this._blurMat1A = new NodeMaterial();
173
+ this._blurMat1A.name = 'MergedOutline.blur1A';
174
+ this._blurMat2A = new NodeMaterial();
175
+ this._blurMat2A.name = 'MergedOutline.blur2A';
176
+ this._compositeMatA = new NodeMaterial();
177
+ this._compositeMatA.name = 'MergedOutline.compositeA';
178
+ this._prepareMaskMatB = new NodeMaterial();
179
+ this._prepareMaskMatB.name = 'MergedOutline.maskB';
180
+ this._prepareMaskSpriteMatB = new SpriteNodeMaterial();
181
+ this._prepareMaskSpriteMatB.name = 'MergedOutline.maskSpriteB';
182
+ this._copyMatB = new NodeMaterial();
183
+ this._copyMatB.name = 'MergedOutline.copyB';
184
+ this._edgeDetectMatB = new NodeMaterial();
185
+ this._edgeDetectMatB.name = 'MergedOutline.edgeB';
186
+ this._blurMat1B = new NodeMaterial();
187
+ this._blurMat1B.name = 'MergedOutline.blur1B';
188
+ this._blurMat2B = new NodeMaterial();
189
+ this._blurMat2B.name = 'MergedOutline.blur2B';
190
+ this._compositeMatB = new NodeMaterial();
191
+ this._compositeMatB.name = 'MergedOutline.compositeB';
192
+ // Output: R = visibleEdge, G = hiddenEdge
193
+ this._textureNodeA = passTexture(this, this._groupA.composite.texture);
194
+ this._textureNodeB = passTexture(this, this._groupB.composite.texture);
195
+ }
196
+ get primaryVisibleEdge() {
197
+ return this._textureNodeA.r;
198
+ }
199
+ get primaryHiddenEdge() {
200
+ return this._textureNodeA.g;
201
+ }
202
+ get secondaryVisibleEdge() {
203
+ return this._textureNodeB.r;
204
+ }
205
+ get secondaryHiddenEdge() {
206
+ return this._textureNodeB.g;
207
+ }
208
+ setSize(width, height) {
209
+ this._depthRT.setSize(width, height);
210
+ this._groupA.setSize(width, height);
211
+ this._groupB.setSize(width, height);
212
+ }
213
+ updateBefore(frame) {
214
+ const hasPrimary = this.primaryObjects.length > 0;
215
+ const hasSecondary = this.secondaryObjects.length > 0;
216
+ const { renderer } = frame;
217
+ const { camera, scene } = this;
218
+ _rendererState = RendererUtils.resetRendererAndSceneState(renderer, scene, _rendererState);
219
+ const size = renderer.getDrawingBufferSize(_size);
220
+ this.setSize(size.width, size.height);
221
+ // Clear composites for inactive groups so stale outlines don't persist on GPU.
222
+ // Must happen inside resetRendererAndSceneState to avoid MSAA state corruption.
223
+ if (!hasPrimary) {
224
+ renderer.setRenderTarget(this._groupA.composite);
225
+ renderer.clearColor();
226
+ }
227
+ if (!hasSecondary) {
228
+ renderer.setRenderTarget(this._groupB.composite);
229
+ renderer.clearColor();
230
+ }
231
+ const hasAny = hasPrimary || hasSecondary;
232
+ if (!hasAny) {
233
+ RendererUtils.restoreRendererAndSceneState(renderer, scene, _rendererState);
234
+ return;
235
+ }
236
+ renderer.setClearColor(0xff_ff_ff, 1);
237
+ if (hasPrimary)
238
+ this._buildCache(this.primaryObjects, this._cacheA);
239
+ if (hasSecondary)
240
+ this._buildCache(this.secondaryObjects, this._cacheB);
241
+ const savedName = scene.name;
242
+ // ── 1. Shared depth pass: all objects NOT in either group ─────────────────
243
+ renderer.setRenderTarget(this._depthRT);
244
+ renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
245
+ const inCache = this._cacheA.has(obj) || this._cacheB.has(obj);
246
+ if (!inCache) {
247
+ const m = obj.isSprite ? this._depthSpriteMaterial : this._depthMaterial;
248
+ renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
249
+ }
250
+ });
251
+ scene.name = 'MergedOutline [ Depth ]';
252
+ renderer.render(scene, camera);
253
+ // ── 2a. Primary mask pass ─────────────────────────────────────────────────
254
+ if (hasPrimary) {
255
+ renderer.setRenderTarget(this._groupA.maskBuffer);
256
+ renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
257
+ if (this._cacheA.has(obj)) {
258
+ const m = obj.isSprite ? this._prepareMaskSpriteMatA : this._prepareMaskMatA;
259
+ renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
260
+ }
261
+ });
262
+ scene.name = 'MergedOutline [ Mask A ]';
263
+ renderer.render(scene, camera);
264
+ }
265
+ // ── 2b. Secondary mask pass ───────────────────────────────────────────────
266
+ if (hasSecondary) {
267
+ renderer.setRenderTarget(this._groupB.maskBuffer);
268
+ renderer.setRenderObjectFunction((obj, sc, cam, geo, _mat, grp, lights, clip) => {
269
+ if (this._cacheB.has(obj)) {
270
+ const m = obj.isSprite ? this._prepareMaskSpriteMatB : this._prepareMaskMatB;
271
+ renderer.renderObject(obj, sc, cam, geo, m, grp, lights, clip);
272
+ }
273
+ });
274
+ scene.name = 'MergedOutline [ Mask B ]';
275
+ renderer.render(scene, camera);
276
+ }
277
+ renderer.setRenderObjectFunction(_rendererState.renderObjectFunction);
278
+ this._cacheA.clear();
279
+ this._cacheB.clear();
280
+ scene.name = savedName;
281
+ // ── 3–7. Edge detect + blur + composite per active group ──────────────────
282
+ if (hasPrimary)
283
+ this._runEdgePipeline(renderer, 'A');
284
+ if (hasSecondary)
285
+ this._runEdgePipeline(renderer, 'B');
286
+ RendererUtils.restoreRendererAndSceneState(renderer, scene, _rendererState);
287
+ }
288
+ _runEdgePipeline(renderer, group) {
289
+ const isA = group === 'A';
290
+ const g = isA ? this._groupA : this._groupB;
291
+ const copyMat = isA ? this._copyMatA : this._copyMatB;
292
+ const edgeMat = isA ? this._edgeDetectMatA : this._edgeDetectMatB;
293
+ const blur1 = isA ? this._blurMat1A : this._blurMat1B;
294
+ const blur2 = isA ? this._blurMat2A : this._blurMat2B;
295
+ const blurDir = isA ? this._blurDirectionA : this._blurDirectionB;
296
+ const blurColorTex = isA ? this._blurColorTexA : this._blurColorTexB;
297
+ const compositeMat = isA ? this._compositeMatA : this._compositeMatB;
298
+ _quadMesh.material = copyMat;
299
+ renderer.setRenderTarget(g.maskDownSample);
300
+ _quadMesh.render(renderer);
301
+ _quadMesh.material = edgeMat;
302
+ renderer.setRenderTarget(g.edgeBuffer1);
303
+ _quadMesh.render(renderer);
304
+ blurColorTex.value = g.edgeBuffer1.texture;
305
+ blurDir.value.copy(_BLUR_X);
306
+ _quadMesh.material = blur1;
307
+ renderer.setRenderTarget(g.blurBuffer1);
308
+ _quadMesh.render(renderer);
309
+ blurColorTex.value = g.blurBuffer1.texture;
310
+ blurDir.value.copy(_BLUR_Y);
311
+ renderer.setRenderTarget(g.edgeBuffer1);
312
+ _quadMesh.render(renderer);
313
+ blurColorTex.value = g.edgeBuffer1.texture;
314
+ blurDir.value.copy(_BLUR_X);
315
+ _quadMesh.material = blur2;
316
+ renderer.setRenderTarget(g.blurBuffer2);
317
+ _quadMesh.render(renderer);
318
+ blurColorTex.value = g.blurBuffer2.texture;
319
+ blurDir.value.copy(_BLUR_Y);
320
+ renderer.setRenderTarget(g.edgeBuffer2);
321
+ _quadMesh.render(renderer);
322
+ _quadMesh.material = compositeMat;
323
+ renderer.setRenderTarget(g.composite);
324
+ _quadMesh.render(renderer);
325
+ }
326
+ setup(_builder) {
327
+ // ── prepareMask ───────────────────────────────────────────────────────────
328
+ const buildPrepareMask = () => {
329
+ const depth = this._depthTexUniform.sample(screenUV);
330
+ const viewZ = this.camera.isPerspectiveCamera
331
+ ? perspectiveDepthToViewZ(depth, this._cameraNear, this._cameraFar)
332
+ : orthographicDepthToViewZ(depth, this._cameraNear, this._cameraFar);
333
+ const depthTest = positionView.z.lessThanEqual(viewZ).select(1, 0);
334
+ return vec3(0.0, depthTest, 1.0);
335
+ };
336
+ const maskColorA = buildPrepareMask();
337
+ this._prepareMaskMatA.colorNode = maskColorA;
338
+ this._prepareMaskMatA.needsUpdate = true;
339
+ this._prepareMaskSpriteMatA.colorNode = maskColorA;
340
+ this._prepareMaskSpriteMatA.needsUpdate = true;
341
+ const maskColorB = buildPrepareMask();
342
+ this._prepareMaskMatB.colorNode = maskColorB;
343
+ this._prepareMaskMatB.needsUpdate = true;
344
+ this._prepareMaskSpriteMatB.colorNode = maskColorB;
345
+ this._prepareMaskSpriteMatB.needsUpdate = true;
346
+ // ── Copy ──────────────────────────────────────────────────────────────────
347
+ this._copyMatA.fragmentNode = this._maskTexA;
348
+ this._copyMatA.needsUpdate = true;
349
+ this._copyMatB.fragmentNode = this._maskTexB;
350
+ this._copyMatB.needsUpdate = true;
351
+ // ── Edge detection ────────────────────────────────────────────────────────
352
+ const buildEdgeDetect = (maskDownTex) => Fn(() => {
353
+ const resolution = textureSize(maskDownTex);
354
+ const invSize = vec2(1).div(resolution).toVar();
355
+ const uvOffset = vec4(1.0, 0.0, 0.0, 1.0).mul(vec4(invSize, invSize));
356
+ const uvNode = uv();
357
+ const c1 = maskDownTex.sample(uvNode.add(uvOffset.xy)).toVar();
358
+ const c2 = maskDownTex.sample(uvNode.sub(uvOffset.xy)).toVar();
359
+ const c3 = maskDownTex.sample(uvNode.add(uvOffset.yw)).toVar();
360
+ const c4 = maskDownTex.sample(uvNode.sub(uvOffset.yw)).toVar();
361
+ const diff1 = mul(c1.r.sub(c2.r), 0.5);
362
+ const diff2 = mul(c3.r.sub(c4.r), 0.5);
363
+ const d = vec2(diff1, diff2).length();
364
+ const a1 = min(c1.g, c2.g);
365
+ const a2 = min(c3.g, c4.g);
366
+ const visibilityFactor = min(a1, a2);
367
+ // R = visible edge, G = hidden edge (matches OutlineNode convention)
368
+ const edgeColor = visibilityFactor
369
+ .oneMinus()
370
+ .greaterThan(0.001)
371
+ .select(vec3(1, 0, 0), vec3(0, 1, 0));
372
+ return vec4(edgeColor, 1).mul(d);
373
+ })();
374
+ this._edgeDetectMatA.fragmentNode = buildEdgeDetect(this._maskDownTexA);
375
+ this._edgeDetectMatA.needsUpdate = true;
376
+ this._edgeDetectMatB.fragmentNode = buildEdgeDetect(this._maskDownTexB);
377
+ this._edgeDetectMatB.needsUpdate = true;
378
+ // ── Separable blur ────────────────────────────────────────────────────────
379
+ const MAX_RADIUS = 4;
380
+ const gaussianPdf = Fn(([x, sigma]) => float(0.398_94).mul(exp(float(-0.5).mul(x).mul(x).div(sigma.mul(sigma))).div(sigma)));
381
+ const buildBlur = (maskDownTex, blurColorTex, blurDir, kernelRadius) => Fn(() => {
382
+ const resolution = textureSize(maskDownTex);
383
+ const invSize = vec2(1).div(resolution).toVar();
384
+ const uvNode = uv();
385
+ const sigma = kernelRadius.div(2).toVar();
386
+ const weightSum = gaussianPdf(0, sigma).toVar();
387
+ const diffuseSum = blurColorTex.sample(uvNode).mul(weightSum).toVar();
388
+ const delta = blurDir.mul(invSize).mul(kernelRadius).div(MAX_RADIUS).toVar();
389
+ const uvOffset = delta.toVar();
390
+ Loop({ start: int(1), end: int(MAX_RADIUS), type: 'int', condition: '<=' }, ({ i }) => {
391
+ const x = kernelRadius.mul(float(i)).div(MAX_RADIUS);
392
+ const w = gaussianPdf(x, sigma);
393
+ diffuseSum.addAssign(blurColorTex
394
+ .sample(uvNode.add(uvOffset))
395
+ .add(blurColorTex.sample(uvNode.sub(uvOffset)))
396
+ .mul(w));
397
+ weightSum.addAssign(w.mul(2));
398
+ uvOffset.addAssign(delta);
399
+ });
400
+ return diffuseSum.div(weightSum);
401
+ })();
402
+ this._blurMat1A.fragmentNode = buildBlur(this._maskDownTexA, this._blurColorTexA, this._blurDirectionA, this.primaryEdgeThicknessNode);
403
+ this._blurMat1A.needsUpdate = true;
404
+ this._blurMat2A.fragmentNode = buildBlur(this._maskDownTexA, this._blurColorTexA, this._blurDirectionA, float(MAX_RADIUS));
405
+ this._blurMat2A.needsUpdate = true;
406
+ this._blurMat1B.fragmentNode = buildBlur(this._maskDownTexB, this._blurColorTexB, this._blurDirectionB, this.secondaryEdgeThicknessNode);
407
+ this._blurMat1B.needsUpdate = true;
408
+ this._blurMat2B.fragmentNode = buildBlur(this._maskDownTexB, this._blurColorTexB, this._blurDirectionB, float(MAX_RADIUS));
409
+ this._blurMat2B.needsUpdate = true;
410
+ // ── Composite ─────────────────────────────────────────────────────────────
411
+ const buildComposite = (maskTex, edge1Tex, edge2Tex, edgeGlowNode) => Fn(() => maskTex.r.mul(edge1Tex.add(edge2Tex.mul(edgeGlowNode))))();
412
+ this._compositeMatA.fragmentNode = buildComposite(this._maskTexA, this._edge1TexA, this._edge2TexA, this.primaryEdgeGlowNode);
413
+ this._compositeMatA.needsUpdate = true;
414
+ this._compositeMatB.fragmentNode = buildComposite(this._maskTexB, this._edge1TexB, this._edge2TexB, this.secondaryEdgeGlowNode);
415
+ this._compositeMatB.needsUpdate = true;
416
+ return this._textureNodeA;
417
+ }
418
+ dispose() {
419
+ this.primaryObjects.length = 0;
420
+ this.secondaryObjects.length = 0;
421
+ this._depthRT.dispose();
422
+ this._groupA.dispose();
423
+ this._groupB.dispose();
424
+ this._depthMaterial.dispose();
425
+ this._depthSpriteMaterial.dispose();
426
+ this._prepareMaskMatA.dispose();
427
+ this._prepareMaskSpriteMatA.dispose();
428
+ this._copyMatA.dispose();
429
+ this._edgeDetectMatA.dispose();
430
+ this._blurMat1A.dispose();
431
+ this._blurMat2A.dispose();
432
+ this._compositeMatA.dispose();
433
+ this._prepareMaskMatB.dispose();
434
+ this._prepareMaskSpriteMatB.dispose();
435
+ this._copyMatB.dispose();
436
+ this._edgeDetectMatB.dispose();
437
+ this._blurMat1B.dispose();
438
+ this._blurMat2B.dispose();
439
+ this._compositeMatB.dispose();
440
+ }
441
+ _buildCache(objects, cache) {
442
+ for (const obj of objects) {
443
+ obj.traverse((child) => {
444
+ if (child.isMesh || child.isSprite)
445
+ cache.add(child);
446
+ });
447
+ }
448
+ }
449
+ }
450
+ export const mergedOutline = (scene, camera, params) => new MergedOutlineNode(scene, camera, params);
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Suppresses the `THREE.Clock: This module has been deprecated` warning
3
+ * emitted by three.js r183+ on every `new THREE.Clock()` call.
4
+ *
5
+ * We don't instantiate `Clock` ourselves — `@react-three/fiber` 9.x
6
+ * (current stable) creates one internally per `<Canvas>` mount. The
7
+ * migration to `THREE.Timer` lands in R3F 10.x (still alpha).
8
+ *
9
+ * Uses three's `setConsoleFunction` hook so we don't touch `console.warn`
10
+ * globally. Only the exact Clock deprecation message is suppressed; all
11
+ * other three.js logs (including TSL stack-trace warnings) pass through
12
+ * untouched.
13
+ *
14
+ * Runs in production as well as dev — the suppressed message is a pure
15
+ * deprecation notice with no user-actionable content.
16
+ *
17
+ * REMOVAL: safe to delete once `@react-three/fiber` no longer constructs
18
+ * `new THREE.Clock()`. To verify after an R3F upgrade:
19
+ * grep -n "new THREE.Clock" node_modules/@react-three/fiber/dist/*.js
20
+ * No hits → delete this file and its import in components/viewer/index.tsx.
21
+ *
22
+ * @see https://github.com/pascalorg/editor/issues/213
23
+ */
24
+ export {};
25
+ //# sourceMappingURL=suppress-three-clock-warning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suppress-three-clock-warning.d.ts","sourceRoot":"","sources":["../../src/lib/suppress-three-clock-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Suppresses the `THREE.Clock: This module has been deprecated` warning
3
+ * emitted by three.js r183+ on every `new THREE.Clock()` call.
4
+ *
5
+ * We don't instantiate `Clock` ourselves — `@react-three/fiber` 9.x
6
+ * (current stable) creates one internally per `<Canvas>` mount. The
7
+ * migration to `THREE.Timer` lands in R3F 10.x (still alpha).
8
+ *
9
+ * Uses three's `setConsoleFunction` hook so we don't touch `console.warn`
10
+ * globally. Only the exact Clock deprecation message is suppressed; all
11
+ * other three.js logs (including TSL stack-trace warnings) pass through
12
+ * untouched.
13
+ *
14
+ * Runs in production as well as dev — the suppressed message is a pure
15
+ * deprecation notice with no user-actionable content.
16
+ *
17
+ * REMOVAL: safe to delete once `@react-three/fiber` no longer constructs
18
+ * `new THREE.Clock()`. To verify after an R3F upgrade:
19
+ * grep -n "new THREE.Clock" node_modules/@react-three/fiber/dist/*.js
20
+ * No hits → delete this file and its import in components/viewer/index.tsx.
21
+ *
22
+ * @see https://github.com/pascalorg/editor/issues/213
23
+ */
24
+ import { setConsoleFunction } from 'three';
25
+ // three's warn() prepends 'THREE.' to its first argument, and the Clock
26
+ // constructor passes 'THREE.Clock: ...', producing a double-prefixed
27
+ // string. Exact equality keeps the suppression surgical — if three ever
28
+ // rewords this, the filter stops matching and the message resurfaces.
29
+ const CLOCK_DEPRECATION_MESSAGE = 'THREE.THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.';
30
+ // HMR-idempotent install guard. setConsoleFunction is a single-slot global
31
+ // in three, so re-evaluating this module on HMR would reinstall the hook.
32
+ const INSTALLED = Symbol.for('@pascal-app/viewer/suppress-three-clock-warning');
33
+ if (!globalThis[INSTALLED]) {
34
+ ;
35
+ globalThis[INSTALLED] = true;
36
+ setConsoleFunction((method, message, ...params) => {
37
+ if (method === 'warn' && message === CLOCK_DEPRECATION_MESSAGE) {
38
+ return;
39
+ }
40
+ // Mirror three's default stack-trace handling so TSL warnings/errors
41
+ // keep their clickable stack frames.
42
+ if (method !== 'log') {
43
+ const first = params[0];
44
+ if (first?.isStackTrace && typeof first.getError === 'function') {
45
+ console[method](first.getError(message));
46
+ return;
47
+ }
48
+ }
49
+ console[method](message, ...params);
50
+ });
51
+ }