@gnsx/three 0.184.5 → 0.184.7

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.
@@ -514,28 +514,71 @@ class Inspector extends RendererInspector {
514
514
 
515
515
  }
516
516
 
517
+ const STORAGE_KEY_THREE_INSPECTOR = 'threejs-inspector';
518
+
519
+ function getStorageOrNull() {
520
+
521
+ try {
522
+
523
+ const storage = globalThis.localStorage;
524
+ if ( storage === undefined || storage === null ) return null;
525
+ if ( typeof storage.getItem !== 'function' || typeof storage.setItem !== 'function' ) return null;
526
+ return storage;
527
+
528
+ } catch {
529
+
530
+ return null;
531
+
532
+ }
533
+
534
+ }
535
+
517
536
  function getItem( id ) {
518
537
 
519
- const data = JSON.parse( localStorage.getItem( 'threejs-inspector' ) || '{}' );
520
- return data[ id ] || {};
538
+ const storage = getStorageOrNull();
539
+ if ( storage === null ) return {};
540
+
541
+ try {
542
+
543
+ const raw = storage.getItem( STORAGE_KEY_THREE_INSPECTOR );
544
+ const data = JSON.parse( raw || '{}' );
545
+ return data[ id ] || {};
546
+
547
+ } catch {
548
+
549
+ return {};
550
+
551
+ }
521
552
 
522
553
  }
523
554
 
524
555
  function setItem( id, state ) {
525
556
 
526
- const data = JSON.parse( localStorage.getItem( 'threejs-inspector' ) || '{}' );
557
+ const storage = getStorageOrNull();
558
+ if ( storage === null ) return;
527
559
 
528
- if ( state === null ) {
560
+ try {
529
561
 
530
- delete data[ id ];
562
+ const raw = storage.getItem( STORAGE_KEY_THREE_INSPECTOR );
563
+ const data = JSON.parse( raw || '{}' );
531
564
 
532
- } else {
565
+ if ( state === null ) {
533
566
 
534
- data[ id ] = state;
567
+ delete data[ id ];
535
568
 
536
- }
569
+ } else {
570
+
571
+ data[ id ] = state;
537
572
 
538
- localStorage.setItem( 'threejs-inspector', JSON.stringify( data ) );
573
+ }
574
+
575
+ storage.setItem( STORAGE_KEY_THREE_INSPECTOR, JSON.stringify( data ) );
576
+
577
+ } catch {
578
+
579
+ // Headless / private mode / blocked storage: skip persistence
580
+
581
+ }
539
582
 
540
583
  }
541
584
 
@@ -232,7 +232,7 @@ class Settings extends Parameters {
232
232
 
233
233
  const extUrl = new URL( extension.url, new URL( _EXTENSIONS_PATH, import.meta.url ) ).href;
234
234
 
235
- const module = await import( extUrl );
235
+ const module = await import( /* webpackIgnore: true */ extUrl );
236
236
 
237
237
  const keys = Object.keys( module );
238
238
  const ExtensionClass = module[ keys[ 0 ] ];
package/package.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "name": "@gnsx/three",
3
- "version": "0.184.5",
4
- "types": "index.d.ts",
3
+ "version": "0.184.7",
5
4
  "description": "JavaScript 3D library",
6
5
  "type": "module",
7
6
  "main": "./build/three.cjs",
8
7
  "module": "./build/three.module.js",
9
8
  "exports": {
10
9
  ".": {
11
- "types": "./index.d.ts",
12
10
  "import": "./build/three.module.js",
13
11
  "require": "./build/three.cjs"
14
12
  },
@@ -31,7 +29,6 @@
31
29
  "build",
32
30
  "examples/jsm",
33
31
  "examples/fonts",
34
- "index.d.ts",
35
32
  "LICENSE",
36
33
  "package.json",
37
34
  "README.md",
@@ -127,8 +124,5 @@
127
124
  "build/three.module.js"
128
125
  ],
129
126
  "directories": {}
130
- },
131
- "dependencies": {
132
- "@gnsx/three-types": "^0.184.1"
133
127
  }
134
128
  }
