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