@react-three/fiber 10.0.0-canary.54ec785 → 10.0.0-canary.58acabc

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/extension.cjs +8 -8
  2. package/dist/extension.d.cts +50 -6
  3. package/dist/extension.d.mts +50 -6
  4. package/dist/extension.d.ts +50 -6
  5. package/dist/extension.mjs +1 -1
  6. package/dist/index.cjs +17 -19
  7. package/dist/index.d.cts +15 -47
  8. package/dist/index.d.mts +15 -47
  9. package/dist/index.d.ts +15 -47
  10. package/dist/index.mjs +7 -8
  11. package/dist/legacy.cjs +37 -15
  12. package/dist/legacy.d.cts +10 -7
  13. package/dist/legacy.d.mts +10 -7
  14. package/dist/legacy.d.ts +10 -7
  15. package/dist/legacy.mjs +13 -5
  16. package/dist/shared/{fiber.BcNm6NAg.d.cts → fiber.34TOMPo3.d.cts} +83 -464
  17. package/dist/shared/fiber.BFuGd7gN.d.cts +90 -0
  18. package/dist/shared/{fiber.khFlPHPf.cjs → fiber.BO8-26r8.cjs} +206 -62
  19. package/dist/shared/fiber.BSXtODQl.cjs +14 -0
  20. package/dist/shared/fiber.Bll9fqKA.d.mts +90 -0
  21. package/dist/shared/{fiber.5Q8N6Hhq.mjs → fiber.BuWl08aJ.mjs} +2375 -1941
  22. package/dist/shared/{fiber.CUKAa7Rv.mjs → fiber.C-3TIsF8.mjs} +200 -64
  23. package/dist/shared/{fiber.CQDCACCJ.d.mts → fiber.CjMAAsJy.d.ts} +83 -464
  24. package/dist/shared/fiber.DEWBFQJe.mjs +9 -0
  25. package/dist/shared/{fiber.CZLeHcML.d.cts → fiber.DQTSZ24m.d.cts} +469 -29
  26. package/dist/shared/{fiber.CZLeHcML.d.mts → fiber.DQTSZ24m.d.mts} +469 -29
  27. package/dist/shared/{fiber.CZLeHcML.d.ts → fiber.DQTSZ24m.d.ts} +469 -29
  28. package/dist/shared/fiber.DuA4F8L5.d.ts +90 -0
  29. package/dist/shared/{fiber.DeBIf2pk.d.ts → fiber.Dy7Uz273.d.mts} +83 -464
  30. package/dist/shared/{fiber.BegWBc5_.cjs → fiber.TRm3lZ7I.cjs} +2407 -1973
  31. package/dist/webgpu/index.cjs +16 -18
  32. package/dist/webgpu/index.d.cts +17 -78
  33. package/dist/webgpu/index.d.mts +17 -78
  34. package/dist/webgpu/index.d.ts +17 -78
  35. package/dist/webgpu/index.mjs +7 -9
  36. package/package.json +3 -3
  37. package/readme.md +10 -1
  38. package/dist/chunks/webgl.cjs +0 -27
  39. package/dist/chunks/webgl.mjs +0 -11
  40. package/dist/shared/fiber.B_GGVI86.d.ts +0 -48
  41. package/dist/shared/fiber.ColkapKS.d.mts +0 -48
  42. package/dist/shared/fiber.DRfTw2kk.d.cts +0 -48
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const jsxRuntime = require('react/jsx-runtime');
4
- const extensions = require('./fiber.khFlPHPf.cjs');
4
+ const textureStaging = require('./fiber.BO8-26r8.cjs');
5
5
  const React = require('react');
6
6
  const useMeasure = require('react-use-measure');
7
7
  const itsFine = require('its-fine');
@@ -25,8 +25,8 @@ function _interopNamespaceCompat(e) {
25
25
  return n;
26
26
  }
27
27
 
28
- const React__default = /*#__PURE__*/_interopDefaultCompat(React);
29
28
  const React__namespace = /*#__PURE__*/_interopNamespaceCompat(React);
29
+ const React__default = /*#__PURE__*/_interopDefaultCompat(React);
30
30
  const useMeasure__default = /*#__PURE__*/_interopDefaultCompat(useMeasure);
31
31
  const w1__default = /*#__PURE__*/_interopDefaultCompat(w1);
32
32
 
@@ -128,6 +128,20 @@ function updateFrustum(camera, frustum) {
128
128
  target.setFromProjectionMatrix(frustumMatrix);
129
129
  return target;
130
130
  }
131
+ function computeInitialSize(canvas, size) {
132
+ if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
133
+ const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
134
+ return { width, height, top, left };
135
+ } else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
136
+ return {
137
+ width: canvas.width,
138
+ height: canvas.height,
139
+ top: 0,
140
+ left: 0
141
+ };
142
+ }
143
+ return { width: 0, height: 0, top: 0, left: 0, ...size };
144
+ }
131
145
 
132
146
  const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
133
147
  function findInitialRoot(instance) {
@@ -195,6 +209,7 @@ function prepare(target, root, type, props) {
195
209
  object,
196
210
  eventCount: 0,
197
211
  handlers: {},
212
+ previousVisible: void 0,
198
213
  isHidden: false
199
214
  };
200
215
  if (object) object.__r3f = instance;
@@ -422,7 +437,19 @@ function assertNodeMaterialSupported(state, value) {
422
437
  const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isNodeMaterial);
423
438
  if (!material) return;
424
439
  throw new Error(
425
- `R3F: ${material.type ?? "Node material"} requires WebGPURenderer (it falls back to WebGL2 automatically). Pass \`renderer\` to <Canvas> from @react-three/fiber, or import from @react-three/fiber/webgpu.`
440
+ `R3F: ${material.type ?? "Node material"} requires WebGPURenderer (it falls back to WebGL2 automatically). Import Canvas from @react-three/fiber or @react-three/fiber/webgpu instead of @react-three/fiber/legacy.`
441
+ );
442
+ }
443
+ const warnedGLSL = /* @__PURE__ */ new Set();
444
+ function warnGLSLMaterialUnsupported(state, value) {
445
+ if (!state || state.isLegacy || state.internal?.support?.kind !== "webgpu" || !textureStaging.isDevelopment()) return;
446
+ const material = (Array.isArray(value) ? value : [value]).find((m) => m?.isShaderMaterial && !m.isNodeMaterial);
447
+ if (!material) return;
448
+ const type = material.type ?? "ShaderMaterial";
449
+ if (warnedGLSL.has(type)) return;
450
+ warnedGLSL.add(type);
451
+ console.warn(
452
+ `R3F: ${type} is a GLSL material, which WebGPURenderer cannot compile; three draws it with a blank default material. @react-three/fiber renders with WebGPU: import Canvas from @react-three/fiber/legacy to keep WebGLRenderer, or port the shader to a node material (TSL).`
426
453
  );
427
454
  }
428
455
 
@@ -443,6 +470,28 @@ const VISIBILITY_EVENT_REGEX = /^on(Framed|Occluded|Visible)$/;
443
470
  const INDEX_REGEX = /-\d+$/;
444
471
  const MEMOIZED_PROTOTYPES = /* @__PURE__ */ new Map();
445
472
  const colorMaps = ["map", "emissiveMap", "sheenColorMap", "specularColorMap", "envMap"];