@@ -1047,7 +1047,10 @@ class NodeMaterial extends Material {
1047
1047
 
1048
1048
  if ( materialLightsNode.length > 0 ) {
1049
1049
 
1050
- lightsN = builder.renderer.lighting.createNode( [ ...lightsN.getLights(), ...materialLightsNode ] );
1050
+ // WITH_GENESYS
1051
+ lightsN = builder.renderer.lighting.createMaterialNode( lightsN, materialLightsNode );
1052
+ // !WITH_GENESYS
1053
+ // lightsN = builder.renderer.lighting.createNode( [ ...lightsN.getLights(), ...materialLightsNode ] );
1051
1054
 
1052
1055
  }
1053
1056
 
@@ -118,6 +118,9 @@ export { default as LightingContextNode } from './lighting/LightingContextNode.j
118
118
  export { default as LightingNode } from './lighting/LightingNode.js';
119
119
  export { default as LightProbeNode } from './lighting/LightProbeNode.js';
120
120
  export { default as LightsNode } from './lighting/LightsNode.js';
121
+ // WITH_GENESYS
122
+ export { MaterialLightsNode } from './lighting/LightsNode.js';
123
+ // !WITH_GENESYS
121
124
  export { default as PointLightNode } from './lighting/PointLightNode.js';
122
125
  export { default as PointShadowNode } from './lighting/PointShadowNode.js';
123
126
  export { default as ProjectorLightNode } from './lighting/ProjectorLightNode.js';
@@ -418,6 +418,114 @@ class LightsNode extends Node {
418
418
 
419
419
  }
420
420
 
421
+ // WITH_GENESYS
422
+ /**
423
+ * A lights node that composes a live scene lights node with material-local
424
+ * lighting nodes like environment, AO and light map lighting.
425
+ *
426
+ * @augments LightsNode
427
+ */
428
+ class MaterialLightsNode extends LightsNode {
429
+
430
+ static get type() {
431
+
432
+ return 'MaterialLightsNode';
433
+
434
+ }
435
+
436
+ /**
437
+ * Constructs a new material lights node.
438
+ *
439
+ * @param {LightsNode} lightsNode - The live scene lights node.
440
+ * @param {Array<LightingNode>} materialLights - Material-local lighting nodes.
441
+ */
442
+ constructor( lightsNode, materialLights = [] ) {
443
+
444
+ super();
445
+
446
+ this.lightsNode = lightsNode;
447
+ this.materialLights = materialLights;
448
+ this.updateType = lightsNode.getUpdateType();
449
+ this.updateBeforeType = lightsNode.getUpdateBeforeType();
450
+ this.updateAfterType = lightsNode.getUpdateAfterType();
451
+
452
+ }
453
+
454
+ customCacheKey() {
455
+
456
+ const hash = [ this.lightsNode.getCacheKey( true ) ];
457
+
458
+ for ( const lightNode of this.materialLights ) {
459
+
460
+ hash.push( lightNode.getCacheKey( true ) );
461
+
462
+ }
463
+
464
+ return hashArray( hash );
465
+
466
+ }
467
+
468
+ setupLights( builder, materialLights ) {
469
+
470
+ this.lightsNode.setupLights( builder, this.lightsNode.getLightNodes( builder ) );
471
+
472
+ for ( const lightNode of materialLights ) {
473
+
474
+ lightNode.build( builder );
475
+
476
+ }
477
+
478
+ }
479
+
480
+ update( frame ) {
481
+
482
+ if ( this.lightsNode.update ) this.lightsNode.update( frame );
483
+
484
+ }
485
+
486
+ updateBefore( frame ) {
487
+
488
+ if ( this.lightsNode.updateBefore ) this.lightsNode.updateBefore( frame );
489
+
490
+ }
491
+
492
+ updateAfter( frame ) {
493
+
494
+ if ( this.lightsNode.updateAfter ) this.lightsNode.updateAfter( frame );
495
+
496
+ }
497
+
498
+ dispose() {
499
+
500
+ super.dispose();
501
+
502
+ this.lightsNode = null;
503
+ this.materialLights = null;
504
+
505
+ }
506
+
507
+ getLightNodes() {
508
+
509
+ return this.materialLights;
510
+
511
+ }
512
+
513
+ getLights() {
514
+
515
+ return this.lightsNode.getLights();
516
+
517
+ }
518
+
519
+ get hasLights() {
520
+
521
+ return this.lightsNode.getScope().hasLights || this.materialLights.length > 0;
522
+
523
+ }
524
+
525
+ }
526
+ export { MaterialLightsNode };
527
+ // !WITH_GENESYS
528
+
421
529
  export default LightsNode;
422
530
 
423
531
  /**
@@ -1,4 +1,9 @@
1
- import { LightsNode } from '../../nodes/Nodes.js';
1
+ import {
2
+ LightsNode,
3
+ // WITH_GENESYS
4
+ MaterialLightsNode,
5
+ // !WITH_GENESYS
6
+ } from '../../nodes/Nodes.js';
2
7
 
3
8
  const _defaultLights = /*@__PURE__*/ new LightsNode();
4
9
  const _weakMap = /*@__PURE__*/ new WeakMap();
@@ -26,6 +31,22 @@ class Lighting {
26
31
 
27
32
  }
28
33
 
34
+ // WITH_GENESYS
35
+ /**
36
+ * Creates a lights node that composes live scene lighting with material-local
37
+ * lighting nodes such as environment, AO and light map lighting.
38
+ *
39
+ * @param {LightsNode} lightsNode - The live scene lights node.
40
+ * @param {Array<LightingNode>} materialLights - Material-local lighting nodes.
41
+ * @return {MaterialLightsNode} The material lights node.
42
+ */
43
+ createMaterialNode( lightsNode, materialLights = [] ) {
44
+
45
+ return new MaterialLightsNode( lightsNode, materialLights );
46
+
47
+ }
48
+ // !WITH_GENESYS
49
+
29
50
  /**
30
51
  * Returns a lights node for the given scene and camera.
31
52
  *
@@ -72,6 +72,21 @@ class RenderObjects {
72
72
  */
73
73
  this.chainMaps = {};
74
74
 
75
+ /**
76
+ * Strongly tracks every render object created through {@link createRenderObject}
77
+ * so {@link dispose} can iterate them. ChainMap is `WeakMap`-backed and not
78
+ * iterable, so without this set the dispose listeners installed by
79
+ * `RenderObject` on shared materials and geometries (e.g. PMREM, `QuadGeometry`)
80
+ * would leak when the renderer is torn down while those singletons live on.
81
+ *
82
+ * Entries are removed in the same `onDispose` callback that cleans the chain
83
+ * map entry, so steady-state behavior is unchanged.
84
+ *
85
+ * @private
86
+ * @type {Set<RenderObject>}
87
+ */
88
+ this._renderObjects = new Set();
89
+
75
90
  }
