@react-three/tsl 10.0.0-canary.bf4b0be → 10.0.0-canary.d458ee7

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/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { registerRootExtension, useStore, useThree, setRenderOverride } from '@react-three/fiber/extension';
1
+ import { registerRootExtension, getTextureView, useStore, useThree, setRenderOverride } from '@react-three/fiber/extension';
2
2
  import { uniform, pass } from 'three/tsl';
3
3
  import * as THREE from 'three/webgpu';
4
4
  import { Color } from 'three/webgpu';
5
5
  import * as React from 'react';
6
- import { useMemo, useRef, useCallback, useState, useEffect, useLayoutEffect } from 'react';
6
+ import { useMemo, useRef, useCallback, useSyncExternalStore, useState, useEffect, useLayoutEffect } from 'react';
7
7
  import { dequal } from 'dequal/lite';
8
8
  import 'zustand/shallow';
9
9
 
@@ -162,6 +162,10 @@ function extractTSLValue(value) {
162
162
  if (node.isConstNode) {
163
163
  return node.value;
164
164
  }
165
+ if (node.isVarNode && node.node) {
166
+ const inner = extractTSLValue(node.node);
167
+ return inner === node.node ? value : inner;
168
+ }
165
169
  if ("value" in node) {
166
170
  let extractedValue = node.value;
167
171
  if (typeof node.traverse === "function") {
@@ -297,33 +301,129 @@ function ensureTSLExtension() {
297
301
  });
298
302
  }
299
303
 
304
+ const SCOPE = Symbol("readTracking.scope");
305
+ const LEAF_GUARDS = {
306
+ uniforms: isUniformNode,
307
+ nodes: isTSLNode,
308
+ buffers: isBufferLike,
309
+ gpuStorage: isStorageLike
310
+ };
311
+ function isScope(kind, value) {
312
+ return !!value && typeof value === "object" && !LEAF_GUARDS[kind](value);
313
+ }
314
+ function classify(kind, value) {
315
+ return kind !== "textures" && isScope(kind, value) ? SCOPE : value;
316
+ }
317
+ function resolveContainer(kind, root, scopePath) {
318
+ let container = root;
319
+ for (const key of scopePath) {
320
+ const next = container?.[key];
321
+ container = isScope(kind, next) ? next : void 0;
322
+ }
323
+ return container;
324
+ }
325
+ function observeNow(read, view) {
326
+ if (read.kind === "textures") {
327
+ const map = view("textures");
328
+ if (read.op === "keys") return [...map.keys()];
329
+ return read.op === "has" ? map.has(read.path[0]) : map.get(read.path[0]);
330
+ }
331
+ const root = view(read.kind);
332
+ if (read.op === "keys") return Object.keys(resolveContainer(read.kind, root, read.path) ?? {});
333
+ const container = resolveContainer(read.kind, root, read.path.slice(0, -1));
334
+ const key = read.path[read.path.length - 1];
335
+ if (read.op === "has") return !!container && key in container;
336
+ return classify(read.kind, container?.[key]);
337
+ }
338
+ function sameKeys(a, b) {
339
+ return a.length === b.length && a.every((key, i) => key === b[i]);
340
+ }
341
+ function hasChanged(read, view) {
342
+ const now = observeNow(read, view);
343
+ return read.op === "keys" ? !sameKeys(read.seen, now) : !Object.is(read.seen, now);
344
+ }
345
+ const warned = /* @__PURE__ */ new Set();
346
+ function warnOnce(message) {
347
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
348
+ if (warned.has(message)) return;
349
+ warned.add(message);
350
+ console.warn(message);
351
+ }
352
+ function describeRead(kind, path) {
353
+ if (kind === "textures") return `textures.get('${path[0]}')`;
354
+ const scopes = path.slice(0, -1).map((key) => `.scope('${key}')`);
355
+ return `${kind}${scopes.join("")}.${path[path.length - 1] ?? ""}`;
356
+ }
357
+ function createReadTracker(hookName) {
358
+ const tracker = {
359
+ reads: [],
360
+ closed: false,
361
+ stale: false,
362
+ observe: (read) => {
363
+ if (tracker.closed) {
364
+ warnOnce(
365
+ `[${hookName}] ${describeRead(read.kind, read.path)} was read after the creator returned, probably inside Fn(). That read is not tracked, so replacing the resource will not rebuild this graph. Read the resource in the creator and close over it in Fn.`
366
+ );
367
+ return;
368
+ }
369
+ tracker.reads.push(read);
370
+ }
371
+ };
372
+ return tracker;
373
+ }
374
+ function isTrackerStale(tracker, view) {
375
+ if (!tracker.stale) tracker.stale = tracker.reads.some((read) => hasChanged(read, view));
376
+ return tracker.stale;
377
+ }
378
+ function warnMissingReads(hookName) {
379
+ return {
380
+ nested: false,
381
+ observe: (read) => {
382
+ if (read.op !== "get" || read.seen !== void 0) return;
383
+ warnOnce(
384
+ `[${hookName}] The creator read ${describeRead(read.kind, read.path)}, which does not exist yet. ${hookName} creators run once per generation, so this one will not re-run when it appears. Register it earlier (above this hook, or higher in the tree), or call rebuild* once it exists. To probe on purpose, use .has().`
385
+ );
386
+ }
387
+ };
388
+ }
389
+
300
390
  var __defProp = Object.defineProperty;
301
391
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
302
392
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
303
- var _a, _b;
393
+ var _a, _b, _c, _d;
304
394
  const INTERNAL_DATA = Symbol("ScopedStore.data");
305
395
  const INTERNAL_IS_LEAF = Symbol("ScopedStore.isLeaf");
306
- _b = INTERNAL_DATA, _a = INTERNAL_IS_LEAF;
396
+ const INTERNAL_READS = Symbol("ScopedStore.reads");
397
+ const INTERNAL_CHILDREN = Symbol("ScopedStore.children");
398
+ _d = INTERNAL_DATA, _c = INTERNAL_IS_LEAF, _b = INTERNAL_READS, _a = INTERNAL_CHILDREN;
307
399
  const _ScopedStore = class _ScopedStore {
308
- constructor(data, isLeaf) {
400
+ constructor(data, isLeaf, reads) {
401
+ /** @internal */
402
+ __publicField(this, _d);
403
+ /** @internal */
404
+ __publicField(this, _c);
405
+ /** @internal */
309
406
  __publicField(this, _b);
407
+ /** @internal */
310
408
  __publicField(this, _a);
311
409
  this[INTERNAL_DATA] = data;
312
410
  this[INTERNAL_IS_LEAF] = isLeaf;
411
+ this[INTERNAL_READS] = reads;
313
412
  return new Proxy(this, {
314
413
  get(target, prop, receiver) {
315
414
  if (typeof prop === "string") {
316
415
  if (prop === "scope" || prop === "has" || prop === "keys") {
317
416
  return Reflect.get(target, prop, receiver);
318
417
  }
319
- return target[INTERNAL_DATA][prop];
418
+ return readEntry(target, prop);
320
419
  }
321
420
  return Reflect.get(target, prop, receiver);
322
421
  },
323
422
  has(target, prop) {
324
- return typeof prop === "string" ? prop in target[INTERNAL_DATA] : Reflect.has(target, prop);
423
+ return typeof prop === "string" ? target.has(prop) : Reflect.has(target, prop);
325
424
  },
326
425
  ownKeys(target) {
426
+ observeKeys(target);
327
427
  return Reflect.ownKeys(target[INTERNAL_DATA]);
328
428
  },
329
429
  getOwnPropertyDescriptor(target, prop) {
@@ -345,54 +445,152 @@ const _ScopedStore = class _ScopedStore {
345
445
  scope(key) {
346
446
  const value = this[INTERNAL_DATA][key];
347
447
  const isLeaf = this[INTERNAL_IS_LEAF];
448
+ const reads = this[INTERNAL_READS];
348
449
  const scope = value && typeof value === "object" && !isLeaf(value) ? value : {};
349
- return new _ScopedStore(scope, isLeaf);
450
+ const child = reads ? { ...reads, path: [...reads.path, key] } : void 0;
451
+ return new _ScopedStore(scope, isLeaf, child);
350
452
  }
351
453
  /**
352
454
  * Check if a key exists in the store.
353
455
  */
354
456
  has(key) {
355
- return key in this[INTERNAL_DATA];
457
+ const found = key in this[INTERNAL_DATA];
458
+ const reads = this[INTERNAL_READS];
459
+ reads?.observe({ kind: reads.kind, op: "has", path: [...reads.path, key], seen: found });
460
+ return found;
356
461
  }
357
462
  /**
358
463
  * Get all keys in the store.
359
464
  */
360
465
  keys() {
466
+ observeKeys(this);
361
467
  return Object.keys(this[INTERNAL_DATA]);
362
468
  }
363
469
  };
364
470
  let ScopedStore = _ScopedStore;
471
+ function readEntry(target, key) {
472
+ const value = target[INTERNAL_DATA][key];
473
+ const reads = target[INTERNAL_READS];
474
+ if (!reads) return value;
475
+ const isLeaf = target[INTERNAL_IS_LEAF];
476
+ const isScope = !!value && typeof value === "object" && !isLeaf(value);
477
+ const path = [...reads.path, key];
478
+ reads.observe({ kind: reads.kind, op: "get", path, seen: isScope ? SCOPE : value });
479
+ if (!isScope || !reads.nested) return value;
480
+ const children = target[INTERNAL_CHILDREN] ?? (target[INTERNAL_CHILDREN] = /* @__PURE__ */ new Map());
481
+ let child = children.get(key);
482
+ if (!child) {
483
+ child = new ScopedStore(value, isLeaf, { ...reads, path });
484
+ children.set(key, child);
485
+ }
486
+ return child;
487
+ }
488
+ function observeKeys(target) {
489
+ const reads = target[INTERNAL_READS];
490
+ reads?.observe({ kind: reads.kind, op: "keys", path: reads.path, seen: Object.keys(target[INTERNAL_DATA]) });
491
+ }
365
492
  function createScopedStore(data, isLeaf) {
366
493
  return new ScopedStore(data, isLeaf);
367
494
  }
368
- function createLazyCreatorState(state, store) {
495
+ function observeTextures(map, observe) {
496
+ const observeKeys2 = () => observe({ kind: "textures", op: "keys", path: [], seen: [...map.keys()] });
497
+ const observeAll = () => {
498
+ observeKeys2();
499
+ for (const [url, texture] of map) observe({ kind: "textures", op: "get", path: [url], seen: texture });
500
+ };
501
+ return new Proxy(map, {
502
+ get(target, prop) {
503
+ switch (prop) {
504
+ case "get":
505
+ return (url) => {
506
+ const texture = target.get(url);
507
+ observe({ kind: "textures", op: "get", path: [url], seen: texture });
508
+ return texture;
509
+ };
510
+ case "has":
511
+ return (url) => {
512
+ const found = target.has(url);
513
+ observe({ kind: "textures", op: "has", path: [url], seen: found });
514
+ return found;
515
+ };
516
+ case "size":
517
+ observeKeys2();
518
+ return target.size;
519
+ case "keys":
520
+ return () => {
521
+ observeKeys2();
522
+ return target.keys();
523
+ };
524
+ case "values":
525
+ return () => {
526
+ observeAll();
527
+ return target.values();
528
+ };
529
+ case "entries":
530
+ case Symbol.iterator:
531
+ return () => {
532
+ observeAll();
533
+ return target.entries();
534
+ };
535
+ case "forEach":
536
+ return (callback, thisArg) => {
537
+ observeAll();
538
+ target.forEach(callback, thisArg);
539
+ };
540
+ }
541
+ const value = Reflect.get(target, prop, target);
542
+ return typeof value === "function" ? value.bind(target) : value;
543
+ }
544
+ });
545
+ }
546
+ function createResourceView(primary, local = primary) {
547
+ return ((kind) => kind === "textures" ? getTextureView(local) : withStagedOverlay(primary, kind, primary.getState()[kind]));
548
+ }
549
+ function createLazyCreatorState(state, store, options = {}) {
550
+ const { reads } = options;
551
+ const view = options.view ?? (store ? createResourceView(store) : void 0);
369
552
  let _uniforms = null;
370
553
  let _nodes = null;
371
554
  let _buffers = null;
372
555
  let _gpuStorage = null;
373
- const view = (kind) => store ? withStagedOverlay(store, kind, state[kind]) : state[kind];
374
- return Object.create(state, {
556
+ let _textures = null;
557
+ const read = (kind) => view ? view(kind) : state[kind];
558
+ const wrap = (kind, isLeaf) => new ScopedStore(
559
+ read(kind),
560
+ isLeaf,
561
+ reads && { ...reads, kind, path: [] }
562
+ );
563
+ const properties = {
375
564
  uniforms: {
376
565
  get() {
377
- return _uniforms ?? (_uniforms = createScopedStore(view("uniforms"), isUniformNode));
566
+ return _uniforms ?? (_uniforms = wrap("uniforms", isUniformNode));
378
567
  }
379
568
  },
380
569
  nodes: {
381
570
  get() {
382
- return _nodes ?? (_nodes = createScopedStore(view("nodes"), isTSLNode));
571
+ return _nodes ?? (_nodes = wrap("nodes", isTSLNode));
383
572
  }
384
573
  },
385
574
  buffers: {
386
575
  get() {
387
- return _buffers ?? (_buffers = createScopedStore(view("buffers"), isBufferLike));
576
+ return _buffers ?? (_buffers = wrap("buffers", isBufferLike));
388
577
  }
389
578
  },
390
579
  gpuStorage: {
391
580
  get() {
392
- return _gpuStorage ?? (_gpuStorage = createScopedStore(view("gpuStorage"), isStorageLike));
581
+ return _gpuStorage ?? (_gpuStorage = wrap("gpuStorage", isStorageLike));
393
582
  }
394
583
  }
395
- });
584
+ };
585
+ if (options.view) {
586
+ properties.textures = {
587
+ get() {
588
+ const textures = options.view("textures");
589
+ return _textures ?? (_textures = reads ? observeTextures(textures, reads.observe) : textures);
590
+ }
591
+ };
592
+ }
593
+ return Object.create(state, properties);
396
594
  }
397
595
 
398
596
  function resolvePrimary(local) {
@@ -468,7 +666,7 @@ function useUniforms(creatorOrScope, scope) {
468
666
  const processedInput = useMemo(() => {
469
667
  let raw = creatorOrScope;
470
668
  if (typeof creatorOrScope === "function") {
471
- const wrappedState = createLazyCreatorState(store.getState(), store);
669
+ const wrappedState = createLazyCreatorState(store.getState(), store, { reads: warnMissingReads("useUniforms") });
472
670
  raw = creatorOrScope(wrappedState);
473
671
  }
474
672
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
@@ -550,18 +748,20 @@ function isSameThreeType(a, b) {
550
748
  const uniformOf = uniform;
551
749
  function useUniform(name, value) {
552
750
  const store = usePrimaryStore();
751
+ const memoizedInput = useCompareMemoize(value === void 0 ? name : { [name]: normalizeValue(value) });
553
752
  const registered = useScopedResource({
554
753
  store,
555
754
  kind: "uniforms",
556
755
  scope: void 0,
557
756
  isLeaf: isUniformNode,
558
- input: name,
757
+ input: memoizedInput,
559
758
  create: () => value === void 0 ? {} : { [name]: value },
560
759
  prepare: createNamedUniform,
561
760
  reconcile: (existing2) => {
562
- if (value !== void 0 && !isTSLNode(value) && !isUniformNode(value)) {
563
- existing2.value = typeof value === "string" ? new Color(value) : value;
564
- }
761
+ if (value === void 0 || isUniformNode(value)) return;
762
+ const next = normalizeValue(value);
763
+ if (isTSLNode(next)) return;
764
+ existing2.value = next;
565
765
  }
566
766
  });
567
767
  if (registered[name]) return registered[name];
@@ -571,6 +771,9 @@ function useUniform(name, value) {
571
771
  `[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
572
772
  );
573
773
  }
774
+ function normalizeValue(value) {
775
+ return typeof value === "string" ? new Color(value) : vectorize(value);
776
+ }
574
777
  function createNamedUniform(name, value) {
575
778
  let node;
576
779
  if (isUniformNode(value)) {
@@ -611,7 +814,16 @@ function useNodes(creatorOrScope, scope) {
611
814
  isLeaf: isTSLNode,
612
815
  create: () => {
613
816
  if (isReader) return {};
614
- return creatorOrScope(createLazyCreatorState(store.getState(), store));
817
+ const nodes2 = creatorOrScope(
818
+ createLazyCreatorState(store.getState(), store, { reads: warnMissingReads("useNodes") })
819
+ );
820
+ if (nodes2 == null) {
821
+ warnOnce(
822
+ "[useNodes] The creator returned nothing, so nothing was registered. useNodes registers the nodes its creator returns. To put a node onto a Three object (scene.fogNode = ...), use useLocalNodes and return a function that assigns it: it runs after commit and may return a cleanup."
823
+ );
824
+ return {};
825
+ }
826
+ return nodes2;
615
827
  },
616
828
  prepare: (name, node) => {
617
829
  const setName = Reflect.get(node, "setName");
@@ -631,16 +843,100 @@ function useNodes(creatorOrScope, scope) {
631
843
  function rebuildAllNodes(store, scope) {
632
844
  rebuildResource(store, "nodes", scope);
633
845
  }
634
- function useLocalNodes(creator) {
846
+ function areDepsEqual(next, prev) {
847
+ if (next.length !== prev.length) return false;
848
+ for (let i = 0; i < next.length; i++) if (!Object.is(next[i], prev[i])) return false;
849
+ return true;
850
+ }
851
+ function useDependencyToken(deps) {
852
+ const previous = useRef(null);
853
+ const record = previous.current;
854
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production" && record) {
855
+ const hadDeps = record.deps !== void 0;
856
+ const hasDeps = deps !== void 0;
857
+ if (hadDeps !== hasDeps) {
858
+ console.warn(
859
+ `[useLocalNodes] The dependency array was ${hasDeps ? "added" : "omitted"} between renders. Pass an array on every render or on none; the mode must not change for a mounted component.`
860
+ );
861
+ } else if (hasDeps && record.deps.length !== deps.length) {
862
+ console.warn(
863
+ `[useLocalNodes] The dependency array length changed between renders (${record.deps.length} \u2192 ${deps.length}). Declare a fixed-length list; conditional dependencies belong inside the array as values.`
864
+ );
865
+ }
866
+ }
867
+ if (deps === void 0) {
868
+ previous.current = { deps: void 0, token: {} };
869
+ } else if (!record || record.deps === void 0 || !areDepsEqual(deps, record.deps)) {
870
+ previous.current = { deps, token: {} };
871
+ } else if (record.deps !== deps) {
872
+ previous.current = { deps, token: record.token };
873
+ }
874
+ return previous.current.token;
875
+ }
876
+ function useLocalNodes(creator, deps) {
877
+ const local = useStore();
635
878
  const store = usePrimaryStore();
636
- const uniforms = usePrimaryThree((s) => s.uniforms);
637
- const nodes = usePrimaryThree((s) => s.nodes);
638
- const textures = usePrimaryThree((s) => s.textures);
879
+ const view = useMemo(() => createResourceView(store, local), [store, local]);
639
880
  const hmrVersion = usePrimaryThree((s) => s._hmrVersion);
640
- return useMemo(() => {
641
- const wrappedState = createLazyCreatorState(store.getState(), store);
642
- return creator(wrappedState);
643
- }, [store, creator, uniforms, nodes, textures, hmrVersion]);
881
+ const depsToken = useDependencyToken(deps);
882
+ const committedReads = useRef(null);
883
+ const readsVersion = useRef(0);
884
+ const getReadsVersion = () => {
885
+ const tracker2 = committedReads.current;
886
+ if (tracker2 && !tracker2.stale && isTrackerStale(tracker2, view)) readsVersion.current++;
887
+ return readsVersion.current;
888
+ };
889
+ const subscribe = useCallback(
890
+ (onChange) => {
891
+ const unsubscribe = store.subscribe(onChange);
892
+ if (local === store) return unsubscribe;
893
+ const unsubscribeLocal = local.subscribe(onChange);
894
+ return () => {
895
+ unsubscribe();
896
+ unsubscribeLocal();
897
+ };
898
+ },
899
+ [store, local]
900
+ );
901
+ const resourceVersion = useSyncExternalStore(subscribe, getReadsVersion, getReadsVersion);
902
+ const evaluation = useMemo(() => {
903
+ const tracker2 = createReadTracker("useLocalNodes");
904
+ const reads = { observe: tracker2.observe, nested: true };
905
+ const value2 = creator(createLazyCreatorState(local.getState(), store, { reads, view }));
906
+ tracker2.closed = true;
907
+ return { value: value2, tracker: tracker2 };
908
+ }, [view, hmrVersion, depsToken, resourceVersion]);
909
+ const { value, tracker } = evaluation;
910
+ const installing = typeof value === "function";
911
+ useModeDiagnostics(value, installing);
912
+ useIsomorphicLayoutEffect(() => {
913
+ committedReads.current = tracker;
914
+ if (!installing) return;
915
+ tracker.closed = false;
916
+ let cleanup;
917
+ try {
918
+ cleanup = value();
919
+ } finally {
920
+ tracker.closed = true;
921
+ }
922
+ return typeof cleanup === "function" ? cleanup : void 0;
923
+ }, [evaluation]);
924
+ return installing ? void 0 : value;
925
+ }
926
+ function useModeDiagnostics(value, installing) {
927
+ const previous = useRef(null);
928
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") return;
929
+ if (value === void 0 || value === null) {
930
+ warnOnce(
931
+ "[useLocalNodes] The creator returned nothing. To put a node onto a Three object (scene.fogNode = ...), build it in the creator and return a function that assigns it: that function runs after commit and may return a cleanup. Assigning inside the creator runs during render, which React may discard or repeat."
932
+ );
933
+ }
934
+ if (previous.current !== null && previous.current !== installing) {
935
+ warnOnce(
936
+ "[useLocalNodes] The creator switched between returning a record and returning an install function. Keep one form for a mounted component."
937
+ );
938
+ }
939
+ previous.current = installing;
644
940
  }
645
941
 
646
942
  const disposeBuffer = (buffer) => {
@@ -686,7 +982,9 @@ function useBuffers(creatorOrScope, scope) {
686
982
  isLeaf: isBufferLike,
687
983
  create: () => {
688
984
  if (isReader) return {};
689
- return creatorOrScope(createLazyCreatorState(store.getState(), store));
985
+ return creatorOrScope(
986
+ createLazyCreatorState(store.getState(), store, { reads: warnMissingReads("useBuffers") })
987
+ );
690
988
  },
691
989
  prepare: (name, buffer) => {
692
990
  const setName = Reflect.get(buffer, "setName");
@@ -750,7 +1048,9 @@ function useGPUStorage(creatorOrScope, scope) {
750
1048
  isLeaf: isStorageLike,
751
1049
  create: () => {
752
1050
  if (isReader) return {};
753
- return creatorOrScope(createLazyCreatorState(store.getState(), store));
1051
+ return creatorOrScope(
1052
+ createLazyCreatorState(store.getState(), store, { reads: warnMissingReads("useGPUStorage") })
1053
+ );
754
1054
  },
755
1055
  prepare: (name, storage) => {
756
1056
  const label = scopedNodeName(scope, name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/tsl",
3
- "version": "10.0.0-canary.bf4b0be",
3
+ "version": "10.0.0-canary.d458ee7",
4
4
  "description": "TSL resource hooks for react-three-fiber: uniforms, nodes, buffers, GPU storage and render pipelines on WebGPU",
5
5
  "keywords": [
6
6
  "react",
@@ -49,14 +49,14 @@
49
49
  },
50
50
  "peerDependencies": {
51
51
  "@react-three/fiber": "^10.0.0-alpha.6",
52
- "react": ">=19.0 <19.3",
52
+ "react": ">=19.0 <19.4",
53
53
  "three": ">=0.185.0"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/three": "^0.185.0",
57
57
  "@webgpu/types": "^0.1.64",
58
58
  "three": ">=0.185.0",
59
- "@react-three/fiber": "10.0.0-canary.bf4b0be"
59
+ "@react-three/fiber": "10.0.0-canary.d458ee7"
60
60
  },
61
61
  "scripts": {
62
62
  "build": "unbuild",