@react-three/fiber 10.0.0-canary.f75fbf6 → 10.0.0-canary.fbd44ae

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 (34) hide show
  1. package/dist/extension.cjs +8 -8
  2. package/dist/extension.d.cts +4 -4
  3. package/dist/extension.d.mts +4 -4
  4. package/dist/extension.d.ts +4 -4
  5. package/dist/extension.mjs +1 -1
  6. package/dist/index.cjs +13 -13
  7. package/dist/index.d.cts +6 -6
  8. package/dist/index.d.mts +6 -6
  9. package/dist/index.d.ts +6 -6
  10. package/dist/index.mjs +3 -3
  11. package/dist/legacy.cjs +13 -13
  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 +4 -4
  16. package/dist/shared/{fiber.DH-VJXM_.d.ts → fiber.3jeDXXYd.d.mts} +82 -458
  17. package/dist/shared/{fiber.AN9kOS0N.d.mts → fiber.B_KQAb3I.d.ts} +82 -458
  18. package/dist/shared/{fiber.EDf0d92E.cjs → fiber.Bi_S5KAx.cjs} +2213 -1675
  19. package/dist/shared/{fiber.BgP4izaL.d.cts → fiber.C6hitYDY.d.cts} +1 -1
  20. package/dist/shared/{fiber.BgxhptM_.mjs → fiber.CFK811nR.mjs} +2099 -1561
  21. package/dist/shared/{fiber.Dh8K6RJr.d.cts → fiber.C_MFx7We.d.cts} +472 -20
  22. package/dist/shared/{fiber.Dh8K6RJr.d.mts → fiber.C_MFx7We.d.mts} +472 -20
  23. package/dist/shared/{fiber.Dh8K6RJr.d.ts → fiber.C_MFx7We.d.ts} +472 -20
  24. package/dist/shared/{fiber.BcX0-yko.d.mts → fiber.D4fD6H74.d.mts} +1 -1
  25. package/dist/shared/{fiber.B0oukOFO.mjs → fiber.QxL_6jra.mjs} +80 -54
  26. package/dist/shared/{fiber.BIhZnMzg.d.ts → fiber.YgTUGbja.d.ts} +1 -1
  27. package/dist/shared/{fiber.khFlPHPf.cjs → fiber.eR9ie2vQ.cjs} +80 -52
  28. package/dist/shared/{fiber.cO-9hDzr.d.cts → fiber.fR3DaJb1.d.cts} +82 -458
  29. package/dist/webgpu/index.cjs +13 -13
  30. package/dist/webgpu/index.d.cts +5 -5
  31. package/dist/webgpu/index.d.mts +5 -5
  32. package/dist/webgpu/index.d.ts +5 -5
  33. package/dist/webgpu/index.mjs +4 -4
  34. package/package.json +2 -2
@@ -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.eR9ie2vQ.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;
@@ -443,6 +458,28 @@ const VISIBILITY_EVENT_REGEX = /^on(Framed|Occluded|Visible)$/;
443
458
  const INDEX_REGEX = /-\d+$/;
444
459
  const MEMOIZED_PROTOTYPES = /* @__PURE__ */ new Map();
445
460
  const colorMaps = ["map", "emissiveMap", "sheenColorMap", "specularColorMap", "envMap"];