473
+ const programProps = /* @__PURE__ */ new Set([
474
+ "transparent",
475
+ "vertexColors",
476
+ "flatShading",
477
+ "fog",
478
+ // Culling is live, but DOUBLE_SIDED / FLIP_SIDED normal flipping is compiled in
479
+ "side",
480
+ "alphaHash",
481
+ "premultipliedAlpha",
482
+ // Both feed the OPAQUE define when the material is not transparent
483
+ "blending",
484
+ "alphaToCoverage",
485
+ "dithering",
486
+ "sizeAttenuation",
487
+ "combine",
488
+ "normalMapType",
489
+ "depthPacking"
490
+ ]);
491
+ function changesProgram(root, key, previous, next) {
492
+ if (!root?.isMaterial || previous === next) return false;
493
+ return programProps.has(key) || isTexture(previous) !== isTexture(next);
494
+ }
446
495
  function resolve(root, key) {
447
496
  if (!key.includes("-")) return { root, key, target: root[key] };
448
497
  if (key in root) return { root, key, target: root[key] };
@@ -473,6 +522,7 @@ function attach(parent, child) {
473
522
  const { root, key } = resolve(parent.object, child.props.attach);
474
523
  child.previousAttach = root[key];
475
524
  root[key] = child.object;
525
+ if (changesProgram(root, key, child.previousAttach, child.object)) root.needsUpdate = true;
476
526
  } else if (is.fun(child.props.attach)) {
477
527
  child.previousAttach = child.props.attach(parent.object, child.object);
478
528
  }
@@ -483,6 +533,7 @@ function detach(parent, child) {
483
533
  const previous = child.previousAttach;
484
534
  if (previous === void 0) delete root[key];
485
535
  else root[key] = previous;
536
+ if (changesProgram(root, key, child.object, previous)) root.needsUpdate = true;
486
537
  } else {
487
538
  child.previousAttach?.(parent.object, child.object);
488
539
  }
@@ -527,7 +578,7 @@ function applyProps(object, props) {
527
578
  const value = props[prop];
528
579
  if (RESERVED_PROPS.includes(prop)) continue;
529
580
  if (prop === "onUpdate") {
530
- extensions.notifyDepreciated({
581
+ textureStaging.notifyDepreciated({
531
582
  heading: "onUpdate is no longer an R3F prop",
532
583
  body: "v10 removed the onUpdate hook: R3F no longer calls it after prop updates. The value is assigned to the object by name. On a Texture that sets three's Texture.onUpdate, which the renderer calls after a GPU upload, not after prop changes. On a node it replaces the Node.onUpdate() method. On other objects it is never called.\n\nUse an effect keyed on the props that change, read the object in useFrame, or use a ref callback.",
533
584
  link: "https://docs.pmnd.rs/react-three-fiber/migration/v10#onupdate-removed"
@@ -562,6 +613,10 @@ function applyProps(object, props) {
562
613
  }
563
614
  continue;
564
615
  }
616
+ if (prop === "visible" && instance?.isHidden && instance.previousVisible !== void 0) {
617
+ instance.previousVisible = value;
618
+ continue;
619
+ }
565
620
  let { root, key, target } = resolve(object, prop);
566
621
  if (target === void 0 && (typeof root !== "object" || root === null)) {
567
622
  throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
@@ -589,17 +644,24 @@ function applyProps(object, props) {
589
644
  for (const name in nextUniforms) {
590
645
  const uniform = nextUniforms[name];
591
646
  const targetUniform = uniforms[name];
592
- if (targetUniform) Object.assign(targetUniform, uniform);
593
- else {
647
+ if (targetUniform) {
648
+ Object.assign(targetUniform, uniform);
649
+ } else {
594
650
  const nextUniform = isUniform(uniform) ? uniform.clone() : new (getThree()).Uniform(uniform.value);
595
651
  uniforms[name] = nextUniform;
596
652
  }
597
653
  }
598
654
  } else {
599
- if (key === "material") assertNodeMaterialSupported(rootState, value);
655
+ if (key === "material") {
656
+ assertNodeMaterialSupported(rootState, value);
657
+ warnGLSLMaterialUnsupported(rootState, value);
658
+ }
659
+ const previous = root[key];
600
660
  root[key] = value;
601
661
  if (key.endsWith("Node") && root.isMaterial) {
602
662
  root.needsUpdate = true;
663
+ } else if (changesProgram(root, key, previous, value)) {
664
+ root.needsUpdate = true;
603
665
  }
604
666
  const three = rootState && getThree();
605
667
  if (three && rootState.renderer?.outputColorSpace === three.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
@@ -640,471 +702,393 @@ function applyProps(object, props) {
640
702
  return object;
641
703
  }
642
704
 
643
- const memoizedLoaders = /* @__PURE__ */ new WeakMap();
644
- const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
645
- function getLoader(Proto) {
646
- if (isConstructor$1(Proto)) {
647
- let loader = memoizedLoaders.get(Proto);
648
- if (!loader) {
649
- loader = new Proto();
650
- memoizedLoaders.set(Proto, loader);
651
- }
652
- return loader;
653
- }
654
- return Proto;
655
- }
656
- function loadingFn(extensions, onProgress) {
657
- return function(Proto, input) {
658
- const loader = getLoader(Proto);
659
- if (extensions) extensions(loader);
660
- if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
661
- return loader.loadAsync(input, onProgress).then((data) => {
662
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
663
- return data;
664
- });
665
- }
666
- return new Promise(
667
- (res, reject) => loader.load(
668
- input,
669
- (data) => {
670
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
671
- res(data);
672
- },
673
- onProgress,
674
- (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
675
- )
676
- );
677
- };
678
- }
679
- function useLoader(loader, input, extensions, onProgress, cacheKey) {
680
- const inputs = Array.isArray(input) ? input : [input];
681
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
682
- const fn = loadingFn(extensions, onProgress);
683
- const results = cacheKeys.map(
684
- (key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
685
- );
686
- const stableRef = React.useRef(null);
687
- const previous = stableRef.current;
688
- const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
689
- stableRef.current = stable;
690
- return Array.isArray(input) ? stable : stable[0];
691
- }
692
- useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
693
- const inputs = Array.isArray(input) ? input : [input];
694
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
695
- cacheKeys.forEach(
696
- (key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
697
- );
698
- };
699
- useLoader.clear = function(loader, input, cacheKey) {
700
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
701
- cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
702
- };
703
- useLoader.loader = getLoader;
704
-
705
- const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
706
- function getUrls(input) {
707
- if (typeof input === "string") return [input];
708
- if (Array.isArray(input)) return input;
709
- return Object.values(input);
710
- }
711
- function inputSignature(input) {
712
- if (typeof input === "string") return input;
713
- if (Array.isArray(input)) return input.join("\0");
714
- return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
715
- }
716
- function allUrlsCached(urls, textureCache) {
717
- return urls.every((url) => textureCache.has(url));
705
+ function updateSize(state, size, imperative) {
706
+ state.set((current) => ({
707
+ size,
708
+ viewport: { ...current.viewport, ...current.viewport.getCurrentViewport(current.camera, void 0, size) },
709
+ _sizeImperative: imperative
710
+ }));
711
+ state.invalidate();
718
712
  }
719
- function buildFromCache(input, textureCache) {
720
- if (typeof input === "string") {
721
- return textureCache.get(input);
722
- } else if (Array.isArray(input)) {
723
- return input.map((url) => textureCache.get(url));
724
- } else {
725
- const result = {};
726
- const objInput = input;
727
- for (const key in objInput) {
728
- result[key] = textureCache.get(objInput[key]);
729
- }
730
- return result;
731
- }
713
+ function configureSize(store, size) {
714
+ const state = store.getState();
715
+ if (state._sizeImperative || is.equ(size, state.size, { objects: "shallow", strict: false })) return;
716
+ updateSize(state, size, false);
732
717
  }
733
- function useTexture(input, optionsOrOnLoad) {
734
- const renderer = extensions.useThree((state) => state.internal.actualRenderer);
735
- const store = extensions.useStore();
736
- const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
737
- const { onLoad, cache = true } = options;
738
- const onLoadRef = React.useRef(onLoad);
739
- onLoadRef.current = onLoad;
740
- const onLoadCalledForRef = React.useRef(null);
741
- const inputKey = React.useMemo(() => inputSignature(input), [input]);
742
- const stableInput = React.useMemo(() => input, [inputKey]);
743
- const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
744
- const cachedResult = React.useMemo(() => {
745
- if (!cache) return null;
746
- const textures = store.getState().textures;
747
- if (!allUrlsCached(urls, textures)) return null;
748
- return buildFromCache(stableInput, textures);
749
- }, [cache, urls, stableInput, store]);
750
- const loadedTextures = useLoader(
751
- getThree().TextureLoader,
752
- IsObject(stableInput) ? Object.values(stableInput) : stableInput
753
- );
754
- const mappedTextures = React.useMemo(() => {
755
- if (cachedResult) return cachedResult;
756
- if (IsObject(stableInput)) {
757
- const keyed = {};
758
- const textureArray = loadedTextures;
759
- let i = 0;
760
- for (const key in stableInput) keyed[key] = textureArray[i++];
761
- return keyed;
762
- } else {
763
- return loadedTextures;
764
- }
765
- }, [stableInput, loadedTextures, cachedResult]);
766
- React.useLayoutEffect(() => {
767
- if (cachedResult) return;
768
- if (onLoadCalledForRef.current === inputKey) return;
769
- onLoadCalledForRef.current = inputKey;
770
- onLoadRef.current?.(mappedTextures);
771
- }, [cachedResult, mappedTextures, inputKey]);
772
- React.useEffect(() => {
773
- if (cachedResult) return;
774
- if ("initTexture" in renderer) {
775
- let textureArray = [];
776
- if (Array.isArray(loadedTextures)) {
777
- textureArray = loadedTextures;
778
- } else if (loadedTextures.isTexture) {
779
- textureArray = [loadedTextures];
780
- } else if (IsObject(loadedTextures)) {
781
- textureArray = Object.values(loadedTextures);
718
+ const createStore = (invalidate, advance) => {
719
+ const rootStore = traditional.createWithEqualityFn((rawSet, get, api) => {
720
+ const set = api.setState = textureStaging.preserveAccessors(rawSet, get);
721
+ let position;
722
+ let defaultTarget;
723
+ let tempTarget;
724
+ function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
725
+ const { Vector3 } = getThree();
726
+ position ?? (position = new Vector3());
727
+ defaultTarget ?? (defaultTarget = new Vector3());
728
+ tempTarget ?? (tempTarget = new Vector3());
729
+ target ?? (target = defaultTarget);
730
+ const { width, height, top, left } = size;
731
+ const aspect = width / height;
732
+ if (target.isVector3) tempTarget.copy(target);
733
+ else tempTarget.set(...target);
734
+ const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
735
+ if (isOrthographicCamera(camera)) {
736
+ return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
737
+ } else {
738
+ const fov = camera.fov * Math.PI / 180;
739
+ const h = 2 * Math.tan(fov / 2) * distance;
740
+ const w = h * (width / height);
741
+ return { width: w, height: h, top, left, factor: width / w, distance, aspect };
782
742
  }
783
- textureArray.forEach((texture) => {
784
- if (texture?.isTexture) {
785
- renderer.initTexture(texture);
786
- }
787
- });
788
743
  }
789
- }, [renderer, loadedTextures, cachedResult]);
790
- React.useEffect(() => {
791
- if (!cache) return;
792
- const urlTextureMap = urlTextureEntries(stableInput, mappedTextures);
793
- store.setState((state) => {
794
- const refs = new Map(state._textureRefs);
795
- let textures = state.textures;
796
- let added = false;
797
- for (const [url, texture] of urlTextureMap) {
798
- if (!textures.has(url)) {
799
- if (!added) {
800
- textures = new Map(textures);
801
- added = true;
802
- }
803
- textures.set(url, texture);
804
- }
805
- refs.set(url, (refs.get(url) ?? 0) + 1);
806
- }
807
- return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
808
- });
809
- extensions.unstageTextures(
810
- store,
811
- urlTextureMap.map(([url]) => url)
812
- );
813
- return () => store.setState((state) => {
814
- const refs = new Map(state._textureRefs);
815
- for (const [url] of urlTextureMap) {
816
- const next = (refs.get(url) ?? 0) - 1;
817
- if (next <= 0) refs.delete(url);
818
- else refs.set(url, next);
819
- }
820
- return { _textureRefs: refs };
821
- });
822
- }, [cache, stableInput, mappedTextures, store]);
823
- if (cache && !cachedResult) extensions.stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
824
- return mappedTextures;
825
- }
826
- function urlTextureEntries(input, textures) {
827
- if (typeof input === "string") return [[input, textures]];
828
- if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
829
- const record = textures;
830
- return Object.keys(input).map((key) => [input[key], record[key]]);
831
- }
832
- useTexture.preload = (url) => {
833
- whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
834
- };
835
- useTexture.clear = (input) => {
836
- if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
837
- };
838
- const Texture = ({
839
- children,
840
- input,
841
- onLoad,
842
- cache
843
- }) => {
844
- const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
845
- const ret = useTexture(input, options);
846
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
847
- };
848
-
849
- function useTextures(selector) {
850
- const store = extensions.useStore();
851
- const registry = React.useMemo(() => {
852
- const getState = store.getState;
853
- const setState = store.setState;
854
- const getOne = (key) => getState().textures.get(key);
855
- return {
856
- get all() {
857
- return getState().textures;
858
- },
859
- get(input) {
860
- if (typeof input === "string") return getOne(input);
861
- if (Array.isArray(input)) return input.map(getOne);
862
- const out = {};
863
- for (const name in input) out[name] = getOne(input[name]);
864
- return out;
865
- },
866
- has: (key) => getState().textures.has(key),
867
- add(keyOrRecord, texture) {
868
- setState((state) => {
869
- const textures = new Map(state.textures);
870
- if (typeof keyOrRecord === "string") {
871
- textures.set(keyOrRecord, texture);
872
- } else {
873
- for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
874
- }
875
- return { textures };
876
- });
744
+ let performanceTimeout = void 0;
745
+ const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
746
+ const rootState = {
747
+ set,
748
+ get,
749
+ // Mock objects that have to be configured
750
+ // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
751
+ primaryStore: null,
752
+ gl: null,
753
+ renderer: null,
754
+ camera: null,
755
+ // frustum, pointer and mouse are three objects; configure() creates them with the renderer
756
+ frustum: null,
757
+ autoUpdateFrustum: true,
758
+ raycaster: null,
759
+ events: {
760
+ priority: 1,
761
+ enabled: true,
762
+ connected: false,
763
+ frameTimedRaycasts: true,
764
+ alwaysFireOnScroll: true,
765
+ updateOnFrame: false
877
766
  },
878
- dispose(key, options) {
879
- const state = getState();
880
- const refs = state._textureRefs.get(key) ?? 0;
881
- if (refs > 0 && !options?.force) {
882
- console.warn(
883
- `[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
767
+ scene: null,
768
+ rootScene: null,
769
+ xr: null,
770
+ inspector: null,
771
+ invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
772
+ advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
773
+ textureColorSpace: "srgb",
774
+ // THREE.SRGBColorSpace
775
+ isLegacy: false,
776
+ webGPUSupported: false,
777
+ isNative: false,
778
+ controls: null,
779
+ pointer: null,
780
+ mouse: null,
781
+ frameloop: "always",
782
+ onPointerMissed: void 0,
783
+ onDragOverMissed: void 0,
784
+ onDropMissed: void 0,
785
+ performance: {
786
+ current: 1,
787
+ min: 0.5,
788
+ max: 1,
789
+ debounce: 200,
790
+ regress: () => {
791
+ const state2 = get();
792
+ if (performanceTimeout) clearTimeout(performanceTimeout);
793
+ if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
794
+ performanceTimeout = setTimeout(
795
+ () => setPerformanceCurrent(get().performance.max),
796
+ state2.performance.debounce
884
797
  );
885
- return false;
886
798
  }
887
- state.textures.get(key)?.dispose();
888
- setState((s) => {
889
- const textures = new Map(s.textures);
890
- textures.delete(key);
891
- const nextRefs = new Map(s._textureRefs);
892
- nextRefs.delete(key);
893
- return { textures, _textureRefs: nextRefs };
894
- });
895
- return true;
896
799
  },
897
- disposeAll() {
898
- for (const texture of getState().textures.values()) texture.dispose();
899
- setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
800
+ size: { width: 0, height: 0, top: 0, left: 0 },
801
+ viewport: {
802
+ initialDpr: 0,
803
+ dpr: 0,
804
+ width: 0,
805
+ height: 0,
806
+ top: 0,
807
+ left: 0,
808
+ aspect: 0,
809
+ distance: 0,
810
+ factor: 0,
811
+ getCurrentViewport
812
+ },
813
+ setEvents: (events) => set((state2) => ({ events: { ...state2.events, ...events } })),
814
+ setSize: (width, height, top, left) => {
815
+ const state2 = get();
816
+ if (width === void 0) {
817
+ if (state2._sizeProps) {
818
+ const { width: propW, height: propH } = state2._sizeProps;
819
+ if (propW !== void 0 || propH !== void 0) {
820
+ const currentSize = state2.size;
821
+ const newSize = {
822
+ width: propW ?? currentSize.width,
823
+ height: propH ?? currentSize.height,
824
+ top: currentSize.top,
825
+ left: currentSize.left
826
+ };
827
+ updateSize(state2, newSize, false);
828
+ return;
829
+ }
830
+ }
831
+ set({ _sizeImperative: false });
832
+ return;
833
+ }
834
+ const w = width;
835
+ const h = height ?? width;
836
+ const t = top ?? state2.size.top;
837
+ const l = left ?? state2.size.left;
838
+ const size = { width: w, height: h, top: t, left: l };
839
+ updateSize(state2, size, true);
840
+ },
841
+ setDpr: (dpr) => set((state2) => {
842
+ const resolved = calculateDpr(dpr);
843
+ return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
844
+ }),
845
+ setFrameloop: (frameloop = "always") => {
846
+ const rootId = get().internal.rootId;
847
+ if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
848
+ set(() => ({ frameloop }));
849
+ },
850
+ setError: (error) => set(() => ({ error })),
851
+ error: null,
852
+ //* Texture registry (useTextures) ==============================
853
+ // TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
854
+ textures: /* @__PURE__ */ new Map(),
855
+ _textureRefs: /* @__PURE__ */ new Map(),
856
+ _sizeImperative: false,
857
+ _sizeProps: null,
858
+ previousRoot: void 0,
859
+ internal: {
860
+ // Events
861
+ interaction: [],
862
+ subscribers: [],
863
+ // Per-pointer state (new unified structure)
864
+ pointerMap: /* @__PURE__ */ new Map(),
865
+ pointerDirty: /* @__PURE__ */ new Map(),
866
+ lastEvent: React__namespace.createRef(),
867
+ // Deprecated but kept for backwards compatibility
868
+ hovered: /* @__PURE__ */ new Map(),
869
+ initialClick: [0, 0],
870
+ initialHits: [],
871
+ capturedMap: /* @__PURE__ */ new Map(),
872
+ // Visibility tracking (onFramed, onOccluded, onVisible)
873
+ visibilityRegistry: /* @__PURE__ */ new Map(),
874
+ // Occlusion system (WebGPU only)
875
+ occlusionEnabled: false,
876
+ occlusionObserver: null,
877
+ occlusionCache: /* @__PURE__ */ new Map(),
878
+ helperGroup: null,
879
+ // Updates
880
+ active: false,
881
+ frames: 0,
882
+ priority: 0,
883
+ subscribe: (ref, priority, store) => {
884
+ const internal = get().internal;
885
+ internal.priority = internal.priority + (priority > 0 ? 1 : 0);
886
+ internal.subscribers.push({ ref, priority, store });
887
+ internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
888
+ return () => {
889
+ const internal2 = get().internal;
890
+ if (internal2?.subscribers) {
891
+ internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
892
+ internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
893
+ }
894
+ };
895
+ },
896
+ // Renderer Storage (single source of truth)
897
+ actualRenderer: null,
898
+ // The renderer support configure() loads for this root
899
+ support: null,
900
+ // Scheduler for useFrameNext (initialized in loop.ts)
901
+ scheduler: null,
902
+ // Replaces the default render call when set (see setRenderOverride)
903
+ renderOverride: null
900
904
  }
901
905
  };
902
- }, [store]);
903
- const subscribe = selector ? () => selector(registry) : (state) => state.textures;
904
- const selected = extensions.useThree(subscribe);
905
- return selector ? selected : registry;
906
- }
907
-
908
- function useRenderTarget(widthOrOptions, heightOrOptions, options) {
909
- const support = extensions.useThree((s) => s.internal.support);
910
- const size = extensions.useThree((s) => s.size);
911
- let width;
912
- let height;
913
- let opts;
914
- if (typeof widthOrOptions === "object") {
915
- opts = widthOrOptions;
916
- } else if (typeof widthOrOptions === "number") {
917
- width = widthOrOptions;
918
- if (typeof heightOrOptions === "object") {
919
- height = widthOrOptions;
920
- opts = heightOrOptions;
921
- } else if (typeof heightOrOptions === "number") {
922
- height = heightOrOptions;
923
- opts = options;
924
- } else {
925
- height = widthOrOptions;
906
+ return rootState;
907
+ });
908
+ const state = rootStore.getState();
909
+ textureStaging.defineRendererAccessors(state);
910
+ let oldScene = state.scene;
911
+ rootStore.subscribe(() => {
912
+ const currentState = rootStore.getState();
913
+ const { scene, rootScene, set } = currentState;
914
+ if (scene !== oldScene) {
915
+ oldScene = scene;
916
+ if (scene?.isScene && scene !== rootScene) {
917
+ set({ rootScene: scene });
918
+ }
926
919
  }
927
- }
928
- return React.useMemo(() => {
929
- const w = width ?? size.width;
930
- const h = height ?? size.height;
931
- const Target = support.RenderTarget;
932
- return new Target(w, h, opts);
933
- }, [width, height, size.width, size.height, opts, support]);
934
- }
935
-
936
- const presetsObj = {
937
- apartment: "lebombo_1k.hdr",
938
- city: "potsdamer_platz_1k.hdr",
939
- dawn: "kiara_1_dawn_1k.hdr",
940
- forest: "forest_slope_1k.hdr",
941
- lobby: "st_fagans_interior_1k.hdr",
942
- night: "dikhololo_night_1k.hdr",
943
- park: "rooitou_park_1k.hdr",
944
- studio: "studio_small_03_1k.hdr",
945
- sunset: "venice_sunset_1k.hdr",
946
- warehouse: "empty_warehouse_01_1k.hdr"
947
- };
948
-
949
- const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
950
- const isArray = (arr) => Array.isArray(arr);
951
- const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
952
- const loadedLoaders = /* @__PURE__ */ new Map();
953
- const pendingLoaders = /* @__PURE__ */ new Map();
954
- function loadLoader(format) {
955
- let pending = pendingLoaders.get(format);
956
- if (!pending) {
957
- pending = importLoader(format).then(
958
- (loader) => {
959
- loadedLoaders.set(format, loader);
960
- return loader;
961
- },
962
- (error) => {
963
- pendingLoaders.delete(format);
964
- throw error;
920
+ });
921
+ let oldSize = state.size;
922
+ let oldDpr = state.viewport.dpr;
923
+ let oldCamera = state.camera;
924
+ rootStore.subscribe(() => {
925
+ const { camera, size, viewport, set, internal } = rootStore.getState();
926
+ const actualRenderer = internal.actualRenderer;
927
+ const canvasTarget = internal.canvasTarget;
928
+ if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
929
+ oldSize = size;
930
+ oldDpr = viewport.dpr;
931
+ updateCamera(camera, size);
932
+ const resizeTarget = canvasTarget ?? actualRenderer;
933
+ if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
934
+ resizeTarget.setSize(size.width, size.height, false);
935
+ const activeTarget = actualRenderer.getCanvasTarget?.();
936
+ if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
937
+ }
938
+ if (camera !== oldCamera) {
939
+ oldCamera = camera;
940
+ const { rootScene } = rootStore.getState();
941
+ if (camera && rootScene && !camera.parent) {
942
+ rootScene.add(camera);
943
+ }
944
+ set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
945
+ const currentState = rootStore.getState();
946
+ if (currentState.autoUpdateFrustum && camera) {
947
+ updateFrustum(camera, currentState.frustum);
965
948
  }
966
- );
967
- pendingLoaders.set(format, pending);
968
- }
969
- return pending;
970
- }
971
- async function importLoader(format) {
972
- let loader;
973
- switch (format) {
974
- case "cube":
975
- loader = getThree().CubeTextureLoader;
976
- break;
977
- case "hdr-cube":
978
- loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
979
- break;
980
- case "hdr":
981
- loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
982
- break;
983
- case "exr":
984
- loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
985
- break;
986
- case "jpg":
987
- loader = (await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader;
988
- break;
989
- }
990
- return loader;
991
- }
992
- const LOADER_KEY = Symbol("r3f-environment-loader");
993
- function useEnvironmentLoader(format) {
994
- return suspendReact.suspend(() => loadLoader(format), [LOADER_KEY, format]);
995
- }
996
- function useEnvironment({
997
- files = defaultFiles,
998
- path = "",
999
- preset = void 0,
1000
- colorSpace = void 0,
1001
- extensions
1002
- } = {}) {
1003
- if (preset) {
1004
- validatePreset(preset);
1005
- files = presetsObj[preset];
1006
- path = CUBEMAP_ROOT;
1007
- }
1008
- const multiFile = isArray(files);
1009
- const { format, isCubemap } = getFormat(files);
1010
- if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1011
- const loader = useEnvironmentLoader(format);
1012
- const loaderResult = useLoader(
1013
- loader,
1014
- multiFile ? [files] : files,
1015
- (loader2) => {
1016
- loader2.setPath?.(path);
1017
- if (extensions) extensions(loader2);
1018
949
  }
1019
- );
1020
- const texture = multiFile ? (
1021
- // @ts-ignore
1022
- loaderResult[0]
1023
- ) : loaderResult;
1024
- const three = getThree();
1025
- texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
1026
- texture.colorSpace = colorSpace ?? (isCubemap && format !== "hdr-cube" ? "srgb" : "srgb-linear");
1027
- return texture;
1028
- }
1029
- const preloadDefaultOptions = {
1030
- files: defaultFiles,
1031
- path: "",
1032
- preset: void 0,
1033
- extensions: void 0
1034
- };
1035
- useEnvironment.preload = (preloadOptions) => {
1036
- const options = { ...preloadDefaultOptions, ...preloadOptions };
1037
- let { files, path = "" } = options;
1038
- const { preset, extensions } = options;
1039
- if (preset) {
1040
- validatePreset(preset);
1041
- files = presetsObj[preset];
1042
- path = CUBEMAP_ROOT;
1043
- }
1044
- const { format } = getFormat(files);
1045
- if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1046
- const input = isArray(files) ? [files] : files;
1047
- loadLoader(format).then((loader) => {
1048
- useLoader.preload(loader, input, (loader2) => {
1049
- loader2.setPath?.(path);
1050
- if (extensions) extensions(loader2);
1051
- });
1052
950
  });
951
+ rootStore.subscribe((state2) => {
952
+ if (state2.internal.active) invalidate(state2);
953
+ });
954
+ return rootStore;
1053
955
  };
1054
- const clearDefaultOptins = {
1055
- files: defaultFiles,
1056
- preset: void 0
1057
- };
1058
- useEnvironment.clear = (clearOptions) => {
1059
- const options = { ...clearDefaultOptins, ...clearOptions };
1060
- let { files } = options;
1061
- const { preset } = options;
1062
- if (preset) {
1063
- validatePreset(preset);
1064
- files = presetsObj[preset];
1065
- }
1066
- const { format } = getFormat(files);
1067
- if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1068
- const input = isArray(files) ? [files] : files;
1069
- const clear = (loader2) => useLoader.clear(loader2, input);
1070
- const loader = loadedLoaders.get(format);
1071
- if (loader) {
1072
- clear(loader);
1073
- } else {
1074
- const pending = pendingLoaders.get(format);
1075
- if (pending) void pending.then(clear, () => {
956
+
957
+ const shallowLoose$1 = { objects: "shallow", strict: false };
958
+ function configureScheduler(store, canvasId, schedulerConfig, previous) {
959
+ const state = store.getState();
960
+ const scheduler$1 = scheduler.getScheduler();
961
+ const rootId = state.internal.rootId;
962
+ const ordersItself = schedulerConfig?.before !== void 0 || schedulerConfig?.after !== void 0;
963
+ const rootBefore = schedulerConfig?.before;
964
+ const rootAfter = ordersItself ? schedulerConfig?.after : state.internal.sharedAfter;
965
+ if (!rootId) {
966
+ const newRootId = state.internal.pendingRootId ?? canvasId ?? scheduler$1.generateRootId();
967
+ const unregisterRoot = scheduler$1.registerRoot(newRootId, {
968
+ // The scheduler spreads this into each frame state; see stateForScheduler
969
+ getState: () => textureStaging.stateForScheduler(store.getState()),
970
+ onError: (err) => store.getState().setError(err),
971
+ frameloop: store.getState().frameloop,
972
+ before: rootBefore,
973
+ after: rootAfter,
974
+ order: schedulerConfig?.order
1076
975
  });
976
+ const unregisterCanvasTarget = scheduler$1.register(
977
+ () => {
978
+ const state2 = store.getState();
979
+ const canvasTarget = state2.internal.canvasTarget;
980
+ if (canvasTarget) {
981
+ const renderer = state2.internal.actualRenderer;
982
+ if (renderer.getCanvasTarget() !== canvasTarget) renderer.setCanvasTarget(canvasTarget);
983
+ if (state2.internal.canvasTargetSizeDirty) {
984
+ state2.internal.canvasTargetSizeDirty = false;
985
+ renderer.backend?.updateSize?.();
986
+ }
987
+ }
988
+ },
989
+ {
990
+ id: `${newRootId}_canvasTarget`,
991
+ rootId: newRootId,
992
+ phase: "start",
993
+ system: true
994
+ }
995
+ );
996
+ const unregisterEventsFlush = scheduler$1.register(
997
+ () => {
998
+ const state2 = store.getState();
999
+ state2.events.flush?.();
1000
+ },
1001
+ {
1002
+ id: `${newRootId}_events`,
1003
+ rootId: newRootId,
1004
+ phase: "input",
1005
+ system: true
1006
+ }
1007
+ );
1008
+ const unregisterFrustum = scheduler$1.register(
1009
+ () => {
1010
+ const state2 = store.getState();
1011
+ if (state2.autoUpdateFrustum && state2.camera) {
1012
+ updateFrustum(state2.camera, state2.frustum);
1013
+ }
1014
+ },
1015
+ {
1016
+ id: `${newRootId}_frustum`,
1017
+ rootId: newRootId,
1018
+ before: "render",
1019
+ system: true
1020
+ }
1021
+ );
1022
+ const unregisterVisibility = scheduler$1.register(
1023
+ () => {
1024
+ const state2 = store.getState();
1025
+ checkVisibility(state2);
1026
+ },
1027
+ {
1028
+ id: `${newRootId}_visibility`,
1029
+ rootId: newRootId,
1030
+ before: "render",
1031
+ system: true,
1032
+ after: `${newRootId}_frustum`
1033
+ }
1034
+ );
1035
+ const unregisterRender = scheduler$1.register(
1036
+ () => {
1037
+ const state2 = store.getState();
1038
+ const renderer = state2.internal.actualRenderer;
1039
+ const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
1040
+ if (userHandlesRender || state2.internal.priority) return;
1041
+ try {
1042
+ const renderOverride = state2.internal.renderOverride;
1043
+ if (renderOverride) renderOverride();
1044
+ else if (renderer?.render) renderer.render(state2.scene, state2.camera);
1045
+ } catch (error) {
1046
+ state2.setError(error instanceof Error ? error : new Error(String(error)));
1047
+ }
1048
+ },
1049
+ {
1050
+ // Use canvas ID directly as job ID if available, otherwise use generated rootId
1051
+ id: canvasId || `${newRootId}_render`,
1052
+ rootId: newRootId,
1053
+ phase: "render",
1054
+ system: true,
1055
+ // Internal flag: this is a system job, not user-controlled
1056
+ // FPS throttles only the default render job; Canvas ordering belongs to the root.
1057
+ ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
1058
+ }
1059
+ );
1060
+ state.set((state2) => ({
1061
+ internal: {
1062
+ ...state2.internal,
1063
+ rootId: newRootId,
1064
+ pendingRootId: void 0,
1065
+ unregisterRoot: () => {
1066
+ unregisterRoot();
1067
+ unregisterCanvasTarget();
1068
+ unregisterEventsFlush();
1069
+ unregisterFrustum();
1070
+ unregisterVisibility();
1071
+ unregisterRender();
1072
+ },
1073
+ scheduler: scheduler$1
1074
+ }
1075
+ }));
1076
+ } else {
1077
+ const constraintsChanged = !is.equ(schedulerConfig?.before, previous?.before, shallowLoose$1) || !is.equ(schedulerConfig?.after, previous?.after, shallowLoose$1);
1078
+ if (constraintsChanged) {
1079
+ scheduler$1.setRootConstraints(rootId, {
1080
+ before: rootBefore,
1081
+ after: rootAfter
1082
+ });
1083
+ }
1084
+ if (schedulerConfig?.order !== previous?.order) {
1085
+ scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
1086
+ }
1077
1087
  }
1078
- };
1079
- function validatePreset(preset) {
1080
- if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
1081
- }
1082
- function getFormat(files) {
1083
- const isCubemap = isArray(files) && files.length === 6;
1084
- const firstEntry = isArray(files) ? files[0] : files;
1085
- const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
1086
- let format;
1087
- if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
1088
- else if (firstEntry.startsWith("data:application/exr")) format = "exr";
1089
- else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
1090
- else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
1091
- else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
1092
- else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
1093
- return { format, isCubemap };
1094
- }
1095
-
1096
- function useInstanceHandle(ref) {
1097
- const instance = React.useRef(null);
1098
- React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
1099
- return instance;
1100
- }
1101
- function useGraph(object) {
1102
- return React.useMemo(() => buildGraph(object), [object]);
1103
1088
  }
1104
-
1105
1089
  let effectId = 0;
1106
1090
  function addEffect(callback) {
1107
- extensions.notifyDepreciated({
1091
+ textureStaging.notifyDepreciated({
1108
1092
  heading: "addEffect is deprecated",
1109
1093
  body: 'Use useFrame(callback, { phase: "start" }) instead.\naddEffect will be removed in a future version.',
1110
1094
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1113,7 +1097,7 @@ function addEffect(callback) {
1113
1097
  return scheduler.getScheduler().registerGlobal("before", id, callback);
1114
1098
  }
1115
1099
  function addAfterEffect(callback) {
1116
- extensions.notifyDepreciated({
1100
+ textureStaging.notifyDepreciated({
1117
1101
  heading: "addAfterEffect is deprecated",
1118
1102
  body: 'Use useFrame(callback, { phase: "finish" }) instead.\naddAfterEffect will be removed in a future version.',
1119
1103
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1122,7 +1106,7 @@ function addAfterEffect(callback) {
1122
1106
  return scheduler.getScheduler().registerGlobal("after", id, callback);
1123
1107
  }
1124
1108
  function addTail(callback) {
1125
- extensions.notifyDepreciated({
1109
+ textureStaging.notifyDepreciated({
1126
1110
  heading: "addTail is deprecated",
1127
1111
  body: "Use scheduler.onIdle(callback) instead.\naddTail will be removed in a future version.",
1128
1112
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1142,340 +1126,974 @@ function advance(timestamp, runGlobalEffects, state) {
1142
1126
  else scheduler$1.step(timestamp);
1143
1127
  }
1144
1128
 
1145
- const version = "10.0.0-alpha.5";
1146
- const packageData = {
1147
- version: version};
1129
+ const isPromiseLike = (value) => typeof value?.then === "function";
1130
+ const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
1131
+ const rejected = (reason) => {
1132
+ const promise = Promise.reject(reason);
1133
+ promise.catch(() => {
1134
+ });
1135
+ return Object.assign(promise, { status: "rejected", reason });
1136
+ };
1137
+ const deferred = () => {
1138
+ let resolve;
1139
+ let reject;
1140
+ const promise = new Promise((yes, no) => {
1141
+ resolve = (value) => {
1142
+ Object.assign(promise, { status: "fulfilled", value });
1143
+ yes(value);
1144
+ };
1145
+ reject = (reason) => {
1146
+ Object.assign(promise, { status: "rejected", reason });
1147
+ no(reason);
1148
+ };
1149
+ });
1150
+ promise.status = "pending";
1151
+ promise.catch(() => {
1152
+ });
1153
+ return { promise, resolve, reject };
1154
+ };
1155
+ function resolveThen(value, apply) {
1156
+ return isPromiseLike(value) ? Promise.resolve(value).then(apply) : apply(value);
1157
+ }
1148
1158
 
1149
- function $1(Ut) {
1150
- return Ut && Ut.__esModule && Object.prototype.hasOwnProperty.call(Ut, "default") ? Ut.default : Ut;
1159
+ const isRenderer = (def) => !!def?.render;
1160
+ function ensureStoreThreeObjects(store) {
1161
+ const state = store.getState();
1162
+ if (state.pointer) return;
1163
+ const { Vector2, Frustum } = getThree();
1164
+ const pointer = new Vector2();
1165
+ state.set({ pointer, mouse: pointer, frustum: new Frustum() });
1151
1166
  }
1152
- var S0 = { exports: {} }, Ob = { exports: {} }, P1;
1153
- function Q1() {
1154
- return P1 || (P1 = 1, (function(Ut) {
1155
- Ut.exports = function(m) {
1156
- function et(t, r, a, l) {
1157
- return new Fe(t, r, a, l);
1158
- }
1159
- function zf() {
1160
- }
1161
- function F(t) {
1162
- var r = "https://react.dev/errors/" + t;
1163
- if (1 < arguments.length) {
1164
- r += "?args[]=" + encodeURIComponent(arguments[1]);
1165
- for (var a = 2; a < arguments.length; a++) r += "&args[]=" + encodeURIComponent(arguments[a]);
1166
- }
1167
- return "Minified React error #" + t + "; visit " + r + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";
1168
- }
1169
- function Ef(t) {
1170
- for (var r = t, a = r; a && !a.alternate; ) r = a, (r.flags & 4098) !== 0 && (t = r.return), a = r.return;
1171
- for (; r.return; ) r = r.return;
1172
- return r.tag === 3 ? t : null;
1173
- }
1174
- function pc(t) {
1175
- if (Ef(t) !== t) throw Error(F(188));
1167
+ const R3F_RENDERER_SETTINGS = ["textureColorSpace", "shadows"];
1168
+ const NON_APPLIED_RENDERER_PROPS = /* @__PURE__ */ new Set([
1169
+ ...R3F_RENDERER_SETTINGS,
1170
+ "canvas",
1171
+ "antialias",
1172
+ "alpha",
1173
+ "samples",
1174
+ "powerPreference",
1175
+ "depth",
1176
+ "stencil",
1177
+ "logarithmicDepthBuffer",
1178
+ "reversedDepthBuffer",
1179
+ // WebGPURenderer only
1180
+ "forceWebGL",
1181
+ "outputBufferType",
1182
+ "multiview",
1183
+ "getFallback",
1184
+ "trackTimestamp"
1185
+ ]);
1186
+ function settingsBag(config) {
1187
+ return is.obj(config) && !isRenderer(config) ? config : void 0;
1188
+ }
1189
+ function isInstanceOrFactory(config) {
1190
+ return is.fun(config) || isRenderer(config);
1191
+ }
1192
+ function assertNoRemovedConfig(props) {
1193
+ if (props.primaryCanvas !== void 0) {
1194
+ throw new Error(
1195
+ 'R3F: `primaryCanvas` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")'
1196
+ );
1197
+ }
1198
+ if (props.shadows !== void 0) {
1199
+ throw new Error(
1200
+ "R3F: the `shadows` Canvas prop moved into the renderer settings: use `renderer={{ shadows }}` (or `gl={{ shadows }}` for WebGL and @react-three/fiber/legacy)"
1201
+ );
1202
+ }
1203
+ for (const name of ["renderer", "gl"]) {
1204
+ const bag = settingsBag(props[name]);
1205
+ if (!bag) continue;
1206
+ if ("primaryCanvas" in bag) {
1207
+ throw new Error(
1208
+ `R3F: \`${name}={{ primaryCanvas }}\` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")`
1209
+ );
1210
+ }
1211
+ if ("scheduler" in bag) {
1212
+ throw new Error(`R3F: \`${name}={{ scheduler }}\` moved to <Canvas scheduler>`);
1213
+ }
1214
+ }
1215
+ }
1216
+ function resolveRenderer(config, defaultProps, RendererClass) {
1217
+ if (typeof config === "function") {
1218
+ return resolveThen(config(defaultProps), (renderer) => ({
1219
+ renderer,
1220
+ owned: true
1221
+ }));
1222
+ }
1223
+ if (isRenderer(config)) return { renderer: config, owned: false };
1224
+ const params = { ...defaultProps };
1225
+ for (const key in settingsBag(config)) if (!R3F_RENDERER_SETTINGS.includes(key)) params[key] = config[key];
1226
+ return { renderer: new RendererClass(params), owned: true };
1227
+ }
1228
+ function createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support) {
1229
+ return resolveThen(resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer), (resolved) => {
1230
+ const renderer = resolved.renderer;
1231
+ if (!renderer.hasInitialized?.()) {
1232
+ const size = computeInitialSize(canvas, propsSize);
1233
+ if (size.width > 0 && size.height > 0) {
1234
+ renderer.setPixelRatio(calculateDpr(dpr));
1235
+ renderer.setSize(size.width, size.height, false);
1176
1236
  }
1177
- function hc(t) {
1178
- var r = t.alternate;
1179
- if (!r) {
1180
- if (r = Ef(t), r === null) throw Error(F(188));
1181
- return r !== t ? null : t;
1182
- }
1183
- for (var a = t, l = r; ; ) {
1184
- var c = a.return;
1185
- if (c === null) break;
1186
- var d = c.alternate;
1187
- if (d === null) {
1188
- if (l = c.return, l !== null) {
1189
- a = l;
1190
- continue;
1191
- }
1192
- break;
1193
- }
1194
- if (c.child === d.child) {
1195
- for (d = c.child; d; ) {
1196
- if (d === a) return pc(c), t;
1197
- if (d === l) return pc(c), r;
1198
- d = d.sibling;
1199
- }
1200
- throw Error(F(188));
1201
- }
1202
- if (a.return !== l.return) a = c, l = d;
1203
- else {
1204
- for (var h = false, y = c.child; y; ) {
1205
- if (y === a) {
1206
- h = true, a = c, l = d;
1207
- break;
1208
- }
1209
- if (y === l) {
1210
- h = true, l = c, a = d;
1211
- break;
1212
- }
1213
- y = y.sibling;
1214
- }
1215
- if (!h) {
1216
- for (y = d.child; y; ) {
1217
- if (y === a) {
1218
- h = true, a = d, l = c;
1219
- break;
1220
- }
1221
- if (y === l) {
1222
- h = true, l = d, a = c;
1223
- break;
1224
- }
1225
- y = y.sibling;
1226
- }
1227
- if (!h) throw Error(F(189));
1228
- }
1229
- }
1230
- if (a.alternate !== l) throw Error(F(190));
1231
- }
1232
- if (a.tag !== 3) throw Error(F(188));
1233
- return a.stateNode.current === a ? t : r;
1234
- }
1235
- function mc(t) {
1236
- var r = t.tag;
1237
- if (r === 5 || r === 26 || r === 27 || r === 6) return t;
1238
- for (t = t.child; t !== null; ) {
1239
- if (r = mc(t), r !== null) return r;
1240
- t = t.sibling;
1241
- }
1242
- return null;
1243
- }
1244
- function ht(t) {
1245
- var r = t.tag;
1246
- if (r === 5 || r === 26 || r === 27 || r === 6) return t;
1247
- for (t = t.child; t !== null; ) {
1248
- if (t.tag !== 4 && (r = ht(t), r !== null)) return r;
1249
- t = t.sibling;
1250
- }
1251
- return null;
1237
+ return resolveThen(renderer.init(), () => ({ renderer, owned: resolved.owned }));
1238
+ }
1239
+ return { renderer, owned: resolved.owned };
1240
+ });
1241
+ }
1242
+ function initializeRenderer(canvas, provider, store, props) {
1243
+ const {
1244
+ id: canvasId,
1245
+ primary = false,
1246
+ share,
1247
+ gl: glConfig,
1248
+ renderer: rendererConfig,
1249
+ size: propsSize,
1250
+ dpr = [1, 2],
1251
+ _primaryToken
1252
+ } = props;
1253
+ assertNoRemovedConfig(props);
1254
+ const rendererBag = settingsBag(rendererConfig);
1255
+ const state = store.getState();
1256
+ const { webgl, webgpu } = provider;
1257
+ const defaultGLProps = {
1258
+ canvas,
1259
+ powerPreference: "high-performance",
1260
+ antialias: true,
1261
+ alpha: true
1262
+ };
1263
+ const defaultGPUProps = {
1264
+ canvas,
1265
+ antialias: true
1266
+ };
1267
+ if (glConfig && !webgl) {
1268
+ throw new Error(
1269
+ "R3F: the `gl` prop configures WebGLRenderer, which is only available on @react-three/fiber/legacy. Import Canvas from @react-three/fiber/legacy to keep WebGL, or move these settings to the `renderer` prop for WebGPU."
1270
+ );
1271
+ }
1272
+ if (rendererConfig && !webgpu) {
1273
+ throw new Error(
1274
+ "WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
1275
+ );
1276
+ }
1277
+ if (glConfig && rendererConfig) {
1278
+ throw new Error("Cannot use both gl and renderer props at the same time");
1279
+ }
1280
+ if (primary && !webgpu) {
1281
+ throw new Error(
1282
+ "R3F: <Canvas primary> shares a WebGPU renderer and is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
1283
+ );
1284
+ }
1285
+ if (primary && glConfig) {
1286
+ throw new Error(
1287
+ "R3F: <Canvas primary> shares a WebGPU renderer and cannot be used with WebGL. Remove the `gl` prop or use the `renderer` prop."
1288
+ );
1289
+ }
1290
+ if (primary && is.str(share)) {
1291
+ throw new Error(`R3F: a <Canvas primary> owns its renderer; remove share="${share}" from it.`);
1292
+ }
1293
+ if (is.str(share)) {
1294
+ if (!webgpu || glConfig) {
1295
+ throw new Error(
1296
+ `R3F: share="${share}" borrows a WebGPU renderer and cannot be used with WebGL. Remove the \`gl\` prop, or use @react-three/fiber or @react-three/fiber/webgpu.`
1297
+ );
1298
+ }
1299
+ if (isInstanceOrFactory(rendererConfig)) {
1300
+ throw new Error(
1301
+ `R3F: share="${share}" borrows the primary's renderer, so it cannot be combined with a renderer instance or factory. Remove one of the two.`
1302
+ );
1303
+ }
1304
+ }
1305
+ const primaryKey = canvasId || DEFAULT_PRIMARY;
1306
+ const primaryToken = _primaryToken ?? store;
1307
+ if (primary && !state.internal.actualRenderer) {
1308
+ announcePrimary(primaryKey, primaryToken);
1309
+ state.internal.unregisterPrimary = () => withdrawPrimary(primaryKey, primaryToken);
1310
+ if (primaryConflict(primaryKey, primaryToken)) {
1311
+ throw new Error(
1312
+ primaryKey === DEFAULT_PRIMARY ? 'R3F: two <Canvas primary> are mounted without ids. Give each primary a distinct `id`, and point the other canvases at one with share="id".' : `R3F: two <Canvas primary> use the id "${primaryKey}". Give each primary a distinct \`id\`.`
1313
+ );
1314
+ }
1315
+ }
1316
+ let shareKey;
1317
+ if (!state.internal.actualRenderer && webgpu && !primary && !glConfig && !state.isLegacy) {
1318
+ if (is.str(share)) {
1319
+ shareKey = share;
1320
+ } else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
1321
+ const live = livePrimaryKeys();
1322
+ if (live.length > 1) {
1323
+ throw new Error(
1324
+ `R3F: ${live.length} primaries are mounted (${live.map(describePrimary).join(", ")}), so this canvas cannot pick one to share. Pass share="id" to name one, or share={false} for its own renderer.`
1325
+ );
1252
1326
  }
1253
- function Ss(t) {
1254
- return t === null || typeof t != "object" ? null : (t = ki && t[ki] || t["@@iterator"], typeof t == "function" ? t : null);
1327
+ shareKey = live[0];
1328
+ }
1329
+ }
1330
+ const explicitShare = is.str(share);
1331
+ const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig && !primary && shareKey === void 0);
1332
+ let renderer = state.internal.actualRenderer;
1333
+ if (!state.internal.actualRenderer) {
1334
+ return resolveThen(wantsGL ? webgl() : webgpu(), (support) => {
1335
+ registerThree(support.three);
1336
+ state.internal.support = support;
1337
+ ensureStoreThreeObjects(store);
1338
+ if (support.kind === "webgl") {
1339
+ return resolveThen(resolveRenderer(glConfig, defaultGLProps, support.Renderer), (resolved) => {
1340
+ renderer = resolved.renderer;
1341
+ state.internal.actualRenderer = renderer;
1342
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1343
+ state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
1344
+ });
1255
1345
  }
1256
- function gc(t) {
1257
- if (t == null) return null;
1258
- if (typeof t == "function") return t.$$typeof === Po ? null : t.displayName || t.name || null;
1259
- if (typeof t == "string") return t;
1260
- switch (t) {
1261
- case wo:
1262
- return "Fragment";
1263
- case Pu:
1264
- return "Profiler";
1265
- case md:
1266
- return "StrictMode";
1267
- case xu:
1268
- return "Suspense";
1269
- case Cu:
1270
- return "SuspenseList";
1271
- case zu:
1272
- return "Activity";
1273
- case yd:
1274
- return "ViewTransition";
1275
- }
1276
- if (typeof t == "object") switch (t.$$typeof) {
1277
- case Si:
1278
- return "Portal";
1279
- case Vr:
1280
- return t.displayName || "Context";
1281
- case gd:
1282
- return (t._context.displayName || "Context") + ".Consumer";
1283
- case bd:
1284
- var r = t.render;
1285
- return t = t.displayName, t || (t = r.displayName || r.name || "", t = t !== "" ? "ForwardRef(" + t + ")" : "ForwardRef"), t;
1286
- case Fl:
1287
- return r = t.displayName || null, r !== null ? r : gc(t.type) || "Memo";
1288
- case Ra:
1289
- r = t._payload, t = t._init;
1290
- try {
1291
- return gc(t(r));
1292
- } catch {
1346
+ const primaryReady = shareKey === void 0 ? null : explicitShare ? waitForPrimary(shareKey) : waitForAnnouncedPrimary(shareKey);
1347
+ return resolveThen(primaryReady, (primaryEntry) => {
1348
+ if (primaryEntry && primaryEntry.store.getState().webGPUSupported) {
1349
+ renderer = primaryEntry.renderer;
1350
+ state.internal.actualRenderer = renderer;
1351
+ state.internal.releaseRenderer = borrowRenderer(renderer);
1352
+ state.internal.sharedAfter = primaryEntry.rootId;
1353
+ const canvasTarget = new support.CanvasTarget(canvas);
1354
+ primaryEntry.store.setState((prev) => ({
1355
+ internal: { ...prev.internal, isMultiCanvas: true }
1356
+ }));
1357
+ state.set((prev) => ({
1358
+ webGPUSupported: primaryEntry.store.getState().webGPUSupported,
1359
+ renderer,
1360
+ primaryStore: primaryEntry.store,
1361
+ internal: {
1362
+ ...prev.internal,
1363
+ canvasTarget,
1364
+ isMultiCanvas: true,
1365
+ isSecondary: true,
1366
+ targetId: shareKey === DEFAULT_PRIMARY ? void 0 : shareKey
1293
1367
  }
1368
+ }));
1369
+ return;
1294
1370
  }
1295
- return null;
1296
- }
1297
- function oo(t) {
1298
- return { current: t };
1299
- }
1300
- function W(t) {
1301
- 0 > Wa || (t.current = Ml[Wa], Ml[Wa] = null, Wa--);
1302
- }
1303
- function Te(t, r) {
1304
- Wa++, Ml[Wa] = t.current, t.current = r;
1305
- }
1306
- function k0(t) {
1307
- return t >>>= 0, t === 0 ? 32 : 31 - (Fd(t) / lh | 0) | 0;
1308
- }
1309
- function ma(t) {
1310
- var r = t & 42;
1311
- if (r !== 0) return r;
1312
- switch (t & -t) {
1313
- case 1:
1314
- return 1;
1315
- case 2:
1316
- return 2;
1317
- case 4:
1318
- return 4;
1319
- case 8:
1320
- return 8;
1321
- case 16:
1322
- return 16;
1323
- case 32:
1324
- return 32;
1325
- case 64:
1326
- return 64;
1327
- case 128:
1328
- return 128;
1329
- case 256:
1330
- case 512:
1331
- case 1024:
1332
- case 2048:
1333
- case 4096:
1334
- case 8192:
1335
- case 16384:
1336
- case 32768:
1337
- case 65536:
1338
- case 131072:
1339
- return t & -t;
1340
- case 262144:
1341
- case 524288:
1342
- case 1048576:
1343
- case 2097152:
1344
- return t & 3932160;
1345
- case 4194304:
1346
- case 8388608:
1347
- case 16777216:
1348
- case 33554432:
1349
- return t & 62914560;
1350
- case 67108864:
1351
- return 67108864;
1352
- case 134217728:
1353
- return 134217728;
1354
- case 268435456:
1355
- return 268435456;
1356
- case 536870912:
1357
- return 536870912;
1358
- case 1073741824:
1359
- return 0;
1360
- default:
1361
- return t;
1362
- }
1363
- }
1364
- function ao(t, r, a) {
1365
- var l = t.pendingLanes;
1366
- if (l === 0) return 0;
1367
- var c = 0, d = t.suspendedLanes, h = t.pingedLanes;
1368
- t = t.warmLanes;
1369
- var y = l & 134217727;
1370
- return y !== 0 ? (l = y & ~d, l !== 0 ? c = ma(l) : (h &= y, h !== 0 ? c = ma(h) : a || (a = y & ~t, a !== 0 && (c = ma(a))))) : (y = l & ~d, y !== 0 ? c = ma(y) : h !== 0 ? c = ma(h) : a || (a = l & ~t, a !== 0 && (c = ma(a)))), c === 0 ? 0 : r !== 0 && r !== c && (r & d) === 0 && (d = c & -c, a = r & -r, d >= a || d === 32 && (a & 4194048) !== 0) ? r : c;
1371
- }
1372
- function Yi(t, r) {
1373
- return (t.pendingLanes & ~(t.suspendedLanes & ~t.pingedLanes) & r) === 0;
1374
- }
1375
- function _f(t, r) {
1376
- (r & 8) !== 0 && (r |= r & 32);
1377
- var a = t.entangledLanes;
1378
- if (a !== 0) for (t = t.entanglements, a &= r; 0 < a; ) {
1379
- var l = 31 - sn(a), c = 1 << l;
1380
- r |= t[l], a &= ~c;
1371
+ if (primaryEntry) {
1372
+ return resolveThen(
1373
+ createOwnedWebGPURenderer(
1374
+ { ...rendererBag, forceWebGL: true },
1375
+ defaultGPUProps,
1376
+ canvas,
1377
+ propsSize,
1378
+ dpr,
1379
+ support
1380
+ ),
1381
+ (resolved) => {
1382
+ renderer = resolved.renderer;
1383
+ const backend = renderer.backend;
1384
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
1385
+ state.internal.actualRenderer = renderer;
1386
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1387
+ state.set((prev) => ({
1388
+ webGPUSupported: isWebGPUBackend,
1389
+ renderer,
1390
+ primaryStore: store,
1391
+ internal: {
1392
+ ...prev.internal,
1393
+ canvasTarget: renderer.getCanvasTarget?.(),
1394
+ sharedRendererFallback: true
1395
+ }
1396
+ }));
1397
+ }
1398
+ );
1381
1399
  }
1382
- return r;
1383
- }
1384
- function am(t, r) {
1385
- switch (t) {
1386
- case 1:
1387
- case 2:
1388
- case 4:
1389
- case 8:
1390
- case 64:
1391
- return r + 250;
1392
- case 16:
1393
- case 32:
1394
- case 128:
1395
- case 256:
1396
- case 512:
1397
- case 1024:
1398
- case 2048:
1399
- case 4096:
1400
- case 8192:
1401
- case 16384:
1402
- case 32768:
1403
- case 65536:
1404
- case 131072:
1405
- case 262144:
1406
- case 524288:
1407
- case 1048576:
1408
- case 2097152:
1409
- return r + 5e3;
1410
- case 4194304:
1411
- case 8388608:
1412
- case 16777216:
1413
- case 33554432:
1414
- return -1;
1415
- case 67108864:
1416
- case 134217728:
1417
- case 268435456:
1418
- case 536870912:
1419
- case 1073741824:
1420
- return -1;
1421
- default:
1422
- return -1;
1423
- }
1424
- }
1425
- function Nf() {
1426
- var t = qn;
1427
- return qn <<= 1, (qn & 62914560) === 0 && (qn = 4194304), t;
1428
- }
1429
- function bc(t) {
1430
- for (var r = [], a = 0; 31 > a; a++) r.push(t);
1431
- return r;
1400
+ return resolveThen(
1401
+ createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support),
1402
+ (resolved) => {
1403
+ var _a;
1404
+ renderer = resolved.renderer;
1405
+ const backend = renderer.backend;
1406
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
1407
+ state.internal.actualRenderer = renderer;
1408
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1409
+ state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
1410
+ if (primary) {
1411
+ const canvasTarget = renderer.getCanvasTarget?.();
1412
+ (_a = state.internal).pendingRootId ?? (_a.pendingRootId = canvasId || scheduler.getScheduler().generateRootId());
1413
+ registerPrimary(primaryKey, renderer, store, {
1414
+ token: primaryToken,
1415
+ rootId: state.internal.pendingRootId
1416
+ });
1417
+ state.set((prev) => ({ internal: { ...prev.internal, canvasTarget } }));
1418
+ } else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
1419
+ state.internal.untrackStandalone = trackStandalone(store);
1420
+ }
1421
+ }
1422
+ );
1423
+ });
1424
+ });
1425
+ }
1426
+ }
1427
+ const records = /* @__PURE__ */ new WeakMap();
1428
+ function take(renderer, record) {
1429
+ record.leases++;
1430
+ let released = false;
1431
+ return () => {
1432
+ if (released) return;
1433
+ released = true;
1434
+ if (--record.leases > 0) return;
1435
+ records.delete(renderer);
1436
+ if (record.owned) return disposeRenderer(renderer);
1437
+ };
1438
+ }
1439
+ function leaseRenderer(renderer, owned) {
1440
+ let record = records.get(renderer);
1441
+ if (!record) records.set(renderer, record = { owned, leases: 0 });
1442
+ return take(renderer, record);
1443
+ }
1444
+ function borrowRenderer(renderer) {
1445
+ const record = records.get(renderer);
1446
+ if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
1447
+ return take(renderer, record);
1448
+ }
1449
+ function disposeRenderer(renderer) {
1450
+ if (renderer.hasInitialized?.() === false) return;
1451
+ const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
1452
+ const loseContext = () => {
1453
+ try {
1454
+ ;
1455
+ renderer.forceContextLoss?.();
1456
+ } catch (error) {
1457
+ warn(error);
1458
+ }
1459
+ };
1460
+ let disposed;
1461
+ try {
1462
+ disposed = renderer.dispose ? renderer.dispose() : renderer.renderLists?.dispose?.();
1463
+ } catch (error) {
1464
+ warn(error);
1465
+ }
1466
+ if (typeof disposed?.then === "function") {
1467
+ return Promise.resolve(disposed).then(loseContext, (error) => {
1468
+ warn(error);
1469
+ loseContext();
1470
+ });
1471
+ }
1472
+ loseContext();
1473
+ }
1474
+ const DEFAULT_PRIMARY = "\0r3f:primary";
1475
+ const primaryRegistry = /* @__PURE__ */ new Map();
1476
+ const announcements = /* @__PURE__ */ new Map();
1477
+ const withdrawing = /* @__PURE__ */ new Set();
1478
+ const pendingSubscribers = /* @__PURE__ */ new Map();
1479
+ const standaloneRoots = /* @__PURE__ */ new Set();
1480
+ const warnedLatePrimary = /* @__PURE__ */ new WeakSet();
1481
+ function describePrimary(key) {
1482
+ return key === DEFAULT_PRIMARY ? "<Canvas primary>" : `<Canvas id="${key}" primary>`;
1483
+ }
1484
+ function notify(key, entry) {
1485
+ const subscribers = pendingSubscribers.get(key);
1486
+ if (!subscribers) return;
1487
+ pendingSubscribers.delete(key);
1488
+ subscribers.forEach((callback) => callback(entry));
1489
+ }
1490
+ function isLive(key) {
1491
+ const owners = announcements.get(key);
1492
+ if (owners) {
1493
+ for (const owner of owners) if (!withdrawing.has(owner)) return true;
1494
+ }
1495
+ const entry = primaryRegistry.get(key);
1496
+ return !!entry && !(entry.token && withdrawing.has(entry.token));
1497
+ }
1498
+ function announcePrimary(key, owner) {
1499
+ withdrawing.delete(owner);
1500
+ let owners = announcements.get(key);
1501
+ if (!owners) announcements.set(key, owners = /* @__PURE__ */ new Set());
1502
+ if (owners.has(owner)) return;
1503
+ owners.add(owner);
1504
+ if (standaloneRoots.size > 0 && !warnedLatePrimary.has(owner) && textureStaging.isDevelopment()) {
1505
+ warnedLatePrimary.add(owner);
1506
+ console.warn(
1507
+ `R3F: ${describePrimary(key)} mounted after ${standaloneRoots.size} other WebGPU canvas(es) had already created their own renderer; those keep it and do not share the primary. Mount the primary with or before the canvases that share it, or give them share="id" so they wait for it.`
1508
+ );
1509
+ }
1510
+ }
1511
+ function markWithdrawing(owner) {
1512
+ withdrawing.add(owner);
1513
+ }
1514
+ function withdrawPrimary(key, owner) {
1515
+ withdrawing.delete(owner);
1516
+ const owners = announcements.get(key);
1517
+ if (owners) {
1518
+ owners.delete(owner);
1519
+ if (owners.size === 0) announcements.delete(key);
1520
+ }
1521
+ const entry = primaryRegistry.get(key);
1522
+ if (entry?.token === owner) primaryRegistry.delete(key);
1523
+ if (!isLive(key)) notify(key, null);
1524
+ }
1525
+ function primaryConflict(key, owner) {
1526
+ const owners = announcements.get(key);
1527
+ if (owners) {
1528
+ for (const other of owners) {
1529
+ if (other === owner) break;
1530
+ if (!withdrawing.has(other)) return true;
1531
+ }
1532
+ }
1533
+ const entry = primaryRegistry.get(key);
1534
+ return !!entry && entry.token !== owner && !(entry.token && withdrawing.has(entry.token));
1535
+ }
1536
+ function livePrimaryKeys() {
1537
+ const keys = /* @__PURE__ */ new Set([...announcements.keys(), ...primaryRegistry.keys()]);
1538
+ return [...keys].filter(isLive);
1539
+ }
1540
+ function trackStandalone(owner) {
1541
+ standaloneRoots.add(owner);
1542
+ return () => {
1543
+ standaloneRoots.delete(owner);
1544
+ };
1545
+ }
1546
+ function registerPrimary(id, renderer, store, options = {}) {
1547
+ if (options.token && !announcements.get(id)?.has(options.token)) return () => {
1548
+ };
1549
+ if (primaryRegistry.has(id)) {
1550
+ console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
1551
+ }
1552
+ const entry = { renderer, store, rootId: options.rootId, token: options.token };
1553
+ primaryRegistry.set(id, entry);
1554
+ notify(id, entry);
1555
+ return () => {
1556
+ const currentEntry = primaryRegistry.get(id);
1557
+ if (currentEntry?.renderer === renderer) {
1558
+ primaryRegistry.delete(id);
1559
+ }
1560
+ };
1561
+ }
1562
+ function getPrimary(id) {
1563
+ return primaryRegistry.get(id);
1564
+ }
1565
+ function subscribe(id, callback) {
1566
+ if (!pendingSubscribers.has(id)) pendingSubscribers.set(id, []);
1567
+ pendingSubscribers.get(id).push(callback);
1568
+ return () => {
1569
+ const subscribers = pendingSubscribers.get(id);
1570
+ if (!subscribers) return;
1571
+ const index = subscribers.indexOf(callback);
1572
+ if (index !== -1) subscribers.splice(index, 1);
1573
+ if (subscribers.length === 0) pendingSubscribers.delete(id);
1574
+ };
1575
+ }
1576
+ function waitForPrimary(id, timeout = 5e3) {
1577
+ const existing = primaryRegistry.get(id);
1578
+ if (existing) {
1579
+ return Promise.resolve(existing);
1580
+ }
1581
+ return new Promise((resolve, reject) => {
1582
+ let unsubscribe = () => {
1583
+ };
1584
+ const timeoutId = setTimeout(() => {
1585
+ unsubscribe();
1586
+ reject(
1587
+ new Error(
1588
+ `Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}" primary> is mounted for share="${id}".`
1589
+ )
1590
+ );
1591
+ }, timeout);
1592
+ const callback = (entry) => {
1593
+ if (!entry) {
1594
+ unsubscribe = subscribe(id, callback);
1595
+ return;
1432
1596
  }
1433
- function Ki(t, r) {
1434
- t.pendingLanes |= r, r !== 268435456 && (t.suspendedLanes = 0, t.pingedLanes = 0, t.warmLanes = 0);
1597
+ clearTimeout(timeoutId);
1598
+ resolve(entry);
1599
+ };
1600
+ unsubscribe = subscribe(id, callback);
1601
+ });
1602
+ }
1603
+ function waitForAnnouncedPrimary(key, timeout = 5e3) {
1604
+ const existing = primaryRegistry.get(key);
1605
+ if (existing && isLive(key)) return Promise.resolve(existing);
1606
+ if (!isLive(key)) return Promise.resolve(null);
1607
+ return new Promise((resolve, reject) => {
1608
+ const timeoutId = setTimeout(() => {
1609
+ unsubscribe();
1610
+ reject(
1611
+ new Error(
1612
+ `Timeout waiting for ${describePrimary(key)} to create its renderer. A canvas mounted next to it shares its renderer automatically; pass share={false} to give it its own.`
1613
+ )
1614
+ );
1615
+ }, timeout);
1616
+ const unsubscribe = subscribe(key, (entry) => {
1617
+ clearTimeout(timeoutId);
1618
+ resolve(entry);
1619
+ });
1620
+ });
1621
+ }
1622
+ function hasPrimary(id) {
1623
+ return primaryRegistry.has(id);
1624
+ }
1625
+ function unregisterPrimary(id) {
1626
+ primaryRegistry.delete(id);
1627
+ }
1628
+ function getPrimaryIds() {
1629
+ return Array.from(primaryRegistry.keys());
1630
+ }
1631
+
1632
+ const shallowLoose = { objects: "shallow", strict: false };
1633
+ function watchDpr(onChange) {
1634
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
1635
+ return () => {
1636
+ };
1637
+ }
1638
+ let watching = true;
1639
+ let query;
1640
+ const listen = () => {
1641
+ try {
1642
+ query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
1643
+ if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
1644
+ else query?.addListener?.(handleChange);
1645
+ } catch {
1646
+ query = void 0;
1647
+ }
1648
+ };
1649
+ const unlisten = () => {
1650
+ if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
1651
+ else query?.removeListener?.(handleChange);
1652
+ query = void 0;
1653
+ };
1654
+ const handleChange = () => {
1655
+ if (!watching) return;
1656
+ unlisten();
1657
+ listen();
1658
+ onChange();
1659
+ };
1660
+ listen();
1661
+ return () => {
1662
+ watching = false;
1663
+ unlisten();
1664
+ };
1665
+ }
1666
+ function createRootConfiguration(store, canvas) {
1667
+ let previous;
1668
+ let lastCamera;
1669
+ const lastConfiguredProps = {};
1670
+ let resolvedDpr = 0;
1671
+ let dprChangedInXR = false;
1672
+ let unwatchDpr;
1673
+ const resolveDpr = () => {
1674
+ const state = store.getState();
1675
+ const xr = state.internal.actualRenderer?.xr;
1676
+ if (xr?.isPresenting || xr?.getSession?.()) {
1677
+ dprChangedInXR = true;
1678
+ return;
1679
+ }
1680
+ dprChangedInXR = false;
1681
+ const dpr = lastConfiguredProps.dpr;
1682
+ if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
1683
+ state.setDpr(dpr);
1684
+ resolvedDpr = store.getState().viewport.dpr;
1685
+ };
1686
+ let warnedSharedSettings = false;
1687
+ let configured = false;
1688
+ return (props) => {
1689
+ const {
1690
+ gl: glConfig,
1691
+ renderer: rendererConfig,
1692
+ size: propsSize,
1693
+ scene: sceneOptions,
1694
+ events,
1695
+ orthographic = false,
1696
+ frameloop = "always",
1697
+ dpr = [1, 2],
1698
+ performance,
1699
+ raycaster: raycastOptions,
1700
+ camera: cameraOptions,
1701
+ onPointerMissed,
1702
+ onDragOverMissed,
1703
+ onDropMissed,
1704
+ autoUpdateFrustum = true,
1705
+ occlusion = false,
1706
+ _sizeProps,
1707
+ forceEven
1708
+ } = props;
1709
+ assertNoRemovedConfig(props);
1710
+ const rendererBag = settingsBag(rendererConfig);
1711
+ const settings = settingsBag(glConfig) ?? rendererBag;
1712
+ const requestedTextureColorSpace = settings?.textureColorSpace || void 0;
1713
+ const shadows = isInstanceOrFactory(glConfig ?? rendererConfig) ? void 0 : settings?.shadows ?? false;
1714
+ const next = { ...props, shadows, frameloop, autoUpdateFrustum, occlusion };
1715
+ const last = previous;
1716
+ const changed = (key) => !last || !is.equ(next[key], last[key], { objects: "shallow" });
1717
+ previous = void 0;
1718
+ const state = store.getState();
1719
+ const renderer = state.internal.actualRenderer;
1720
+ const three = getThree();
1721
+ const borrowsRenderer = state.internal.isSecondary === true;
1722
+ if (borrowsRenderer && !warnedSharedSettings && rendererBag && Object.keys(rendererBag).some((key) => key !== "textureColorSpace") && textureStaging.isDevelopment()) {
1723
+ warnedSharedSettings = true;
1724
+ console.warn(
1725
+ "R3F: renderer settings on a sharing canvas are ignored; set them on the <Canvas primary>. This canvas borrows the primary's renderer, so renderer-wide settings come from the primary. Pass share={false} to give this canvas its own renderer."
1726
+ );
1727
+ }
1728
+ let raycaster = state.raycaster;
1729
+ if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
1730
+ if (changed("raycaster")) {
1731
+ const { params, ...options } = raycastOptions || {};
1732
+ if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
1733
+ if (!is.equ(params, raycaster.params, shallowLoose)) {
1734
+ applyProps(raycaster, { params: { ...raycaster.params, ...params } });
1435
1735
  }
1436
- function ti(t, r, a, l, c, d) {
1437
- var h = t.pendingLanes;
1438
- t.pendingLanes = a, t.suspendedLanes = 0, t.pingedLanes = 0, t.warmLanes = 0, t.expiredLanes &= a, t.entangledLanes &= a, t.errorRecoveryDisabledLanes &= a, t.shellSuspendCounter = 0;
1439
- var y = t.entanglements, C = t.expirationTimes, R = t.hiddenUpdates;
1440
- for (a = h & ~a; 0 < a; ) {
1441
- var D = 31 - sn(a), U = 1 << D;
1442
- y[D] = 0, C[D] = -1;
1443
- var A = R[D];
1444
- if (A !== null) for (R[D] = null, D = 0; D < A.length; D++) {
1445
- var fe = A[D];
1446
- fe !== null && (fe.lane &= -536870913);
1736
+ }
1737
+ let tempCamera = state.camera;
1738
+ if (!state.camera || state.camera === lastCamera && changed("camera")) {
1739
+ lastCamera = cameraOptions;
1740
+ const isCamera = cameraOptions?.isCamera;
1741
+ const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
1742
+ if (!isCamera) {
1743
+ camera.position.z = 5;
1744
+ if (cameraOptions) {
1745
+ applyProps(camera, cameraOptions);
1746
+ if (!camera.manual) {
1747
+ const projectionProps = ["aspect", "left", "right", "bottom", "top"];
1748
+ if (projectionProps.some((prop) => prop in cameraOptions)) {
1749
+ camera.manual = true;
1750
+ camera.updateProjectionMatrix();
1751
+ }
1447
1752
  }
1448
- a &= ~U;
1449
1753
  }
1450
- l !== 0 && en(t, l, 0), d !== 0 && c === 0 && t.tag !== 0 && (t.suspendedLanes |= d & ~(h & ~r));
1451
- }
1452
- function en(t, r, a) {
1453
- t.pendingLanes |= r, t.suspendedLanes &= ~r;
1454
- var l = 31 - sn(r);
1455
- t.entangledLanes |= r, t.entanglements[l] = t.entanglements[l] | 1073741824 | a & 261930;
1754
+ if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
1456
1755
  }
1457
- function G(t, r) {
1458
- var a = t.entangledLanes |= r;
1459
- for (t = t.entanglements; a; ) {
1460
- var l = 31 - sn(a), c = 1 << l;
1461
- c & r | t[l] & r && (t[l] |= r), a &= ~c;
1462
- }
1756
+ state.set({ camera });
1757
+ tempCamera = camera;
1758
+ raycaster.camera = camera;
1759
+ }
1760
+ if (!state.scene) {
1761
+ let scene;
1762
+ if (sceneOptions?.isScene) {
1763
+ scene = sceneOptions;
1764
+ prepare(scene, store, "", {});
1765
+ } else {
1766
+ scene = new three.Scene();
1767
+ prepare(scene, store, "", {});
1768
+ if (sceneOptions) applyProps(scene, sceneOptions);
1769
+ }
1770
+ state.set((prev) => ({
1771
+ scene,
1772
+ rootScene: scene,
1773
+ internal: { ...prev.internal, container: scene }
1774
+ }));
1775
+ const camera = tempCamera;
1776
+ if (camera && !camera.parent) scene.add(camera);
1777
+ }
1778
+ if (events && !state.events.handlers) {
1779
+ state.set({ events: events(store) });
1780
+ let wasEnabled = true;
1781
+ store.subscribe((state2) => {
1782
+ const { enabled } = state2.events;
1783
+ if (enabled && !wasEnabled) {
1784
+ state2.events.update?.();
1785
+ }
1786
+ wasEnabled = enabled;
1787
+ });
1788
+ }
1789
+ if (_sizeProps !== void 0 && changed("_sizeProps")) {
1790
+ state.set({ _sizeProps });
1791
+ }
1792
+ if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
1793
+ state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
1794
+ }
1795
+ configureSize(store, computeInitialSize(canvas, propsSize));
1796
+ if (dpr !== void 0 && (!last || !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose))) {
1797
+ state.setDpr(dpr);
1798
+ lastConfiguredProps.dpr = dpr;
1799
+ resolvedDpr = store.getState().viewport.dpr;
1800
+ }
1801
+ const internal = store.getState().internal;
1802
+ if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
1803
+ internal.unwatchDpr?.();
1804
+ internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
1805
+ }
1806
+ resolveDpr();
1807
+ if (frameloop !== void 0 && changed("frameloop")) {
1808
+ state.setFrameloop(frameloop);
1809
+ }
1810
+ if (changed("onPointerMissed")) state.set({ onPointerMissed });
1811
+ if (changed("onDragOverMissed")) state.set({ onDragOverMissed });
1812
+ if (changed("onDropMissed")) state.set({ onDropMissed });
1813
+ if (changed("autoUpdateFrustum") && state.autoUpdateFrustum !== autoUpdateFrustum) {
1814
+ state.set({ autoUpdateFrustum });
1815
+ }
1816
+ if (occlusion && !state.internal.occlusionEnabled) {
1817
+ enableOcclusion(store);
1818
+ }
1819
+ if (performance && changed("performance")) {
1820
+ state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
1821
+ }
1822
+ if (!state.xr) {
1823
+ const handleXRFrame = (timestamp, _frame) => {
1824
+ const state2 = store.getState();
1825
+ if (state2.frameloop === "never") return;
1826
+ advance(timestamp, true, state2);
1827
+ };
1828
+ const actualRenderer = state.internal.actualRenderer;
1829
+ const handleSessionChange = () => {
1830
+ const state2 = store.getState();
1831
+ const renderer2 = state2.internal.actualRenderer;
1832
+ actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
1833
+ renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
1834
+ if (!renderer2.xr.isPresenting) {
1835
+ if (dprChangedInXR) resolveDpr();
1836
+ invalidate(state2);
1837
+ }
1838
+ };
1839
+ const xr = {
1840
+ connect() {
1841
+ const xrManager = store.getState().renderer.xr;
1842
+ xrManager.addEventListener("sessionstart", handleSessionChange);
1843
+ xrManager.addEventListener("sessionend", handleSessionChange);
1844
+ },
1845
+ disconnect() {
1846
+ const xrManager = store.getState().renderer.xr;
1847
+ xrManager.removeEventListener("sessionstart", handleSessionChange);
1848
+ xrManager.removeEventListener("sessionend", handleSessionChange);
1849
+ }
1850
+ };
1851
+ if (!borrowsRenderer && typeof renderer.xr?.addEventListener === "function") xr.connect();
1852
+ state.set({ xr });
1853
+ }
1854
+ if (!borrowsRenderer && shadows !== void 0 && renderer.shadowMap && changed("shadows")) {
1855
+ const oldEnabled = renderer.shadowMap.enabled;
1856
+ const oldType = renderer.shadowMap.type;
1857
+ renderer.shadowMap.enabled = !!shadows;
1858
+ if (is.boo(shadows)) {
1859
+ renderer.shadowMap.type = three.PCFShadowMap;
1860
+ } else if (is.str(shadows)) {
1861
+ if (shadows === "soft") {
1862
+ textureStaging.notifyDepreciated({
1863
+ heading: 'shadows="soft" is deprecated',
1864
+ body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
1865
+ link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
1866
+ });
1867
+ }
1868
+ const types = {
1869
+ basic: three.BasicShadowMap,
1870
+ percentage: three.PCFShadowMap,
1871
+ soft: three.PCFShadowMap,
1872
+ variance: three.VSMShadowMap
1873
+ };
1874
+ renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
1875
+ } else if (is.obj(shadows)) {
1876
+ Object.assign(renderer.shadowMap, shadows);
1463
1877
  }
1464
- function Wt(t, r) {
1465
- var a = r & -r;
1466
- return a = (a & 42) !== 0 ? 1 : mn(a), (a & (t.suspendedLanes | r)) !== 0 ? 0 : a;
1878
+ if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
1879
+ renderer.shadowMap.needsUpdate = true;
1467
1880
  }
1468
- function mn(t) {
1881
+ }
1882
+ if (!configured && !borrowsRenderer) {
1883
+ renderer.outputColorSpace = three.SRGBColorSpace;
1884
+ renderer.toneMapping = three.ACESFilmicToneMapping;
1885
+ }
1886
+ const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
1887
+ if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
1888
+ if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
1889
+ lastConfiguredProps.textureColorSpace = textureColorSpace;
1890
+ }
1891
+ if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && changed("gl")) {
1892
+ const glProps = {};
1893
+ for (const key in glConfig) {
1894
+ if (!NON_APPLIED_RENDERER_PROPS.has(key)) glProps[key] = glConfig[key];
1895
+ }
1896
+ applyProps(renderer, glProps);
1897
+ }
1898
+ if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer && !borrowsRenderer) {
1899
+ const currentRenderer = state.renderer;
1900
+ if (changed("renderer")) {
1901
+ const rendererProps = {};
1902
+ for (const key in rendererConfig) {
1903
+ if (!NON_APPLIED_RENDERER_PROPS.has(key)) rendererProps[key] = rendererConfig[key];
1904
+ }
1905
+ applyProps(currentRenderer, rendererProps);
1906
+ }
1907
+ }
1908
+ configured = true;
1909
+ previous = next;
1910
+ };
1911
+ }
1912
+
1913
+ const version = "10.0.0-alpha.6";
1914
+ const packageData = {
1915
+ version: version};
1916
+
1917
+ function $1(Ut) {
1918
+ return Ut && Ut.__esModule && Object.prototype.hasOwnProperty.call(Ut, "default") ? Ut.default : Ut;
1919
+ }
1920
+ var S0 = { exports: {} }, Ob = { exports: {} }, P1;
1921
+ function Q1() {
1922
+ return P1 || (P1 = 1, (function(Ut) {
1923
+ Ut.exports = function(m) {
1924
+ function et(t, r, a, l) {
1925
+ return new Fe(t, r, a, l);
1926
+ }
1927
+ function zf() {
1928
+ }
1929
+ function F(t) {
1930
+ var r = "https://react.dev/errors/" + t;
1931
+ if (1 < arguments.length) {
1932
+ r += "?args[]=" + encodeURIComponent(arguments[1]);
1933
+ for (var a = 2; a < arguments.length; a++) r += "&args[]=" + encodeURIComponent(arguments[a]);
1934
+ }
1935
+ return "Minified React error #" + t + "; visit " + r + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings.";
1936
+ }
1937
+ function Ef(t) {
1938
+ for (var r = t, a = r; a && !a.alternate; ) r = a, (r.flags & 4098) !== 0 && (t = r.return), a = r.return;
1939
+ for (; r.return; ) r = r.return;
1940
+ return r.tag === 3 ? t : null;
1941
+ }
1942
+ function pc(t) {
1943
+ if (Ef(t) !== t) throw Error(F(188));
1944
+ }
1945
+ function hc(t) {
1946
+ var r = t.alternate;
1947
+ if (!r) {
1948
+ if (r = Ef(t), r === null) throw Error(F(188));
1949
+ return r !== t ? null : t;
1950
+ }
1951
+ for (var a = t, l = r; ; ) {
1952
+ var c = a.return;
1953
+ if (c === null) break;
1954
+ var d = c.alternate;
1955
+ if (d === null) {
1956
+ if (l = c.return, l !== null) {
1957
+ a = l;
1958
+ continue;
1959
+ }
1960
+ break;
1961
+ }
1962
+ if (c.child === d.child) {
1963
+ for (d = c.child; d; ) {
1964
+ if (d === a) return pc(c), t;
1965
+ if (d === l) return pc(c), r;
1966
+ d = d.sibling;
1967
+ }
1968
+ throw Error(F(188));
1969
+ }
1970
+ if (a.return !== l.return) a = c, l = d;
1971
+ else {
1972
+ for (var h = false, y = c.child; y; ) {
1973
+ if (y === a) {
1974
+ h = true, a = c, l = d;
1975
+ break;
1976
+ }
1977
+ if (y === l) {
1978
+ h = true, l = c, a = d;
1979
+ break;
1980
+ }
1981
+ y = y.sibling;
1982
+ }
1983
+ if (!h) {
1984
+ for (y = d.child; y; ) {
1985
+ if (y === a) {
1986
+ h = true, a = d, l = c;
1987
+ break;
1988
+ }
1989
+ if (y === l) {
1990
+ h = true, l = d, a = c;
1991
+ break;
1992
+ }
1993
+ y = y.sibling;
1994
+ }
1995
+ if (!h) throw Error(F(189));
1996
+ }
1997
+ }
1998
+ if (a.alternate !== l) throw Error(F(190));
1999
+ }
2000
+ if (a.tag !== 3) throw Error(F(188));
2001
+ return a.stateNode.current === a ? t : r;
2002
+ }
2003
+ function mc(t) {
2004
+ var r = t.tag;
2005
+ if (r === 5 || r === 26 || r === 27 || r === 6) return t;
2006
+ for (t = t.child; t !== null; ) {
2007
+ if (r = mc(t), r !== null) return r;
2008
+ t = t.sibling;
2009
+ }
2010
+ return null;
2011
+ }
2012
+ function ht(t) {
2013
+ var r = t.tag;
2014
+ if (r === 5 || r === 26 || r === 27 || r === 6) return t;
2015
+ for (t = t.child; t !== null; ) {
2016
+ if (t.tag !== 4 && (r = ht(t), r !== null)) return r;
2017
+ t = t.sibling;
2018
+ }
2019
+ return null;
2020
+ }
2021
+ function Ss(t) {
2022
+ return t === null || typeof t != "object" ? null : (t = ki && t[ki] || t["@@iterator"], typeof t == "function" ? t : null);
2023
+ }
2024
+ function gc(t) {
2025
+ if (t == null) return null;
2026
+ if (typeof t == "function") return t.$$typeof === Po ? null : t.displayName || t.name || null;
2027
+ if (typeof t == "string") return t;
1469
2028
  switch (t) {
2029
+ case wo:
2030
+ return "Fragment";
2031
+ case Pu:
2032
+ return "Profiler";
2033
+ case md:
2034
+ return "StrictMode";
2035
+ case xu:
2036
+ return "Suspense";
2037
+ case Cu:
2038
+ return "SuspenseList";
2039
+ case zu:
2040
+ return "Activity";
2041
+ case yd:
2042
+ return "ViewTransition";
2043
+ }
2044
+ if (typeof t == "object") switch (t.$$typeof) {
2045
+ case Si:
2046
+ return "Portal";
2047
+ case Vr:
2048
+ return t.displayName || "Context";
2049
+ case gd:
2050
+ return (t._context.displayName || "Context") + ".Consumer";
2051
+ case bd:
2052
+ var r = t.render;
2053
+ return t = t.displayName, t || (t = r.displayName || r.name || "", t = t !== "" ? "ForwardRef(" + t + ")" : "ForwardRef"), t;
2054
+ case Fl:
2055
+ return r = t.displayName || null, r !== null ? r : gc(t.type) || "Memo";
2056
+ case Ra:
2057
+ r = t._payload, t = t._init;
2058
+ try {
2059
+ return gc(t(r));
2060
+ } catch {
2061
+ }
2062
+ }
2063
+ return null;
2064
+ }
2065
+ function oo(t) {
2066
+ return { current: t };
2067
+ }
2068
+ function W(t) {
2069
+ 0 > Wa || (t.current = Ml[Wa], Ml[Wa] = null, Wa--);
2070
+ }
2071
+ function Te(t, r) {
2072
+ Wa++, Ml[Wa] = t.current, t.current = r;
2073
+ }
2074
+ function k0(t) {
2075
+ return t >>>= 0, t === 0 ? 32 : 31 - (Fd(t) / lh | 0) | 0;
2076
+ }
2077
+ function ma(t) {
2078
+ var r = t & 42;
2079
+ if (r !== 0) return r;
2080
+ switch (t & -t) {
2081
+ case 1:
2082
+ return 1;
1470
2083
  case 2:
1471
- t = 1;
1472
- break;
2084
+ return 2;
2085
+ case 4:
2086
+ return 4;
1473
2087
  case 8:
1474
- t = 4;
1475
- break;
2088
+ return 8;
2089
+ case 16:
2090
+ return 16;
1476
2091
  case 32:
1477
- t = 16;
1478
- break;
2092
+ return 32;
2093
+ case 64:
2094
+ return 64;
2095
+ case 128:
2096
+ return 128;
1479
2097
  case 256:
1480
2098
  case 512:
1481
2099
  case 1024:
@@ -1486,31 +2104,181 @@ function Q1() {
1486
2104
  case 32768:
1487
2105
  case 65536:
1488
2106
  case 131072:
2107
+ return t & -t;
1489
2108
  case 262144:
1490
2109
  case 524288:
1491
2110
  case 1048576:
1492
2111
  case 2097152:
2112
+ return t & 3932160;
1493
2113
  case 4194304:
1494
2114
  case 8388608:
1495
2115
  case 16777216:
1496
2116
  case 33554432:
1497
- t = 128;
1498
- break;
2117
+ return t & 62914560;
2118
+ case 67108864:
2119
+ return 67108864;
2120
+ case 134217728:
2121
+ return 134217728;
1499
2122
  case 268435456:
1500
- t = 134217728;
1501
- break;
2123
+ return 268435456;
2124
+ case 536870912:
2125
+ return 536870912;
2126
+ case 1073741824:
2127
+ return 0;
1502
2128
  default:
1503
- t = 0;
2129
+ return t;
1504
2130
  }
1505
- return t;
1506
2131
  }
1507
- function ze(t) {
1508
- return t &= -t, 2 < t ? 8 < t ? (t & 134217727) !== 0 ? 32 : 268435456 : 8 : 2;
2132
+ function ao(t, r, a) {
2133
+ var l = t.pendingLanes;
2134
+ if (l === 0) return 0;
2135
+ var c = 0, d = t.suspendedLanes, h = t.pingedLanes;
2136
+ t = t.warmLanes;
2137
+ var y = l & 134217727;
2138
+ return y !== 0 ? (l = y & ~d, l !== 0 ? c = ma(l) : (h &= y, h !== 0 ? c = ma(h) : a || (a = y & ~t, a !== 0 && (c = ma(a))))) : (y = l & ~d, y !== 0 ? c = ma(y) : h !== 0 ? c = ma(h) : a || (a = l & ~t, a !== 0 && (c = ma(a)))), c === 0 ? 0 : r !== 0 && r !== c && (r & d) === 0 && (d = c & -c, a = r & -r, d >= a || d === 32 && (a & 4194048) !== 0) ? r : c;
1509
2139
  }
1510
- function ga(t) {
1511
- if (typeof N == "function" && U0(t), It && typeof It.setStrictMode == "function") try {
1512
- It.setStrictMode(Lu, t);
1513
- } catch {
2140
+ function Yi(t, r) {
2141
+ return (t.pendingLanes & ~(t.suspendedLanes & ~t.pingedLanes) & r) === 0;
2142
+ }
2143
+ function _f(t, r) {
2144
+ (r & 8) !== 0 && (r |= r & 32);
2145
+ var a = t.entangledLanes;
2146
+ if (a !== 0) for (t = t.entanglements, a &= r; 0 < a; ) {
2147
+ var l = 31 - sn(a), c = 1 << l;
2148
+ r |= t[l], a &= ~c;
2149
+ }
2150
+ return r;
2151
+ }
2152
+ function am(t, r) {
2153
+ switch (t) {
2154
+ case 1:
2155
+ case 2:
2156
+ case 4:
2157
+ case 8:
2158
+ case 64:
2159
+ return r + 250;
2160
+ case 16:
2161
+ case 32:
2162
+ case 128:
2163
+ case 256:
2164
+ case 512:
2165
+ case 1024:
2166
+ case 2048:
2167
+ case 4096:
2168
+ case 8192:
2169
+ case 16384:
2170
+ case 32768:
2171
+ case 65536:
2172
+ case 131072:
2173
+ case 262144:
2174
+ case 524288:
2175
+ case 1048576:
2176
+ case 2097152:
2177
+ return r + 5e3;
2178
+ case 4194304:
2179
+ case 8388608:
2180
+ case 16777216:
2181
+ case 33554432:
2182
+ return -1;
2183
+ case 67108864:
2184
+ case 134217728:
2185
+ case 268435456:
2186
+ case 536870912:
2187
+ case 1073741824:
2188
+ return -1;
2189
+ default:
2190
+ return -1;
2191
+ }
2192
+ }
2193
+ function Nf() {
2194
+ var t = qn;
2195
+ return qn <<= 1, (qn & 62914560) === 0 && (qn = 4194304), t;
2196
+ }
2197
+ function bc(t) {
2198
+ for (var r = [], a = 0; 31 > a; a++) r.push(t);
2199
+ return r;
2200
+ }
2201
+ function Ki(t, r) {
2202
+ t.pendingLanes |= r, r !== 268435456 && (t.suspendedLanes = 0, t.pingedLanes = 0, t.warmLanes = 0);
2203
+ }
2204
+ function ti(t, r, a, l, c, d) {
2205
+ var h = t.pendingLanes;
2206
+ t.pendingLanes = a, t.suspendedLanes = 0, t.pingedLanes = 0, t.warmLanes = 0, t.expiredLanes &= a, t.entangledLanes &= a, t.errorRecoveryDisabledLanes &= a, t.shellSuspendCounter = 0;
2207
+ var y = t.entanglements, C = t.expirationTimes, R = t.hiddenUpdates;
2208
+ for (a = h & ~a; 0 < a; ) {
2209
+ var D = 31 - sn(a), U = 1 << D;
2210
+ y[D] = 0, C[D] = -1;
2211
+ var A = R[D];
2212
+ if (A !== null) for (R[D] = null, D = 0; D < A.length; D++) {
2213
+ var fe = A[D];
2214
+ fe !== null && (fe.lane &= -536870913);
2215
+ }
2216
+ a &= ~U;
2217
+ }
2218
+ l !== 0 && en(t, l, 0), d !== 0 && c === 0 && t.tag !== 0 && (t.suspendedLanes |= d & ~(h & ~r));
2219
+ }
2220
+ function en(t, r, a) {
2221
+ t.pendingLanes |= r, t.suspendedLanes &= ~r;
2222
+ var l = 31 - sn(r);
2223
+ t.entangledLanes |= r, t.entanglements[l] = t.entanglements[l] | 1073741824 | a & 261930;
2224
+ }
2225
+ function G(t, r) {
2226
+ var a = t.entangledLanes |= r;
2227
+ for (t = t.entanglements; a; ) {
2228
+ var l = 31 - sn(a), c = 1 << l;
2229
+ c & r | t[l] & r && (t[l] |= r), a &= ~c;
2230
+ }
2231
+ }
2232
+ function Wt(t, r) {
2233
+ var a = r & -r;
2234
+ return a = (a & 42) !== 0 ? 1 : mn(a), (a & (t.suspendedLanes | r)) !== 0 ? 0 : a;
2235
+ }
2236
+ function mn(t) {
2237
+ switch (t) {
2238
+ case 2:
2239
+ t = 1;
2240
+ break;
2241
+ case 8:
2242
+ t = 4;
2243
+ break;
2244
+ case 32:
2245
+ t = 16;
2246
+ break;
2247
+ case 256:
2248
+ case 512:
2249
+ case 1024:
2250
+ case 2048:
2251
+ case 4096:
2252
+ case 8192:
2253
+ case 16384:
2254
+ case 32768:
2255
+ case 65536:
2256
+ case 131072:
2257
+ case 262144:
2258
+ case 524288:
2259
+ case 1048576:
2260
+ case 2097152:
2261
+ case 4194304:
2262
+ case 8388608:
2263
+ case 16777216:
2264
+ case 33554432:
2265
+ t = 128;
2266
+ break;
2267
+ case 268435456:
2268
+ t = 134217728;
2269
+ break;
2270
+ default:
2271
+ t = 0;
2272
+ }
2273
+ return t;
2274
+ }
2275
+ function ze(t) {
2276
+ return t &= -t, 2 < t ? 8 < t ? (t & 134217727) !== 0 ? 32 : 268435456 : 8 : 2;
2277
+ }
2278
+ function ga(t) {
2279
+ if (typeof N == "function" && U0(t), It && typeof It.setStrictMode == "function") try {
2280
+ It.setStrictMode(Lu, t);
2281
+ } catch {
1514
2282
  }
1515
2283
  }
1516
2284
  function mt(t, r) {
@@ -13340,15 +14108,16 @@ function swapInteractivity(store, object, newObject) {
13340
14108
  pointerState.hovered.set(makeId(next), next);
13341
14109
  }
13342
14110
  });
13343
- const captureData = pointerState.captured.get(object);
13344
- if (captureData) {
13345
- pointerState.captured.delete(object);
13346
- pointerState.captured.set(newObject, {
14111
+ for (const [key, captureData] of Array.from(pointerState.captured)) {
14112
+ const { intersection } = captureData;
14113
+ if (key !== object && intersection.object !== object && intersection.eventObject !== object) continue;
14114
+ if (key === object) pointerState.captured.delete(key);
14115
+ pointerState.captured.set(key === object ? newObject : key, {
13347
14116
  ...captureData,
13348
14117
  intersection: {
13349
- ...captureData.intersection,
13350
- object: captureData.intersection.object === object ? newObject : captureData.intersection.object,
13351
- eventObject: captureData.intersection.eventObject === object ? newObject : captureData.intersection.eventObject
14118
+ ...intersection,
14119
+ object: intersection.object === object ? newObject : intersection.object,
14120
+ eventObject: intersection.eventObject === object ? newObject : intersection.eventObject
13352
14121
  }
13353
14122
  });
13354
14123
  }
@@ -13877,10 +14646,11 @@ const catalogue = globalThis[R3F_CATALOGUE] ?? (globalThis[R3F_CATALOGUE] = {});
13877
14646
  const R3F_EXTEND_ID = Symbol.for("@react-three/fiber.extendId");
13878
14647
  const ids = globalThis;
13879
14648
  const toPascalCase = (type) => `${type[0].toUpperCase()}${type.slice(1)}`;
13880
- const isConstructor = (object) => typeof object === "function";
14649
+ const isConstructor$1 = (object) => typeof object === "function";
13881
14650
  function extend(objects) {
13882
- if (isConstructor(objects)) {
13883
- const id = ids[R3F_EXTEND_ID] ?? 0;
14651
+ if (isConstructor$1(objects)) {
14652
+ let id = ids[R3F_EXTEND_ID] ?? 0;
14653
+ while (`${id}` in catalogue) id++;
13884
14654
  ids[R3F_EXTEND_ID] = id + 1;
13885
14655
  const Component = `${id}`;
13886
14656
  catalogue[Component] = objects;
@@ -13888,15 +14658,14 @@ function extend(objects) {
13888
14658
  } else {
13889
14659
  for (const name in objects) {
13890
14660
  const object = objects[name];
13891
- if (isConstructor(object)) catalogue[name] = object;
14661
+ if (isConstructor$1(object)) catalogue[name] = object;
13892
14662
  }
13893
14663
  }
13894
14664
  }
13895
-
13896
14665
  function resolveConstructor(name, root) {
13897
14666
  if (Object.prototype.hasOwnProperty.call(catalogue, name)) return catalogue[name];
13898
14667
  const object = root.getState().internal.support?.three[name];
13899
- return isConstructor(object) ? object : void 0;
14668
+ return isConstructor$1(object) ? object : void 0;
13900
14669
  }
13901
14670
 
13902
14671
  function createReconciler(config) {
@@ -13933,6 +14702,7 @@ function hideInstance(instance) {
13933
14702
  if (instance.props.attach && instance.parent?.object) {
13934
14703
  detach(instance.parent, instance);
13935
14704
  } else if (isObject3D(instance.object)) {
14705
+ instance.previousVisible = instance.object.visible;
13936
14706
  instance.object.visible = false;
13937
14707
  }
13938
14708
  instance.isHidden = true;
@@ -13943,9 +14713,10 @@ function unhideInstance(instance) {
13943
14713
  if (instance.isHidden) {
13944
14714
  if (instance.props.attach && instance.parent?.object) {
13945
14715
  attach(instance.parent, instance);
13946
- } else if (isObject3D(instance.object) && instance.props.visible !== false) {
13947
- instance.object.visible = true;
14716
+ } else if (isObject3D(instance.object)) {
14717
+ instance.object.visible = instance.previousVisible ?? true;
13948
14718
  }
14719
+ instance.previousVisible = void 0;
13949
14720
  instance.isHidden = false;
13950
14721
  invalidateInstance(instance);
13951
14722
  }
@@ -13958,6 +14729,7 @@ function handleContainerEffects(parent, child, beforeChild) {
13958
14729
  child.object = child.props.object ?? new target(...child.props.args ?? []);
13959
14730
  child.object.__r3f = child;
13960
14731
  }
14732
+ warnGLSLMaterialUnsupported(state, child.object);
13961
14733
  applyProps(child.object, child.props);
13962
14734
  if (child.props.attach) {
13963
14735
  attach(parent, child);
@@ -14439,476 +15211,48 @@ const reconciler = /* @__PURE__ */ createReconciler({
14439
15211
  commitNewChildToFragmentInstance(_child, _fragmentInstance) {
14440
15212
  },
14441
15213
  deleteChildFromFragmentInstance(_child, _fragmentInstance) {
14442
- },
14443
- // https://github.com/facebook/react/pull/32653
14444
- measureClonedInstance: (_instance) => null,
14445
- // https://github.com/facebook/react/pull/32819
14446
- maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
14447
- maySuspendCommitInSyncRender: (_type, _props) => false,
14448
- // https://github.com/facebook/react/pull/34486
14449
- startSuspendingCommit: () => null,
14450
- // https://github.com/facebook/react/pull/34522
14451
- getSuspendedCommitReason: (_state, _rootContainer) => null
14452
- });
14453
-
14454
- const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
14455
- function isInternalRendererAccess(stack, callerDepth = 2) {
14456
- if (!stack) return false;
14457
- const caller = stack.split("\n")[callerDepth] ?? "";
14458
- return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
14459
- }
14460
-
14461
- const createStore = (invalidate, advance) => {
14462
- const rootStore = traditional.createWithEqualityFn((set, get) => {
14463
- let position;
14464
- let defaultTarget;
14465
- let tempTarget;
14466
- function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
14467
- const { Vector3 } = getThree();
14468
- position ?? (position = new Vector3());
14469
- defaultTarget ?? (defaultTarget = new Vector3());
14470
- tempTarget ?? (tempTarget = new Vector3());
14471
- target ?? (target = defaultTarget);
14472
- const { width, height, top, left } = size;
14473
- const aspect = width / height;
14474
- if (target.isVector3) tempTarget.copy(target);
14475
- else tempTarget.set(...target);
14476
- const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
14477
- if (isOrthographicCamera(camera)) {
14478
- return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
14479
- } else {
14480
- const fov = camera.fov * Math.PI / 180;
14481
- const h = 2 * Math.tan(fov / 2) * distance;
14482
- const w = h * (width / height);
14483
- return { width: w, height: h, top, left, factor: width / w, distance, aspect };
14484
- }
14485
- }
14486
- let performanceTimeout = void 0;
14487
- const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
14488
- const rootState = {
14489
- set,
14490
- get,
14491
- // Mock objects that have to be configured
14492
- // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
14493
- primaryStore: null,
14494
- gl: null,
14495
- renderer: null,
14496
- camera: null,
14497
- // frustum, pointer and mouse are three objects; configure() creates them with the renderer
14498
- frustum: null,
14499
- autoUpdateFrustum: true,
14500
- raycaster: null,
14501
- events: {
14502
- priority: 1,
14503
- enabled: true,
14504
- connected: false,
14505
- frameTimedRaycasts: true,
14506
- alwaysFireOnScroll: true,
14507
- updateOnFrame: false
14508
- },
14509
- scene: null,
14510
- rootScene: null,
14511
- xr: null,
14512
- inspector: null,
14513
- invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
14514
- advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
14515
- textureColorSpace: "srgb",
14516
- // THREE.SRGBColorSpace
14517
- isLegacy: false,
14518
- webGPUSupported: false,
14519
- isNative: false,
14520
- controls: null,
14521
- pointer: null,
14522
- mouse: null,
14523
- frameloop: "always",
14524
- onPointerMissed: void 0,
14525
- onDragOverMissed: void 0,
14526
- onDropMissed: void 0,
14527
- performance: {
14528
- current: 1,
14529
- min: 0.5,
14530
- max: 1,
14531
- debounce: 200,
14532
- regress: () => {
14533
- const state2 = get();
14534
- if (performanceTimeout) clearTimeout(performanceTimeout);
14535
- if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
14536
- performanceTimeout = setTimeout(
14537
- () => setPerformanceCurrent(get().performance.max),
14538
- state2.performance.debounce
14539
- );
14540
- }
14541
- },
14542
- size: { width: 0, height: 0, top: 0, left: 0 },
14543
- viewport: {
14544
- initialDpr: 0,
14545
- dpr: 0,
14546
- width: 0,
14547
- height: 0,
14548
- top: 0,
14549
- left: 0,
14550
- aspect: 0,
14551
- distance: 0,
14552
- factor: 0,
14553
- getCurrentViewport
14554
- },
14555
- setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
14556
- setSize: (width, height, top, left) => {
14557
- const state2 = get();
14558
- if (width === void 0) {
14559
- set({ _sizeImperative: false });
14560
- if (state2._sizeProps) {
14561
- const { width: propW, height: propH } = state2._sizeProps;
14562
- if (propW !== void 0 || propH !== void 0) {
14563
- const currentSize = state2.size;
14564
- const newSize = {
14565
- width: propW ?? currentSize.width,
14566
- height: propH ?? currentSize.height,
14567
- top: currentSize.top,
14568
- left: currentSize.left
14569
- };
14570
- set((s) => ({
14571
- size: newSize,
14572
- viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
14573
- }));
14574
- get().invalidate();
14575
- }
14576
- }
14577
- return;
14578
- }
14579
- const w = width;
14580
- const h = height ?? width;
14581
- const t = top ?? state2.size.top;
14582
- const l = left ?? state2.size.left;
14583
- const size = { width: w, height: h, top: t, left: l };
14584
- set((s) => ({
14585
- size,
14586
- viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
14587
- _sizeImperative: true
14588
- }));
14589
- get().invalidate();
14590
- },
14591
- setDpr: (dpr) => set((state2) => {
14592
- const resolved = calculateDpr(dpr);
14593
- return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
14594
- }),
14595
- setFrameloop: (frameloop = "always") => {
14596
- const rootId = get().internal.rootId;
14597
- if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
14598
- set(() => ({ frameloop }));
14599
- },
14600
- setError: (error) => set(() => ({ error })),
14601
- error: null,
14602
- //* Texture registry (useTextures) ==============================
14603
- // TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
14604
- textures: /* @__PURE__ */ new Map(),
14605
- _textureRefs: /* @__PURE__ */ new Map(),
14606
- _sizeImperative: false,
14607
- _sizeProps: null,
14608
- previousRoot: void 0,
14609
- internal: {
14610
- // Events
14611
- interaction: [],
14612
- subscribers: [],
14613
- // Per-pointer state (new unified structure)
14614
- pointerMap: /* @__PURE__ */ new Map(),
14615
- pointerDirty: /* @__PURE__ */ new Map(),
14616
- lastEvent: React__namespace.createRef(),
14617
- // Deprecated but kept for backwards compatibility
14618
- hovered: /* @__PURE__ */ new Map(),
14619
- initialClick: [0, 0],
14620
- initialHits: [],
14621
- capturedMap: /* @__PURE__ */ new Map(),
14622
- // Visibility tracking (onFramed, onOccluded, onVisible)
14623
- visibilityRegistry: /* @__PURE__ */ new Map(),
14624
- // Occlusion system (WebGPU only)
14625
- occlusionEnabled: false,
14626
- occlusionObserver: null,
14627
- occlusionCache: /* @__PURE__ */ new Map(),
14628
- helperGroup: null,
14629
- // Updates
14630
- active: false,
14631
- frames: 0,
14632
- priority: 0,
14633
- subscribe: (ref, priority, store) => {
14634
- const internal = get().internal;
14635
- internal.priority = internal.priority + (priority > 0 ? 1 : 0);
14636
- internal.subscribers.push({ ref, priority, store });
14637
- internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
14638
- return () => {
14639
- const internal2 = get().internal;
14640
- if (internal2?.subscribers) {
14641
- internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
14642
- internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
14643
- }
14644
- };
14645
- },
14646
- // Renderer Storage (single source of truth)
14647
- actualRenderer: null,
14648
- // The renderer support configure() loads for this root
14649
- support: null,
14650
- // Scheduler for useFrameNext (initialized in renderer.tsx)
14651
- scheduler: null,
14652
- // Replaces the default render call when set (see setRenderOverride)
14653
- renderOverride: null
14654
- }
14655
- };
14656
- return rootState;
14657
- });
14658
- const state = rootStore.getState();
14659
- Object.defineProperty(state, "gl", {
14660
- get() {
14661
- const currentState = rootStore.getState();
14662
- if (!currentState.isLegacy && currentState.internal.actualRenderer) {
14663
- const stack = new Error().stack || "";
14664
- if (!isInternalRendererAccess(stack)) {
14665
- const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
14666
- extensions.notifyDepreciated({
14667
- heading: "Accessing state.gl in WebGPU mode",
14668
- body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
14669
- });
14670
- }
14671
- }
14672
- return currentState.internal.actualRenderer;
14673
- },
14674
- set(value) {
14675
- rootStore.getState().internal.actualRenderer = value;
14676
- },
14677
- enumerable: true,
14678
- configurable: true
14679
- });
14680
- Object.defineProperty(state, "renderer", {
14681
- get() {
14682
- return rootStore.getState().internal.actualRenderer;
14683
- },
14684
- set(value) {
14685
- rootStore.getState().internal.actualRenderer = value;
14686
- },
14687
- enumerable: true,
14688
- configurable: true
14689
- });
14690
- let oldScene = state.scene;
14691
- rootStore.subscribe(() => {
14692
- const currentState = rootStore.getState();
14693
- const { scene, rootScene, set } = currentState;
14694
- if (scene !== oldScene) {
14695
- oldScene = scene;
14696
- if (scene?.isScene && scene !== rootScene) {
14697
- set({ rootScene: scene });
14698
- }
14699
- }
14700
- });
14701
- let oldSize = state.size;
14702
- let oldDpr = state.viewport.dpr;
14703
- let oldCamera = state.camera;
14704
- rootStore.subscribe(() => {
14705
- const { camera, size, viewport, set, internal } = rootStore.getState();
14706
- const actualRenderer = internal.actualRenderer;
14707
- const canvasTarget = internal.canvasTarget;
14708
- if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
14709
- oldSize = size;
14710
- oldDpr = viewport.dpr;
14711
- updateCamera(camera, size);
14712
- const resizeTarget = canvasTarget ?? actualRenderer;
14713
- if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
14714
- resizeTarget.setSize(size.width, size.height, false);
14715
- const activeTarget = actualRenderer.getCanvasTarget?.();
14716
- if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
14717
- }
14718
- if (camera !== oldCamera) {
14719
- oldCamera = camera;
14720
- const { rootScene } = rootStore.getState();
14721
- if (camera && rootScene && !camera.parent) {
14722
- rootScene.add(camera);
14723
- }
14724
- set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
14725
- const currentState = rootStore.getState();
14726
- if (currentState.autoUpdateFrustum && camera) {
14727
- updateFrustum(camera, currentState.frustum);
14728
- }
14729
- }
14730
- });
14731
- rootStore.subscribe((state2) => invalidate(state2));
14732
- return rootStore;
14733
- };
14734
-
14735
- const primaryRegistry = /* @__PURE__ */ new Map();
14736
- const pendingSubscribers = /* @__PURE__ */ new Map();
14737
- function registerPrimary(id, renderer, store) {
14738
- if (primaryRegistry.has(id)) {
14739
- console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
14740
- }
14741
- const entry = { renderer, store };
14742
- primaryRegistry.set(id, entry);
14743
- const subscribers = pendingSubscribers.get(id);
14744
- if (subscribers) {
14745
- subscribers.forEach((callback) => callback(entry));
14746
- pendingSubscribers.delete(id);
14747
- }
14748
- return () => {
14749
- const currentEntry = primaryRegistry.get(id);
14750
- if (currentEntry?.renderer === renderer) {
14751
- primaryRegistry.delete(id);
14752
- }
14753
- };
14754
- }
14755
- function getPrimary(id) {
14756
- return primaryRegistry.get(id);
14757
- }
14758
- function waitForPrimary(id, timeout = 5e3) {
14759
- const existing = primaryRegistry.get(id);
14760
- if (existing) {
14761
- return Promise.resolve(existing);
14762
- }
14763
- return new Promise((resolve, reject) => {
14764
- const timeoutId = setTimeout(() => {
14765
- const subscribers = pendingSubscribers.get(id);
14766
- if (subscribers) {
14767
- const index = subscribers.indexOf(callback);
14768
- if (index !== -1) subscribers.splice(index, 1);
14769
- if (subscribers.length === 0) pendingSubscribers.delete(id);
14770
- }
14771
- reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
14772
- }, timeout);
14773
- const callback = (entry) => {
14774
- clearTimeout(timeoutId);
14775
- resolve(entry);
14776
- };
14777
- if (!pendingSubscribers.has(id)) {
14778
- pendingSubscribers.set(id, []);
14779
- }
14780
- pendingSubscribers.get(id).push(callback);
14781
- });
14782
- }
14783
- function hasPrimary(id) {
14784
- return primaryRegistry.has(id);
14785
- }
14786
- function unregisterPrimary(id) {
14787
- primaryRegistry.delete(id);
14788
- }
14789
- function getPrimaryIds() {
14790
- return Array.from(primaryRegistry.keys());
14791
- }
14792
-
14793
- const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
14794
- const tracked = (promise) => {
14795
- const result = Promise.resolve(promise);
14796
- result.status = "pending";
14797
- result.then(
14798
- (value) => {
14799
- Object.assign(result, { status: "fulfilled", value });
14800
- },
14801
- (reason) => {
14802
- Object.assign(result, { status: "rejected", reason });
14803
- }
14804
- );
14805
- return result;
14806
- };
14807
-
14808
- const records = /* @__PURE__ */ new WeakMap();
14809
- function take(renderer, record) {
14810
- record.leases++;
14811
- let released = false;
14812
- return () => {
14813
- if (released) return;
14814
- released = true;
14815
- if (--record.leases > 0) return;
14816
- records.delete(renderer);
14817
- if (record.owned) return disposeRenderer(renderer);
14818
- };
14819
- }
14820
- function leaseRenderer(renderer, owned) {
14821
- let record = records.get(renderer);
14822
- if (!record) records.set(renderer, record = { owned, leases: 0 });
14823
- return take(renderer, record);
14824
- }
14825
- function borrowRenderer(renderer) {
14826
- const record = records.get(renderer);
14827
- if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
14828
- return take(renderer, record);
14829
- }
14830
- function disposeRenderer(renderer) {
14831
- if (renderer.hasInitialized?.() === false) return;
14832
- const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
14833
- const loseContext = () => {
14834
- try {
14835
- ;
14836
- renderer.forceContextLoss?.();
14837
- } catch (error) {
14838
- warn(error);
14839
- }
14840
- };
14841
- let disposed;
14842
- try {
14843
- disposed = renderer.dispose();
14844
- } catch (error) {
14845
- warn(error);
14846
- }
14847
- if (typeof disposed?.then === "function") {
14848
- return Promise.resolve(disposed).then(loseContext, (error) => {
14849
- warn(error);
14850
- loseContext();
14851
- });
14852
- }
14853
- loseContext();
14854
- }
14855
-
14856
- const isRenderer = (def) => !!def?.render;
14857
- const _roots = /* @__PURE__ */ new Map();
14858
- function ensureStoreThreeObjects(store) {
14859
- const state = store.getState();
14860
- if (state.pointer) return;
14861
- const { Vector2, Frustum } = getThree();
14862
- const pointer = new Vector2();
14863
- state.set({ pointer, mouse: pointer, frustum: new Frustum() });
14864
- }
14865
- const shallowLoose = { objects: "shallow", strict: false };
14866
- async function resolveRenderer(config, defaultProps, RendererClass) {
14867
- if (typeof config === "function") return { renderer: await config(defaultProps), owned: true };
14868
- if (isRenderer(config)) return { renderer: config, owned: false };
14869
- return { renderer: new RendererClass({ ...defaultProps, ...config }), owned: true };
14870
- }
14871
- function computeInitialSize(canvas, size) {
14872
- if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
14873
- const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
14874
- return { width, height, top, left };
14875
- } else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
14876
- return {
14877
- width: canvas.width,
14878
- height: canvas.height,
14879
- top: 0,
14880
- left: 0
14881
- };
14882
- }
14883
- return { width: 0, height: 0, top: 0, left: 0, ...size };
15214
+ },
15215
+ // https://github.com/facebook/react/pull/32653
15216
+ measureClonedInstance: (_instance) => null,
15217
+ // https://github.com/facebook/react/pull/32819
15218
+ maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
15219
+ maySuspendCommitInSyncRender: (_type, _props) => false,
15220
+ // https://github.com/facebook/react/pull/34486
15221
+ startSuspendingCommit: () => null,
15222
+ // https://github.com/facebook/react/pull/34522
15223
+ getSuspendedCommitReason: (_state, _rootContainer) => null
15224
+ });
15225
+ function flushSync(fn) {
15226
+ return reconciler.flushSyncFromReconciler(fn);
14884
15227
  }
14885
- function watchDpr(onChange) {
14886
- if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
14887
- return () => {
14888
- };
14889
- }
14890
- let query;
14891
- const listen = () => {
14892
- try {
14893
- query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
14894
- if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
14895
- else query?.addListener?.(handleChange);
14896
- } catch {
14897
- query = void 0;
15228
+
15229
+ const noop = () => {
15230
+ };
15231
+ const _roots = /* @__PURE__ */ new Map();
15232
+ function transitionRoot(root, event) {
15233
+ const state = root.state;
15234
+ switch (event.type) {
15235
+ case "use":
15236
+ if (state.status === "disposed") return false;
15237
+ if (state.status === "closing") {
15238
+ root.store.getState().internal.active = true;
15239
+ state.settle();
15240
+ }
15241
+ root.state = { status: "open" };
15242
+ return true;
15243
+ case "unmount": {
15244
+ if (state.status === "disposed") return false;
15245
+ if (state.status === "closing") state.settle();
15246
+ const { promise, resolve } = deferred();
15247
+ root.state = { status: "closing", token: event.token, settled: promise, settle: resolve };
15248
+ return true;
14898
15249
  }
14899
- };
14900
- const unlisten = () => {
14901
- if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
14902
- else query?.removeListener?.(handleChange);
14903
- query = void 0;
14904
- };
14905
- const handleChange = () => {
14906
- unlisten();
14907
- listen();
14908
- onChange();
14909
- };
14910
- listen();
14911
- return unlisten;
15250
+ case "dispose":
15251
+ if (state.status !== "closing" || state.token !== event.token) return false;
15252
+ root.state = { status: "disposed" };
15253
+ state.settle();
15254
+ return true;
15255
+ }
14912
15256
  }
14913
15257
  function createRoot(canvas, provider) {
14914
15258
  const prevRoot = _roots.get(canvas);
@@ -14946,585 +15290,670 @@ function createRoot(canvas, provider) {
14946
15290
  null
14947
15291
  // transitionCallbacks
14948
15292
  );
14949
- const root = prevRoot || { fiber, store, unmountClaim: null, ready: fulfilled(void 0) };
14950
- if (!prevRoot) _roots.set(canvas, root);
14951
- let onCreated;
14952
- let lastCamera;
14953
- const lastConfiguredProps = {};
14954
- let resolvedDpr = 0;
14955
- let dprChangedInXR = false;
14956
- let unwatchDpr;
14957
- const resolveDpr = () => {
14958
- if (_roots.get(canvas)?.store !== store) return unwatchDpr?.();
14959
- const state = store.getState();
14960
- const xr = state.internal.actualRenderer?.xr;
14961
- if (xr?.isPresenting || xr?.getSession?.()) {
14962
- dprChangedInXR = true;
14963
- return;
14964
- }
14965
- dprChangedInXR = false;
14966
- const dpr = lastConfiguredProps.dpr;
14967
- if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
14968
- state.setDpr(dpr);
14969
- resolvedDpr = store.getState().viewport.dpr;
14970
- };
14971
- let configured = false;
14972
- let pending = null;
14973
- const cancelUnmount = () => {
14974
- if (!root.unmountClaim) return;
14975
- root.unmountClaim = null;
14976
- store.getState().internal.active = true;
15293
+ const root = prevRoot || {
15294
+ fiber,
15295
+ store,
15296
+ state: { status: "open" },
15297
+ ready: fulfilled(void 0),
15298
+ configuration: {}
14977
15299
  };
15300
+ if (!prevRoot) _roots.set(canvas, root);
15301
+ if (!prevRoot) root.configuration.apply = createRootConfiguration(store, canvas);
15302
+ let mounted = false;
14978
15303
  return {
14979
- async configure(props = {}) {
14980
- if (_roots.get(canvas) !== root) throw new Error("R3F: cannot configure a root after it has unmounted");
14981
- cancelUnmount();
14982
- let resolve;
14983
- pending = new Promise((_resolve) => resolve = _resolve);
14984
- const {
14985
- id: canvasId,
14986
- primaryCanvas,
14987
- scheduler: schedulerConfig,
14988
- gl: glConfig,
14989
- renderer: rendererConfig,
14990
- size: propsSize,
14991
- scene: sceneOptions,
14992
- events,
14993
- onCreated: onCreatedCallback,
14994
- shadows = false,
14995
- orthographic = false,
14996
- frameloop = "always",
14997
- dpr = [1, 2],
14998
- performance,
14999
- raycaster: raycastOptions,
15000
- camera: cameraOptions,
15001
- onPointerMissed,
15002
- onDragOverMissed,
15003
- onDropMissed,
15004
- autoUpdateFrustum = true,
15005
- occlusion = false,
15006
- _sizeProps,
15007
- forceEven
15008
- } = props;
15009
- const requestedTextureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || void 0;
15010
- let state = store.getState();
15011
- const { webgl, webgpu } = provider;
15012
- const defaultGLProps = {
15013
- canvas,
15014
- powerPreference: "high-performance",
15015
- antialias: true,
15016
- alpha: true
15304
+ get ready() {
15305
+ return root.ready;
15306
+ },
15307
+ configure(props = {}) {
15308
+ if (!transitionRoot(root, { type: "use" })) {
15309
+ return rejected(new Error("R3F: Cannot configure a root after it has unmounted (disposal has started)."));
15310
+ }
15311
+ const previous = root.ready;
15312
+ const { promise, resolve, reject } = deferred();
15313
+ root.ready = promise;
15314
+ const run = () => {
15315
+ try {
15316
+ const initialized = initializeRenderer(canvas, provider, store, props);
15317
+ const apply = () => {
15318
+ if (props.id) {
15319
+ for (const other of _roots.values()) {
15320
+ if (other !== root && other.state.status === "closing" && other.store.getState().internal.rootId === props.id) {
15321
+ other.state.settled.then(apply).catch(reject);
15322
+ return;
15323
+ }
15324
+ }
15325
+ }
15326
+ const previous2 = root.configuration.previous;
15327
+ root.configuration.apply(props);
15328
+ configureScheduler(store, props.id, props.scheduler, previous2?.scheduler);
15329
+ textureStaging.attachRootExtensions(store);
15330
+ root.configuration.previous = props;
15331
+ resolve(this);
15332
+ };
15333
+ if (isPromiseLike(initialized)) Promise.resolve(initialized).then(apply).catch(reject);
15334
+ else apply();
15335
+ } catch (error) {
15336
+ reject(error);
15337
+ }
15017
15338
  };
15018
- const defaultGPUProps = {
15019
- canvas,
15020
- antialias: true
15339
+ if (previous.status === "pending") previous.then(run, reject);
15340
+ else run();
15341
+ return promise;
15342
+ },
15343
+ render(children) {
15344
+ if (!transitionRoot(root, { type: "use" })) return store;
15345
+ if (!store.getState().internal.actualRenderer && root.ready.status === "fulfilled") this.configure();
15346
+ if (root.ready.status === "rejected") throw root.ready.reason;
15347
+ const commit = () => {
15348
+ if (root.state.status !== "open" || root.ready.status === "rejected") return;
15349
+ if (root.ready.status === "pending") {
15350
+ root.ready.then(commit, logRecoverableError);
15351
+ return;
15352
+ }
15353
+ const onCreated = root.configuration.previous?.onCreated;
15354
+ const element = /* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas });
15355
+ if (mounted) {
15356
+ reconciler.updateContainer(element, fiber, null, noop);
15357
+ return;
15358
+ }
15359
+ mounted = true;
15360
+ reconciler.updateContainerSync(element, fiber, null, noop);
15361
+ reconciler.flushSyncWork();
15021
15362
  };
15022
- if (glConfig && !webgl) {
15023
- throw new Error(
15024
- "WebGLRenderer (gl prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/legacy instead."
15025
- );
15026
- }
15027
- if (rendererConfig && !webgpu) {
15028
- throw new Error(
15029
- "WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
15030
- );
15031
- }
15032
- const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig);
15033
- if (glConfig && rendererConfig) {
15034
- throw new Error("Cannot use both gl and renderer props at the same time");
15035
- }
15036
- if (webgl && webgpu && !state.isLegacy && wantsGL) {
15037
- extensions.notifyDepreciated({
15038
- heading: "WebGlRenderer Usage",
15039
- body: "WebGlRenderer usage is deprecated in favor of WebGPU. Import from /legacy directly or upgrade to WebGPU.",
15040
- link: "https://docs.pmnd.rs/react-three-fiber/api/renderer"
15041
- });
15363
+ commit();
15364
+ return store;
15365
+ },
15366
+ unmount() {
15367
+ if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
15368
+ }
15369
+ };
15370
+ }
15371
+ function Provider({
15372
+ store,
15373
+ children,
15374
+ onCreated,
15375
+ rootElement
15376
+ }) {
15377
+ textureStaging.useIsomorphicLayoutEffect(() => {
15378
+ const state = store.getState();
15379
+ state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
15380
+ if (onCreated) onCreated(state);
15381
+ if (!store.getState().events.connected) state.events.connect?.(rootElement);
15382
+ }, []);
15383
+ return /* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: store, children });
15384
+ }
15385
+ function unmountComponentAtNode(canvas, callback) {
15386
+ const claim = Symbol("unmount");
15387
+ const root = _roots.get(canvas);
15388
+ if (!root || !transitionRoot(root, { type: "unmount", token: claim })) return;
15389
+ root.store.getState().internal.active = false;
15390
+ reconciler.updateContainer(null, root.fiber, null, () => {
15391
+ if (root.state.status !== "closing" || root.state.token !== claim) return;
15392
+ reconciler.updateContainer(null, root.fiber, null, () => {
15393
+ if (root.state.status !== "closing" || root.state.token !== claim) return;
15394
+ if (root.ready.status === "pending") root.ready.then(teardown, teardown);
15395
+ else teardown();
15396
+ });
15397
+ });
15398
+ function teardown() {
15399
+ if (root.ready.status === "pending") {
15400
+ root.ready.then(teardown, teardown);
15401
+ return;
15402
+ }
15403
+ if (!transitionRoot(root, { type: "dispose", token: claim })) return;
15404
+ _roots.delete(canvas);
15405
+ const state = root.store.getState();
15406
+ const internal = state.internal;
15407
+ internal.active = false;
15408
+ const attempt = (step) => {
15409
+ try {
15410
+ return step();
15411
+ } catch (error) {
15412
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15042
15413
  }
15043
- let renderer = state.internal.actualRenderer;
15044
- if (primaryCanvas && !webgpu) {
15045
- throw new Error(
15046
- "The `primaryCanvas` prop for multi-canvas rendering is only available with WebGPU. Use @react-three/fiber/webgpu instead."
15047
- );
15414
+ };
15415
+ attempt(() => internal.unwatchDpr?.());
15416
+ internal.unwatchDpr = void 0;
15417
+ attempt(() => internal.unregisterRoot?.());
15418
+ internal.unregisterRoot = void 0;
15419
+ attempt(() => textureStaging.detachRootExtensions(root.store));
15420
+ attempt(() => internal.unregisterPrimary?.());
15421
+ attempt(() => internal.untrackStandalone?.());
15422
+ attempt(() => state.events.disconnect?.());
15423
+ if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
15424
+ attempt(() => cleanupHelperGroup(root.store));
15425
+ if (state.scene) attempt(() => dispose(state.scene));
15426
+ const canvasTarget = internal.canvasTarget;
15427
+ if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
15428
+ const released = attempt(() => internal.releaseRenderer?.());
15429
+ internal.releaseRenderer = void 0;
15430
+ if (callback) {
15431
+ if (released) {
15432
+ released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
15433
+ } else {
15434
+ callback(canvas);
15048
15435
  }
15049
- if (primaryCanvas && wantsGL) {
15050
- throw new Error(
15051
- "The `primaryCanvas` prop for multi-canvas rendering cannot be used with WebGL. Remove the `gl` prop or use WebGPU."
15052
- );
15436
+ }
15437
+ }
15438
+ }
15439
+
15440
+ const memoizedLoaders = /* @__PURE__ */ new WeakMap();
15441
+ const isConstructor = (value) => typeof value === "function" && value?.prototype?.constructor === value;
15442
+ function getLoader(Proto) {
15443
+ if (isConstructor(Proto)) {
15444
+ let loader = memoizedLoaders.get(Proto);
15445
+ if (!loader) {
15446
+ loader = new Proto();
15447
+ memoizedLoaders.set(Proto, loader);
15448
+ }
15449
+ return loader;
15450
+ }
15451
+ return Proto;
15452
+ }
15453
+ function loadingFn(extensions, onProgress) {
15454
+ return function(Proto, input) {
15455
+ const loader = getLoader(Proto);
15456
+ if (extensions) extensions(loader);
15457
+ if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
15458
+ return loader.loadAsync(input, onProgress).then((data) => {
15459
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
15460
+ return data;
15461
+ });
15462
+ }
15463
+ return new Promise(
15464
+ (res, reject) => loader.load(
15465
+ input,
15466
+ (data) => {
15467
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
15468
+ res(data);
15469
+ },
15470
+ onProgress,
15471
+ (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
15472
+ )
15473
+ );
15474
+ };
15475
+ }
15476
+ function useLoader(loader, input, extensions, onProgress, cacheKey) {
15477
+ const inputs = Array.isArray(input) ? input : [input];
15478
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15479
+ const fn = loadingFn(extensions, onProgress);
15480
+ const results = cacheKeys.map(
15481
+ (key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
15482
+ );
15483
+ const stableRef = React.useRef(null);
15484
+ const previous = stableRef.current;
15485
+ const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
15486
+ stableRef.current = stable;
15487
+ return Array.isArray(input) ? stable : stable[0];
15488
+ }
15489
+ useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
15490
+ const inputs = Array.isArray(input) ? input : [input];
15491
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15492
+ cacheKeys.forEach(
15493
+ (key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
15494
+ );
15495
+ };
15496
+ useLoader.clear = function(loader, input, cacheKey) {
15497
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15498
+ cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
15499
+ };
15500
+ useLoader.loader = getLoader;
15501
+
15502
+ const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
15503
+ function getUrls(input) {
15504
+ if (typeof input === "string") return [input];
15505
+ if (Array.isArray(input)) return input;
15506
+ return Object.values(input);
15507
+ }
15508
+ function inputSignature(input) {
15509
+ if (typeof input === "string") return input;
15510
+ if (Array.isArray(input)) return input.join("\0");
15511
+ return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
15512
+ }
15513
+ function allUrlsCached(urls, textureCache) {
15514
+ return urls.every((url) => textureCache.has(url));
15515
+ }
15516
+ function buildFromCache(input, textureCache) {
15517
+ if (typeof input === "string") {
15518
+ return textureCache.get(input);
15519
+ } else if (Array.isArray(input)) {
15520
+ return input.map((url) => textureCache.get(url));
15521
+ } else {
15522
+ const result = {};
15523
+ const objInput = input;
15524
+ for (const key in objInput) {
15525
+ result[key] = textureCache.get(objInput[key]);
15526
+ }
15527
+ return result;
15528
+ }
15529
+ }
15530
+ function useTexture(input, optionsOrOnLoad) {
15531
+ const renderer = textureStaging.useThree((state) => state.internal.actualRenderer);
15532
+ const store = textureStaging.useStore();
15533
+ const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
15534
+ const { onLoad, cache = true } = options;
15535
+ const onLoadRef = React.useRef(onLoad);
15536
+ onLoadRef.current = onLoad;
15537
+ const onLoadCalledForRef = React.useRef(null);
15538
+ const inputKey = React.useMemo(() => inputSignature(input), [input]);
15539
+ const stableInput = React.useMemo(() => input, [inputKey]);
15540
+ const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
15541
+ const cachedResult = React.useMemo(() => {
15542
+ if (!cache) return null;
15543
+ const textures = store.getState().textures;
15544
+ if (!allUrlsCached(urls, textures)) return null;
15545
+ return buildFromCache(stableInput, textures);
15546
+ }, [cache, urls, stableInput, store]);
15547
+ const loadedTextures = useLoader(
15548
+ getThree().TextureLoader,
15549
+ IsObject(stableInput) ? Object.values(stableInput) : stableInput
15550
+ );
15551
+ const mappedTextures = React.useMemo(() => {
15552
+ if (cachedResult) return cachedResult;
15553
+ if (IsObject(stableInput)) {
15554
+ const keyed = {};
15555
+ const textureArray = loadedTextures;
15556
+ let i = 0;
15557
+ for (const key in stableInput) keyed[key] = textureArray[i++];
15558
+ return keyed;
15559
+ } else {
15560
+ return loadedTextures;
15561
+ }
15562
+ }, [stableInput, loadedTextures, cachedResult]);
15563
+ React.useLayoutEffect(() => {
15564
+ if (cachedResult) return;
15565
+ if (onLoadCalledForRef.current === inputKey) return;
15566
+ onLoadCalledForRef.current = inputKey;
15567
+ onLoadRef.current?.(mappedTextures);
15568
+ }, [cachedResult, mappedTextures, inputKey]);
15569
+ React.useEffect(() => {
15570
+ if (cachedResult) return;
15571
+ if ("initTexture" in renderer) {
15572
+ let textureArray = [];
15573
+ if (Array.isArray(loadedTextures)) {
15574
+ textureArray = loadedTextures;
15575
+ } else if (loadedTextures.isTexture) {
15576
+ textureArray = [loadedTextures];
15577
+ } else if (IsObject(loadedTextures)) {
15578
+ textureArray = Object.values(loadedTextures);
15053
15579
  }
15054
- if (!state.internal.actualRenderer) {
15055
- if (root.ready.status !== "pending") {
15056
- const setup = (async () => {
15057
- const support = wantsGL ? await webgl() : await webgpu();
15058
- registerThree(support.three);
15059
- state.internal.support = support;
15060
- ensureStoreThreeObjects(store);
15061
- if (support.kind === "webgl") {
15062
- const resolved = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
15063
- renderer = resolved.renderer;
15064
- state.internal.actualRenderer = renderer;
15065
- state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
15066
- state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
15067
- } else if (primaryCanvas) {
15068
- const primary = await waitForPrimary(primaryCanvas);
15069
- renderer = primary.renderer;
15070
- state.internal.actualRenderer = renderer;
15071
- state.internal.releaseRenderer = borrowRenderer(renderer);
15072
- const canvasTarget = new support.CanvasTarget(canvas);
15073
- primary.store.setState((prev) => ({
15074
- internal: { ...prev.internal, isMultiCanvas: true }
15075
- }));
15076
- state.set((prev) => ({
15077
- webGPUSupported: primary.store.getState().webGPUSupported,
15078
- renderer,
15079
- primaryStore: primary.store,
15080
- internal: {
15081
- ...prev.internal,
15082
- canvasTarget,
15083
- isMultiCanvas: true,
15084
- isSecondary: true,
15085
- targetId: primaryCanvas
15086
- }
15087
- }));
15088
- } else {
15089
- const resolved = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
15090
- renderer = resolved.renderer;
15091
- if (!renderer.hasInitialized?.()) {
15092
- const size2 = computeInitialSize(canvas, propsSize);
15093
- if (size2.width > 0 && size2.height > 0) {
15094
- renderer.setPixelRatio(calculateDpr(dpr));
15095
- renderer.setSize(size2.width, size2.height, false);
15096
- }
15097
- await renderer.init();
15098
- }
15099
- const backend = renderer.backend;
15100
- const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
15101
- state.internal.actualRenderer = renderer;
15102
- state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
15103
- state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
15104
- if (canvasId && !state.internal.isSecondary) {
15105
- const canvasTarget = renderer.getCanvasTarget?.();
15106
- const unregisterPrimary = registerPrimary(canvasId, renderer, store);
15107
- state.set((prev) => ({
15108
- internal: {
15109
- ...prev.internal,
15110
- canvasTarget,
15111
- unregisterPrimary
15112
- }
15113
- }));
15114
- }
15115
- }
15116
- })();
15117
- root.ready = tracked(setup);
15580
+ textureArray.forEach((texture) => {
15581
+ if (texture?.isTexture) {
15582
+ renderer.initTexture(texture);
15583
+ }
15584
+ });
15585
+ }
15586
+ }, [renderer, loadedTextures, cachedResult]);
15587
+ React.useEffect(() => {
15588
+ if (!cache) return;
15589
+ const urlTextureMap = urlTextureEntries(stableInput, mappedTextures);
15590
+ store.setState((state) => {
15591
+ const refs = new Map(state._textureRefs);
15592
+ let textures = state.textures;
15593
+ let added = false;
15594
+ for (const [url, texture] of urlTextureMap) {
15595
+ if (!textures.has(url)) {
15596
+ if (!added) {
15597
+ textures = new Map(textures);
15598
+ added = true;
15599
+ }
15600
+ textures.set(url, texture);
15118
15601
  }
15119
- await root.ready;
15120
- state = store.getState();
15121
- renderer = state.internal.actualRenderer;
15602
+ refs.set(url, (refs.get(url) ?? 0) + 1);
15122
15603
  }
15123
- const three = getThree();
15124
- let raycaster = state.raycaster;
15125
- if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
15126
- const { params, ...options } = raycastOptions || {};
15127
- if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
15128
- if (!is.equ(params, raycaster.params, shallowLoose)) {
15129
- applyProps(raycaster, { params: { ...raycaster.params, ...params } });
15604
+ return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
15605
+ });
15606
+ textureStaging.unstageTextures(
15607
+ store,
15608
+ urlTextureMap.map(([url]) => url)
15609
+ );
15610
+ return () => store.setState((state) => {
15611
+ const refs = new Map(state._textureRefs);
15612
+ for (const [url] of urlTextureMap) {
15613
+ const next = (refs.get(url) ?? 0) - 1;
15614
+ if (next <= 0) refs.delete(url);
15615
+ else refs.set(url, next);
15130
15616
  }
15131
- let tempCamera = state.camera;
15132
- if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
15133
- lastCamera = cameraOptions;
15134
- const isCamera = cameraOptions?.isCamera;
15135
- const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
15136
- if (!isCamera) {
15137
- camera.position.z = 5;
15138
- if (cameraOptions) {
15139
- applyProps(camera, cameraOptions);
15140
- if (!camera.manual) {
15141
- const projectionProps = ["aspect", "left", "right", "bottom", "top"];
15142
- if (projectionProps.some((prop) => prop in cameraOptions)) {
15143
- camera.manual = true;
15144
- camera.updateProjectionMatrix();
15145
- }
15146
- }
15617
+ return { _textureRefs: refs };
15618
+ });
15619
+ }, [cache, stableInput, mappedTextures, store]);
15620
+ if (cache && !cachedResult) textureStaging.stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
15621
+ return mappedTextures;
15622
+ }
15623
+ function urlTextureEntries(input, textures) {
15624
+ if (typeof input === "string") return [[input, textures]];
15625
+ if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
15626
+ const record = textures;
15627
+ return Object.keys(input).map((key) => [input[key], record[key]]);
15628
+ }
15629
+ useTexture.preload = (url) => {
15630
+ whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
15631
+ };
15632
+ useTexture.clear = (input) => {
15633
+ if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
15634
+ };
15635
+ const Texture = ({
15636
+ children,
15637
+ input,
15638
+ onLoad,
15639
+ cache
15640
+ }) => {
15641
+ const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
15642
+ const ret = useTexture(input, options);
15643
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
15644
+ };
15645
+
15646
+ function useTextures(selector) {
15647
+ const store = textureStaging.useStore();
15648
+ const registry = React.useMemo(() => {
15649
+ const getState = store.getState;
15650
+ const setState = store.setState;
15651
+ const getOne = (key) => getState().textures.get(key);
15652
+ return {
15653
+ get all() {
15654
+ return getState().textures;
15655
+ },
15656
+ get(input) {
15657
+ if (typeof input === "string") return getOne(input);
15658
+ if (Array.isArray(input)) return input.map(getOne);
15659
+ const out = {};
15660
+ for (const name in input) out[name] = getOne(input[name]);
15661
+ return out;
15662
+ },
15663
+ has: (key) => getState().textures.has(key),
15664
+ add(keyOrRecord, texture) {
15665
+ setState((state) => {
15666
+ const textures = new Map(state.textures);
15667
+ if (typeof keyOrRecord === "string") {
15668
+ textures.set(keyOrRecord, texture);
15669
+ } else {
15670
+ for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
15147
15671
  }
15148
- if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
15672
+ return { textures };
15673
+ });
15674
+ },
15675
+ dispose(key, options) {
15676
+ const state = getState();
15677
+ const refs = state._textureRefs.get(key) ?? 0;
15678
+ if (refs > 0 && !options?.force) {
15679
+ console.warn(
15680
+ `[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
15681
+ );
15682
+ return false;
15149
15683
  }
15150
- state.set({ camera });
15151
- tempCamera = camera;
15152
- raycaster.camera = camera;
15153
- }
15154
- if (!state.scene) {
15155
- let scene;
15156
- if (sceneOptions?.isScene) {
15157
- scene = sceneOptions;
15158
- prepare(scene, store, "", {});
15159
- } else {
15160
- scene = new three.Scene();
15161
- prepare(scene, store, "", {});
15162
- if (sceneOptions) applyProps(scene, sceneOptions);
15163
- }
15164
- state.set((prev) => ({
15165
- scene,
15166
- rootScene: scene,
15167
- internal: { ...prev.internal, container: scene }
15168
- }));
15169
- const camera = tempCamera;
15170
- if (camera && !camera.parent) scene.add(camera);
15171
- }
15172
- if (events && !state.events.handlers) {
15173
- state.set({ events: events(store) });
15174
- let wasEnabled = true;
15175
- store.subscribe((state2) => {
15176
- const { enabled } = state2.events;
15177
- if (enabled && !wasEnabled) {
15178
- state2.events.update?.();
15179
- }
15180
- wasEnabled = enabled;
15684
+ state.textures.get(key)?.dispose();
15685
+ setState((s) => {
15686
+ const textures = new Map(s.textures);
15687
+ textures.delete(key);
15688
+ const nextRefs = new Map(s._textureRefs);
15689
+ nextRefs.delete(key);
15690
+ return { textures, _textureRefs: nextRefs };
15181
15691
  });
15692
+ return true;
15693
+ },
15694
+ disposeAll() {
15695
+ for (const texture of getState().textures.values()) texture.dispose();
15696
+ setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
15182
15697
  }
15183
- if (_sizeProps !== void 0) {
15184
- state.set({ _sizeProps });
15185
- }
15186
- if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
15187
- state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
15698
+ };
15699
+ }, [store]);
15700
+ const subscribe = selector ? () => selector(registry) : (state) => state.textures;
15701
+ const selected = textureStaging.useThree(subscribe);
15702
+ return selector ? selected : registry;
15703
+ }
15704
+
15705
+ function useRenderTarget(widthOrOptions, heightOrOptions, options) {
15706
+ const support = textureStaging.useThree((s) => s.internal.support);
15707
+ const size = textureStaging.useThree((s) => s.size);
15708
+ let width;
15709
+ let height;
15710
+ let opts;
15711
+ if (typeof widthOrOptions === "object") {
15712
+ opts = widthOrOptions;
15713
+ } else if (typeof widthOrOptions === "number") {
15714
+ width = widthOrOptions;
15715
+ if (typeof heightOrOptions === "object") {
15716
+ height = widthOrOptions;
15717
+ opts = heightOrOptions;
15718
+ } else if (typeof heightOrOptions === "number") {
15719
+ height = heightOrOptions;
15720
+ opts = options;
15721
+ } else {
15722
+ height = widthOrOptions;
15723
+ }
15724
+ }
15725
+ return React.useMemo(() => {
15726
+ const w = width ?? size.width;
15727
+ const h = height ?? size.height;
15728
+ const Target = support.RenderTarget;
15729
+ return new Target(w, h, opts);
15730
+ }, [width, height, size.width, size.height, opts, support]);
15731
+ }
15732
+
15733
+ const presetsObj = {
15734
+ apartment: "lebombo_1k.hdr",
15735
+ city: "potsdamer_platz_1k.hdr",
15736
+ dawn: "kiara_1_dawn_1k.hdr",
15737
+ forest: "forest_slope_1k.hdr",
15738
+ lobby: "st_fagans_interior_1k.hdr",
15739
+ night: "dikhololo_night_1k.hdr",
15740
+ park: "rooitou_park_1k.hdr",
15741
+ studio: "studio_small_03_1k.hdr",
15742
+ sunset: "venice_sunset_1k.hdr",
15743
+ warehouse: "empty_warehouse_01_1k.hdr"
15744
+ };
15745
+
15746
+ const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
15747
+ const isArray = (arr) => Array.isArray(arr);
15748
+ const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
15749
+ const loadedLoaders = /* @__PURE__ */ new Map();
15750
+ const pendingLoaders = /* @__PURE__ */ new Map();
15751
+ function loadLoader(format) {
15752
+ let pending = pendingLoaders.get(format);
15753
+ if (!pending) {
15754
+ pending = importLoader(format).then(
15755
+ (loader) => {
15756
+ loadedLoaders.set(format, loader);
15757
+ return loader;
15758
+ },
15759
+ (error) => {
15760
+ pendingLoaders.delete(format);
15761
+ throw error;
15188
15762
  }
15189
- const size = computeInitialSize(canvas, propsSize);
15190
- if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
15191
- const wasImperative = state._sizeImperative;
15192
- state.setSize(size.width, size.height, size.top, size.left);
15193
- if (!wasImperative) state.set({ _sizeImperative: false });
15194
- }
15195
- if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
15196
- state.setDpr(dpr);
15197
- lastConfiguredProps.dpr = dpr;
15198
- resolvedDpr = store.getState().viewport.dpr;
15199
- }
15200
- const internal = store.getState().internal;
15201
- if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
15202
- internal.unwatchDpr?.();
15203
- internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
15204
- }
15205
- if (frameloop !== void 0 && frameloop !== lastConfiguredProps.frameloop) {
15206
- state.setFrameloop(frameloop);
15207
- lastConfiguredProps.frameloop = frameloop;
15208
- }
15209
- if (!state.onPointerMissed) state.set({ onPointerMissed });
15210
- if (!state.onDragOverMissed) state.set({ onDragOverMissed });
15211
- if (!state.onDropMissed) state.set({ onDropMissed });
15212
- if (state.autoUpdateFrustum !== autoUpdateFrustum) state.set({ autoUpdateFrustum });
15213
- if (occlusion && !state.internal.occlusionEnabled) {
15214
- enableOcclusion(store);
15215
- }
15216
- if (performance && !is.equ(performance, lastConfiguredProps.performance, shallowLoose)) {
15217
- state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
15218
- lastConfiguredProps.performance = performance;
15219
- }
15220
- if (!state.xr) {
15221
- const handleXRFrame = (timestamp, _frame) => {
15222
- const state2 = store.getState();
15223
- if (state2.frameloop === "never") return;
15224
- advance(timestamp, true, state2);
15225
- };
15226
- const actualRenderer = state.internal.actualRenderer;
15227
- const handleSessionChange = () => {
15228
- const state2 = store.getState();
15229
- const renderer2 = state2.internal.actualRenderer;
15230
- actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
15231
- renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
15232
- if (!renderer2.xr.isPresenting) {
15233
- if (dprChangedInXR) resolveDpr();
15234
- invalidate(state2);
15235
- }
15236
- };
15237
- const xr = {
15238
- connect() {
15239
- const { gl, renderer: renderer2 } = store.getState();
15240
- const xrManager = (renderer2 || gl).xr;
15241
- xrManager.addEventListener("sessionstart", handleSessionChange);
15242
- xrManager.addEventListener("sessionend", handleSessionChange);
15243
- },
15244
- disconnect() {
15245
- const { gl, renderer: renderer2 } = store.getState();
15246
- const xrManager = (renderer2 || gl).xr;
15247
- xrManager.removeEventListener("sessionstart", handleSessionChange);
15248
- xrManager.removeEventListener("sessionend", handleSessionChange);
15249
- }
15250
- };
15251
- if (typeof renderer.xr?.addEventListener === "function") xr.connect();
15252
- state.set({ xr });
15253
- }
15254
- if (renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
15255
- lastConfiguredProps.shadows = shadows;
15256
- const oldEnabled = renderer.shadowMap.enabled;
15257
- const oldType = renderer.shadowMap.type;
15258
- renderer.shadowMap.enabled = !!shadows;
15259
- if (is.boo(shadows)) {
15260
- renderer.shadowMap.type = three.PCFShadowMap;
15261
- } else if (is.str(shadows)) {
15262
- if (shadows === "soft") {
15263
- extensions.notifyDepreciated({
15264
- heading: 'shadows="soft" is deprecated',
15265
- body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
15266
- link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
15763
+ );
15764
+ pendingLoaders.set(format, pending);
15765
+ }
15766
+ return pending;
15767
+ }
15768
+ async function importLoader(format) {
15769
+ let loader;
15770
+ switch (format) {
15771
+ case "cube":
15772
+ loader = getThree().CubeTextureLoader;
15773
+ break;
15774
+ case "hdr-cube":
15775
+ loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
15776
+ break;
15777
+ case "hdr":
15778
+ loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
15779
+ break;
15780
+ case "exr":
15781
+ loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
15782
+ break;
15783
+ case "jpg":
15784
+ loader = createJpegLoader((await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader);
15785
+ break;
15786
+ case "ldr":
15787
+ loader = getThree().TextureLoader;
15788
+ break;
15789
+ }
15790
+ return loader;
15791
+ }
15792
+ function createJpegLoader(UltraHDR) {
15793
+ return class JpegEnvironmentLoader extends UltraHDR {
15794
+ // @ts-expect-error A plain JPEG resolves to a Texture, not the DataTexture UltraHDRLoader declares
15795
+ load(url, onLoad, onProgress, onError) {
15796
+ const three = getThree();
15797
+ const file = new three.FileLoader(this.manager);
15798
+ file.setResponseType("arraybuffer");
15799
+ file.setRequestHeader(this.requestHeader);
15800
+ file.setPath(this.path);
15801
+ file.setWithCredentials(this.withCredentials);
15802
+ file.load(
15803
+ url,
15804
+ (buffer) => {
15805
+ try {
15806
+ this.parse(buffer, (texData) => {
15807
+ const { data } = texData;
15808
+ const texture = new three.DataTexture(data, texData.width, texData.height, three.RGBAFormat, texData.type);
15809
+ texture.minFilter = three.LinearMipMapLinearFilter;
15810
+ texture.magFilter = three.LinearFilter;
15811
+ texture.generateMipmaps = true;
15812
+ texture.flipY = true;
15813
+ texture.needsUpdate = true;
15814
+ onLoad?.(texture);
15267
15815
  });
15268
- }
15269
- const types = {
15270
- basic: three.BasicShadowMap,
15271
- percentage: three.PCFShadowMap,
15272
- soft: three.PCFShadowMap,
15273
- variance: three.VSMShadowMap
15274
- };
15275
- renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
15276
- } else if (is.obj(shadows)) {
15277
- Object.assign(renderer.shadowMap, shadows);
15278
- }
15279
- if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
15280
- renderer.shadowMap.needsUpdate = true;
15281
- }
15282
- }
15283
- if (!configured) {
15284
- renderer.outputColorSpace = three.SRGBColorSpace;
15285
- renderer.toneMapping = three.ACESFilmicToneMapping;
15286
- }
15287
- const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
15288
- if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
15289
- if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
15290
- lastConfiguredProps.textureColorSpace = textureColorSpace;
15291
- }
15292
- const r3fProps = ["textureColorSpace"];
15293
- const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
15294
- const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
15295
- if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
15296
- const glProps = {};
15297
- for (const key in glConfig) {
15298
- if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
15299
- }
15300
- applyProps(renderer, glProps);
15301
- }
15302
- if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
15303
- const currentRenderer = state.renderer;
15304
- if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
15305
- const rendererProps = {};
15306
- for (const key in rendererConfig) {
15307
- if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
15308
- }
15309
- applyProps(currentRenderer, rendererProps);
15310
- }
15311
- }
15312
- const scheduler$1 = scheduler.getScheduler();
15313
- const rootId = state.internal.rootId;
15314
- if (!rootId) {
15315
- const newRootId = canvasId || scheduler$1.generateRootId();
15316
- const unregisterRoot = scheduler$1.registerRoot(newRootId, {
15317
- getState: () => store.getState(),
15318
- onError: (err) => store.getState().setError(err),
15319
- frameloop: store.getState().frameloop,
15320
- before: schedulerConfig?.before,
15321
- after: schedulerConfig?.after,
15322
- order: schedulerConfig?.order
15323
- });
15324
- const unregisterCanvasTarget = scheduler$1.register(
15325
- () => {
15326
- const state2 = store.getState();
15327
- const canvasTarget = state2.internal.canvasTarget;
15328
- if (canvasTarget) {
15329
- const renderer2 = state2.internal.actualRenderer;
15330
- if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
15331
- if (state2.internal.canvasTargetSizeDirty) {
15332
- state2.internal.canvasTargetSizeDirty = false;
15333
- renderer2.backend?.updateSize?.();
15816
+ } catch {
15817
+ const objectURL = URL.createObjectURL(new Blob([buffer], { type: "image/jpeg" }));
15818
+ const settle = () => URL.revokeObjectURL(objectURL);
15819
+ new three.ImageLoader().load(
15820
+ objectURL,
15821
+ (image) => {
15822
+ settle();
15823
+ const texture = new three.Texture(image);
15824
+ texture.needsUpdate = true;
15825
+ onLoad?.(texture);
15826
+ },
15827
+ void 0,
15828
+ (error) => {
15829
+ settle();
15830
+ onError?.(error);
15334
15831
  }
15335
- }
15336
- },
15337
- {
15338
- id: `${newRootId}_canvasTarget`,
15339
- rootId: newRootId,
15340
- phase: "start",
15341
- system: true
15342
- }
15343
- );
15344
- const unregisterEventsFlush = scheduler$1.register(
15345
- () => {
15346
- const state2 = store.getState();
15347
- state2.events.flush?.();
15348
- },
15349
- {
15350
- id: `${newRootId}_events`,
15351
- rootId: newRootId,
15352
- phase: "input",
15353
- system: true
15354
- }
15355
- );
15356
- const unregisterFrustum = scheduler$1.register(
15357
- () => {
15358
- const state2 = store.getState();
15359
- if (state2.autoUpdateFrustum && state2.camera) {
15360
- updateFrustum(state2.camera, state2.frustum);
15361
- }
15362
- },
15363
- {
15364
- id: `${newRootId}_frustum`,
15365
- rootId: newRootId,
15366
- before: "render",
15367
- system: true
15368
- }
15369
- );
15370
- const unregisterVisibility = scheduler$1.register(
15371
- () => {
15372
- const state2 = store.getState();
15373
- checkVisibility(state2);
15374
- },
15375
- {
15376
- id: `${newRootId}_visibility`,
15377
- rootId: newRootId,
15378
- before: "render",
15379
- system: true,
15380
- after: `${newRootId}_frustum`
15381
- }
15382
- );
15383
- const unregisterRender = scheduler$1.register(
15384
- () => {
15385
- const state2 = store.getState();
15386
- const renderer2 = state2.internal.actualRenderer;
15387
- const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
15388
- if (userHandlesRender || state2.internal.priority) return;
15389
- try {
15390
- const renderOverride = state2.internal.renderOverride;
15391
- if (renderOverride) renderOverride();
15392
- else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
15393
- } catch (error) {
15394
- state2.setError(error instanceof Error ? error : new Error(String(error)));
15395
- }
15396
- },
15397
- {
15398
- // Use canvas ID directly as job ID if available, otherwise use generated rootId
15399
- id: canvasId || `${newRootId}_render`,
15400
- rootId: newRootId,
15401
- phase: "render",
15402
- system: true,
15403
- // Internal flag: this is a system job, not user-controlled
15404
- // FPS throttles only the default render job; Canvas ordering belongs to the root.
15405
- ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
15406
- }
15407
- );
15408
- state.set((state2) => ({
15409
- internal: {
15410
- ...state2.internal,
15411
- rootId: newRootId,
15412
- unregisterRoot: () => {
15413
- unregisterRoot();
15414
- unregisterCanvasTarget();
15415
- unregisterEventsFlush();
15416
- unregisterFrustum();
15417
- unregisterVisibility();
15418
- unregisterRender();
15419
- },
15420
- scheduler: scheduler$1
15832
+ );
15421
15833
  }
15422
- }));
15423
- } else {
15424
- const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
15425
- if (constraintsChanged) {
15426
- scheduler$1.setRootConstraints(rootId, {
15427
- before: schedulerConfig?.before,
15428
- after: schedulerConfig?.after
15429
- });
15430
- }
15431
- if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
15432
- scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
15433
- }
15434
- }
15435
- lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
15436
- lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
15437
- lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
15438
- extensions.attachRootExtensions(store);
15439
- onCreated = onCreatedCallback;
15440
- configured = true;
15441
- resolve();
15442
- return this;
15443
- },
15444
- render(children) {
15445
- if (_roots.get(canvas) !== root) return store;
15446
- cancelUnmount();
15447
- if (!configured && !pending) this.configure();
15448
- pending.then(() => {
15449
- if (_roots.get(canvas) !== root || root.unmountClaim) return;
15450
- reconciler.updateContainer(
15451
- /* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas }),
15452
- fiber,
15453
- null,
15454
- () => void 0
15455
- );
15456
- });
15457
- return store;
15458
- },
15459
- unmount() {
15460
- if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
15834
+ },
15835
+ onProgress,
15836
+ onError
15837
+ );
15461
15838
  }
15462
15839
  };
15463
15840
  }
15464
- function Provider({
15465
- store,
15466
- children,
15467
- onCreated,
15468
- rootElement
15469
- }) {
15470
- extensions.useIsomorphicLayoutEffect(() => {
15471
- const state = store.getState();
15472
- state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
15473
- if (onCreated) onCreated(state);
15474
- if (!store.getState().events.connected) state.events.connect?.(rootElement);
15475
- }, []);
15476
- return /* @__PURE__ */ jsxRuntime.jsx(extensions.context.Provider, { value: store, children });
15841
+ const LOADER_KEY = Symbol("r3f-environment-loader");
15842
+ function useEnvironmentLoader(format) {
15843
+ return suspendReact.suspend(() => loadLoader(format), [LOADER_KEY, format]);
15477
15844
  }
15478
- function unmountComponentAtNode(canvas, callback) {
15479
- const root = _roots.get(canvas);
15480
- if (!root) return;
15481
- const claim = root.unmountClaim = Symbol("unmount");
15482
- root.store.getState().internal.active = false;
15483
- reconciler.updateContainer(null, root.fiber, null, () => {
15484
- if (root.unmountClaim !== claim) return;
15485
- reconciler.updateContainer(null, root.fiber, null, () => {
15486
- if (root.unmountClaim !== claim) return;
15487
- if (root.ready.status === "pending") root.ready.then(teardown, teardown);
15488
- else teardown();
15845
+ function useEnvironment({
15846
+ files = defaultFiles,
15847
+ path = "",
15848
+ preset = void 0,
15849
+ colorSpace = void 0,
15850
+ extensions
15851
+ } = {}) {
15852
+ if (preset) {
15853
+ validatePreset(preset);
15854
+ files = presetsObj[preset];
15855
+ path = CUBEMAP_ROOT;
15856
+ }
15857
+ const multiFile = isArray(files);
15858
+ const { format, isCubemap } = getFormat(files);
15859
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15860
+ const loader = useEnvironmentLoader(format);
15861
+ const loaderResult = useLoader(
15862
+ loader,
15863
+ multiFile ? [files] : files,
15864
+ (loader2) => {
15865
+ loader2.setPath?.(path);
15866
+ if (extensions) extensions(loader2);
15867
+ }
15868
+ );
15869
+ const texture = multiFile ? (
15870
+ // @ts-ignore
15871
+ loaderResult[0]
15872
+ ) : loaderResult;
15873
+ const three = getThree();
15874
+ texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
15875
+ const hdr = format === "hdr-cube" || texture.isDataTexture === true;
15876
+ texture.colorSpace = colorSpace ?? (hdr ? "srgb-linear" : "srgb");
15877
+ return texture;
15878
+ }
15879
+ const preloadDefaultOptions = {
15880
+ files: defaultFiles,
15881
+ path: "",
15882
+ preset: void 0,
15883
+ extensions: void 0
15884
+ };
15885
+ useEnvironment.preload = (preloadOptions) => {
15886
+ const options = { ...preloadDefaultOptions, ...preloadOptions };
15887
+ let { files, path = "" } = options;
15888
+ const { preset, extensions } = options;
15889
+ if (preset) {
15890
+ validatePreset(preset);
15891
+ files = presetsObj[preset];
15892
+ path = CUBEMAP_ROOT;
15893
+ }
15894
+ const { format } = getFormat(files);
15895
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15896
+ const input = isArray(files) ? [files] : files;
15897
+ loadLoader(format).then((loader) => {
15898
+ useLoader.preload(loader, input, (loader2) => {
15899
+ loader2.setPath?.(path);
15900
+ if (extensions) extensions(loader2);
15489
15901
  });
15490
15902
  });
15491
- function teardown() {
15492
- if (root.unmountClaim !== claim) return;
15493
- root.unmountClaim = null;
15494
- _roots.delete(canvas);
15495
- const state = root.store.getState();
15496
- const internal = state.internal;
15497
- internal.active = false;
15498
- const attempt = (step) => {
15499
- try {
15500
- return step();
15501
- } catch (error) {
15502
- console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15503
- }
15504
- };
15505
- attempt(() => internal.unwatchDpr?.());
15506
- internal.unwatchDpr = void 0;
15507
- attempt(() => internal.unregisterRoot?.());
15508
- internal.unregisterRoot = void 0;
15509
- attempt(() => extensions.detachRootExtensions(root.store));
15510
- attempt(() => internal.unregisterPrimary?.());
15511
- attempt(() => state.events.disconnect?.());
15512
- if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
15513
- attempt(() => cleanupHelperGroup(root.store));
15514
- if (state.scene) attempt(() => dispose(state.scene));
15515
- const canvasTarget = internal.canvasTarget;
15516
- if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
15517
- const released = attempt(() => internal.releaseRenderer?.());
15518
- internal.releaseRenderer = void 0;
15519
- if (callback) {
15520
- if (released) {
15521
- released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
15522
- } else {
15523
- callback(canvas);
15524
- }
15525
- }
15903
+ };
15904
+ const clearDefaultOptins = {
15905
+ files: defaultFiles,
15906
+ preset: void 0
15907
+ };
15908
+ useEnvironment.clear = (clearOptions) => {
15909
+ const options = { ...clearDefaultOptins, ...clearOptions };
15910
+ let { files } = options;
15911
+ const { preset } = options;
15912
+ if (preset) {
15913
+ validatePreset(preset);
15914
+ files = presetsObj[preset];
15526
15915
  }
15916
+ const { format } = getFormat(files);
15917
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15918
+ const input = isArray(files) ? [files] : files;
15919
+ const clear = (loader2) => useLoader.clear(loader2, input);
15920
+ const loader = loadedLoaders.get(format);
15921
+ if (loader) {
15922
+ clear(loader);
15923
+ } else {
15924
+ const pending = pendingLoaders.get(format);
15925
+ if (pending) void pending.then(clear, () => {
15926
+ });
15927
+ }
15928
+ };
15929
+ function validatePreset(preset) {
15930
+ if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
15931
+ }
15932
+ function getFormat(files) {
15933
+ const isCubemap = isArray(files) && files.length === 6;
15934
+ const firstEntry = isArray(files) ? files[0] : files;
15935
+ const firstExtension = firstEntry.split(/[?#]/)[0].split(".").pop()?.toLowerCase();
15936
+ let format;
15937
+ if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
15938
+ else if (firstEntry.startsWith("data:application/exr")) format = "exr";
15939
+ else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
15940
+ else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
15941
+ else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
15942
+ else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
15943
+ else if (/^data:image\/(png|webp|avif|gif)[;,]/.test(firstEntry)) format = "ldr";
15944
+ else if (["png", "webp", "avif", "gif"].includes(firstExtension)) format = "ldr";
15945
+ return { format, isCubemap };
15946
+ }
15947
+
15948
+ function useInstanceHandle(ref) {
15949
+ const instance = React.useRef(null);
15950
+ React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
15951
+ return instance;
15952
+ }
15953
+ function useGraph(object) {
15954
+ return React.useMemo(() => buildGraph(object), [object]);
15527
15955
  }
15956
+
15528
15957
  function createPortal(children, container, state) {
15529
15958
  return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
15530
15959
  }
@@ -15555,30 +15984,28 @@ function Portal({ children, container, state }) {
15555
15984
  }
15556
15985
  function PortalInner({ state = {}, children, container }) {
15557
15986
  const { events, size, injectScene = true, ...rest } = state;
15558
- const previousRoot = extensions.useStore();
15987
+ const previousRoot = textureStaging.useStore();
15559
15988
  const [raycaster] = React.useState(() => new (getThree()).Raycaster());
15560
15989
  const [pointer] = React.useState(() => new (getThree()).Vector2());
15561
15990
  const [portalScene] = React.useState(() => {
15562
15991
  if ("isScene" in container && container.isScene) return container;
15563
15992
  if (!injectScene) return container;
15564
- const scene = new (getThree()).Scene();
15565
- container.add(scene);
15566
- return scene;
15993
+ return new (getThree()).Scene();
15567
15994
  });
15568
- extensions.useIsomorphicLayoutEffect(() => {
15995
+ textureStaging.useIsomorphicLayoutEffect(() => {
15996
+ if (portalScene === container || !injectScene) return;
15997
+ container.add(portalScene);
15569
15998
  return () => {
15570
- if (portalScene !== container && injectScene) {
15571
- container.remove(portalScene);
15572
- dispose(portalScene);
15573
- }
15999
+ container.remove(portalScene);
15574
16000
  };
15575
16001
  }, [portalScene, container, injectScene]);
15576
16002
  const lastRootState = React.useRef(null);
15577
- const inject = extensions.useMutableCallback((rootState, injectState) => {
16003
+ const inject = textureStaging.useMutableCallback((rootState, injectState) => {
15578
16004
  const followed = {};
15579
16005
  const lastRoot = lastRootState.current;
15580
16006
  if (lastRoot) {
15581
16007
  for (const key in rootState) {
16008
+ if (textureStaging.isAccessor(rootState, key)) continue;
15582
16009
  const field = key;
15583
16010
  const changed = rootState[field] !== lastRoot[field];
15584
16011
  const inherited = !(key in rest) && injectState[field] === lastRoot[field];
@@ -15595,11 +16022,7 @@ function PortalInner({ state = {}, children, container }) {
15595
16022
  if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
15596
16023
  }
15597
16024
  const set = injectState.set;
15598
- return {
15599
- // The intersect consists of the previous root state
15600
- ...rootState,
15601
- ...injectState,
15602
- ...followed,
16025
+ return Object.assign(textureStaging.cloneState(rootState, injectState, followed), {
15603
16026
  // Portals have their own scene - always a real THREE.Scene (injected if needed)
15604
16027
  scene: portalScene,
15605
16028
  // rootScene always points to the actual THREE.Scene, even inside portals
@@ -15614,18 +16037,24 @@ function PortalInner({ state = {}, children, container }) {
15614
16037
  size: resolvedSize,
15615
16038
  viewport: { ...rootState.viewport, ...viewport },
15616
16039
  // Layers are allowed to override events
15617
- setEvents: (events2) => set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
15618
- // Container for child attachment - the portalScene (injected or container itself)
15619
- internal: { ...rootState.internal, ...injectState.internal, container: portalScene }
15620
- };
16040
+ setEvents: (events2) => set((state2) => ({ events: { ...state2.events, ...events2 } })),
16041
+ // Container for child attachment - the portalScene (injected or container itself). A portal
16042
+ // renders with its parent's renderer, which `renderer` / `gl` read from `actualRenderer`
16043
+ internal: {
16044
+ ...rootState.internal,
16045
+ ...injectState.internal,
16046
+ actualRenderer: rootState.internal.actualRenderer,
16047
+ container: portalScene
16048
+ }
16049
+ });
15621
16050
  });
15622
16051
  const usePortalStore = React.useMemo(() => {
15623
- const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
16052
+ const store = traditional.createWithEqualityFn(textureStaging.keepAccessors((set, get) => ({ ...rest, set, get })));
15624
16053
  const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
15625
16054
  onMutate(previousRoot.getState());
15626
16055
  return store;
15627
16056
  }, [previousRoot, container]);
15628
- extensions.useIsomorphicLayoutEffect(() => {
16057
+ textureStaging.useIsomorphicLayoutEffect(() => {
15629
16058
  const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
15630
16059
  const unsubscribe = previousRoot.subscribe(onMutate);
15631
16060
  return unsubscribe;
@@ -15633,15 +16062,12 @@ function PortalInner({ state = {}, children, container }) {
15633
16062
  return (
15634
16063
  // @ts-ignore, reconciler types are not maintained
15635
16064
  /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
15636
- /* @__PURE__ */ jsxRuntime.jsx(extensions.context.Provider, { value: usePortalStore, children }),
16065
+ /* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: usePortalStore, children }),
15637
16066
  usePortalStore,
15638
16067
  null
15639
16068
  ) })
15640
16069
  );
15641
16070
  }
15642
- function flushSync(fn) {
15643
- return reconciler.flushSyncFromReconciler(fn);
15644
- }
15645
16071
 
15646
16072
  const isRef = (obj) => obj.current && obj.current.isScene;
15647
16073
  const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
@@ -15674,7 +16100,7 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
15674
16100
  };
15675
16101
  }
15676
16102
  function EnvironmentMap({ scene, background = false, map, ...config }) {
15677
- const defaultScene = extensions.useThree((state) => state.scene);
16103
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15678
16104
  React__namespace.useLayoutEffect(() => {
15679
16105
  if (map) return setEnvProps(background, scene, defaultScene, map, config);
15680
16106
  });
@@ -15692,7 +16118,7 @@ function EnvironmentCube({
15692
16118
  ...rest
15693
16119
  }) {
15694
16120
  const texture = useEnvironment(rest);
15695
- const defaultScene = extensions.useThree((state) => state.scene);
16121
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15696
16122
  React__namespace.useLayoutEffect(() => {
15697
16123
  return setEnvProps(background, scene, defaultScene, texture, {
15698
16124
  backgroundBlurriness: blur ?? backgroundBlurriness,
@@ -15727,11 +16153,11 @@ function EnvironmentPortal({
15727
16153
  files,
15728
16154
  path,
15729
16155
  preset = void 0,
15730
- extensions: extensions$1
16156
+ extensions
15731
16157
  }) {
15732
- const renderer = extensions.useThree((state) => state.renderer);
15733
- const support = extensions.useThree((state) => state.internal.support);
15734
- const defaultScene = extensions.useThree((state) => state.scene);
16158
+ const renderer = textureStaging.useThree((state) => state.renderer);
16159
+ const support = textureStaging.useThree((state) => state.internal.support);
16160
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15735
16161
  const camera = React__namespace.useRef(null);
15736
16162
  const [virtualScene] = React__namespace.useState(() => new (getThree()).Scene());
15737
16163
  const fbo = React__namespace.useMemo(() => {
@@ -15775,7 +16201,7 @@ function EnvironmentPortal({
15775
16201
  environmentRotation
15776
16202
  ]);
15777
16203
  let count = 1;
15778
- extensions.useFrame(() => {
16204
+ textureStaging.useFrame(() => {
15779
16205
  if (frames === Infinity || count < frames) {
15780
16206
  const autoClear = renderer.autoClear;
15781
16207
  renderer.autoClear = true;
@@ -15788,7 +16214,7 @@ function EnvironmentPortal({
15788
16214
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15789
16215
  children,
15790
16216
  /* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
15791
- files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions: extensions$1 }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions: extensions$1 }) : null
16217
+ files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
15792
16218
  ] }),
15793
16219
  virtualScene
15794
16220
  ) });
@@ -15818,7 +16244,7 @@ function EnvironmentGround(props) {
15818
16244
  ] });
15819
16245
  }
15820
16246
  function EnvironmentColor({ color, scene }) {
15821
- const defaultScene = extensions.useThree((state) => state.scene);
16247
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15822
16248
  React__namespace.useLayoutEffect(() => {
15823
16249
  if (color === void 0) return;
15824
16250
  const target = resolveScene(scene || defaultScene);
@@ -15833,12 +16259,12 @@ function EnvironmentColor({ color, scene }) {
15833
16259
  function EnvironmentDualSource(props) {
15834
16260
  const { backgroundFiles, ...envProps } = props;
15835
16261
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15836
- /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
15837
- /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
16262
+ (envProps.files || envProps.preset) && /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
16263
+ /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, preset: void 0, background: "only" })
15838
16264
  ] });
15839
16265
  }
15840
16266
  function Environment(props) {
15841
- if (props.color && !props.files && !props.preset && !props.map) {
16267
+ if (props.color !== void 0 && !props.files && !props.preset && !props.map) {
15842
16268
  return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentColor, { ...props });
15843
16269
  }
15844
16270
  if (props.backgroundFiles && props.backgroundFiles !== props.files) {
@@ -15848,7 +16274,7 @@ function Environment(props) {
15848
16274
  }
15849
16275
 
15850
16276
  function parseBackground(background) {
15851
- if (!background) return null;
16277
+ if (background === void 0 || background === null || background === "") return null;
15852
16278
  if (typeof background === "object" && !background.isColor) {
15853
16279
  const { backgroundMap, envMap, files, preset, ...rest } = background;
15854
16280
  return {
@@ -15866,7 +16292,7 @@ function parseBackground(background) {
15866
16292
  if (background in presetsObj) {
15867
16293
  return { preset: background, background: true };
15868
16294
  }
15869
- if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
16295
+ if (/^(https?:\/\/|\/|\.\/|\.\.\/|data:)|\.(hdr|exr|jpg|jpeg|png|webp|avif|gif)([?#].*)?$/i.test(background)) {
15870
16296
  return { files: background, background: true };
15871
16297
  }
15872
16298
  return { color: background, background: true };
@@ -15877,19 +16303,6 @@ function parseBackground(background) {
15877
16303
  return null;
15878
16304
  }
15879
16305
 
15880
- function parseRendererConfig(rendererProp) {
15881
- const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
15882
- if (isRendererConfig) {
15883
- const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
15884
- return {
15885
- primaryCanvas: pc,
15886
- scheduler: sc,
15887
- renderer: Object.keys(rest).length > 0 ? rest : rendererProp
15888
- };
15889
- }
15890
- return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
15891
- }
15892
-
15893
16306
  function CanvasImpl({
15894
16307
  ref,
15895
16308
  children,
@@ -15898,11 +16311,13 @@ function CanvasImpl({
15898
16311
  style,
15899
16312
  id,
15900
16313
  gl,
15901
- renderer: rendererProp,
16314
+ renderer,
16315
+ primary,
16316
+ share,
16317
+ scheduler,
15902
16318
  events = createPointerEvents,
15903
16319
  eventSource,
15904
16320
  eventPrefix,
15905
- shadows,
15906
16321
  orthographic,
15907
16322
  frameloop,
15908
16323
  dpr,
@@ -15924,8 +16339,12 @@ function CanvasImpl({
15924
16339
  provider,
15925
16340
  ...props
15926
16341
  }) {
15927
- const { primaryCanvas, scheduler, renderer } = parseRendererConfig(rendererProp);
15928
- const Bridge = extensions.useBridge();
16342
+ const {
16343
+ shadows: removedShadows,
16344
+ primaryCanvas: removedPrimaryCanvas,
16345
+ ...divProps
16346
+ } = props;
16347
+ const Bridge = textureStaging.useBridge();
15929
16348
  const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
15930
16349
  const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
15931
16350
  const measureConfig = React__namespace.useMemo(() => {
@@ -15961,119 +16380,131 @@ function CanvasImpl({
15961
16380
  const canvasRef = React__namespace.useRef(null);
15962
16381
  const divRef = React__namespace.useRef(null);
15963
16382
  React__namespace.useImperativeHandle(ref, () => canvasRef.current);
15964
- const handlePointerMissed = extensions.useMutableCallback(onPointerMissed);
15965
- const handleDragOverMissed = extensions.useMutableCallback(onDragOverMissed);
15966
- const handleDropMissed = extensions.useMutableCallback(onDropMissed);
16383
+ const handlePointerMissed = textureStaging.useMutableCallback(onPointerMissed);
16384
+ const handleDragOverMissed = textureStaging.useMutableCallback(onDragOverMissed);
16385
+ const handleDropMissed = textureStaging.useMutableCallback(onDropMissed);
15967
16386
  const [block, setBlock] = React__namespace.useState(false);
15968
16387
  const [error, setError] = React__namespace.useState(false);
15969
16388
  const [fallbackVisible, setFallbackVisible] = React__namespace.useState(false);
15970
16389
  if (block) throw block;
15971
16390
  if (error) throw error;
15972
16391
  const root = React__namespace.useRef(null);
15973
- const effectActiveRef = React__namespace.useRef(true);
15974
- const unsubscribeErrorRef = React__namespace.useRef(null);
15975
- extensions.useIsomorphicLayoutEffect(() => {
15976
- effectActiveRef.current = true;
16392
+ const [gate, waitFor] = textureStaging.useGate();
16393
+ const rootState = React__namespace.useRef(null);
16394
+ const eventTarget = () => eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current;
16395
+ const pointerMissed = React__namespace.useCallback(
16396
+ (...args) => handlePointerMissed.current?.(...args),
16397
+ [handlePointerMissed]
16398
+ );
16399
+ const dragOverMissed = React__namespace.useCallback(
16400
+ (...args) => handleDragOverMissed.current?.(...args),
16401
+ [handleDragOverMissed]
16402
+ );
16403
+ const dropMissed = React__namespace.useCallback(
16404
+ (...args) => handleDropMissed.current?.(...args),
16405
+ [handleDropMissed]
16406
+ );
16407
+ textureStaging.useIsomorphicLayoutEffect(() => {
15977
16408
  if (fallbackVisible) return;
15978
16409
  const canvas = canvasRef.current;
15979
16410
  if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
15980
16411
  if (!root.current) {
15981
16412
  root.current = createRoot(canvas, provider);
15982
- extensions.notifyAlpha({
16413
+ textureStaging.notifyAlpha({
15983
16414
  message: "React Three Fiber v10 is in ALPHA - expect breaking changes",
15984
16415
  link: "https://github.com/pmndrs/react-three-fiber/discussions"
15985
16416
  });
15986
- const rootEntry = _roots.get(canvas);
15987
- if (rootEntry?.store) {
15988
- if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
15989
- unsubscribeErrorRef.current = rootEntry.store.subscribe((state) => {
15990
- if (state.error && effectActiveRef.current) {
15991
- setError(state.error);
15992
- }
15993
- });
15994
- }
15995
16417
  }
15996
- async function run() {
15997
- if (!effectActiveRef.current || !root.current) return;
15998
- const configured = await root.current.configure({
15999
- id,
16000
- primaryCanvas,
16001
- scheduler,
16002
- gl,
16003
- renderer,
16004
- scene,
16005
- events,
16006
- shadows,
16007
- orthographic,
16008
- frameloop,
16009
- dpr,
16010
- performance,
16011
- raycaster,
16012
- camera,
16013
- autoUpdateFrustum,
16014
- occlusion,
16015
- size: effectiveSize,
16016
- // Store size props for reset functionality
16017
- _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
16018
- forceEven,
16019
- // Pass mutable reference to onPointerMissed so it's free to update
16020
- onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
16021
- onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
16022
- onDropMissed: (...args) => handleDropMissed.current?.(...args),
16023
- onCreated: (state) => {
16024
- state.events.connect?.(
16025
- eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current
16026
- );
16027
- if (eventPrefix) {
16028
- state.setEvents({
16029
- compute: (event, state2) => {
16030
- const x = event[eventPrefix + "X"];
16031
- const y = event[eventPrefix + "Y"];
16032
- state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
16033
- state2.raycaster.setFromCamera(state2.pointer, state2.camera);
16034
- }
16035
- });
16036
- }
16037
- onCreated?.(state);
16038
- }
16039
- }).then(
16040
- () => true,
16041
- // Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
16042
- // inside <canvas>, which browsers don't display, so surface it as visible DOM
16043
- // instead; with no fallback, rethrow to an external error boundary. (#3757)
16044
- (setupError) => {
16045
- if (effectActiveRef.current) {
16046
- if (fallback != null) setFallbackVisible(true);
16047
- else setError(setupError);
16048
- }
16049
- return false;
16418
+ const current = root.current;
16419
+ current.configure({
16420
+ id,
16421
+ primary,
16422
+ share,
16423
+ scheduler,
16424
+ gl,
16425
+ renderer,
16426
+ scene,
16427
+ events,
16428
+ _primaryToken: primaryToken,
16429
+ ...{ shadows: removedShadows, primaryCanvas: removedPrimaryCanvas },
16430
+ orthographic,
16431
+ frameloop,
16432
+ dpr,
16433
+ performance,
16434
+ raycaster,
16435
+ camera,
16436
+ autoUpdateFrustum,
16437
+ occlusion,
16438
+ size: effectiveSize,
16439
+ // Store size props for reset functionality
16440
+ _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
16441
+ forceEven,
16442
+ // Pass mutable reference to onPointerMissed so it's free to update
16443
+ onPointerMissed: pointerMissed,
16444
+ onDragOverMissed: dragOverMissed,
16445
+ onDropMissed: dropMissed,
16446
+ onCreated: (state) => {
16447
+ rootState.current = state;
16448
+ state.events.connect?.(eventTarget() ?? divRef.current);
16449
+ if (eventPrefix) {
16450
+ state.setEvents({
16451
+ compute: (event, state2) => {
16452
+ const x = event[eventPrefix + "X"];
16453
+ const y = event[eventPrefix + "Y"];
16454
+ state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
16455
+ state2.raycaster.setFromCamera(state2.pointer, state2.camera);
16456
+ }
16457
+ });
16050
16458
  }
16051
- );
16052
- if (!configured || !effectActiveRef.current || !root.current) return;
16053
- root.current.render(
16054
- /* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(extensions.ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(extensions.Block, { set: setBlock }), children: [
16459
+ onCreated?.(state);
16460
+ }
16461
+ }).catch((setupError) => {
16462
+ if (root.current !== current) return;
16463
+ if (fallback != null) setFallbackVisible(true);
16464
+ else setError(setupError);
16465
+ });
16466
+ if (current.ready.status === "fulfilled") {
16467
+ current.render(
16468
+ /* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(textureStaging.ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(textureStaging.Block, { set: setBlock }), children: [
16055
16469
  backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
16056
16470
  children ?? null
16057
16471
  ] }) }) })
16058
16472
  );
16473
+ } else if (current.ready.status === "pending") {
16474
+ waitFor(current.ready);
16059
16475
  }
16060
- run();
16061
16476
  }
16062
- return () => {
16063
- effectActiveRef.current = false;
16064
- if (unsubscribeErrorRef.current) {
16065
- unsubscribeErrorRef.current();
16066
- unsubscribeErrorRef.current = null;
16067
- }
16477
+ });
16478
+ textureStaging.useIsomorphicLayoutEffect(() => {
16479
+ const store = canvasRef.current && _roots.get(canvasRef.current)?.store;
16480
+ if (!store) return;
16481
+ const report = () => {
16482
+ const error2 = store.getState().error;
16483
+ if (error2) setError(error2);
16068
16484
  };
16485
+ report();
16486
+ return store.subscribe(report);
16487
+ });
16488
+ React__namespace.useEffect(() => {
16489
+ const state = rootState.current?.get();
16490
+ const target = eventTarget();
16491
+ if (state && target && state.events.connected !== target) state.events.connect?.(target);
16069
16492
  });
16070
16493
  const insertionMounted = React__namespace.useRef(false);
16494
+ const [primaryToken] = React__namespace.useState(() => ({}));
16495
+ const primaryKey = React__namespace.useRef(null);
16071
16496
  React__namespace.useInsertionEffect(() => {
16072
16497
  insertionMounted.current = true;
16498
+ if (primary && provider.webgpu) {
16499
+ primaryKey.current ?? (primaryKey.current = id || DEFAULT_PRIMARY);
16500
+ announcePrimary(primaryKey.current, primaryToken);
16501
+ }
16073
16502
  return () => {
16074
16503
  insertionMounted.current = false;
16504
+ if (primaryKey.current) markWithdrawing(primaryToken);
16075
16505
  queueMicrotask(() => {
16076
16506
  if (insertionMounted.current) return;
16507
+ if (primaryKey.current) withdrawPrimary(primaryKey.current, primaryToken);
16077
16508
  const current = root.current;
16078
16509
  root.current = null;
16079
16510
  current?.unmount();
@@ -16098,10 +16529,10 @@ function CanvasImpl({
16098
16529
  const handleHMR = () => {
16099
16530
  queueMicrotask(() => {
16100
16531
  const rootEntry = _roots.get(canvas);
16101
- if (rootEntry?.store) extensions.notifyRootExtensionsHmr(rootEntry.store);
16532
+ if (rootEntry?.store) textureStaging.notifyRootExtensionsHmr(rootEntry.store);
16102
16533
  });
16103
16534
  };
16104
- if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.BegWBc5_.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
16535
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.TRm3lZ7I.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
16105
16536
  const hot = undefined;
16106
16537
  hot.on("vite:afterUpdate", handleHMR);
16107
16538
  return () => hot.off?.("vite:afterUpdate", handleHMR);
@@ -16114,7 +16545,7 @@ function CanvasImpl({
16114
16545
  }
16115
16546
  }, [hmr]);
16116
16547
  const pointerEvents = eventSource ? "none" : "auto";
16117
- return /* @__PURE__ */ jsxRuntime.jsx(
16548
+ return /* @__PURE__ */ jsxRuntime.jsxs(
16118
16549
  "div",
16119
16550
  {
16120
16551
  ref: divRef,
@@ -16126,21 +16557,24 @@ function CanvasImpl({
16126
16557
  pointerEvents,
16127
16558
  ...style
16128
16559
  },
16129
- ...props,
16130
- children: fallbackVisible ? (
16131
- // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
16132
- // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
16133
- fallback
16134
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
16135
- "canvas",
16136
- {
16137
- ref: canvasRef,
16138
- id,
16139
- className: "r3f-canvas",
16140
- style: { display: "block", width: "100%", height: "100%" },
16141
- children: fallback
16142
- }
16143
- ) })
16560
+ ...divProps,
16561
+ children: [
16562
+ fallbackVisible ? (
16563
+ // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
16564
+ // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
16565
+ fallback
16566
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
16567
+ "canvas",
16568
+ {
16569
+ ref: canvasRef,
16570
+ id,
16571
+ className: "r3f-canvas",
16572
+ style: { display: "block", width: "100%", height: "100%" },
16573
+ children: fallback
16574
+ }
16575
+ ) }),
16576
+ gate
16577
+ ]
16144
16578
  }
16145
16579
  );
16146
16580
  }