76
91
 
77
92
  /**
@@ -172,6 +187,18 @@ class RenderObjects {
172
187
  */
173
188
  dispose() {
174
189
 
190
+ // Snapshot first: `RenderObject.dispose()` fires `onDispose` which
191
+ // mutates `_renderObjects` (and the chain map). Iterating the live set
192
+ // would skip entries.
193
+ const renderObjects = Array.from( this._renderObjects );
194
+ this._renderObjects.clear();
195
+
196
+ for ( const renderObject of renderObjects ) {
197
+
198
+ renderObject.dispose();
199
+
200
+ }
201
+
175
202
  this.chainMaps = {};
176
203
 
177
204
  }
@@ -198,6 +225,8 @@ class RenderObjects {
198
225
 
199
226
  const renderObject = new RenderObject( nodes, geometries, renderer, object, material, scene, camera, lightsNode, renderContext, clippingContext );
200
227
 
228
+ this._renderObjects.add( renderObject );
229
+
201
230
  renderObject.onDispose = () => {
202
231
 
203
232
  this.pipelines.delete( renderObject );
@@ -206,6 +235,8 @@ class RenderObjects {
206
235
 
207
236
  chainMap.delete( renderObject.getChainArray() );
208
237
 
238
+ this._renderObjects.delete( renderObject );
239
+
209
240
  };
210
241
 
211
242
  return renderObject;
@@ -2529,6 +2529,11 @@ class Renderer {
2529
2529
 
2530
2530
  } );
2531
2531
 
2532
+ // Drop the strong reference to the active `RenderContext` so module-level
2533
+ // `WeakMap<RenderContext, …>` caches can release entries once
2534
+ // `_renderContexts.dispose()` has cleared its dictionary.
2535
+ this._currentRenderContext = null;
2536
+
2532
2537
  }