461
+ const programProps = /* @__PURE__ */ new Set([
462
+ "transparent",
463
+ "vertexColors",
464
+ "flatShading",
465
+ "fog",
466
+ // Culling is live, but DOUBLE_SIDED / FLIP_SIDED normal flipping is compiled in
467
+ "side",
468
+ "alphaHash",
469
+ "premultipliedAlpha",
470
+ // Both feed the OPAQUE define when the material is not transparent
471
+ "blending",
472
+ "alphaToCoverage",
473
+ "dithering",
474
+ "sizeAttenuation",
475
+ "combine",
476
+ "normalMapType",
477
+ "depthPacking"
478
+ ]);
479
+ function changesProgram(root, key, previous, next) {
480
+ if (!root?.isMaterial || previous === next) return false;
481
+ return programProps.has(key) || isTexture(previous) !== isTexture(next);
482
+ }
446
483
  function resolve(root, key) {
447
484
  if (!key.includes("-")) return { root, key, target: root[key] };
448
485
  if (key in root) return { root, key, target: root[key] };
@@ -473,6 +510,7 @@ function attach(parent, child) {
473
510
  const { root, key } = resolve(parent.object, child.props.attach);
474
511
  child.previousAttach = root[key];
475
512
  root[key] = child.object;
513
+ if (changesProgram(root, key, child.previousAttach, child.object)) root.needsUpdate = true;
476
514
  } else if (is.fun(child.props.attach)) {
477
515
  child.previousAttach = child.props.attach(parent.object, child.object);
478
516
  }
@@ -483,6 +521,7 @@ function detach(parent, child) {
483
521
  const previous = child.previousAttach;
484
522
  if (previous === void 0) delete root[key];
485
523
  else root[key] = previous;
524
+ if (changesProgram(root, key, child.object, previous)) root.needsUpdate = true;
486
525
  } else {
487
526
  child.previousAttach?.(parent.object, child.object);
488
527
  }
@@ -527,7 +566,7 @@ function applyProps(object, props) {
527
566
  const value = props[prop];
528
567
  if (RESERVED_PROPS.includes(prop)) continue;
529
568
  if (prop === "onUpdate") {
530
- extensions.notifyDepreciated({
569
+ textureStaging.notifyDepreciated({
531
570
  heading: "onUpdate is no longer an R3F prop",
532
571
  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
572
  link: "https://docs.pmnd.rs/react-three-fiber/migration/v10#onupdate-removed"
@@ -562,6 +601,10 @@ function applyProps(object, props) {
562
601
  }
563
602
  continue;
564
603
  }
604
+ if (prop === "visible" && instance?.isHidden && instance.previousVisible !== void 0) {
605
+ instance.previousVisible = value;
606
+ continue;
607
+ }
565
608
  let { root, key, target } = resolve(object, prop);
566
609
  if (target === void 0 && (typeof root !== "object" || root === null)) {
567
610
  throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
@@ -597,9 +640,12 @@ function applyProps(object, props) {
597
640
  }
598
641
  } else {
599
642
  if (key === "material") assertNodeMaterialSupported(rootState, value);
643
+ const previous = root[key];
600
644
  root[key] = value;
601
645
  if (key.endsWith("Node") && root.isMaterial) {
602
646
  root.needsUpdate = true;
647
+ } else if (changesProgram(root, key, previous, value)) {
648
+ root.needsUpdate = true;
603
649
  }
604
650
  const three = rootState && getThree();
605
651
  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 +686,428 @@ function applyProps(object, props) {
640
686
  return object;
641
687
  }
642
688
 
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];
689
+ const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
690
+ function isInternalRendererAccess(stack, callerDepth = 2) {
691
+ if (!stack) return false;
692
+ const caller = stack.split("\n")[callerDepth] ?? "";
693
+ return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
691
694
  }
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
695
 
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));
696
+ function updateSize(state, size, imperative) {
697
+ state.set((current) => ({
698
+ size,
699
+ viewport: { ...current.viewport, ...current.viewport.getCurrentViewport(current.camera, void 0, size) },
700
+ _sizeImperative: imperative
701
+ }));
702
+ state.invalidate();
718
703
  }
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
- }
704
+ function configureSize(store, size) {
705
+ const state = store.getState();
706
+ if (state._sizeImperative || is.equ(size, state.size, { objects: "shallow", strict: false })) return;
707
+ updateSize(state, size, false);
732
708
  }
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);
709
+ const createStore = (invalidate, advance) => {
710
+ const rootStore = traditional.createWithEqualityFn((set, get) => {
711
+ let position;
712
+ let defaultTarget;
713
+ let tempTarget;
714
+ function getCurrentViewport(camera = get().camera, target = void 0, size = get().size) {
715
+ const { Vector3 } = getThree();
716
+ position ?? (position = new Vector3());
717
+ defaultTarget ?? (defaultTarget = new Vector3());
718
+ tempTarget ?? (tempTarget = new Vector3());
719
+ target ?? (target = defaultTarget);
720
+ const { width, height, top, left } = size;
721
+ const aspect = width / height;
722
+ if (target.isVector3) tempTarget.copy(target);
723
+ else tempTarget.set(...target);
724
+ const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
725
+ if (isOrthographicCamera(camera)) {
726
+ return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
727
+ } else {
728
+ const fov = camera.fov * Math.PI / 180;
729
+ const h = 2 * Math.tan(fov / 2) * distance;
730
+ const w = h * (width / height);
731
+ return { width: w, height: h, top, left, factor: width / w, distance, aspect };
782
732
  }
783
- textureArray.forEach((texture) => {
784
- if (texture?.isTexture) {
785
- renderer.initTexture(texture);
786
- }
787
- });
788
733
  }
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);
734
+ let performanceTimeout = void 0;
735
+ const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
736
+ const rootState = {
737
+ set,
738
+ get,
739
+ // Mock objects that have to be configured
740
+ // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
741
+ primaryStore: null,
742
+ gl: null,
743
+ renderer: null,
744
+ camera: null,
745
+ // frustum, pointer and mouse are three objects; configure() creates them with the renderer
746
+ frustum: null,
747
+ autoUpdateFrustum: true,
748
+ raycaster: null,
749
+ events: {
750
+ priority: 1,
751
+ enabled: true,
752
+ connected: false,
753
+ frameTimedRaycasts: true,
754
+ alwaysFireOnScroll: true,
755
+ updateOnFrame: false
756
+ },
757
+ scene: null,
758
+ rootScene: null,
759
+ xr: null,
760
+ inspector: null,
761
+ invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
762
+ advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
763
+ textureColorSpace: "srgb",
764
+ // THREE.SRGBColorSpace
765
+ isLegacy: false,
766
+ webGPUSupported: false,
767
+ isNative: false,
768
+ controls: null,
769
+ pointer: null,
770
+ mouse: null,
771
+ frameloop: "always",
772
+ onPointerMissed: void 0,
773
+ onDragOverMissed: void 0,
774
+ onDropMissed: void 0,
775
+ performance: {
776
+ current: 1,
777
+ min: 0.5,
778
+ max: 1,
779
+ debounce: 200,
780
+ regress: () => {
781
+ const state2 = get();
782
+ if (performanceTimeout) clearTimeout(performanceTimeout);
783
+ if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
784
+ performanceTimeout = setTimeout(
785
+ () => setPerformanceCurrent(get().performance.max),
786
+ state2.performance.debounce
787
+ );
804
788
  }
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
789
  },
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;
790
+ size: { width: 0, height: 0, top: 0, left: 0 },
791
+ viewport: {
792
+ initialDpr: 0,
793
+ dpr: 0,
794
+ width: 0,
795
+ height: 0,
796
+ top: 0,
797
+ left: 0,
798
+ aspect: 0,
799
+ distance: 0,
800
+ factor: 0,
801
+ getCurrentViewport
865
802
  },
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]);
803
+ setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
804
+ setSize: (width, height, top, left) => {
805
+ const state2 = get();
806
+ if (width === void 0) {
807
+ if (state2._sizeProps) {
808
+ const { width: propW, height: propH } = state2._sizeProps;
809
+ if (propW !== void 0 || propH !== void 0) {
810
+ const currentSize = state2.size;
811
+ const newSize = {
812
+ width: propW ?? currentSize.width,
813
+ height: propH ?? currentSize.height,
814
+ top: currentSize.top,
815
+ left: currentSize.left
816
+ };
817
+ updateSize(state2, newSize, false);
818
+ return;
819
+ }
874
820
  }
875
- return { textures };
876
- });
877
- },
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.`
884
- );
885
- return false;
821
+ set({ _sizeImperative: false });
822
+ return;
886
823
  }
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;
824
+ const w = width;
825
+ const h = height ?? width;
826
+ const t = top ?? state2.size.top;
827
+ const l = left ?? state2.size.left;
828
+ const size = { width: w, height: h, top: t, left: l };
829
+ updateSize(state2, size, true);
896
830
  },
897
- disposeAll() {
898
- for (const texture of getState().textures.values()) texture.dispose();
899
- setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
831
+ setDpr: (dpr) => set((state2) => {
832
+ const resolved = calculateDpr(dpr);
833
+ return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
834
+ }),
835
+ setFrameloop: (frameloop = "always") => {
836
+ const rootId = get().internal.rootId;
837
+ if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
838
+ set(() => ({ frameloop }));
839
+ },
840
+ setError: (error) => set(() => ({ error })),
841
+ error: null,
842
+ //* Texture registry (useTextures) ==============================
843
+ // TSL fields (uniforms, nodes, ..., renderPipeline) are added by @react-three/tsl's root extension.
844
+ textures: /* @__PURE__ */ new Map(),
845
+ _textureRefs: /* @__PURE__ */ new Map(),
846
+ _sizeImperative: false,
847
+ _sizeProps: null,
848
+ previousRoot: void 0,
849
+ internal: {
850
+ // Events
851
+ interaction: [],
852
+ subscribers: [],
853
+ // Per-pointer state (new unified structure)
854
+ pointerMap: /* @__PURE__ */ new Map(),
855
+ pointerDirty: /* @__PURE__ */ new Map(),
856
+ lastEvent: React__namespace.createRef(),
857
+ // Deprecated but kept for backwards compatibility
858
+ hovered: /* @__PURE__ */ new Map(),
859
+ initialClick: [0, 0],
860
+ initialHits: [],
861
+ capturedMap: /* @__PURE__ */ new Map(),
862
+ // Visibility tracking (onFramed, onOccluded, onVisible)
863
+ visibilityRegistry: /* @__PURE__ */ new Map(),
864
+ // Occlusion system (WebGPU only)
865
+ occlusionEnabled: false,
866
+ occlusionObserver: null,
867
+ occlusionCache: /* @__PURE__ */ new Map(),
868
+ helperGroup: null,
869
+ // Updates
870
+ active: false,
871
+ frames: 0,
872
+ priority: 0,
873
+ subscribe: (ref, priority, store) => {
874
+ const internal = get().internal;
875
+ internal.priority = internal.priority + (priority > 0 ? 1 : 0);
876
+ internal.subscribers.push({ ref, priority, store });
877
+ internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
878
+ return () => {
879
+ const internal2 = get().internal;
880
+ if (internal2?.subscribers) {
881
+ internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
882
+ internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
883
+ }
884
+ };
885
+ },
886
+ // Renderer Storage (single source of truth)
887
+ actualRenderer: null,
888
+ // The renderer support configure() loads for this root
889
+ support: null,
890
+ // Scheduler for useFrameNext (initialized in loop.ts)
891
+ scheduler: null,
892
+ // Replaces the default render call when set (see setRenderOverride)
893
+ renderOverride: null
900
894
  }
901
895
  };
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;
896
+ return rootState;
897
+ });
898
+ const state = rootStore.getState();
899
+ Object.defineProperty(state, "gl", {
900
+ get() {
901
+ const currentState = rootStore.getState();
902
+ if (!currentState.isLegacy && currentState.internal.actualRenderer) {
903
+ const stack = new Error().stack || "";
904
+ if (!isInternalRendererAccess(stack)) {
905
+ const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
906
+ textureStaging.notifyDepreciated({
907
+ heading: "Accessing state.gl in WebGPU mode",
908
+ 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
909
+ });
910
+ }
911
+ }
912
+ return currentState.internal.actualRenderer;
913
+ },
914
+ set(value) {
915
+ rootStore.getState().internal.actualRenderer = value;
916
+ },
917
+ enumerable: true,
918
+ configurable: true
919
+ });
920
+ Object.defineProperty(state, "renderer", {
921
+ get() {
922
+ return rootStore.getState().internal.actualRenderer;
923
+ },
924
+ set(value) {
925
+ rootStore.getState().internal.actualRenderer = value;
926
+ },
927
+ enumerable: true,
928
+ configurable: true
929
+ });
930
+ let oldScene = state.scene;
931
+ rootStore.subscribe(() => {
932
+ const currentState = rootStore.getState();
933
+ const { scene, rootScene, set } = currentState;
934
+ if (scene !== oldScene) {
935
+ oldScene = scene;
936
+ if (scene?.isScene && scene !== rootScene) {
937
+ set({ rootScene: scene });
938
+ }
926
939
  }
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"
940
+ });
941
+ let oldSize = state.size;
942
+ let oldDpr = state.viewport.dpr;
943
+ let oldCamera = state.camera;
944
+ rootStore.subscribe(() => {
945
+ const { camera, size, viewport, set, internal } = rootStore.getState();
946
+ const actualRenderer = internal.actualRenderer;
947
+ const canvasTarget = internal.canvasTarget;
948
+ if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
949
+ oldSize = size;
950
+ oldDpr = viewport.dpr;
951
+ updateCamera(camera, size);
952
+ const resizeTarget = canvasTarget ?? actualRenderer;
953
+ if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
954
+ resizeTarget.setSize(size.width, size.height, false);
955
+ const activeTarget = actualRenderer.getCanvasTarget?.();
956
+ if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
957
+ }
958
+ if (camera !== oldCamera) {
959
+ oldCamera = camera;
960
+ const { rootScene } = rootStore.getState();
961
+ if (camera && rootScene && !camera.parent) {
962
+ rootScene.add(camera);
963
+ }
964
+ set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
965
+ const currentState = rootStore.getState();
966
+ if (currentState.autoUpdateFrustum && camera) {
967
+ updateFrustum(camera, currentState.frustum);
968
+ }
969
+ }
970
+ });
971
+ rootStore.subscribe((state2) => {
972
+ if (state2.internal.active) invalidate(state2);
973
+ });
974
+ return rootStore;
947
975
  };
948
976
 
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;
977
+ const shallowLoose$1 = { objects: "shallow", strict: false };
978
+ function configureScheduler(store, canvasId, schedulerConfig, previous) {
979
+ const state = store.getState();
980
+ const scheduler$1 = scheduler.getScheduler();
981
+ const rootId = state.internal.rootId;
982
+ const ordersItself = schedulerConfig?.before !== void 0 || schedulerConfig?.after !== void 0;
983
+ const rootBefore = schedulerConfig?.before;
984
+ const rootAfter = ordersItself ? schedulerConfig?.after : state.internal.sharedAfter;
985
+ if (!rootId) {
986
+ const newRootId = state.internal.pendingRootId ?? canvasId ?? scheduler$1.generateRootId();
987
+ const unregisterRoot = scheduler$1.registerRoot(newRootId, {
988
+ getState: () => store.getState(),
989
+ onError: (err) => store.getState().setError(err),
990
+ frameloop: store.getState().frameloop,
991
+ before: rootBefore,
992
+ after: rootAfter,
993
+ order: schedulerConfig?.order
994
+ });
995
+ const unregisterCanvasTarget = scheduler$1.register(
996
+ () => {
997
+ const state2 = store.getState();
998
+ const canvasTarget = state2.internal.canvasTarget;
999
+ if (canvasTarget) {
1000
+ const renderer = state2.internal.actualRenderer;
1001
+ if (renderer.getCanvasTarget() !== canvasTarget) renderer.setCanvasTarget(canvasTarget);
1002
+ if (state2.internal.canvasTargetSizeDirty) {
1003
+ state2.internal.canvasTargetSizeDirty = false;
1004
+ renderer.backend?.updateSize?.();
1005
+ }
1006
+ }
961
1007
  },
962
- (error) => {
963
- pendingLoaders.delete(format);
964
- throw error;
1008
+ {
1009
+ id: `${newRootId}_canvasTarget`,
1010
+ rootId: newRootId,
1011
+ phase: "start",
1012
+ system: true
965
1013
  }
966
1014
  );
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
- }
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
- });
1053
- };
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);
1015
+ const unregisterEventsFlush = scheduler$1.register(
1016
+ () => {
1017
+ const state2 = store.getState();
1018
+ state2.events.flush?.();
1019
+ },
1020
+ {
1021
+ id: `${newRootId}_events`,
1022
+ rootId: newRootId,
1023
+ phase: "input",
1024
+ system: true
1025
+ }
1026
+ );
1027
+ const unregisterFrustum = scheduler$1.register(
1028
+ () => {
1029
+ const state2 = store.getState();
1030
+ if (state2.autoUpdateFrustum && state2.camera) {
1031
+ updateFrustum(state2.camera, state2.frustum);
1032
+ }
1033
+ },
1034
+ {
1035
+ id: `${newRootId}_frustum`,
1036
+ rootId: newRootId,
1037
+ before: "render",
1038
+ system: true
1039
+ }
1040
+ );
1041
+ const unregisterVisibility = scheduler$1.register(
1042
+ () => {
1043
+ const state2 = store.getState();
1044
+ checkVisibility(state2);
1045
+ },
1046
+ {
1047
+ id: `${newRootId}_visibility`,
1048
+ rootId: newRootId,
1049
+ before: "render",
1050
+ system: true,
1051
+ after: `${newRootId}_frustum`
1052
+ }
1053
+ );
1054
+ const unregisterRender = scheduler$1.register(
1055
+ () => {
1056
+ const state2 = store.getState();
1057
+ const renderer = state2.internal.actualRenderer;
1058
+ const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
1059
+ if (userHandlesRender || state2.internal.priority) return;
1060
+ try {
1061
+ const renderOverride = state2.internal.renderOverride;
1062
+ if (renderOverride) renderOverride();
1063
+ else if (renderer?.render) renderer.render(state2.scene, state2.camera);
1064
+ } catch (error) {
1065
+ state2.setError(error instanceof Error ? error : new Error(String(error)));
1066
+ }
1067
+ },
1068
+ {
1069
+ // Use canvas ID directly as job ID if available, otherwise use generated rootId
1070
+ id: canvasId || `${newRootId}_render`,
1071
+ rootId: newRootId,
1072
+ phase: "render",
1073
+ system: true,
1074
+ // Internal flag: this is a system job, not user-controlled
1075
+ // FPS throttles only the default render job; Canvas ordering belongs to the root.
1076
+ ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
1077
+ }
1078
+ );
1079
+ state.set((state2) => ({
1080
+ internal: {
1081
+ ...state2.internal,
1082
+ rootId: newRootId,
1083
+ pendingRootId: void 0,
1084
+ unregisterRoot: () => {
1085
+ unregisterRoot();
1086
+ unregisterCanvasTarget();
1087
+ unregisterEventsFlush();
1088
+ unregisterFrustum();
1089
+ unregisterVisibility();
1090
+ unregisterRender();
1091
+ },
1092
+ scheduler: scheduler$1
1093
+ }
1094
+ }));
1073
1095
  } else {
1074
- const pending = pendingLoaders.get(format);
1075
- if (pending) void pending.then(clear, () => {
1076
- });
1096
+ const constraintsChanged = !is.equ(schedulerConfig?.before, previous?.before, shallowLoose$1) || !is.equ(schedulerConfig?.after, previous?.after, shallowLoose$1);
1097
+ if (constraintsChanged) {
1098
+ scheduler$1.setRootConstraints(rootId, {
1099
+ before: rootBefore,
1100
+ after: rootAfter
1101
+ });
1102
+ }
1103
+ if (schedulerConfig?.order !== previous?.order) {
1104
+ scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
1105
+ }
1077
1106
  }
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
1107
  }
1101
- function useGraph(object) {
1102
- return React.useMemo(() => buildGraph(object), [object]);
1103
- }
1104
-
1105
1108
  let effectId = 0;
1106
1109
  function addEffect(callback) {
1107
- extensions.notifyDepreciated({
1110
+ textureStaging.notifyDepreciated({
1108
1111
  heading: "addEffect is deprecated",
1109
1112
  body: 'Use useFrame(callback, { phase: "start" }) instead.\naddEffect will be removed in a future version.',
1110
1113
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1113,7 +1116,7 @@ function addEffect(callback) {
1113
1116
  return scheduler.getScheduler().registerGlobal("before", id, callback);
1114
1117
  }
1115
1118
  function addAfterEffect(callback) {
1116
- extensions.notifyDepreciated({
1119
+ textureStaging.notifyDepreciated({
1117
1120
  heading: "addAfterEffect is deprecated",
1118
1121
  body: 'Use useFrame(callback, { phase: "finish" }) instead.\naddAfterEffect will be removed in a future version.',
1119
1122
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1122,7 +1125,7 @@ function addAfterEffect(callback) {
1122
1125
  return scheduler.getScheduler().registerGlobal("after", id, callback);
1123
1126
  }
1124
1127
  function addTail(callback) {
1125
- extensions.notifyDepreciated({
1128
+ textureStaging.notifyDepreciated({
1126
1129
  heading: "addTail is deprecated",
1127
1130
  body: "Use scheduler.onIdle(callback) instead.\naddTail will be removed in a future version.",
1128
1131
  link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
@@ -1142,107 +1145,900 @@ function advance(timestamp, runGlobalEffects, state) {
1142
1145
  else scheduler$1.step(timestamp);
1143
1146
  }
1144
1147
 
1145
- const version = "10.0.0-alpha.5";
1146
- const packageData = {
1147
- version: version};
1148
+ const isPromiseLike = (value) => typeof value?.then === "function";
1149
+ const fulfilled = (value) => Object.assign(Promise.resolve(value), { status: "fulfilled", value });
1150
+ const rejected = (reason) => {
1151
+ const promise = Promise.reject(reason);
1152
+ promise.catch(() => {
1153
+ });
1154
+ return Object.assign(promise, { status: "rejected", reason });
1155
+ };
1156
+ const deferred = () => {
1157
+ let resolve;
1158
+ let reject;
1159
+ const promise = new Promise((yes, no) => {
1160
+ resolve = (value) => {
1161
+ Object.assign(promise, { status: "fulfilled", value });
1162
+ yes(value);
1163
+ };
1164
+ reject = (reason) => {
1165
+ Object.assign(promise, { status: "rejected", reason });
1166
+ no(reason);
1167
+ };
1168
+ });
1169
+ promise.status = "pending";
1170
+ promise.catch(() => {
1171
+ });
1172
+ return { promise, resolve, reject };
1173
+ };
1174
+ function resolveThen(value, apply) {
1175
+ return isPromiseLike(value) ? Promise.resolve(value).then(apply) : apply(value);
1176
+ }
1148
1177
 
1149
- function $1(Ut) {
1150
- return Ut && Ut.__esModule && Object.prototype.hasOwnProperty.call(Ut, "default") ? Ut.default : Ut;
1178
+ const isRenderer = (def) => !!def?.render;
1179
+ function ensureStoreThreeObjects(store) {
1180
+ const state = store.getState();
1181
+ if (state.pointer) return;
1182
+ const { Vector2, Frustum } = getThree();
1183
+ const pointer = new Vector2();
1184
+ state.set({ pointer, mouse: pointer, frustum: new Frustum() });
1151
1185
  }
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.";
1186
+ const R3F_RENDERER_SETTINGS = ["textureColorSpace", "shadows"];
1187
+ const NON_APPLIED_RENDERER_PROPS = /* @__PURE__ */ new Set([
1188
+ ...R3F_RENDERER_SETTINGS,
1189
+ "canvas",
1190
+ "antialias",
1191
+ "alpha",
1192
+ "samples",
1193
+ "powerPreference",
1194
+ "depth",
1195
+ "stencil",
1196
+ "logarithmicDepthBuffer",
1197
+ "reversedDepthBuffer",
1198
+ // WebGPURenderer only
1199
+ "forceWebGL",
1200
+ "outputBufferType",
1201
+ "multiview",
1202
+ "getFallback",
1203
+ "trackTimestamp"
1204
+ ]);
1205
+ function settingsBag(config) {
1206
+ return is.obj(config) && !isRenderer(config) ? config : void 0;
1207
+ }
1208
+ function isInstanceOrFactory(config) {
1209
+ return is.fun(config) || isRenderer(config);
1210
+ }
1211
+ function assertNoRemovedConfig(props) {
1212
+ if (props.primaryCanvas !== void 0) {
1213
+ throw new Error(
1214
+ 'R3F: `primaryCanvas` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")'
1215
+ );
1216
+ }
1217
+ if (props.shadows !== void 0) {
1218
+ throw new Error(
1219
+ "R3F: the `shadows` Canvas prop moved into the renderer settings: use `renderer={{ shadows }}` (or `gl={{ shadows }}` for WebGL and @react-three/fiber/legacy)"
1220
+ );
1221
+ }
1222
+ for (const name of ["renderer", "gl"]) {
1223
+ const bag = settingsBag(props[name]);
1224
+ if (!bag) continue;
1225
+ if ("primaryCanvas" in bag) {
1226
+ throw new Error(
1227
+ `R3F: \`${name}={{ primaryCanvas }}\` was removed: mark the owner <Canvas primary> and other canvases share it automatically (or use share="id")`
1228
+ );
1229
+ }
1230
+ if ("scheduler" in bag) {
1231
+ throw new Error(`R3F: \`${name}={{ scheduler }}\` moved to <Canvas scheduler>`);
1232
+ }
1233
+ }
1234
+ }
1235
+ function resolveRenderer(config, defaultProps, RendererClass) {
1236
+ if (typeof config === "function") {
1237
+ return resolveThen(config(defaultProps), (renderer) => ({
1238
+ renderer,
1239
+ owned: true
1240
+ }));
1241
+ }
1242
+ if (isRenderer(config)) return { renderer: config, owned: false };
1243
+ const params = { ...defaultProps };
1244
+ for (const key in settingsBag(config)) if (!R3F_RENDERER_SETTINGS.includes(key)) params[key] = config[key];
1245
+ return { renderer: new RendererClass(params), owned: true };
1246
+ }
1247
+ function createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support) {
1248
+ return resolveThen(resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer), (resolved) => {
1249
+ const renderer = resolved.renderer;
1250
+ if (!renderer.hasInitialized?.()) {
1251
+ const size = computeInitialSize(canvas, propsSize);
1252
+ if (size.width > 0 && size.height > 0) {
1253
+ renderer.setPixelRatio(calculateDpr(dpr));
1254
+ renderer.setSize(size.width, size.height, false);
1168
1255
  }
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;
1256
+ return resolveThen(renderer.init(), () => ({ renderer, owned: resolved.owned }));
1257
+ }
1258
+ return { renderer, owned: resolved.owned };
1259
+ });
1260
+ }
1261
+ function initializeRenderer(canvas, provider, store, props) {
1262
+ const {
1263
+ id: canvasId,
1264
+ primary = false,
1265
+ share,
1266
+ gl: glConfig,
1267
+ renderer: rendererConfig,
1268
+ size: propsSize,
1269
+ dpr = [1, 2],
1270
+ _primaryToken
1271
+ } = props;
1272
+ assertNoRemovedConfig(props);
1273
+ const rendererBag = settingsBag(rendererConfig);
1274
+ const state = store.getState();
1275
+ const { webgl, webgpu } = provider;
1276
+ const defaultGLProps = {
1277
+ canvas,
1278
+ powerPreference: "high-performance",
1279
+ antialias: true,
1280
+ alpha: true
1281
+ };
1282
+ const defaultGPUProps = {
1283
+ canvas,
1284
+ antialias: true
1285
+ };
1286
+ if (glConfig && !webgl) {
1287
+ throw new Error(
1288
+ "WebGLRenderer (gl prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/legacy instead."
1289
+ );
1290
+ }
1291
+ if (rendererConfig && !webgpu) {
1292
+ throw new Error(
1293
+ "WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
1294
+ );
1295
+ }
1296
+ if (glConfig && rendererConfig) {
1297
+ throw new Error("Cannot use both gl and renderer props at the same time");
1298
+ }
1299
+ if (primary && !webgpu) {
1300
+ throw new Error(
1301
+ "R3F: <Canvas primary> shares a WebGPU renderer and is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
1302
+ );
1303
+ }
1304
+ if (primary && glConfig) {
1305
+ throw new Error(
1306
+ "R3F: <Canvas primary> shares a WebGPU renderer and cannot be used with WebGL. Remove the `gl` prop or use the `renderer` prop."
1307
+ );
1308
+ }
1309
+ if (primary && is.str(share)) {
1310
+ throw new Error(`R3F: a <Canvas primary> owns its renderer; remove share="${share}" from it.`);
1311
+ }
1312
+ if (is.str(share)) {
1313
+ if (!webgpu || glConfig) {
1314
+ throw new Error(
1315
+ `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.`
1316
+ );
1317
+ }
1318
+ if (isInstanceOrFactory(rendererConfig)) {
1319
+ throw new Error(
1320
+ `R3F: share="${share}" borrows the primary's renderer, so it cannot be combined with a renderer instance or factory. Remove one of the two.`
1321
+ );
1322
+ }
1323
+ }
1324
+ const primaryKey = canvasId || DEFAULT_PRIMARY;
1325
+ const primaryToken = _primaryToken ?? store;
1326
+ if (primary && !state.internal.actualRenderer) {
1327
+ announcePrimary(primaryKey, primaryToken);
1328
+ state.internal.unregisterPrimary = () => withdrawPrimary(primaryKey, primaryToken);
1329
+ if (primaryConflict(primaryKey, primaryToken)) {
1330
+ throw new Error(
1331
+ 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\`.`
1332
+ );
1333
+ }
1334
+ }
1335
+ let shareKey;
1336
+ if (!state.internal.actualRenderer && webgpu && !primary && !glConfig && !state.isLegacy) {
1337
+ if (is.str(share)) {
1338
+ shareKey = share;
1339
+ } else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
1340
+ const live = livePrimaryKeys();
1341
+ if (live.length > 1) {
1342
+ throw new Error(
1343
+ `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.`
1344
+ );
1173
1345
  }
1174
- function pc(t) {
1175
- if (Ef(t) !== t) throw Error(F(188));
1346
+ shareKey = live[0];
1347
+ }
1348
+ }
1349
+ const explicitShare = is.str(share);
1350
+ const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig && !primary && shareKey === void 0);
1351
+ if (webgl && webgpu && !state.isLegacy && wantsGL) {
1352
+ textureStaging.notifyDepreciated({
1353
+ heading: "WebGlRenderer Usage",
1354
+ body: "WebGlRenderer usage is deprecated in favor of WebGPU. Import from /legacy directly or upgrade to WebGPU.",
1355
+ link: "https://docs.pmnd.rs/react-three-fiber/api/renderer"
1356
+ });
1357
+ }
1358
+ let renderer = state.internal.actualRenderer;
1359
+ if (!state.internal.actualRenderer) {
1360
+ return resolveThen(wantsGL ? webgl() : webgpu(), (support) => {
1361
+ registerThree(support.three);
1362
+ state.internal.support = support;
1363
+ ensureStoreThreeObjects(store);
1364
+ if (support.kind === "webgl") {
1365
+ return resolveThen(resolveRenderer(glConfig, defaultGLProps, support.Renderer), (resolved) => {
1366
+ renderer = resolved.renderer;
1367
+ state.internal.actualRenderer = renderer;
1368
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1369
+ state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
1370
+ });
1176
1371
  }
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;
1372
+ const primaryReady = shareKey === void 0 ? null : explicitShare ? waitForPrimary(shareKey) : waitForAnnouncedPrimary(shareKey);
1373
+ return resolveThen(primaryReady, (primaryEntry) => {
1374
+ if (primaryEntry && primaryEntry.store.getState().webGPUSupported) {
1375
+ renderer = primaryEntry.renderer;
1376
+ state.internal.actualRenderer = renderer;
1377
+ state.internal.releaseRenderer = borrowRenderer(renderer);
1378
+ state.internal.sharedAfter = primaryEntry.rootId;
1379
+ const canvasTarget = new support.CanvasTarget(canvas);
1380
+ primaryEntry.store.setState((prev) => ({
1381
+ internal: { ...prev.internal, isMultiCanvas: true }
1382
+ }));
1383
+ state.set((prev) => ({
1384
+ webGPUSupported: primaryEntry.store.getState().webGPUSupported,
1385
+ renderer,
1386
+ primaryStore: primaryEntry.store,
1387
+ internal: {
1388
+ ...prev.internal,
1389
+ canvasTarget,
1390
+ isMultiCanvas: true,
1391
+ isSecondary: true,
1392
+ targetId: shareKey === DEFAULT_PRIMARY ? void 0 : shareKey
1393
+ }
1394
+ }));
1395
+ return;
1182
1396
  }
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;
1397
+ if (primaryEntry) {
1398
+ return resolveThen(
1399
+ createOwnedWebGPURenderer(
1400
+ { ...rendererBag, forceWebGL: true },
1401
+ defaultGPUProps,
1402
+ canvas,
1403
+ propsSize,
1404
+ dpr,
1405
+ support
1406
+ ),
1407
+ (resolved) => {
1408
+ renderer = resolved.renderer;
1409
+ const backend = renderer.backend;
1410
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
1411
+ state.internal.actualRenderer = renderer;
1412
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1413
+ state.set((prev) => ({
1414
+ webGPUSupported: isWebGPUBackend,
1415
+ renderer,
1416
+ primaryStore: store,
1417
+ internal: {
1418
+ ...prev.internal,
1419
+ canvasTarget: renderer.getCanvasTarget?.(),
1420
+ sharedRendererFallback: true
1421
+ }
1422
+ }));
1191
1423
  }
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;
1424
+ );
1425
+ }
1426
+ return resolveThen(
1427
+ createOwnedWebGPURenderer(rendererConfig, defaultGPUProps, canvas, propsSize, dpr, support),
1428
+ (resolved) => {
1429
+ var _a;
1430
+ renderer = resolved.renderer;
1431
+ const backend = renderer.backend;
1432
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
1433
+ state.internal.actualRenderer = renderer;
1434
+ state.internal.releaseRenderer = leaseRenderer(renderer, resolved.owned);
1435
+ state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
1436
+ if (primary) {
1437
+ const canvasTarget = renderer.getCanvasTarget?.();
1438
+ (_a = state.internal).pendingRootId ?? (_a.pendingRootId = canvasId || scheduler.getScheduler().generateRootId());
1439
+ registerPrimary(primaryKey, renderer, store, {
1440
+ token: primaryToken,
1441
+ rootId: state.internal.pendingRootId
1442
+ });
1443
+ state.set((prev) => ({ internal: { ...prev.internal, canvasTarget } }));
1444
+ } else if (share !== false && !isInstanceOrFactory(rendererConfig)) {
1445
+ state.internal.untrackStandalone = trackStandalone(store);
1199
1446
  }
1200
- throw Error(F(188));
1201
1447
  }
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));
1448
+ );
1449
+ });
1450
+ });
1451
+ }
1452
+ }
1453
+ const records = /* @__PURE__ */ new WeakMap();
1454
+ function take(renderer, record) {
1455
+ record.leases++;
1456
+ let released = false;
1457
+ return () => {
1458
+ if (released) return;
1459
+ released = true;
1460
+ if (--record.leases > 0) return;
1461
+ records.delete(renderer);
1462
+ if (record.owned) return disposeRenderer(renderer);
1463
+ };
1464
+ }
1465
+ function leaseRenderer(renderer, owned) {
1466
+ let record = records.get(renderer);
1467
+ if (!record) records.set(renderer, record = { owned, leases: 0 });
1468
+ return take(renderer, record);
1469
+ }
1470
+ function borrowRenderer(renderer) {
1471
+ const record = records.get(renderer);
1472
+ if (!record) throw new Error("R3F: cannot share a renderer whose canvas has already unmounted");
1473
+ return take(renderer, record);
1474
+ }
1475
+ function disposeRenderer(renderer) {
1476
+ if (renderer.hasInitialized?.() === false) return;
1477
+ const warn = (error) => console.warn("[R3F] Error disposing renderer", error);
1478
+ const loseContext = () => {
1479
+ try {
1480
+ ;
1481
+ renderer.forceContextLoss?.();
1482
+ } catch (error) {
1483
+ warn(error);
1484
+ }
1485
+ };
1486
+ let disposed;
1487
+ try {
1488
+ disposed = renderer.dispose ? renderer.dispose() : renderer.renderLists?.dispose?.();
1489
+ } catch (error) {
1490
+ warn(error);
1491
+ }
1492
+ if (typeof disposed?.then === "function") {
1493
+ return Promise.resolve(disposed).then(loseContext, (error) => {
1494
+ warn(error);
1495
+ loseContext();
1496
+ });
1497
+ }
1498
+ loseContext();
1499
+ }
1500
+ const DEFAULT_PRIMARY = "\0r3f:primary";
1501
+ const primaryRegistry = /* @__PURE__ */ new Map();
1502
+ const announcements = /* @__PURE__ */ new Map();
1503
+ const withdrawing = /* @__PURE__ */ new Set();
1504
+ const pendingSubscribers = /* @__PURE__ */ new Map();
1505
+ const standaloneRoots = /* @__PURE__ */ new Set();
1506
+ const warnedLatePrimary = /* @__PURE__ */ new WeakSet();
1507
+ function describePrimary(key) {
1508
+ return key === DEFAULT_PRIMARY ? "<Canvas primary>" : `<Canvas id="${key}" primary>`;
1509
+ }
1510
+ function notify(key, entry) {
1511
+ const subscribers = pendingSubscribers.get(key);
1512
+ if (!subscribers) return;
1513
+ pendingSubscribers.delete(key);
1514
+ subscribers.forEach((callback) => callback(entry));
1515
+ }
1516
+ function isLive(key) {
1517
+ const owners = announcements.get(key);
1518
+ if (owners) {
1519
+ for (const owner of owners) if (!withdrawing.has(owner)) return true;
1520
+ }
1521
+ const entry = primaryRegistry.get(key);
1522
+ return !!entry && !(entry.token && withdrawing.has(entry.token));
1523
+ }
1524
+ function announcePrimary(key, owner) {
1525
+ withdrawing.delete(owner);
1526
+ let owners = announcements.get(key);
1527
+ if (!owners) announcements.set(key, owners = /* @__PURE__ */ new Set());
1528
+ if (owners.has(owner)) return;
1529
+ owners.add(owner);
1530
+ if (standaloneRoots.size > 0 && !warnedLatePrimary.has(owner) && textureStaging.isDevelopment()) {
1531
+ warnedLatePrimary.add(owner);
1532
+ console.warn(
1533
+ `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.`
1534
+ );
1535
+ }
1536
+ }
1537
+ function markWithdrawing(owner) {
1538
+ withdrawing.add(owner);
1539
+ }
1540
+ function withdrawPrimary(key, owner) {
1541
+ withdrawing.delete(owner);
1542
+ const owners = announcements.get(key);
1543
+ if (owners) {
1544
+ owners.delete(owner);
1545
+ if (owners.size === 0) announcements.delete(key);
1546
+ }
1547
+ const entry = primaryRegistry.get(key);
1548
+ if (entry?.token === owner) primaryRegistry.delete(key);
1549
+ if (!isLive(key)) notify(key, null);
1550
+ }
1551
+ function primaryConflict(key, owner) {
1552
+ const owners = announcements.get(key);
1553
+ if (owners) {
1554
+ for (const other of owners) {
1555
+ if (other === owner) break;
1556
+ if (!withdrawing.has(other)) return true;
1557
+ }
1558
+ }
1559
+ const entry = primaryRegistry.get(key);
1560
+ return !!entry && entry.token !== owner && !(entry.token && withdrawing.has(entry.token));
1561
+ }
1562
+ function livePrimaryKeys() {
1563
+ const keys = /* @__PURE__ */ new Set([...announcements.keys(), ...primaryRegistry.keys()]);
1564
+ return [...keys].filter(isLive);
1565
+ }
1566
+ function trackStandalone(owner) {
1567
+ standaloneRoots.add(owner);
1568
+ return () => {
1569
+ standaloneRoots.delete(owner);
1570
+ };
1571
+ }
1572
+ function registerPrimary(id, renderer, store, options = {}) {
1573
+ if (options.token && !announcements.get(id)?.has(options.token)) return () => {
1574
+ };
1575
+ if (primaryRegistry.has(id)) {
1576
+ console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
1577
+ }
1578
+ const entry = { renderer, store, rootId: options.rootId, token: options.token };
1579
+ primaryRegistry.set(id, entry);
1580
+ notify(id, entry);
1581
+ return () => {
1582
+ const currentEntry = primaryRegistry.get(id);
1583
+ if (currentEntry?.renderer === renderer) {
1584
+ primaryRegistry.delete(id);
1585
+ }
1586
+ };
1587
+ }
1588
+ function getPrimary(id) {
1589
+ return primaryRegistry.get(id);
1590
+ }
1591
+ function subscribe(id, callback) {
1592
+ if (!pendingSubscribers.has(id)) pendingSubscribers.set(id, []);
1593
+ pendingSubscribers.get(id).push(callback);
1594
+ return () => {
1595
+ const subscribers = pendingSubscribers.get(id);
1596
+ if (!subscribers) return;
1597
+ const index = subscribers.indexOf(callback);
1598
+ if (index !== -1) subscribers.splice(index, 1);
1599
+ if (subscribers.length === 0) pendingSubscribers.delete(id);
1600
+ };
1601
+ }
1602
+ function waitForPrimary(id, timeout = 5e3) {
1603
+ const existing = primaryRegistry.get(id);
1604
+ if (existing) {
1605
+ return Promise.resolve(existing);
1606
+ }
1607
+ return new Promise((resolve, reject) => {
1608
+ let unsubscribe = () => {
1609
+ };
1610
+ const timeoutId = setTimeout(() => {
1611
+ unsubscribe();
1612
+ reject(
1613
+ new Error(
1614
+ `Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}" primary> is mounted for share="${id}".`
1615
+ )
1616
+ );
1617
+ }, timeout);
1618
+ const callback = (entry) => {
1619
+ if (!entry) {
1620
+ unsubscribe = subscribe(id, callback);
1621
+ return;
1622
+ }
1623
+ clearTimeout(timeoutId);
1624
+ resolve(entry);
1625
+ };
1626
+ unsubscribe = subscribe(id, callback);
1627
+ });
1628
+ }
1629
+ function waitForAnnouncedPrimary(key, timeout = 5e3) {
1630
+ const existing = primaryRegistry.get(key);
1631
+ if (existing && isLive(key)) return Promise.resolve(existing);
1632
+ if (!isLive(key)) return Promise.resolve(null);
1633
+ return new Promise((resolve, reject) => {
1634
+ const timeoutId = setTimeout(() => {
1635
+ unsubscribe();
1636
+ reject(
1637
+ new Error(
1638
+ `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.`
1639
+ )
1640
+ );
1641
+ }, timeout);
1642
+ const unsubscribe = subscribe(key, (entry) => {
1643
+ clearTimeout(timeoutId);
1644
+ resolve(entry);
1645
+ });
1646
+ });
1647
+ }
1648
+ function hasPrimary(id) {
1649
+ return primaryRegistry.has(id);
1650
+ }
1651
+ function unregisterPrimary(id) {
1652
+ primaryRegistry.delete(id);
1653
+ }
1654
+ function getPrimaryIds() {
1655
+ return Array.from(primaryRegistry.keys());
1656
+ }
1657
+
1658
+ const shallowLoose = { objects: "shallow", strict: false };
1659
+ function watchDpr(onChange) {
1660
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function" || !window.devicePixelRatio) {
1661
+ return () => {
1662
+ };
1663
+ }
1664
+ let watching = true;
1665
+ let query;
1666
+ const listen = () => {
1667
+ try {
1668
+ query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
1669
+ if (typeof query?.addEventListener === "function") query.addEventListener("change", handleChange);
1670
+ else query?.addListener?.(handleChange);
1671
+ } catch {
1672
+ query = void 0;
1673
+ }
1674
+ };
1675
+ const unlisten = () => {
1676
+ if (typeof query?.removeEventListener === "function") query.removeEventListener("change", handleChange);
1677
+ else query?.removeListener?.(handleChange);
1678
+ query = void 0;
1679
+ };
1680
+ const handleChange = () => {
1681
+ if (!watching) return;
1682
+ unlisten();
1683
+ listen();
1684
+ onChange();
1685
+ };
1686
+ listen();
1687
+ return () => {
1688
+ watching = false;
1689
+ unlisten();
1690
+ };
1691
+ }
1692
+ function createRootConfiguration(store, canvas) {
1693
+ let previous;
1694
+ let lastCamera;
1695
+ const lastConfiguredProps = {};
1696
+ let resolvedDpr = 0;
1697
+ let dprChangedInXR = false;
1698
+ let unwatchDpr;
1699
+ const resolveDpr = () => {
1700
+ const state = store.getState();
1701
+ const xr = state.internal.actualRenderer?.xr;
1702
+ if (xr?.isPresenting || xr?.getSession?.()) {
1703
+ dprChangedInXR = true;
1704
+ return;
1705
+ }
1706
+ dprChangedInXR = false;
1707
+ const dpr = lastConfiguredProps.dpr;
1708
+ if (dpr === void 0 || state.viewport.dpr !== resolvedDpr || calculateDpr(dpr) === resolvedDpr) return;
1709
+ state.setDpr(dpr);
1710
+ resolvedDpr = store.getState().viewport.dpr;
1711
+ };
1712
+ let warnedSharedSettings = false;
1713
+ let configured = false;
1714
+ return (props) => {
1715
+ const {
1716
+ gl: glConfig,
1717
+ renderer: rendererConfig,
1718
+ size: propsSize,
1719
+ scene: sceneOptions,
1720
+ events,
1721
+ orthographic = false,
1722
+ frameloop = "always",
1723
+ dpr = [1, 2],
1724
+ performance,
1725
+ raycaster: raycastOptions,
1726
+ camera: cameraOptions,
1727
+ onPointerMissed,
1728
+ onDragOverMissed,
1729
+ onDropMissed,
1730
+ autoUpdateFrustum = true,
1731
+ occlusion = false,
1732
+ _sizeProps,
1733
+ forceEven
1734
+ } = props;
1735
+ assertNoRemovedConfig(props);
1736
+ const rendererBag = settingsBag(rendererConfig);
1737
+ const settings = settingsBag(glConfig) ?? rendererBag;
1738
+ const requestedTextureColorSpace = settings?.textureColorSpace || void 0;
1739
+ const shadows = isInstanceOrFactory(glConfig ?? rendererConfig) ? void 0 : settings?.shadows ?? false;
1740
+ const next = { ...props, shadows, frameloop, autoUpdateFrustum, occlusion };
1741
+ const last = previous;
1742
+ const changed = (key) => !last || !is.equ(next[key], last[key], { objects: "shallow" });
1743
+ previous = void 0;
1744
+ const state = store.getState();
1745
+ const renderer = state.internal.actualRenderer;
1746
+ const three = getThree();
1747
+ const borrowsRenderer = state.internal.isSecondary === true;
1748
+ if (borrowsRenderer && !warnedSharedSettings && rendererBag && Object.keys(rendererBag).some((key) => key !== "textureColorSpace") && textureStaging.isDevelopment()) {
1749
+ warnedSharedSettings = true;
1750
+ console.warn(
1751
+ "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."
1752
+ );
1753
+ }
1754
+ let raycaster = state.raycaster;
1755
+ if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
1756
+ if (changed("raycaster")) {
1757
+ const { params, ...options } = raycastOptions || {};
1758
+ if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
1759
+ if (!is.equ(params, raycaster.params, shallowLoose)) {
1760
+ applyProps(raycaster, { params: { ...raycaster.params, ...params } });
1761
+ }
1762
+ }
1763
+ let tempCamera = state.camera;
1764
+ if (!state.camera || state.camera === lastCamera && changed("camera")) {
1765
+ lastCamera = cameraOptions;
1766
+ const isCamera = cameraOptions?.isCamera;
1767
+ const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
1768
+ if (!isCamera) {
1769
+ camera.position.z = 5;
1770
+ if (cameraOptions) {
1771
+ applyProps(camera, cameraOptions);
1772
+ if (!camera.manual) {
1773
+ const projectionProps = ["aspect", "left", "right", "bottom", "top"];
1774
+ if (projectionProps.some((prop) => prop in cameraOptions)) {
1775
+ camera.manual = true;
1776
+ camera.updateProjectionMatrix();
1228
1777
  }
1229
1778
  }
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
1779
  }
1242
- return null;
1780
+ if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
1243
1781
  }
1244
- function ht(t) {
1245
- var r = t.tag;
1782
+ state.set({ camera });
1783
+ tempCamera = camera;
1784
+ raycaster.camera = camera;
1785
+ }
1786
+ if (!state.scene) {
1787
+ let scene;
1788
+ if (sceneOptions?.isScene) {
1789
+ scene = sceneOptions;
1790
+ prepare(scene, store, "", {});
1791
+ } else {
1792
+ scene = new three.Scene();
1793
+ prepare(scene, store, "", {});
1794
+ if (sceneOptions) applyProps(scene, sceneOptions);
1795
+ }
1796
+ state.set((prev) => ({
1797
+ scene,
1798
+ rootScene: scene,
1799
+ internal: { ...prev.internal, container: scene }
1800
+ }));
1801
+ const camera = tempCamera;
1802
+ if (camera && !camera.parent) scene.add(camera);
1803
+ }
1804
+ if (events && !state.events.handlers) {
1805
+ state.set({ events: events(store) });
1806
+ let wasEnabled = true;
1807
+ store.subscribe((state2) => {
1808
+ const { enabled } = state2.events;
1809
+ if (enabled && !wasEnabled) {
1810
+ state2.events.update?.();
1811
+ }
1812
+ wasEnabled = enabled;
1813
+ });
1814
+ }
1815
+ if (_sizeProps !== void 0 && changed("_sizeProps")) {
1816
+ state.set({ _sizeProps });
1817
+ }
1818
+ if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
1819
+ state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
1820
+ }
1821
+ configureSize(store, computeInitialSize(canvas, propsSize));
1822
+ if (dpr !== void 0 && (!last || !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose))) {
1823
+ state.setDpr(dpr);
1824
+ lastConfiguredProps.dpr = dpr;
1825
+ resolvedDpr = store.getState().viewport.dpr;
1826
+ }
1827
+ const internal = store.getState().internal;
1828
+ if (Array.isArray(dpr) && (!unwatchDpr || internal.unwatchDpr !== unwatchDpr)) {
1829
+ internal.unwatchDpr?.();
1830
+ internal.unwatchDpr = unwatchDpr = watchDpr(resolveDpr);
1831
+ }
1832
+ resolveDpr();
1833
+ if (frameloop !== void 0 && changed("frameloop")) {
1834
+ state.setFrameloop(frameloop);
1835
+ }
1836
+ if (changed("onPointerMissed")) state.set({ onPointerMissed });
1837
+ if (changed("onDragOverMissed")) state.set({ onDragOverMissed });
1838
+ if (changed("onDropMissed")) state.set({ onDropMissed });
1839
+ if (changed("autoUpdateFrustum") && state.autoUpdateFrustum !== autoUpdateFrustum) {
1840
+ state.set({ autoUpdateFrustum });
1841
+ }
1842
+ if (occlusion && !state.internal.occlusionEnabled) {
1843
+ enableOcclusion(store);
1844
+ }
1845
+ if (performance && changed("performance")) {
1846
+ state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
1847
+ }
1848
+ if (!state.xr) {
1849
+ const handleXRFrame = (timestamp, _frame) => {
1850
+ const state2 = store.getState();
1851
+ if (state2.frameloop === "never") return;
1852
+ advance(timestamp, true, state2);
1853
+ };
1854
+ const actualRenderer = state.internal.actualRenderer;
1855
+ const handleSessionChange = () => {
1856
+ const state2 = store.getState();
1857
+ const renderer2 = state2.internal.actualRenderer;
1858
+ actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
1859
+ renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
1860
+ if (!renderer2.xr.isPresenting) {
1861
+ if (dprChangedInXR) resolveDpr();
1862
+ invalidate(state2);
1863
+ }
1864
+ };
1865
+ const xr = {
1866
+ connect() {
1867
+ const { gl, renderer: renderer2 } = store.getState();
1868
+ const xrManager = (renderer2 || gl).xr;
1869
+ xrManager.addEventListener("sessionstart", handleSessionChange);
1870
+ xrManager.addEventListener("sessionend", handleSessionChange);
1871
+ },
1872
+ disconnect() {
1873
+ const { gl, renderer: renderer2 } = store.getState();
1874
+ const xrManager = (renderer2 || gl).xr;
1875
+ xrManager.removeEventListener("sessionstart", handleSessionChange);
1876
+ xrManager.removeEventListener("sessionend", handleSessionChange);
1877
+ }
1878
+ };
1879
+ if (!borrowsRenderer && typeof renderer.xr?.addEventListener === "function") xr.connect();
1880
+ state.set({ xr });
1881
+ }
1882
+ if (!borrowsRenderer && shadows !== void 0 && renderer.shadowMap && changed("shadows")) {
1883
+ const oldEnabled = renderer.shadowMap.enabled;
1884
+ const oldType = renderer.shadowMap.type;
1885
+ renderer.shadowMap.enabled = !!shadows;
1886
+ if (is.boo(shadows)) {
1887
+ renderer.shadowMap.type = three.PCFShadowMap;
1888
+ } else if (is.str(shadows)) {
1889
+ if (shadows === "soft") {
1890
+ textureStaging.notifyDepreciated({
1891
+ heading: 'shadows="soft" is deprecated',
1892
+ body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
1893
+ link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
1894
+ });
1895
+ }
1896
+ const types = {
1897
+ basic: three.BasicShadowMap,
1898
+ percentage: three.PCFShadowMap,
1899
+ soft: three.PCFShadowMap,
1900
+ variance: three.VSMShadowMap
1901
+ };
1902
+ renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
1903
+ } else if (is.obj(shadows)) {
1904
+ Object.assign(renderer.shadowMap, shadows);
1905
+ }
1906
+ if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
1907
+ renderer.shadowMap.needsUpdate = true;
1908
+ }
1909
+ }
1910
+ if (!configured && !borrowsRenderer) {
1911
+ renderer.outputColorSpace = three.SRGBColorSpace;
1912
+ renderer.toneMapping = three.ACESFilmicToneMapping;
1913
+ }
1914
+ const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
1915
+ if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
1916
+ if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
1917
+ lastConfiguredProps.textureColorSpace = textureColorSpace;
1918
+ }
1919
+ if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && changed("gl")) {
1920
+ const glProps = {};
1921
+ for (const key in glConfig) {
1922
+ if (!NON_APPLIED_RENDERER_PROPS.has(key)) glProps[key] = glConfig[key];
1923
+ }
1924
+ applyProps(renderer, glProps);
1925
+ }
1926
+ if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer && !borrowsRenderer) {
1927
+ const currentRenderer = state.renderer;
1928
+ if (changed("renderer")) {
1929
+ const rendererProps = {};
1930
+ for (const key in rendererConfig) {
1931
+ if (!NON_APPLIED_RENDERER_PROPS.has(key)) rendererProps[key] = rendererConfig[key];
1932
+ }
1933
+ applyProps(currentRenderer, rendererProps);
1934
+ }
1935
+ }
1936
+ configured = true;
1937
+ previous = next;
1938
+ };
1939
+ }
1940
+
1941
+ const version = "10.0.0-alpha.5";
1942
+ const packageData = {
1943
+ version: version};
1944
+
1945
+ function $1(Ut) {
1946
+ return Ut && Ut.__esModule && Object.prototype.hasOwnProperty.call(Ut, "default") ? Ut.default : Ut;
1947
+ }
1948
+ var S0 = { exports: {} }, Ob = { exports: {} }, P1;
1949
+ function Q1() {
1950
+ return P1 || (P1 = 1, (function(Ut) {
1951
+ Ut.exports = function(m) {
1952
+ function et(t, r, a, l) {
1953
+ return new Fe(t, r, a, l);
1954
+ }
1955
+ function zf() {
1956
+ }
1957
+ function F(t) {
1958
+ var r = "https://react.dev/errors/" + t;
1959
+ if (1 < arguments.length) {
1960
+ r += "?args[]=" + encodeURIComponent(arguments[1]);
1961
+ for (var a = 2; a < arguments.length; a++) r += "&args[]=" + encodeURIComponent(arguments[a]);
1962
+ }
1963
+ 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.";
1964
+ }
1965
+ function Ef(t) {
1966
+ for (var r = t, a = r; a && !a.alternate; ) r = a, (r.flags & 4098) !== 0 && (t = r.return), a = r.return;
1967
+ for (; r.return; ) r = r.return;
1968
+ return r.tag === 3 ? t : null;
1969
+ }
1970
+ function pc(t) {
1971
+ if (Ef(t) !== t) throw Error(F(188));
1972
+ }
1973
+ function hc(t) {
1974
+ var r = t.alternate;
1975
+ if (!r) {
1976
+ if (r = Ef(t), r === null) throw Error(F(188));
1977
+ return r !== t ? null : t;
1978
+ }
1979
+ for (var a = t, l = r; ; ) {
1980
+ var c = a.return;
1981
+ if (c === null) break;
1982
+ var d = c.alternate;
1983
+ if (d === null) {
1984
+ if (l = c.return, l !== null) {
1985
+ a = l;
1986
+ continue;
1987
+ }
1988
+ break;
1989
+ }
1990
+ if (c.child === d.child) {
1991
+ for (d = c.child; d; ) {
1992
+ if (d === a) return pc(c), t;
1993
+ if (d === l) return pc(c), r;
1994
+ d = d.sibling;
1995
+ }
1996
+ throw Error(F(188));
1997
+ }
1998
+ if (a.return !== l.return) a = c, l = d;
1999
+ else {
2000
+ for (var h = false, y = c.child; y; ) {
2001
+ if (y === a) {
2002
+ h = true, a = c, l = d;
2003
+ break;
2004
+ }
2005
+ if (y === l) {
2006
+ h = true, l = c, a = d;
2007
+ break;
2008
+ }
2009
+ y = y.sibling;
2010
+ }
2011
+ if (!h) {
2012
+ for (y = d.child; y; ) {
2013
+ if (y === a) {
2014
+ h = true, a = d, l = c;
2015
+ break;
2016
+ }
2017
+ if (y === l) {
2018
+ h = true, l = d, a = c;
2019
+ break;
2020
+ }
2021
+ y = y.sibling;
2022
+ }
2023
+ if (!h) throw Error(F(189));
2024
+ }
2025
+ }
2026
+ if (a.alternate !== l) throw Error(F(190));
2027
+ }
2028
+ if (a.tag !== 3) throw Error(F(188));
2029
+ return a.stateNode.current === a ? t : r;
2030
+ }
2031
+ function mc(t) {
2032
+ var r = t.tag;
2033
+ if (r === 5 || r === 26 || r === 27 || r === 6) return t;
2034
+ for (t = t.child; t !== null; ) {
2035
+ if (r = mc(t), r !== null) return r;
2036
+ t = t.sibling;
2037
+ }
2038
+ return null;
2039
+ }
2040
+ function ht(t) {
2041
+ var r = t.tag;
1246
2042
  if (r === 5 || r === 26 || r === 27 || r === 6) return t;
1247
2043
  for (t = t.child; t !== null; ) {
1248
2044
  if (t.tag !== 4 && (r = ht(t), r !== null)) return r;
@@ -13340,15 +14136,16 @@ function swapInteractivity(store, object, newObject) {
13340
14136
  pointerState.hovered.set(makeId(next), next);
13341
14137
  }
13342
14138
  });
13343
- const captureData = pointerState.captured.get(object);
13344
- if (captureData) {
13345
- pointerState.captured.delete(object);
13346
- pointerState.captured.set(newObject, {
14139
+ for (const [key, captureData] of Array.from(pointerState.captured)) {
14140
+ const { intersection } = captureData;
14141
+ if (key !== object && intersection.object !== object && intersection.eventObject !== object) continue;
14142
+ if (key === object) pointerState.captured.delete(key);
14143
+ pointerState.captured.set(key === object ? newObject : key, {
13347
14144
  ...captureData,
13348
14145
  intersection: {
13349
- ...captureData.intersection,
13350
- object: captureData.intersection.object === object ? newObject : captureData.intersection.object,
13351
- eventObject: captureData.intersection.eventObject === object ? newObject : captureData.intersection.eventObject
14146
+ ...intersection,
14147
+ object: intersection.object === object ? newObject : intersection.object,
14148
+ eventObject: intersection.eventObject === object ? newObject : intersection.eventObject
13352
14149
  }
13353
14150
  });
13354
14151
  }
@@ -13877,9 +14674,9 @@ const catalogue = globalThis[R3F_CATALOGUE] ?? (globalThis[R3F_CATALOGUE] = {});
13877
14674
  const R3F_EXTEND_ID = Symbol.for("@react-three/fiber.extendId");
13878
14675
  const ids = globalThis;
13879
14676
  const toPascalCase = (type) => `${type[0].toUpperCase()}${type.slice(1)}`;
13880
- const isConstructor = (object) => typeof object === "function";
14677
+ const isConstructor$1 = (object) => typeof object === "function";
13881
14678
  function extend(objects) {
13882
- if (isConstructor(objects)) {
14679
+ if (isConstructor$1(objects)) {
13883
14680
  const id = ids[R3F_EXTEND_ID] ?? 0;
13884
14681
  ids[R3F_EXTEND_ID] = id + 1;
13885
14682
  const Component = `${id}`;
@@ -13888,15 +14685,14 @@ function extend(objects) {
13888
14685
  } else {
13889
14686
  for (const name in objects) {
13890
14687
  const object = objects[name];
13891
- if (isConstructor(object)) catalogue[name] = object;
14688
+ if (isConstructor$1(object)) catalogue[name] = object;
13892
14689
  }
13893
14690
  }
13894
14691
  }
13895
-
13896
14692
  function resolveConstructor(name, root) {
13897
14693
  if (Object.prototype.hasOwnProperty.call(catalogue, name)) return catalogue[name];
13898
14694
  const object = root.getState().internal.support?.three[name];
13899
- return isConstructor(object) ? object : void 0;
14695
+ return isConstructor$1(object) ? object : void 0;
13900
14696
  }
13901
14697
 
13902
14698
  function createReconciler(config) {
@@ -13933,6 +14729,7 @@ function hideInstance(instance) {
13933
14729
  if (instance.props.attach && instance.parent?.object) {
13934
14730
  detach(instance.parent, instance);
13935
14731
  } else if (isObject3D(instance.object)) {
14732
+ instance.previousVisible = instance.object.visible;
13936
14733
  instance.object.visible = false;
13937
14734
  }
13938
14735
  instance.isHidden = true;
@@ -13943,9 +14740,10 @@ function unhideInstance(instance) {
13943
14740
  if (instance.isHidden) {
13944
14741
  if (instance.props.attach && instance.parent?.object) {
13945
14742
  attach(instance.parent, instance);
13946
- } else if (isObject3D(instance.object) && instance.props.visible !== false) {
13947
- instance.object.visible = true;
14743
+ } else if (isObject3D(instance.object)) {
14744
+ instance.object.visible = instance.previousVisible ?? true;
13948
14745
  }
14746
+ instance.previousVisible = void 0;
13949
14747
  instance.isHidden = false;
13950
14748
  invalidateInstance(instance);
13951
14749
  }
@@ -14344,480 +15142,143 @@ const reconciler = /* @__PURE__ */ createReconciler({
14344
15142
  HostTransitionContext: /* @__PURE__ */ React__namespace.createContext(
14345
15143
  null
14346
15144
  ),
14347
- setCurrentUpdatePriority(newPriority) {
14348
- currentUpdatePriority = newPriority;
14349
- },
14350
- getCurrentUpdatePriority() {
14351
- return currentUpdatePriority;
14352
- },
14353
- resolveUpdatePriority() {
14354
- if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
14355
- const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
14356
- if (eventType === void 0) return r;
14357
- return getEventPriority(eventType);
14358
- },
14359
- resetFormInstance() {
14360
- },
14361
- // @ts-ignore DefinitelyTyped is not up to date
14362
- rendererPackageName: "@react-three/fiber",
14363
- rendererVersion: packageData.version,
14364
- // 19.2 Reconciler
14365
- // https://github.com/facebook/react/pull/31975
14366
- // https://github.com/facebook/react/pull/31999
14367
- applyViewTransitionName(_instance, _name, _className) {
14368
- },
14369
- restoreViewTransitionName(_instance, _props) {
14370
- },
14371
- cancelViewTransitionName(_instance, _name, _props) {
14372
- },
14373
- cancelRootViewTransitionName(_rootContainer) {
14374
- },
14375
- restoreRootViewTransitionName(_rootContainer) {
14376
- },
14377
- InstanceMeasurement: null,
14378
- measureInstance: (_instance) => null,
14379
- wasInstanceInViewport: (_measurement) => true,
14380
- hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
14381
- hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
14382
- // https://github.com/facebook/react/pull/32002
14383
- // https://github.com/facebook/react/pull/34486
14384
- suspendOnActiveViewTransition(_state, _container) {
14385
- },
14386
- // https://github.com/facebook/react/pull/32451
14387
- // https://github.com/facebook/react/pull/32760
14388
- // React hands the whole commit to the host when a transition touches a <ViewTransition> subtree.
14389
- // three.js has nothing to animate between commits, so this mirrors the react-dom fallback for
14390
- // browsers without document.startViewTransition and flushes the commit synchronously.
14391
- startViewTransition(_suspendedState, _rootContainer, _transitionTypes, mutationCallback, layoutCallback, _afterMutationCallback, spawnedWorkCallback, _passiveCallback, _errorCallback, _blockedCallback, finishedAnimation) {
14392
- mutationCallback();
14393
- layoutCallback();
14394
- finishedAnimation?.();
14395
- spawnedWorkCallback();
14396
- return null;
14397
- },
14398
- startGestureTransition(_suspendedState, _rootContainer, _timeline, _rangeStart, _rangeEnd, _transitionTypes, mutationCallback, animateCallback, _errorCallback, finishedAnimation) {
14399
- mutationCallback();
14400
- animateCallback();
14401
- finishedAnimation?.();
14402
- return null;
14403
- },
14404
- stopViewTransition(_transition) {
14405
- },
14406
- // https://github.com/facebook/react/pull/35564
14407
- // Only reached with a non-null transition from startViewTransition, which never returns one here
14408
- addViewTransitionFinishedListener(_transition, callback) {
14409
- callback();
14410
- },
14411
- // https://github.com/facebook/react/pull/32038
14412
- createViewTransitionInstance: (_name) => null,
14413
- // https://github.com/facebook/react/pull/32379
14414
- // https://github.com/facebook/react/pull/32786
14415
- getCurrentGestureOffset(_provider) {
14416
- throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
14417
- },
14418
- // https://github.com/facebook/react/pull/32500
14419
- cloneMutableInstance(instance, _keepChildren) {
14420
- return instance;
14421
- },
14422
- cloneMutableTextInstance(textInstance) {
14423
- return textInstance;
14424
- },
14425
- // React 19.2 added these for root-level view transitions. They only run for hosts that opt into
14426
- // view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
14427
- // into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
14428
- // React never calls them. They stay as no-ops rather than throws: the host config is shared by
14429
- // every root, and a throw here would turn a React-internal probe into a hard crash for users.
14430
- // Guarded by a test asserting a full render + unmount never reaches them.
14431
- cloneRootViewTransitionContainer(_rootContainer) {
14432
- },
14433
- removeRootViewTransitionClone(_rootContainer, _clone) {
14434
- },
14435
- // https://github.com/facebook/react/pull/32465
14436
- createFragmentInstance: (_fiber) => null,
14437
- updateFragmentInstanceFiber(_fiber, _instance) {
14438
- },
14439
- commitNewChildToFragmentInstance(_child, _fragmentInstance) {
14440
- },
14441
- 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());
15145
+ setCurrentUpdatePriority(newPriority) {
15146
+ currentUpdatePriority = newPriority;
15147
+ },
15148
+ getCurrentUpdatePriority() {
15149
+ return currentUpdatePriority;
15150
+ },
15151
+ resolveUpdatePriority() {
15152
+ if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
15153
+ const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
15154
+ if (eventType === void 0) return r;
15155
+ return getEventPriority(eventType);
15156
+ },
15157
+ resetFormInstance() {
15158
+ },
15159
+ // @ts-ignore DefinitelyTyped is not up to date
15160
+ rendererPackageName: "@react-three/fiber",
15161
+ rendererVersion: packageData.version,
15162
+ // 19.2 Reconciler
15163
+ // https://github.com/facebook/react/pull/31975
15164
+ // https://github.com/facebook/react/pull/31999
15165
+ applyViewTransitionName(_instance, _name, _className) {
15166
+ },
15167
+ restoreViewTransitionName(_instance, _props) {
15168
+ },
15169
+ cancelViewTransitionName(_instance, _name, _props) {
15170
+ },
15171
+ cancelRootViewTransitionName(_rootContainer) {
15172
+ },
15173
+ restoreRootViewTransitionName(_rootContainer) {
15174
+ },
15175
+ InstanceMeasurement: null,
15176
+ measureInstance: (_instance) => null,
15177
+ wasInstanceInViewport: (_measurement) => true,
15178
+ hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
15179
+ hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
15180
+ // https://github.com/facebook/react/pull/32002
15181
+ // https://github.com/facebook/react/pull/34486
15182
+ suspendOnActiveViewTransition(_state, _container) {
15183
+ },
15184
+ // https://github.com/facebook/react/pull/32451
15185
+ // https://github.com/facebook/react/pull/32760
15186
+ // React hands the whole commit to the host when a transition touches a <ViewTransition> subtree.
15187
+ // three.js has nothing to animate between commits, so this mirrors the react-dom fallback for
15188
+ // browsers without document.startViewTransition and flushes the commit synchronously.
15189
+ startViewTransition(_suspendedState, _rootContainer, _transitionTypes, mutationCallback, layoutCallback, _afterMutationCallback, spawnedWorkCallback, _passiveCallback, _errorCallback, _blockedCallback, finishedAnimation) {
15190
+ mutationCallback();
15191
+ layoutCallback();
15192
+ finishedAnimation?.();
15193
+ spawnedWorkCallback();
15194
+ return null;
15195
+ },
15196
+ startGestureTransition(_suspendedState, _rootContainer, _timeline, _rangeStart, _rangeEnd, _transitionTypes, mutationCallback, animateCallback, _errorCallback, finishedAnimation) {
15197
+ mutationCallback();
15198
+ animateCallback();
15199
+ finishedAnimation?.();
15200
+ return null;
15201
+ },
15202
+ stopViewTransition(_transition) {
15203
+ },
15204
+ // https://github.com/facebook/react/pull/35564
15205
+ // Only reached with a non-null transition from startViewTransition, which never returns one here
15206
+ addViewTransitionFinishedListener(_transition, callback) {
15207
+ callback();
15208
+ },
15209
+ // https://github.com/facebook/react/pull/32038
15210
+ createViewTransitionInstance: (_name) => null,
15211
+ // https://github.com/facebook/react/pull/32379
15212
+ // https://github.com/facebook/react/pull/32786
15213
+ getCurrentGestureOffset(_provider) {
15214
+ throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
15215
+ },
15216
+ // https://github.com/facebook/react/pull/32500
15217
+ cloneMutableInstance(instance, _keepChildren) {
15218
+ return instance;
15219
+ },
15220
+ cloneMutableTextInstance(textInstance) {
15221
+ return textInstance;
15222
+ },
15223
+ // React 19.2 added these for root-level view transitions. They only run for hosts that opt into
15224
+ // view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
15225
+ // into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
15226
+ // React never calls them. They stay as no-ops rather than throws: the host config is shared by
15227
+ // every root, and a throw here would turn a React-internal probe into a hard crash for users.
15228
+ // Guarded by a test asserting a full render + unmount never reaches them.
15229
+ cloneRootViewTransitionContainer(_rootContainer) {
15230
+ },
15231
+ removeRootViewTransitionClone(_rootContainer, _clone) {
15232
+ },
15233
+ // https://github.com/facebook/react/pull/32465
15234
+ createFragmentInstance: (_fiber) => null,
15235
+ updateFragmentInstanceFiber(_fiber, _instance) {
15236
+ },
15237
+ commitNewChildToFragmentInstance(_child, _fragmentInstance) {
15238
+ },
15239
+ deleteChildFromFragmentInstance(_child, _fragmentInstance) {
15240
+ },
15241
+ // https://github.com/facebook/react/pull/32653
15242
+ measureClonedInstance: (_instance) => null,
15243
+ // https://github.com/facebook/react/pull/32819
15244
+ maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
15245
+ maySuspendCommitInSyncRender: (_type, _props) => false,
15246
+ // https://github.com/facebook/react/pull/34486
15247
+ startSuspendingCommit: () => null,
15248
+ // https://github.com/facebook/react/pull/34522
15249
+ getSuspendedCommitReason: (_state, _rootContainer) => null
15250
+ });
15251
+ function flushSync(fn) {
15252
+ return reconciler.flushSyncFromReconciler(fn);
14791
15253
  }
14792
15254
 
14793
- const isRenderer = (def) => !!def?.render;
15255
+ const noop = () => {
15256
+ };
14794
15257
  const _roots = /* @__PURE__ */ new Map();
14795
- function ensureStoreThreeObjects(store) {
14796
- const state = store.getState();
14797
- if (state.pointer) return;
14798
- const { Vector2, Frustum } = getThree();
14799
- const pointer = new Vector2();
14800
- state.set({ pointer, mouse: pointer, frustum: new Frustum() });
14801
- }
14802
- const shallowLoose = { objects: "shallow", strict: false };
14803
- async function resolveRenderer(config, defaultProps, RendererClass) {
14804
- if (typeof config === "function") return await config(defaultProps);
14805
- if (isRenderer(config)) return config;
14806
- return new RendererClass({ ...defaultProps, ...config });
14807
- }
14808
- function computeInitialSize(canvas, size) {
14809
- if (!size && typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
14810
- const { width, height, top, left } = canvas.parentElement.getBoundingClientRect();
14811
- return { width, height, top, left };
14812
- } else if (!size && typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas) {
14813
- return {
14814
- width: canvas.width,
14815
- height: canvas.height,
14816
- top: 0,
14817
- left: 0
14818
- };
15258
+ function transitionRoot(root, event) {
15259
+ const state = root.state;
15260
+ switch (event.type) {
15261
+ case "use":
15262
+ if (state.status === "disposed") return false;
15263
+ if (state.status === "closing") {
15264
+ root.store.getState().internal.active = true;
15265
+ state.settle();
15266
+ }
15267
+ root.state = { status: "open" };
15268
+ return true;
15269
+ case "unmount": {
15270
+ if (state.status === "disposed") return false;
15271
+ if (state.status === "closing") state.settle();
15272
+ const { promise, resolve } = deferred();
15273
+ root.state = { status: "closing", token: event.token, settled: promise, settle: resolve };
15274
+ return true;
15275
+ }
15276
+ case "dispose":
15277
+ if (state.status !== "closing" || state.token !== event.token) return false;
15278
+ root.state = { status: "disposed" };
15279
+ state.settle();
15280
+ return true;
14819
15281
  }
14820
- return { width: 0, height: 0, top: 0, left: 0, ...size };
14821
15282
  }
14822
15283
  function createRoot(canvas, provider) {
14823
15284
  const prevRoot = _roots.get(canvas);
@@ -14855,540 +15316,615 @@ function createRoot(canvas, provider) {
14855
15316
  null
14856
15317
  // transitionCallbacks
14857
15318
  );
14858
- if (!prevRoot) _roots.set(canvas, { fiber, store });
14859
- let onCreated;
14860
- let lastCamera;
14861
- const lastConfiguredProps = {};
14862
- let configured = false;
14863
- let pending = null;
14864
- let rendererSetup = null;
14865
- return {
14866
- async configure(props = {}) {
14867
- let resolve;
14868
- pending = new Promise((_resolve) => resolve = _resolve);
14869
- const {
14870
- id: canvasId,
14871
- primaryCanvas,
14872
- scheduler: schedulerConfig,
14873
- gl: glConfig,
14874
- renderer: rendererConfig,
14875
- size: propsSize,
14876
- scene: sceneOptions,
14877
- events,
14878
- onCreated: onCreatedCallback,
14879
- shadows = false,
14880
- orthographic = false,
14881
- frameloop = "always",
14882
- dpr = [1, 2],
14883
- performance,
14884
- raycaster: raycastOptions,
14885
- camera: cameraOptions,
14886
- onPointerMissed,
14887
- onDragOverMissed,
14888
- onDropMissed,
14889
- autoUpdateFrustum = true,
14890
- occlusion = false,
14891
- _sizeProps,
14892
- forceEven
14893
- } = props;
14894
- const requestedTextureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || void 0;
14895
- let state = store.getState();
14896
- const { webgl, webgpu } = provider;
14897
- const defaultGLProps = {
14898
- canvas,
14899
- powerPreference: "high-performance",
14900
- antialias: true,
14901
- alpha: true
14902
- };
14903
- const defaultGPUProps = {
14904
- canvas,
14905
- antialias: true
14906
- };
14907
- if (glConfig && !webgl) {
14908
- throw new Error(
14909
- "WebGLRenderer (gl prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/legacy instead."
14910
- );
14911
- }
14912
- if (rendererConfig && !webgpu) {
14913
- throw new Error(
14914
- "WebGPURenderer (renderer prop) is not available on this entry. Use @react-three/fiber or @react-three/fiber/webgpu instead."
14915
- );
14916
- }
14917
- const wantsGL = !!webgl && (state.isLegacy || !!glConfig || !webgpu || !rendererConfig);
14918
- if (glConfig && rendererConfig) {
14919
- throw new Error("Cannot use both gl and renderer props at the same time");
14920
- }
14921
- if (webgl && webgpu && !state.isLegacy && wantsGL) {
14922
- extensions.notifyDepreciated({
14923
- heading: "WebGlRenderer Usage",
14924
- body: "WebGlRenderer usage is deprecated in favor of WebGPU. Import from /legacy directly or upgrade to WebGPU.",
14925
- link: "https://docs.pmnd.rs/react-three-fiber/api/renderer"
14926
- });
14927
- }
14928
- let renderer = state.internal.actualRenderer;
14929
- if (primaryCanvas && !webgpu) {
14930
- throw new Error(
14931
- "The `primaryCanvas` prop for multi-canvas rendering is only available with WebGPU. Use @react-three/fiber/webgpu instead."
14932
- );
14933
- }
14934
- if (primaryCanvas && wantsGL) {
14935
- throw new Error(
14936
- "The `primaryCanvas` prop for multi-canvas rendering cannot be used with WebGL. Remove the `gl` prop or use WebGPU."
14937
- );
15319
+ const root = prevRoot || {
15320
+ fiber,
15321
+ store,
15322
+ state: { status: "open" },
15323
+ ready: fulfilled(void 0),
15324
+ configuration: {}
15325
+ };
15326
+ if (!prevRoot) _roots.set(canvas, root);
15327
+ if (!prevRoot) root.configuration.apply = createRootConfiguration(store, canvas);
15328
+ let mounted = false;
15329
+ return {
15330
+ get ready() {
15331
+ return root.ready;
15332
+ },
15333
+ configure(props = {}) {
15334
+ if (!transitionRoot(root, { type: "use" })) {
15335
+ return rejected(new Error("R3F: Cannot configure a root after it has unmounted (disposal has started)."));
15336
+ }
15337
+ const previous = root.ready;
15338
+ const { promise, resolve, reject } = deferred();
15339
+ root.ready = promise;
15340
+ const run = () => {
15341
+ try {
15342
+ const initialized = initializeRenderer(canvas, provider, store, props);
15343
+ const apply = () => {
15344
+ if (props.id) {
15345
+ for (const other of _roots.values()) {
15346
+ if (other !== root && other.state.status === "closing" && other.store.getState().internal.rootId === props.id) {
15347
+ other.state.settled.then(apply).catch(reject);
15348
+ return;
15349
+ }
15350
+ }
15351
+ }
15352
+ const previous2 = root.configuration.previous;
15353
+ root.configuration.apply(props);
15354
+ configureScheduler(store, props.id, props.scheduler, previous2?.scheduler);
15355
+ textureStaging.attachRootExtensions(store);
15356
+ root.configuration.previous = props;
15357
+ resolve(this);
15358
+ };
15359
+ if (isPromiseLike(initialized)) Promise.resolve(initialized).then(apply).catch(reject);
15360
+ else apply();
15361
+ } catch (error) {
15362
+ reject(error);
15363
+ }
15364
+ };
15365
+ if (previous.status === "pending") previous.then(run, reject);
15366
+ else run();
15367
+ return promise;
15368
+ },
15369
+ render(children) {
15370
+ if (!transitionRoot(root, { type: "use" })) return store;
15371
+ if (!store.getState().internal.actualRenderer && root.ready.status === "fulfilled") this.configure();
15372
+ if (root.ready.status === "rejected") throw root.ready.reason;
15373
+ const commit = () => {
15374
+ if (root.state.status !== "open" || root.ready.status === "rejected") return;
15375
+ if (root.ready.status === "pending") {
15376
+ root.ready.then(commit, logRecoverableError);
15377
+ return;
15378
+ }
15379
+ const onCreated = root.configuration.previous?.onCreated;
15380
+ const element = /* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas });
15381
+ if (mounted) {
15382
+ reconciler.updateContainer(element, fiber, null, noop);
15383
+ return;
15384
+ }
15385
+ mounted = true;
15386
+ reconciler.updateContainerSync(element, fiber, null, noop);
15387
+ reconciler.flushSyncWork();
15388
+ };
15389
+ commit();
15390
+ return store;
15391
+ },
15392
+ unmount() {
15393
+ if (_roots.get(canvas) === root) unmountComponentAtNode(canvas);
15394
+ }
15395
+ };
15396
+ }
15397
+ function Provider({
15398
+ store,
15399
+ children,
15400
+ onCreated,
15401
+ rootElement
15402
+ }) {
15403
+ textureStaging.useIsomorphicLayoutEffect(() => {
15404
+ const state = store.getState();
15405
+ state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
15406
+ if (onCreated) onCreated(state);
15407
+ if (!store.getState().events.connected) state.events.connect?.(rootElement);
15408
+ }, []);
15409
+ return /* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: store, children });
15410
+ }
15411
+ function unmountComponentAtNode(canvas, callback) {
15412
+ const claim = Symbol("unmount");
15413
+ const root = _roots.get(canvas);
15414
+ if (!root || !transitionRoot(root, { type: "unmount", token: claim })) return;
15415
+ root.store.getState().internal.active = false;
15416
+ reconciler.updateContainer(null, root.fiber, null, () => {
15417
+ if (root.state.status !== "closing" || root.state.token !== claim) return;
15418
+ reconciler.updateContainer(null, root.fiber, null, () => {
15419
+ if (root.state.status !== "closing" || root.state.token !== claim) return;
15420
+ if (root.ready.status === "pending") root.ready.then(teardown, teardown);
15421
+ else teardown();
15422
+ });
15423
+ });
15424
+ function teardown() {
15425
+ if (root.ready.status === "pending") {
15426
+ root.ready.then(teardown, teardown);
15427
+ return;
15428
+ }
15429
+ if (!transitionRoot(root, { type: "dispose", token: claim })) return;
15430
+ _roots.delete(canvas);
15431
+ const state = root.store.getState();
15432
+ const internal = state.internal;
15433
+ internal.active = false;
15434
+ const attempt = (step) => {
15435
+ try {
15436
+ return step();
15437
+ } catch (error) {
15438
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15439
+ }
15440
+ };
15441
+ attempt(() => internal.unwatchDpr?.());
15442
+ internal.unwatchDpr = void 0;
15443
+ attempt(() => internal.unregisterRoot?.());
15444
+ internal.unregisterRoot = void 0;
15445
+ attempt(() => textureStaging.detachRootExtensions(root.store));
15446
+ attempt(() => internal.unregisterPrimary?.());
15447
+ attempt(() => internal.untrackStandalone?.());
15448
+ attempt(() => state.events.disconnect?.());
15449
+ if (!internal.isSecondary && internal.actualRenderer?.xr && state.xr) attempt(() => state.xr.disconnect());
15450
+ attempt(() => cleanupHelperGroup(root.store));
15451
+ if (state.scene) attempt(() => dispose(state.scene));
15452
+ const canvasTarget = internal.canvasTarget;
15453
+ if (internal.isSecondary && canvasTarget?.dispose) attempt(() => canvasTarget.dispose());
15454
+ const released = attempt(() => internal.releaseRenderer?.());
15455
+ internal.releaseRenderer = void 0;
15456
+ if (callback) {
15457
+ if (released) {
15458
+ released.then(() => callback(canvas)).catch((error) => console.warn("[R3F] Error in unmount callback", error));
15459
+ } else {
15460
+ callback(canvas);
15461
+ }
15462
+ }
15463
+ }
15464
+ }
15465
+
15466
+ const memoizedLoaders = /* @__PURE__ */ new WeakMap();
15467
+ const isConstructor = (value) => typeof value === "function" && value?.prototype?.constructor === value;
15468
+ function getLoader(Proto) {
15469
+ if (isConstructor(Proto)) {
15470
+ let loader = memoizedLoaders.get(Proto);
15471
+ if (!loader) {
15472
+ loader = new Proto();
15473
+ memoizedLoaders.set(Proto, loader);
15474
+ }
15475
+ return loader;
15476
+ }
15477
+ return Proto;
15478
+ }
15479
+ function loadingFn(extensions, onProgress) {
15480
+ return function(Proto, input) {
15481
+ const loader = getLoader(Proto);
15482
+ if (extensions) extensions(loader);
15483
+ if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
15484
+ return loader.loadAsync(input, onProgress).then((data) => {
15485
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
15486
+ return data;
15487
+ });
15488
+ }
15489
+ return new Promise(
15490
+ (res, reject) => loader.load(
15491
+ input,
15492
+ (data) => {
15493
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
15494
+ res(data);
15495
+ },
15496
+ onProgress,
15497
+ (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
15498
+ )
15499
+ );
15500
+ };
15501
+ }
15502
+ function useLoader(loader, input, extensions, onProgress, cacheKey) {
15503
+ const inputs = Array.isArray(input) ? input : [input];
15504
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15505
+ const fn = loadingFn(extensions, onProgress);
15506
+ const results = cacheKeys.map(
15507
+ (key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
15508
+ );
15509
+ const stableRef = React.useRef(null);
15510
+ const previous = stableRef.current;
15511
+ const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
15512
+ stableRef.current = stable;
15513
+ return Array.isArray(input) ? stable : stable[0];
15514
+ }
15515
+ useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
15516
+ const inputs = Array.isArray(input) ? input : [input];
15517
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15518
+ cacheKeys.forEach(
15519
+ (key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
15520
+ );
15521
+ };
15522
+ useLoader.clear = function(loader, input, cacheKey) {
15523
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
15524
+ cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
15525
+ };
15526
+ useLoader.loader = getLoader;
15527
+
15528
+ const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
15529
+ function getUrls(input) {
15530
+ if (typeof input === "string") return [input];
15531
+ if (Array.isArray(input)) return input;
15532
+ return Object.values(input);
15533
+ }
15534
+ function inputSignature(input) {
15535
+ if (typeof input === "string") return input;
15536
+ if (Array.isArray(input)) return input.join("\0");
15537
+ return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
15538
+ }
15539
+ function allUrlsCached(urls, textureCache) {
15540
+ return urls.every((url) => textureCache.has(url));
15541
+ }
15542
+ function buildFromCache(input, textureCache) {
15543
+ if (typeof input === "string") {
15544
+ return textureCache.get(input);
15545
+ } else if (Array.isArray(input)) {
15546
+ return input.map((url) => textureCache.get(url));
15547
+ } else {
15548
+ const result = {};
15549
+ const objInput = input;
15550
+ for (const key in objInput) {
15551
+ result[key] = textureCache.get(objInput[key]);
15552
+ }
15553
+ return result;
15554
+ }
15555
+ }
15556
+ function useTexture(input, optionsOrOnLoad) {
15557
+ const renderer = textureStaging.useThree((state) => state.internal.actualRenderer);
15558
+ const store = textureStaging.useStore();
15559
+ const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
15560
+ const { onLoad, cache = true } = options;
15561
+ const onLoadRef = React.useRef(onLoad);
15562
+ onLoadRef.current = onLoad;
15563
+ const onLoadCalledForRef = React.useRef(null);
15564
+ const inputKey = React.useMemo(() => inputSignature(input), [input]);
15565
+ const stableInput = React.useMemo(() => input, [inputKey]);
15566
+ const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
15567
+ const cachedResult = React.useMemo(() => {
15568
+ if (!cache) return null;
15569
+ const textures = store.getState().textures;
15570
+ if (!allUrlsCached(urls, textures)) return null;
15571
+ return buildFromCache(stableInput, textures);
15572
+ }, [cache, urls, stableInput, store]);
15573
+ const loadedTextures = useLoader(
15574
+ getThree().TextureLoader,
15575
+ IsObject(stableInput) ? Object.values(stableInput) : stableInput
15576
+ );
15577
+ const mappedTextures = React.useMemo(() => {
15578
+ if (cachedResult) return cachedResult;
15579
+ if (IsObject(stableInput)) {
15580
+ const keyed = {};
15581
+ const textureArray = loadedTextures;
15582
+ let i = 0;
15583
+ for (const key in stableInput) keyed[key] = textureArray[i++];
15584
+ return keyed;
15585
+ } else {
15586
+ return loadedTextures;
15587
+ }
15588
+ }, [stableInput, loadedTextures, cachedResult]);
15589
+ React.useLayoutEffect(() => {
15590
+ if (cachedResult) return;
15591
+ if (onLoadCalledForRef.current === inputKey) return;
15592
+ onLoadCalledForRef.current = inputKey;
15593
+ onLoadRef.current?.(mappedTextures);
15594
+ }, [cachedResult, mappedTextures, inputKey]);
15595
+ React.useEffect(() => {
15596
+ if (cachedResult) return;
15597
+ if ("initTexture" in renderer) {
15598
+ let textureArray = [];
15599
+ if (Array.isArray(loadedTextures)) {
15600
+ textureArray = loadedTextures;
15601
+ } else if (loadedTextures.isTexture) {
15602
+ textureArray = [loadedTextures];
15603
+ } else if (IsObject(loadedTextures)) {
15604
+ textureArray = Object.values(loadedTextures);
14938
15605
  }
14939
- if (!state.internal.actualRenderer) {
14940
- if (!rendererSetup) {
14941
- rendererSetup = (async () => {
14942
- const support = wantsGL ? await webgl() : await webgpu();
14943
- registerThree(support.three);
14944
- state.internal.support = support;
14945
- ensureStoreThreeObjects(store);
14946
- if (support.kind === "webgl") {
14947
- renderer = await resolveRenderer(glConfig, defaultGLProps, support.Renderer);
14948
- state.internal.actualRenderer = renderer;
14949
- state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14950
- } else if (primaryCanvas) {
14951
- const primary = await waitForPrimary(primaryCanvas);
14952
- renderer = primary.renderer;
14953
- state.internal.actualRenderer = renderer;
14954
- const canvasTarget = new support.CanvasTarget(canvas);
14955
- primary.store.setState((prev) => ({
14956
- internal: { ...prev.internal, isMultiCanvas: true }
14957
- }));
14958
- state.set((prev) => ({
14959
- webGPUSupported: primary.store.getState().webGPUSupported,
14960
- renderer,
14961
- primaryStore: primary.store,
14962
- internal: {
14963
- ...prev.internal,
14964
- canvasTarget,
14965
- isMultiCanvas: true,
14966
- isSecondary: true,
14967
- targetId: primaryCanvas
14968
- }
14969
- }));
14970
- } else {
14971
- renderer = await resolveRenderer(rendererConfig, defaultGPUProps, support.Renderer);
14972
- if (!renderer.hasInitialized?.()) {
14973
- const size2 = computeInitialSize(canvas, propsSize);
14974
- if (size2.width > 0 && size2.height > 0) {
14975
- renderer.setPixelRatio(calculateDpr(dpr));
14976
- renderer.setSize(size2.width, size2.height, false);
14977
- }
14978
- await renderer.init();
14979
- }
14980
- const backend = renderer.backend;
14981
- const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14982
- state.internal.actualRenderer = renderer;
14983
- state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14984
- if (canvasId && !state.internal.isSecondary) {
14985
- const canvasTarget = renderer.getCanvasTarget?.();
14986
- const unregisterPrimary = registerPrimary(canvasId, renderer, store);
14987
- state.set((prev) => ({
14988
- internal: {
14989
- ...prev.internal,
14990
- canvasTarget,
14991
- unregisterPrimary
14992
- }
14993
- }));
14994
- }
14995
- }
14996
- })().catch((err) => {
14997
- rendererSetup = null;
14998
- throw err;
14999
- });
15606
+ textureArray.forEach((texture) => {
15607
+ if (texture?.isTexture) {
15608
+ renderer.initTexture(texture);
15000
15609
  }
15001
- await rendererSetup;
15002
- state = store.getState();
15003
- renderer = state.internal.actualRenderer;
15004
- }
15005
- const three = getThree();
15006
- let raycaster = state.raycaster;
15007
- if (!raycaster) state.set({ raycaster: raycaster = new three.Raycaster() });
15008
- const { params, ...options } = raycastOptions || {};
15009
- if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
15010
- if (!is.equ(params, raycaster.params, shallowLoose)) {
15011
- applyProps(raycaster, { params: { ...raycaster.params, ...params } });
15012
- }
15013
- let tempCamera = state.camera;
15014
- if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
15015
- lastCamera = cameraOptions;
15016
- const isCamera = cameraOptions?.isCamera;
15017
- const camera = isCamera ? cameraOptions : orthographic ? new three.OrthographicCamera(0, 0, 0, 0, 0.1, 1e3) : new three.PerspectiveCamera(50, 0, 0.1, 1e3);
15018
- if (!isCamera) {
15019
- camera.position.z = 5;
15020
- if (cameraOptions) {
15021
- applyProps(camera, cameraOptions);
15022
- if (!camera.manual) {
15023
- const projectionProps = ["aspect", "left", "right", "bottom", "top"];
15024
- if (projectionProps.some((prop) => prop in cameraOptions)) {
15025
- camera.manual = true;
15026
- camera.updateProjectionMatrix();
15027
- }
15028
- }
15610
+ });
15611
+ }
15612
+ }, [renderer, loadedTextures, cachedResult]);
15613
+ React.useEffect(() => {
15614
+ if (!cache) return;
15615
+ const urlTextureMap = urlTextureEntries(stableInput, mappedTextures);
15616
+ store.setState((state) => {
15617
+ const refs = new Map(state._textureRefs);
15618
+ let textures = state.textures;
15619
+ let added = false;
15620
+ for (const [url, texture] of urlTextureMap) {
15621
+ if (!textures.has(url)) {
15622
+ if (!added) {
15623
+ textures = new Map(textures);
15624
+ added = true;
15029
15625
  }
15030
- if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
15626
+ textures.set(url, texture);
15031
15627
  }
15032
- state.set({ camera });
15033
- tempCamera = camera;
15034
- raycaster.camera = camera;
15035
- }
15036
- if (!state.scene) {
15037
- let scene;
15038
- if (sceneOptions?.isScene) {
15039
- scene = sceneOptions;
15040
- prepare(scene, store, "", {});
15041
- } else {
15042
- scene = new three.Scene();
15043
- prepare(scene, store, "", {});
15044
- if (sceneOptions) applyProps(scene, sceneOptions);
15045
- }
15046
- state.set((prev) => ({
15047
- scene,
15048
- rootScene: scene,
15049
- internal: { ...prev.internal, container: scene }
15050
- }));
15051
- const camera = tempCamera;
15052
- if (camera && !camera.parent) scene.add(camera);
15053
- }
15054
- if (events && !state.events.handlers) {
15055
- state.set({ events: events(store) });
15056
- let wasEnabled = true;
15057
- store.subscribe((state2) => {
15058
- const { enabled } = state2.events;
15059
- if (enabled && !wasEnabled) {
15060
- state2.events.update?.();
15061
- }
15062
- wasEnabled = enabled;
15063
- });
15064
- }
15065
- if (_sizeProps !== void 0) {
15066
- state.set({ _sizeProps });
15628
+ refs.set(url, (refs.get(url) ?? 0) + 1);
15067
15629
  }
15068
- if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
15069
- state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
15630
+ return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
15631
+ });
15632
+ textureStaging.unstageTextures(
15633
+ store,
15634
+ urlTextureMap.map(([url]) => url)
15635
+ );
15636
+ return () => store.setState((state) => {
15637
+ const refs = new Map(state._textureRefs);
15638
+ for (const [url] of urlTextureMap) {
15639
+ const next = (refs.get(url) ?? 0) - 1;
15640
+ if (next <= 0) refs.delete(url);
15641
+ else refs.set(url, next);
15070
15642
  }
15071
- const size = computeInitialSize(canvas, propsSize);
15072
- if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
15073
- const wasImperative = state._sizeImperative;
15074
- state.setSize(size.width, size.height, size.top, size.left);
15075
- if (!wasImperative) state.set({ _sizeImperative: false });
15076
- }
15077
- if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
15078
- state.setDpr(dpr);
15079
- lastConfiguredProps.dpr = dpr;
15080
- }
15081
- if (frameloop !== void 0 && frameloop !== lastConfiguredProps.frameloop) {
15082
- state.setFrameloop(frameloop);
15083
- lastConfiguredProps.frameloop = frameloop;
15084
- }
15085
- if (!state.onPointerMissed) state.set({ onPointerMissed });
15086
- if (!state.onDragOverMissed) state.set({ onDragOverMissed });
15087
- if (!state.onDropMissed) state.set({ onDropMissed });
15088
- if (state.autoUpdateFrustum !== autoUpdateFrustum) state.set({ autoUpdateFrustum });
15089
- if (occlusion && !state.internal.occlusionEnabled) {
15090
- enableOcclusion(store);
15091
- }
15092
- if (performance && !is.equ(performance, lastConfiguredProps.performance, shallowLoose)) {
15093
- state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
15094
- lastConfiguredProps.performance = performance;
15095
- }
15096
- if (!state.xr) {
15097
- const handleXRFrame = (timestamp, _frame) => {
15098
- const state2 = store.getState();
15099
- if (state2.frameloop === "never") return;
15100
- advance(timestamp, true, state2);
15101
- };
15102
- const actualRenderer = state.internal.actualRenderer;
15103
- const handleSessionChange = () => {
15104
- const state2 = store.getState();
15105
- const renderer2 = state2.internal.actualRenderer;
15106
- actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
15107
- renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
15108
- if (!renderer2.xr.isPresenting) invalidate(state2);
15109
- };
15110
- const xr = {
15111
- connect() {
15112
- const { gl, renderer: renderer2 } = store.getState();
15113
- const xrManager = (renderer2 || gl).xr;
15114
- xrManager.addEventListener("sessionstart", handleSessionChange);
15115
- xrManager.addEventListener("sessionend", handleSessionChange);
15116
- },
15117
- disconnect() {
15118
- const { gl, renderer: renderer2 } = store.getState();
15119
- const xrManager = (renderer2 || gl).xr;
15120
- xrManager.removeEventListener("sessionstart", handleSessionChange);
15121
- xrManager.removeEventListener("sessionend", handleSessionChange);
15122
- }
15123
- };
15124
- if (typeof renderer.xr?.addEventListener === "function") xr.connect();
15125
- state.set({ xr });
15126
- }
15127
- if (renderer.shadowMap && !is.equ(shadows, lastConfiguredProps.shadows, shallowLoose)) {
15128
- lastConfiguredProps.shadows = shadows;
15129
- const oldEnabled = renderer.shadowMap.enabled;
15130
- const oldType = renderer.shadowMap.type;
15131
- renderer.shadowMap.enabled = !!shadows;
15132
- if (is.boo(shadows)) {
15133
- renderer.shadowMap.type = three.PCFShadowMap;
15134
- } else if (is.str(shadows)) {
15135
- if (shadows === "soft") {
15136
- extensions.notifyDepreciated({
15137
- heading: 'shadows="soft" is deprecated',
15138
- body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
15139
- link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
15140
- });
15643
+ return { _textureRefs: refs };
15644
+ });
15645
+ }, [cache, stableInput, mappedTextures, store]);
15646
+ if (cache && !cachedResult) textureStaging.stageTextures(store, urlTextureEntries(stableInput, mappedTextures));
15647
+ return mappedTextures;
15648
+ }
15649
+ function urlTextureEntries(input, textures) {
15650
+ if (typeof input === "string") return [[input, textures]];
15651
+ if (Array.isArray(input)) return input.map((url, i) => [url, textures[i]]);
15652
+ const record = textures;
15653
+ return Object.keys(input).map((key) => [input[key], record[key]]);
15654
+ }
15655
+ useTexture.preload = (url) => {
15656
+ whenThree().then((three) => useLoader.preload(three.TextureLoader, url));
15657
+ };
15658
+ useTexture.clear = (input) => {
15659
+ if (hasThree()) useLoader.clear(getThree().TextureLoader, input);
15660
+ };
15661
+ const Texture = ({
15662
+ children,
15663
+ input,
15664
+ onLoad,
15665
+ cache
15666
+ }) => {
15667
+ const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
15668
+ const ret = useTexture(input, options);
15669
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
15670
+ };
15671
+
15672
+ function useTextures(selector) {
15673
+ const store = textureStaging.useStore();
15674
+ const registry = React.useMemo(() => {
15675
+ const getState = store.getState;
15676
+ const setState = store.setState;
15677
+ const getOne = (key) => getState().textures.get(key);
15678
+ return {
15679
+ get all() {
15680
+ return getState().textures;
15681
+ },
15682
+ get(input) {
15683
+ if (typeof input === "string") return getOne(input);
15684
+ if (Array.isArray(input)) return input.map(getOne);
15685
+ const out = {};
15686
+ for (const name in input) out[name] = getOne(input[name]);
15687
+ return out;
15688
+ },
15689
+ has: (key) => getState().textures.has(key),
15690
+ add(keyOrRecord, texture) {
15691
+ setState((state) => {
15692
+ const textures = new Map(state.textures);
15693
+ if (typeof keyOrRecord === "string") {
15694
+ textures.set(keyOrRecord, texture);
15695
+ } else {
15696
+ for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
15141
15697
  }
15142
- const types = {
15143
- basic: three.BasicShadowMap,
15144
- percentage: three.PCFShadowMap,
15145
- soft: three.PCFShadowMap,
15146
- variance: three.VSMShadowMap
15147
- };
15148
- renderer.shadowMap.type = types[shadows] ?? three.PCFShadowMap;
15149
- } else if (is.obj(shadows)) {
15150
- Object.assign(renderer.shadowMap, shadows);
15151
- }
15152
- if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
15153
- renderer.shadowMap.needsUpdate = true;
15154
- }
15155
- }
15156
- if (!configured) {
15157
- renderer.outputColorSpace = three.SRGBColorSpace;
15158
- renderer.toneMapping = three.ACESFilmicToneMapping;
15159
- }
15160
- const textureColorSpace = requestedTextureColorSpace ?? three.SRGBColorSpace;
15161
- if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
15162
- if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
15163
- lastConfiguredProps.textureColorSpace = textureColorSpace;
15164
- }
15165
- const r3fProps = ["textureColorSpace"];
15166
- const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
15167
- const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
15168
- if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
15169
- const glProps = {};
15170
- for (const key in glConfig) {
15171
- if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
15172
- }
15173
- applyProps(renderer, glProps);
15174
- }
15175
- if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
15176
- const currentRenderer = state.renderer;
15177
- if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
15178
- const rendererProps = {};
15179
- for (const key in rendererConfig) {
15180
- if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
15181
- }
15182
- applyProps(currentRenderer, rendererProps);
15183
- }
15184
- }
15185
- const scheduler$1 = scheduler.getScheduler();
15186
- const rootId = state.internal.rootId;
15187
- if (!rootId) {
15188
- const newRootId = canvasId || scheduler$1.generateRootId();
15189
- const unregisterRoot = scheduler$1.registerRoot(newRootId, {
15190
- getState: () => store.getState(),
15191
- onError: (err) => store.getState().setError(err),
15192
- frameloop: store.getState().frameloop,
15193
- before: schedulerConfig?.before,
15194
- after: schedulerConfig?.after,
15195
- order: schedulerConfig?.order
15698
+ return { textures };
15196
15699
  });
15197
- const unregisterCanvasTarget = scheduler$1.register(
15198
- () => {
15199
- const state2 = store.getState();
15200
- const canvasTarget = state2.internal.canvasTarget;
15201
- if (canvasTarget) {
15202
- const renderer2 = state2.internal.actualRenderer;
15203
- if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
15204
- if (state2.internal.canvasTargetSizeDirty) {
15205
- state2.internal.canvasTargetSizeDirty = false;
15206
- renderer2.backend?.updateSize?.();
15207
- }
15208
- }
15209
- },
15210
- {
15211
- id: `${newRootId}_canvasTarget`,
15212
- rootId: newRootId,
15213
- phase: "start",
15214
- system: true
15215
- }
15216
- );
15217
- const unregisterEventsFlush = scheduler$1.register(
15218
- () => {
15219
- const state2 = store.getState();
15220
- state2.events.flush?.();
15221
- },
15222
- {
15223
- id: `${newRootId}_events`,
15224
- rootId: newRootId,
15225
- phase: "input",
15226
- system: true
15227
- }
15228
- );
15229
- const unregisterFrustum = scheduler$1.register(
15230
- () => {
15231
- const state2 = store.getState();
15232
- if (state2.autoUpdateFrustum && state2.camera) {
15233
- updateFrustum(state2.camera, state2.frustum);
15234
- }
15235
- },
15236
- {
15237
- id: `${newRootId}_frustum`,
15238
- rootId: newRootId,
15239
- before: "render",
15240
- system: true
15241
- }
15242
- );
15243
- const unregisterVisibility = scheduler$1.register(
15244
- () => {
15245
- const state2 = store.getState();
15246
- checkVisibility(state2);
15247
- },
15248
- {
15249
- id: `${newRootId}_visibility`,
15250
- rootId: newRootId,
15251
- before: "render",
15252
- system: true,
15253
- after: `${newRootId}_frustum`
15254
- }
15255
- );
15256
- const unregisterRender = scheduler$1.register(
15257
- () => {
15258
- const state2 = store.getState();
15259
- const renderer2 = state2.internal.actualRenderer;
15260
- const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
15261
- if (userHandlesRender || state2.internal.priority) return;
15262
- try {
15263
- const renderOverride = state2.internal.renderOverride;
15264
- if (renderOverride) renderOverride();
15265
- else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
15266
- } catch (error) {
15267
- state2.setError(error instanceof Error ? error : new Error(String(error)));
15268
- }
15269
- },
15270
- {
15271
- // Use canvas ID directly as job ID if available, otherwise use generated rootId
15272
- id: canvasId || `${newRootId}_render`,
15273
- rootId: newRootId,
15274
- phase: "render",
15275
- system: true,
15276
- // Internal flag: this is a system job, not user-controlled
15277
- // FPS throttles only the default render job; Canvas ordering belongs to the root.
15278
- ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
15279
- }
15280
- );
15281
- state.set((state2) => ({
15282
- internal: {
15283
- ...state2.internal,
15284
- rootId: newRootId,
15285
- unregisterRoot: () => {
15286
- unregisterRoot();
15287
- unregisterCanvasTarget();
15288
- unregisterEventsFlush();
15289
- unregisterFrustum();
15290
- unregisterVisibility();
15291
- unregisterRender();
15292
- },
15293
- scheduler: scheduler$1
15294
- }
15295
- }));
15296
- } else {
15297
- const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
15298
- if (constraintsChanged) {
15299
- scheduler$1.setRootConstraints(rootId, {
15300
- before: schedulerConfig?.before,
15301
- after: schedulerConfig?.after
15302
- });
15303
- }
15304
- if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
15305
- scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
15700
+ },
15701
+ dispose(key, options) {
15702
+ const state = getState();
15703
+ const refs = state._textureRefs.get(key) ?? 0;
15704
+ if (refs > 0 && !options?.force) {
15705
+ console.warn(
15706
+ `[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
15707
+ );
15708
+ return false;
15306
15709
  }
15710
+ state.textures.get(key)?.dispose();
15711
+ setState((s) => {
15712
+ const textures = new Map(s.textures);
15713
+ textures.delete(key);
15714
+ const nextRefs = new Map(s._textureRefs);
15715
+ nextRefs.delete(key);
15716
+ return { textures, _textureRefs: nextRefs };
15717
+ });
15718
+ return true;
15719
+ },
15720
+ disposeAll() {
15721
+ for (const texture of getState().textures.values()) texture.dispose();
15722
+ setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
15307
15723
  }
15308
- lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
15309
- lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
15310
- lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
15311
- extensions.attachRootExtensions(store);
15312
- onCreated = onCreatedCallback;
15313
- configured = true;
15314
- resolve();
15315
- return this;
15316
- },
15317
- render(children) {
15318
- if (!configured && !pending) this.configure();
15319
- pending.then(() => {
15320
- reconciler.updateContainer(
15321
- /* @__PURE__ */ jsxRuntime.jsx(Provider, { store, children, onCreated, rootElement: canvas }),
15322
- fiber,
15323
- null,
15324
- () => void 0
15325
- );
15326
- });
15327
- return store;
15328
- },
15329
- unmount() {
15330
- unmountComponentAtNode(canvas);
15331
- }
15332
- };
15724
+ };
15725
+ }, [store]);
15726
+ const subscribe = selector ? () => selector(registry) : (state) => state.textures;
15727
+ const selected = textureStaging.useThree(subscribe);
15728
+ return selector ? selected : registry;
15333
15729
  }
15334
- function Provider({
15335
- store,
15336
- children,
15337
- onCreated,
15338
- rootElement
15339
- }) {
15340
- extensions.useIsomorphicLayoutEffect(() => {
15341
- const state = store.getState();
15342
- state.set((state2) => ({ internal: { ...state2.internal, active: true } }));
15343
- if (onCreated) onCreated(state);
15344
- if (!store.getState().events.connected) state.events.connect?.(rootElement);
15345
- }, []);
15346
- return /* @__PURE__ */ jsxRuntime.jsx(extensions.context.Provider, { value: store, children });
15730
+
15731
+ function useRenderTarget(widthOrOptions, heightOrOptions, options) {
15732
+ const support = textureStaging.useThree((s) => s.internal.support);
15733
+ const size = textureStaging.useThree((s) => s.size);
15734
+ let width;
15735
+ let height;
15736
+ let opts;
15737
+ if (typeof widthOrOptions === "object") {
15738
+ opts = widthOrOptions;
15739
+ } else if (typeof widthOrOptions === "number") {
15740
+ width = widthOrOptions;
15741
+ if (typeof heightOrOptions === "object") {
15742
+ height = widthOrOptions;
15743
+ opts = heightOrOptions;
15744
+ } else if (typeof heightOrOptions === "number") {
15745
+ height = heightOrOptions;
15746
+ opts = options;
15747
+ } else {
15748
+ height = widthOrOptions;
15749
+ }
15750
+ }
15751
+ return React.useMemo(() => {
15752
+ const w = width ?? size.width;
15753
+ const h = height ?? size.height;
15754
+ const Target = support.RenderTarget;
15755
+ return new Target(w, h, opts);
15756
+ }, [width, height, size.width, size.height, opts, support]);
15347
15757
  }
15348
- function unmountComponentAtNode(canvas, callback) {
15349
- const root = _roots.get(canvas);
15350
- const fiber = root?.fiber;
15351
- if (fiber) {
15352
- const state = root?.store.getState();
15353
- if (state) {
15354
- state.internal.active = false;
15355
- const unregisterRoot = state.internal.unregisterRoot;
15356
- if (unregisterRoot) {
15357
- unregisterRoot();
15358
- state.internal.unregisterRoot = void 0;
15758
+
15759
+ const presetsObj = {
15760
+ apartment: "lebombo_1k.hdr",
15761
+ city: "potsdamer_platz_1k.hdr",
15762
+ dawn: "kiara_1_dawn_1k.hdr",
15763
+ forest: "forest_slope_1k.hdr",
15764
+ lobby: "st_fagans_interior_1k.hdr",
15765
+ night: "dikhololo_night_1k.hdr",
15766
+ park: "rooitou_park_1k.hdr",
15767
+ studio: "studio_small_03_1k.hdr",
15768
+ sunset: "venice_sunset_1k.hdr",
15769
+ warehouse: "empty_warehouse_01_1k.hdr"
15770
+ };
15771
+
15772
+ const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
15773
+ const isArray = (arr) => Array.isArray(arr);
15774
+ const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
15775
+ const loadedLoaders = /* @__PURE__ */ new Map();
15776
+ const pendingLoaders = /* @__PURE__ */ new Map();
15777
+ function loadLoader(format) {
15778
+ let pending = pendingLoaders.get(format);
15779
+ if (!pending) {
15780
+ pending = importLoader(format).then(
15781
+ (loader) => {
15782
+ loadedLoaders.set(format, loader);
15783
+ return loader;
15784
+ },
15785
+ (error) => {
15786
+ pendingLoaders.delete(format);
15787
+ throw error;
15359
15788
  }
15789
+ );
15790
+ pendingLoaders.set(format, pending);
15791
+ }
15792
+ return pending;
15793
+ }
15794
+ async function importLoader(format) {
15795
+ let loader;
15796
+ switch (format) {
15797
+ case "cube":
15798
+ loader = getThree().CubeTextureLoader;
15799
+ break;
15800
+ case "hdr-cube":
15801
+ loader = (await import('three/examples/jsm/loaders/HDRCubeTextureLoader.js')).HDRCubeTextureLoader;
15802
+ break;
15803
+ case "hdr":
15804
+ loader = (await import('three/examples/jsm/loaders/HDRLoader.js')).HDRLoader;
15805
+ break;
15806
+ case "exr":
15807
+ loader = (await import('three/examples/jsm/loaders/EXRLoader.js')).EXRLoader;
15808
+ break;
15809
+ case "jpg":
15810
+ loader = (await import('three/examples/jsm/loaders/UltraHDRLoader.js')).UltraHDRLoader;
15811
+ break;
15812
+ }
15813
+ return loader;
15814
+ }
15815
+ const LOADER_KEY = Symbol("r3f-environment-loader");
15816
+ function useEnvironmentLoader(format) {
15817
+ return suspendReact.suspend(() => loadLoader(format), [LOADER_KEY, format]);
15818
+ }
15819
+ function useEnvironment({
15820
+ files = defaultFiles,
15821
+ path = "",
15822
+ preset = void 0,
15823
+ colorSpace = void 0,
15824
+ extensions
15825
+ } = {}) {
15826
+ if (preset) {
15827
+ validatePreset(preset);
15828
+ files = presetsObj[preset];
15829
+ path = CUBEMAP_ROOT;
15830
+ }
15831
+ const multiFile = isArray(files);
15832
+ const { format, isCubemap } = getFormat(files);
15833
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15834
+ const loader = useEnvironmentLoader(format);
15835
+ const loaderResult = useLoader(
15836
+ loader,
15837
+ multiFile ? [files] : files,
15838
+ (loader2) => {
15839
+ loader2.setPath?.(path);
15840
+ if (extensions) extensions(loader2);
15360
15841
  }
15361
- reconciler.updateContainer(null, fiber, null, () => {
15362
- if (root?.store) extensions.detachRootExtensions(root.store);
15363
- if (state) {
15364
- setTimeout(() => {
15365
- try {
15366
- const renderer = state.internal.actualRenderer;
15367
- const unregisterPrimary = state.internal.unregisterPrimary;
15368
- if (unregisterPrimary) unregisterPrimary();
15369
- const canvasTarget = state.internal.canvasTarget;
15370
- if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
15371
- state.events.disconnect?.();
15372
- cleanupHelperGroup(root.store);
15373
- if (state.isLegacy && renderer) {
15374
- ;
15375
- renderer.renderLists?.dispose?.();
15376
- renderer.forceContextLoss?.();
15377
- }
15378
- if (!state.internal.isSecondary) {
15379
- if (renderer?.xr) state.xr.disconnect();
15380
- }
15381
- dispose(state.scene);
15382
- _roots.delete(canvas);
15383
- if (callback) callback(canvas);
15384
- } catch (error) {
15385
- console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
15386
- }
15387
- }, 500);
15388
- }
15842
+ );
15843
+ const texture = multiFile ? (
15844
+ // @ts-ignore
15845
+ loaderResult[0]
15846
+ ) : loaderResult;
15847
+ const three = getThree();
15848
+ texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
15849
+ texture.colorSpace = colorSpace ?? (isCubemap && format !== "hdr-cube" ? "srgb" : "srgb-linear");
15850
+ return texture;
15851
+ }
15852
+ const preloadDefaultOptions = {
15853
+ files: defaultFiles,
15854
+ path: "",
15855
+ preset: void 0,
15856
+ extensions: void 0
15857
+ };
15858
+ useEnvironment.preload = (preloadOptions) => {
15859
+ const options = { ...preloadDefaultOptions, ...preloadOptions };
15860
+ let { files, path = "" } = options;
15861
+ const { preset, extensions } = options;
15862
+ if (preset) {
15863
+ validatePreset(preset);
15864
+ files = presetsObj[preset];
15865
+ path = CUBEMAP_ROOT;
15866
+ }
15867
+ const { format } = getFormat(files);
15868
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15869
+ const input = isArray(files) ? [files] : files;
15870
+ loadLoader(format).then((loader) => {
15871
+ useLoader.preload(loader, input, (loader2) => {
15872
+ loader2.setPath?.(path);
15873
+ if (extensions) extensions(loader2);
15874
+ });
15875
+ });
15876
+ };
15877
+ const clearDefaultOptins = {
15878
+ files: defaultFiles,
15879
+ preset: void 0
15880
+ };
15881
+ useEnvironment.clear = (clearOptions) => {
15882
+ const options = { ...clearDefaultOptins, ...clearOptions };
15883
+ let { files } = options;
15884
+ const { preset } = options;
15885
+ if (preset) {
15886
+ validatePreset(preset);
15887
+ files = presetsObj[preset];
15888
+ }
15889
+ const { format } = getFormat(files);
15890
+ if (!format) throw new Error("useEnvironment: Unrecognized file extension: " + files);
15891
+ const input = isArray(files) ? [files] : files;
15892
+ const clear = (loader2) => useLoader.clear(loader2, input);
15893
+ const loader = loadedLoaders.get(format);
15894
+ if (loader) {
15895
+ clear(loader);
15896
+ } else {
15897
+ const pending = pendingLoaders.get(format);
15898
+ if (pending) void pending.then(clear, () => {
15389
15899
  });
15390
15900
  }
15901
+ };
15902
+ function validatePreset(preset) {
15903
+ if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
15904
+ }
15905
+ function getFormat(files) {
15906
+ const isCubemap = isArray(files) && files.length === 6;
15907
+ const firstEntry = isArray(files) ? files[0] : files;
15908
+ const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
15909
+ let format;
15910
+ if (isCubemap) format = firstExtension === "hdr" ? "hdr-cube" : "cube";
15911
+ else if (firstEntry.startsWith("data:application/exr")) format = "exr";
15912
+ else if (firstEntry.startsWith("data:application/hdr")) format = "hdr";
15913
+ else if (firstEntry.startsWith("data:image/jpeg")) format = "jpg";
15914
+ else if (firstExtension === "hdr" || firstExtension === "exr") format = firstExtension;
15915
+ else if (firstExtension === "jpg" || firstExtension === "jpeg") format = "jpg";
15916
+ return { format, isCubemap };
15917
+ }
15918
+
15919
+ function useInstanceHandle(ref) {
15920
+ const instance = React.useRef(null);
15921
+ React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
15922
+ return instance;
15923
+ }
15924
+ function useGraph(object) {
15925
+ return React.useMemo(() => buildGraph(object), [object]);
15391
15926
  }
15927
+
15392
15928
  function createPortal(children, container, state) {
15393
15929
  return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
15394
15930
  }
@@ -15419,26 +15955,23 @@ function Portal({ children, container, state }) {
15419
15955
  }
15420
15956
  function PortalInner({ state = {}, children, container }) {
15421
15957
  const { events, size, injectScene = true, ...rest } = state;
15422
- const previousRoot = extensions.useStore();
15958
+ const previousRoot = textureStaging.useStore();
15423
15959
  const [raycaster] = React.useState(() => new (getThree()).Raycaster());
15424
15960
  const [pointer] = React.useState(() => new (getThree()).Vector2());
15425
15961
  const [portalScene] = React.useState(() => {
15426
15962
  if ("isScene" in container && container.isScene) return container;
15427
15963
  if (!injectScene) return container;
15428
- const scene = new (getThree()).Scene();
15429
- container.add(scene);
15430
- return scene;
15964
+ return new (getThree()).Scene();
15431
15965
  });
15432
- extensions.useIsomorphicLayoutEffect(() => {
15966
+ textureStaging.useIsomorphicLayoutEffect(() => {
15967
+ if (portalScene === container || !injectScene) return;
15968
+ container.add(portalScene);
15433
15969
  return () => {
15434
- if (portalScene !== container && injectScene) {
15435
- container.remove(portalScene);
15436
- dispose(portalScene);
15437
- }
15970
+ container.remove(portalScene);
15438
15971
  };
15439
15972
  }, [portalScene, container, injectScene]);
15440
15973
  const lastRootState = React.useRef(null);
15441
- const inject = extensions.useMutableCallback((rootState, injectState) => {
15974
+ const inject = textureStaging.useMutableCallback((rootState, injectState) => {
15442
15975
  const followed = {};
15443
15976
  const lastRoot = lastRootState.current;
15444
15977
  if (lastRoot) {
@@ -15489,7 +16022,7 @@ function PortalInner({ state = {}, children, container }) {
15489
16022
  onMutate(previousRoot.getState());
15490
16023
  return store;
15491
16024
  }, [previousRoot, container]);
15492
- extensions.useIsomorphicLayoutEffect(() => {
16025
+ textureStaging.useIsomorphicLayoutEffect(() => {
15493
16026
  const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
15494
16027
  const unsubscribe = previousRoot.subscribe(onMutate);
15495
16028
  return unsubscribe;
@@ -15497,15 +16030,12 @@ function PortalInner({ state = {}, children, container }) {
15497
16030
  return (
15498
16031
  // @ts-ignore, reconciler types are not maintained
15499
16032
  /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
15500
- /* @__PURE__ */ jsxRuntime.jsx(extensions.context.Provider, { value: usePortalStore, children }),
16033
+ /* @__PURE__ */ jsxRuntime.jsx(textureStaging.context.Provider, { value: usePortalStore, children }),
15501
16034
  usePortalStore,
15502
16035
  null
15503
16036
  ) })
15504
16037
  );
15505
16038
  }
15506
- function flushSync(fn) {
15507
- return reconciler.flushSyncFromReconciler(fn);
15508
- }
15509
16039
 
15510
16040
  const isRef = (obj) => obj.current && obj.current.isScene;
15511
16041
  const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
@@ -15538,7 +16068,7 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
15538
16068
  };
15539
16069
  }
15540
16070
  function EnvironmentMap({ scene, background = false, map, ...config }) {
15541
- const defaultScene = extensions.useThree((state) => state.scene);
16071
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15542
16072
  React__namespace.useLayoutEffect(() => {
15543
16073
  if (map) return setEnvProps(background, scene, defaultScene, map, config);
15544
16074
  });
@@ -15556,7 +16086,7 @@ function EnvironmentCube({
15556
16086
  ...rest
15557
16087
  }) {
15558
16088
  const texture = useEnvironment(rest);
15559
- const defaultScene = extensions.useThree((state) => state.scene);
16089
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15560
16090
  React__namespace.useLayoutEffect(() => {
15561
16091
  return setEnvProps(background, scene, defaultScene, texture, {
15562
16092
  backgroundBlurriness: blur ?? backgroundBlurriness,
@@ -15591,11 +16121,11 @@ function EnvironmentPortal({
15591
16121
  files,
15592
16122
  path,
15593
16123
  preset = void 0,
15594
- extensions: extensions$1
16124
+ extensions
15595
16125
  }) {
15596
- const renderer = extensions.useThree((state) => state.renderer);
15597
- const support = extensions.useThree((state) => state.internal.support);
15598
- const defaultScene = extensions.useThree((state) => state.scene);
16126
+ const renderer = textureStaging.useThree((state) => state.renderer);
16127
+ const support = textureStaging.useThree((state) => state.internal.support);
16128
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15599
16129
  const camera = React__namespace.useRef(null);
15600
16130
  const [virtualScene] = React__namespace.useState(() => new (getThree()).Scene());
15601
16131
  const fbo = React__namespace.useMemo(() => {
@@ -15639,7 +16169,7 @@ function EnvironmentPortal({
15639
16169
  environmentRotation
15640
16170
  ]);
15641
16171
  let count = 1;
15642
- extensions.useFrame(() => {
16172
+ textureStaging.useFrame(() => {
15643
16173
  if (frames === Infinity || count < frames) {
15644
16174
  const autoClear = renderer.autoClear;
15645
16175
  renderer.autoClear = true;
@@ -15652,7 +16182,7 @@ function EnvironmentPortal({
15652
16182
  /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
15653
16183
  children,
15654
16184
  /* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
15655
- 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
16185
+ files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
15656
16186
  ] }),
15657
16187
  virtualScene
15658
16188
  ) });
@@ -15682,7 +16212,7 @@ function EnvironmentGround(props) {
15682
16212
  ] });
15683
16213
  }
15684
16214
  function EnvironmentColor({ color, scene }) {
15685
- const defaultScene = extensions.useThree((state) => state.scene);
16215
+ const defaultScene = textureStaging.useThree((state) => state.scene);
15686
16216
  React__namespace.useLayoutEffect(() => {
15687
16217
  if (color === void 0) return;
15688
16218
  const target = resolveScene(scene || defaultScene);
@@ -15741,19 +16271,6 @@ function parseBackground(background) {
15741
16271
  return null;
15742
16272
  }
15743
16273
 
15744
- function parseRendererConfig(rendererProp) {
15745
- const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
15746
- if (isRendererConfig) {
15747
- const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
15748
- return {
15749
- primaryCanvas: pc,
15750
- scheduler: sc,
15751
- renderer: Object.keys(rest).length > 0 ? rest : rendererProp
15752
- };
15753
- }
15754
- return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
15755
- }
15756
-
15757
16274
  function CanvasImpl({
15758
16275
  ref,
15759
16276
  children,
@@ -15762,11 +16279,13 @@ function CanvasImpl({
15762
16279
  style,
15763
16280
  id,
15764
16281
  gl,
15765
- renderer: rendererProp,
16282
+ renderer,
16283
+ primary,
16284
+ share,
16285
+ scheduler,
15766
16286
  events = createPointerEvents,
15767
16287
  eventSource,
15768
16288
  eventPrefix,
15769
- shadows,
15770
16289
  orthographic,
15771
16290
  frameloop,
15772
16291
  dpr,
@@ -15788,8 +16307,12 @@ function CanvasImpl({
15788
16307
  provider,
15789
16308
  ...props
15790
16309
  }) {
15791
- const { primaryCanvas, scheduler, renderer } = parseRendererConfig(rendererProp);
15792
- const Bridge = extensions.useBridge();
16310
+ const {
16311
+ shadows: removedShadows,
16312
+ primaryCanvas: removedPrimaryCanvas,
16313
+ ...divProps
16314
+ } = props;
16315
+ const Bridge = textureStaging.useBridge();
15793
16316
  const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
15794
16317
  const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
15795
16318
  const measureConfig = React__namespace.useMemo(() => {
@@ -15825,119 +16348,131 @@ function CanvasImpl({
15825
16348
  const canvasRef = React__namespace.useRef(null);
15826
16349
  const divRef = React__namespace.useRef(null);
15827
16350
  React__namespace.useImperativeHandle(ref, () => canvasRef.current);
15828
- const handlePointerMissed = extensions.useMutableCallback(onPointerMissed);
15829
- const handleDragOverMissed = extensions.useMutableCallback(onDragOverMissed);
15830
- const handleDropMissed = extensions.useMutableCallback(onDropMissed);
16351
+ const handlePointerMissed = textureStaging.useMutableCallback(onPointerMissed);
16352
+ const handleDragOverMissed = textureStaging.useMutableCallback(onDragOverMissed);
16353
+ const handleDropMissed = textureStaging.useMutableCallback(onDropMissed);
15831
16354
  const [block, setBlock] = React__namespace.useState(false);
15832
16355
  const [error, setError] = React__namespace.useState(false);
15833
16356
  const [fallbackVisible, setFallbackVisible] = React__namespace.useState(false);
15834
16357
  if (block) throw block;
15835
16358
  if (error) throw error;
15836
16359
  const root = React__namespace.useRef(null);
15837
- const effectActiveRef = React__namespace.useRef(true);
15838
- const unsubscribeErrorRef = React__namespace.useRef(null);
15839
- extensions.useIsomorphicLayoutEffect(() => {
15840
- effectActiveRef.current = true;
16360
+ const [gate, waitFor] = textureStaging.useGate();
16361
+ const rootState = React__namespace.useRef(null);
16362
+ const eventTarget = () => eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current;
16363
+ const pointerMissed = React__namespace.useCallback(
16364
+ (...args) => handlePointerMissed.current?.(...args),
16365
+ [handlePointerMissed]
16366
+ );
16367
+ const dragOverMissed = React__namespace.useCallback(
16368
+ (...args) => handleDragOverMissed.current?.(...args),
16369
+ [handleDragOverMissed]
16370
+ );
16371
+ const dropMissed = React__namespace.useCallback(
16372
+ (...args) => handleDropMissed.current?.(...args),
16373
+ [handleDropMissed]
16374
+ );
16375
+ textureStaging.useIsomorphicLayoutEffect(() => {
15841
16376
  if (fallbackVisible) return;
15842
16377
  const canvas = canvasRef.current;
15843
16378
  if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
15844
16379
  if (!root.current) {
15845
16380
  root.current = createRoot(canvas, provider);
15846
- extensions.notifyAlpha({
16381
+ textureStaging.notifyAlpha({
15847
16382
  message: "React Three Fiber v10 is in ALPHA - expect breaking changes",
15848
16383
  link: "https://github.com/pmndrs/react-three-fiber/discussions"
15849
16384
  });
15850
- const rootEntry = _roots.get(canvas);
15851
- if (rootEntry?.store) {
15852
- if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
15853
- unsubscribeErrorRef.current = rootEntry.store.subscribe((state) => {
15854
- if (state.error && effectActiveRef.current) {
15855
- setError(state.error);
15856
- }
15857
- });
15858
- }
15859
16385
  }
15860
- async function run() {
15861
- if (!effectActiveRef.current || !root.current) return;
15862
- const configured = await root.current.configure({
15863
- id,
15864
- primaryCanvas,
15865
- scheduler,
15866
- gl,
15867
- renderer,
15868
- scene,
15869
- events,
15870
- shadows,
15871
- orthographic,
15872
- frameloop,
15873
- dpr,
15874
- performance,
15875
- raycaster,
15876
- camera,
15877
- autoUpdateFrustum,
15878
- occlusion,
15879
- size: effectiveSize,
15880
- // Store size props for reset functionality
15881
- _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
15882
- forceEven,
15883
- // Pass mutable reference to onPointerMissed so it's free to update
15884
- onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
15885
- onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
15886
- onDropMissed: (...args) => handleDropMissed.current?.(...args),
15887
- onCreated: (state) => {
15888
- state.events.connect?.(
15889
- eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current
15890
- );
15891
- if (eventPrefix) {
15892
- state.setEvents({
15893
- compute: (event, state2) => {
15894
- const x = event[eventPrefix + "X"];
15895
- const y = event[eventPrefix + "Y"];
15896
- state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
15897
- state2.raycaster.setFromCamera(state2.pointer, state2.camera);
15898
- }
15899
- });
15900
- }
15901
- onCreated?.(state);
15902
- }
15903
- }).then(
15904
- () => true,
15905
- // Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
15906
- // inside <canvas>, which browsers don't display, so surface it as visible DOM
15907
- // instead; with no fallback, rethrow to an external error boundary. (#3757)
15908
- (setupError) => {
15909
- if (effectActiveRef.current) {
15910
- if (fallback != null) setFallbackVisible(true);
15911
- else setError(setupError);
15912
- }
15913
- return false;
16386
+ const current = root.current;
16387
+ current.configure({
16388
+ id,
16389
+ primary,
16390
+ share,
16391
+ scheduler,
16392
+ gl,
16393
+ renderer,
16394
+ scene,
16395
+ events,
16396
+ _primaryToken: primaryToken,
16397
+ ...{ shadows: removedShadows, primaryCanvas: removedPrimaryCanvas },
16398
+ orthographic,
16399
+ frameloop,
16400
+ dpr,
16401
+ performance,
16402
+ raycaster,
16403
+ camera,
16404
+ autoUpdateFrustum,
16405
+ occlusion,
16406
+ size: effectiveSize,
16407
+ // Store size props for reset functionality
16408
+ _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
16409
+ forceEven,
16410
+ // Pass mutable reference to onPointerMissed so it's free to update
16411
+ onPointerMissed: pointerMissed,
16412
+ onDragOverMissed: dragOverMissed,
16413
+ onDropMissed: dropMissed,
16414
+ onCreated: (state) => {
16415
+ rootState.current = state;
16416
+ state.events.connect?.(eventTarget() ?? divRef.current);
16417
+ if (eventPrefix) {
16418
+ state.setEvents({
16419
+ compute: (event, state2) => {
16420
+ const x = event[eventPrefix + "X"];
16421
+ const y = event[eventPrefix + "Y"];
16422
+ state2.pointer.set(x / state2.size.width * 2 - 1, -(y / state2.size.height) * 2 + 1);
16423
+ state2.raycaster.setFromCamera(state2.pointer, state2.camera);
16424
+ }
16425
+ });
15914
16426
  }
15915
- );
15916
- if (!configured || !effectActiveRef.current || !root.current) return;
15917
- root.current.render(
15918
- /* @__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: [
16427
+ onCreated?.(state);
16428
+ }
16429
+ }).catch((setupError) => {
16430
+ if (root.current !== current) return;
16431
+ if (fallback != null) setFallbackVisible(true);
16432
+ else setError(setupError);
16433
+ });
16434
+ if (current.ready.status === "fulfilled") {
16435
+ current.render(
16436
+ /* @__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: [
15919
16437
  backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
15920
16438
  children ?? null
15921
16439
  ] }) }) })
15922
16440
  );
16441
+ } else if (current.ready.status === "pending") {
16442
+ waitFor(current.ready);
15923
16443
  }
15924
- run();
15925
16444
  }
15926
- return () => {
15927
- effectActiveRef.current = false;
15928
- if (unsubscribeErrorRef.current) {
15929
- unsubscribeErrorRef.current();
15930
- unsubscribeErrorRef.current = null;
15931
- }
16445
+ });
16446
+ textureStaging.useIsomorphicLayoutEffect(() => {
16447
+ const store = canvasRef.current && _roots.get(canvasRef.current)?.store;
16448
+ if (!store) return;
16449
+ const report = () => {
16450
+ const error2 = store.getState().error;
16451
+ if (error2) setError(error2);
15932
16452
  };
16453
+ report();
16454
+ return store.subscribe(report);
16455
+ });
16456
+ React__namespace.useEffect(() => {
16457
+ const state = rootState.current?.get();
16458
+ const target = eventTarget();
16459
+ if (state && target && state.events.connected !== target) state.events.connect?.(target);
15933
16460
  });
15934
16461
  const insertionMounted = React__namespace.useRef(false);
16462
+ const [primaryToken] = React__namespace.useState(() => ({}));
16463
+ const primaryKey = React__namespace.useRef(null);
15935
16464
  React__namespace.useInsertionEffect(() => {
15936
16465
  insertionMounted.current = true;
16466
+ if (primary && provider.webgpu) {
16467
+ primaryKey.current ?? (primaryKey.current = id || DEFAULT_PRIMARY);
16468
+ announcePrimary(primaryKey.current, primaryToken);
16469
+ }
15937
16470
  return () => {
15938
16471
  insertionMounted.current = false;
16472
+ if (primaryKey.current) markWithdrawing(primaryToken);
15939
16473
  queueMicrotask(() => {
15940
16474
  if (insertionMounted.current) return;
16475
+ if (primaryKey.current) withdrawPrimary(primaryKey.current, primaryToken);
15941
16476
  const current = root.current;
15942
16477
  root.current = null;
15943
16478
  current?.unmount();
@@ -15962,10 +16497,10 @@ function CanvasImpl({
15962
16497
  const handleHMR = () => {
15963
16498
  queueMicrotask(() => {
15964
16499
  const rootEntry = _roots.get(canvas);
15965
- if (rootEntry?.store) extensions.notifyRootExtensionsHmr(rootEntry.store);
16500
+ if (rootEntry?.store) textureStaging.notifyRootExtensionsHmr(rootEntry.store);
15966
16501
  });
15967
16502
  };
15968
- if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.EDf0d92E.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
16503
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/fiber.Bi_S5KAx.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
15969
16504
  const hot = undefined;
15970
16505
  hot.on("vite:afterUpdate", handleHMR);
15971
16506
  return () => hot.off?.("vite:afterUpdate", handleHMR);
@@ -15978,7 +16513,7 @@ function CanvasImpl({
15978
16513
  }
15979
16514
  }, [hmr]);
15980
16515
  const pointerEvents = eventSource ? "none" : "auto";
15981
- return /* @__PURE__ */ jsxRuntime.jsx(
16516
+ return /* @__PURE__ */ jsxRuntime.jsxs(
15982
16517
  "div",
15983
16518
  {
15984
16519
  ref: divRef,
@@ -15990,21 +16525,24 @@ function CanvasImpl({
15990
16525
  pointerEvents,
15991
16526
  ...style
15992
16527
  },
15993
- ...props,
15994
- children: fallbackVisible ? (
15995
- // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
15996
- // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
15997
- fallback
15998
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
15999
- "canvas",
16000
- {
16001
- ref: canvasRef,
16002
- id,
16003
- className: "r3f-canvas",
16004
- style: { display: "block", width: "100%", height: "100%" },
16005
- children: fallback
16006
- }
16007
- ) })
16528
+ ...divProps,
16529
+ children: [
16530
+ fallbackVisible ? (
16531
+ // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
16532
+ // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
16533
+ fallback
16534
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
16535
+ "canvas",
16536
+ {
16537
+ ref: canvasRef,
16538
+ id,
16539
+ className: "r3f-canvas",
16540
+ style: { display: "block", width: "100%", height: "100%" },
16541
+ children: fallback
16542
+ }
16543
+ ) }),
16544
+ gate
16545
+ ]
16008
16546
  }
16009
16547
  );
16010
16548
  }