2533
2538
 
2534
2539
  this.setRenderTarget( null );
@@ -55,6 +55,28 @@ class Textures extends DataMap {
55
55
  */
56
56
  this._htmlTextures = new Set();
57
57
 
58
+ /**
59
+ * Strongly tracks every texture that has had a `'dispose'` listener
60
+ * installed by {@link updateTexture}. `DataMap` is `WeakMap`-backed and
61
+ * not iterable; without this set the listener (whose closure references
62
+ * `Textures` → `renderer`) would leak when {@link dispose} is called
63
+ * while shared textures live on.
64
+ *
65
+ * @private
66
+ * @type {Set<Texture>}
67
+ */
68
+ this._textures = new Set();
69
+
70
+ /**
71
+ * Strongly tracks every render target that has had a `'dispose'` listener
72
+ * installed by {@link updateRenderTarget}. Same rationale as
73
+ * {@link _textures}.
74
+ *
75
+ * @private
76
+ * @type {Set<RenderTarget>}
77
+ */
78
+ this._renderTargets = new Set();
79
+
58
80
  }
59
81
 
60
82
  /**
@@ -181,6 +203,8 @@ class Textures extends DataMap {
181
203
 
182
204
  renderTarget.addEventListener( 'dispose', renderTargetData.onDispose );
183
205
 
206
+ this._renderTargets.add( renderTarget );
207
+
184
208
  }
185
209
 
186
210
  }
@@ -401,6 +425,8 @@ class Textures extends DataMap {
401
425
 
402
426
  texture.addEventListener( 'dispose', textureData.onDispose );
403
427
 
428
+ this._textures.add( texture );
429
+
404
430
  }
405
431
 
406
432
  //
@@ -569,6 +595,8 @@ class Textures extends DataMap {
569
595
  this.delete( renderTarget );
570
596
  this.backend.delete( renderTarget );
571
597
 
598
+ this._renderTargets.delete( renderTarget );
599
+
572
600
  this.info.memory.renderTargets --;
573
601
 
574
602
  }
@@ -618,12 +646,50 @@ class Textures extends DataMap {
618
646
 
619
647
  this.delete( texture );
620
648
 
649
+ this._textures.delete( texture );
650
+
621
651
  this.info.destroyTexture( texture );
622
652
 
623
653
  }
624
654
 
625
655
  }
626
656
 
657
+ /**
658
+ * Frees internal resources. Destroys every tracked render target and
659
+ * texture so the `'dispose'` listeners installed by {@link updateTexture}
660
+ * and {@link updateRenderTarget} are removed; without this, listeners on
661
+ * shared textures (PMREM, environment maps, etc.) would retain this
662
+ * `Textures` instance (and its renderer) across renderer teardown.
663
+ *
664
+ * @override
665
+ */
666
+ dispose() {
667
+
668
+ // Snapshot first: `_destroy*` mutates the sets.
669
+ const renderTargets = Array.from( this._renderTargets );
670
+ this._renderTargets.clear();
671
+
672
+ for ( const renderTarget of renderTargets ) {
673
+
674
+ this._destroyRenderTarget( renderTarget );
675
+
676
+ }
677
+
678
+ const textures = Array.from( this._textures );
679
+ this._textures.clear();
680
+
681
+ for ( const texture of textures ) {
682
+
683
+ this._destroyTexture( texture );
684
+
685
+ }
686
+
687
+ this._htmlTextures.clear();
688
+
689
+ super.dispose();
690
+
691
+ }
692
+
627
693
  }
628
694
 
629
695
  export default Textures;
package/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from '@gnsx/three-types';