@react-three/fiber 10.0.0-canary.da7a768 → 10.0.0-canary.dc0ec15
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 +278 -0
- package/dist/extension.d.cts +1675 -0
- package/dist/extension.d.mts +1675 -0
- package/dist/extension.d.ts +1647 -0
- package/dist/extension.mjs +258 -0
- package/dist/index.cjs +994 -898
- package/dist/index.d.cts +331 -155
- package/dist/index.d.mts +331 -155
- package/dist/index.d.ts +331 -183
- package/dist/index.mjs +995 -901
- package/dist/legacy.cjs +1345 -1245
- package/dist/legacy.d.cts +353 -205
- package/dist/legacy.d.mts +353 -205
- package/dist/legacy.d.ts +353 -231
- package/dist/legacy.mjs +1346 -1248
- package/dist/webgpu/index.cjs +908 -713
- package/dist/webgpu/index.d.cts +389 -212
- package/dist/webgpu/index.d.mts +389 -212
- package/dist/webgpu/index.d.ts +389 -240
- package/dist/webgpu/index.mjs +910 -717
- package/package.json +7 -2
package/dist/index.cjs
CHANGED
|
@@ -11,6 +11,7 @@ const scheduler = require('@pmndrs/scheduler');
|
|
|
11
11
|
const Tb = require('scheduler');
|
|
12
12
|
const GroundedSkybox_js = require('three/examples/jsm/objects/GroundedSkybox.js');
|
|
13
13
|
const HDRLoader_js = require('three/examples/jsm/loaders/HDRLoader.js');
|
|
14
|
+
const HDRCubeTextureLoader_js = require('three/examples/jsm/loaders/HDRCubeTextureLoader.js');
|
|
14
15
|
const EXRLoader_js = require('three/examples/jsm/loaders/EXRLoader.js');
|
|
15
16
|
const UltraHDRLoader_js = require('three/examples/jsm/loaders/UltraHDRLoader.js');
|
|
16
17
|
const gainmapJs = require('@monogrid/gainmap-js');
|
|
@@ -313,7 +314,6 @@ function prepare(target, root, type, props) {
|
|
|
313
314
|
}
|
|
314
315
|
function invalidateInstance(instance) {
|
|
315
316
|
if (!instance.parent) return;
|
|
316
|
-
instance.props.onUpdate?.(instance.object);
|
|
317
317
|
const state = instance.root?.getState?.();
|
|
318
318
|
if (state && state.internal.frames === 0) state.invalidate();
|
|
319
319
|
}
|
|
@@ -529,8 +529,10 @@ function hasVisibilityHandlers(handlers) {
|
|
|
529
529
|
}
|
|
530
530
|
|
|
531
531
|
const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
|
|
532
|
-
function fromRef(ref) {
|
|
533
|
-
|
|
532
|
+
function fromRef(ref, transform) {
|
|
533
|
+
const marker = { [FROM_REF]: ref };
|
|
534
|
+
if (transform) marker.transform = transform;
|
|
535
|
+
return marker;
|
|
534
536
|
}
|
|
535
537
|
function isFromRef(value) {
|
|
536
538
|
return value !== null && typeof value === "object" && FROM_REF in value;
|
|
@@ -544,6 +546,63 @@ function isOnce(value) {
|
|
|
544
546
|
return value !== null && typeof value === "object" && ONCE in value;
|
|
545
547
|
}
|
|
546
548
|
|
|
549
|
+
const shownNotices = /* @__PURE__ */ new Set();
|
|
550
|
+
function notifyDepreciated({ heading, body, link }) {
|
|
551
|
+
if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_DEPRECATION_WARNINGS !== "true") {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
if (shownNotices.has(heading)) return;
|
|
555
|
+
shownNotices.add(heading);
|
|
556
|
+
const caller = getCallerFrame();
|
|
557
|
+
if (caller) {
|
|
558
|
+
console.log();
|
|
559
|
+
}
|
|
560
|
+
const boxStyle = "background: #ff9800; color: #1a1a1a; padding: 8px 12px; border-radius: 4px; font-weight: 500;";
|
|
561
|
+
if (caller) {
|
|
562
|
+
console.log(`%c\u26A0\uFE0F ${heading}`, boxStyle);
|
|
563
|
+
}
|
|
564
|
+
if (body || link) {
|
|
565
|
+
let message = "";
|
|
566
|
+
if (body) message += body;
|
|
567
|
+
if (link) message += (body ? "\n\n" : "") + `More info: ${link}`;
|
|
568
|
+
console.warn(`%c${message}`, "font-weight: bold;");
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function getCallerFrame(depth = 3) {
|
|
572
|
+
const stack = new Error().stack;
|
|
573
|
+
if (!stack) return null;
|
|
574
|
+
const lines = stack.split("\n");
|
|
575
|
+
const frame = lines[depth];
|
|
576
|
+
if (!frame) return null;
|
|
577
|
+
let match = frame.match(/^\s*at (?:(.+?) )?\(?(.+?):(\d+):(\d+)\)?$/);
|
|
578
|
+
if (!match) {
|
|
579
|
+
match = frame.match(/^(?:(.+?)@)?(.+?):(\d+):(\d+)$/);
|
|
580
|
+
}
|
|
581
|
+
if (!match) return null;
|
|
582
|
+
const [, fn, url, line] = match;
|
|
583
|
+
return {
|
|
584
|
+
functionName: fn ?? "<anonymous>",
|
|
585
|
+
location: formatLocation(url, Number(line))
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
function formatLocation(url, line) {
|
|
589
|
+
const clean = url.split("?")[0];
|
|
590
|
+
const file = clean.split("/").pop() ?? clean;
|
|
591
|
+
return `${file}:${line}`;
|
|
592
|
+
}
|
|
593
|
+
function notifyAlpha({ message, link }) {
|
|
594
|
+
if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_ALPHA_WARNINGS !== "true") {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (shownNotices.has(message)) return;
|
|
598
|
+
shownNotices.add(message);
|
|
599
|
+
const boxStyle = "background: #6366f1; color: #ffffff; padding: 6px 10px; border-radius: 4px; font-weight: 500;";
|
|
600
|
+
console.log(`%c\u{1F52C} ${message}`, boxStyle);
|
|
601
|
+
{
|
|
602
|
+
console.log(`%cMore info: ${link}`, "color: #6366f1; font-weight: normal;");
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
547
606
|
const RESERVED_PROPS = [
|
|
548
607
|
"children",
|
|
549
608
|
"key",
|
|
@@ -553,7 +612,6 @@ const RESERVED_PROPS = [
|
|
|
553
612
|
"dispose",
|
|
554
613
|
"attach",
|
|
555
614
|
"object",
|
|
556
|
-
"onUpdate",
|
|
557
615
|
// Behavior flags
|
|
558
616
|
"dispose"
|
|
559
617
|
];
|
|
@@ -631,11 +689,9 @@ function diffProps(instance, newProps) {
|
|
|
631
689
|
for (const prop in instance.props) {
|
|
632
690
|
if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
|
|
633
691
|
const { root, key } = resolve(instance.object, prop);
|
|
634
|
-
if (
|
|
692
|
+
if (typeof root?.constructor === "function") {
|
|
635
693
|
const ctor = getMemoizedPrototype(root);
|
|
636
694
|
if (!is.und(ctor)) changedProps[prop] = ctor[key];
|
|
637
|
-
} else {
|
|
638
|
-
changedProps[prop] = 0;
|
|
639
695
|
}
|
|
640
696
|
}
|
|
641
697
|
return changedProps;
|
|
@@ -647,6 +703,13 @@ function applyProps(object, props) {
|
|
|
647
703
|
for (const prop in props) {
|
|
648
704
|
const value = props[prop];
|
|
649
705
|
if (RESERVED_PROPS.includes(prop)) continue;
|
|
706
|
+
if (prop === "onUpdate") {
|
|
707
|
+
notifyDepreciated({
|
|
708
|
+
heading: "onUpdate is no longer an R3F prop",
|
|
709
|
+
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.",
|
|
710
|
+
link: "https://docs.pmnd.rs/react-three-fiber/migration/v10#onupdate-removed"
|
|
711
|
+
});
|
|
712
|
+
}
|
|
650
713
|
if (instance && EVENT_REGEX.test(prop)) {
|
|
651
714
|
if (typeof value === "function") instance.handlers[prop] = value;
|
|
652
715
|
else delete instance.handlers[prop];
|
|
@@ -752,682 +815,378 @@ function applyProps(object, props) {
|
|
|
752
815
|
return object;
|
|
753
816
|
}
|
|
754
817
|
|
|
755
|
-
const
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
if (
|
|
761
|
-
|
|
762
|
-
const caller = getCallerFrame();
|
|
763
|
-
if (caller) {
|
|
764
|
-
console.log();
|
|
765
|
-
}
|
|
766
|
-
const boxStyle = "background: #ff9800; color: #1a1a1a; padding: 8px 12px; border-radius: 4px; font-weight: 500;";
|
|
767
|
-
if (caller) {
|
|
768
|
-
console.log(`%c\u26A0\uFE0F ${heading}`, boxStyle);
|
|
769
|
-
}
|
|
770
|
-
if (body || link) {
|
|
771
|
-
let message = "";
|
|
772
|
-
if (body) message += body;
|
|
773
|
-
if (link) message += (body ? "\n\n" : "") + `More info: ${link}`;
|
|
774
|
-
console.warn(`%c${message}`, "font-weight: bold;");
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
function getCallerFrame(depth = 3) {
|
|
778
|
-
const stack = new Error().stack;
|
|
779
|
-
if (!stack) return null;
|
|
780
|
-
const lines = stack.split("\n");
|
|
781
|
-
const frame = lines[depth];
|
|
782
|
-
if (!frame) return null;
|
|
783
|
-
let match = frame.match(/^\s*at (?:(.+?) )?\(?(.+?):(\d+):(\d+)\)?$/);
|
|
784
|
-
if (!match) {
|
|
785
|
-
match = frame.match(/^(?:(.+?)@)?(.+?):(\d+):(\d+)$/);
|
|
786
|
-
}
|
|
787
|
-
if (!match) return null;
|
|
788
|
-
const [, fn, url, line] = match;
|
|
789
|
-
return {
|
|
790
|
-
functionName: fn ?? "<anonymous>",
|
|
791
|
-
location: formatLocation(url, Number(line))
|
|
792
|
-
};
|
|
818
|
+
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
819
|
+
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
|
|
820
|
+
|
|
821
|
+
function useStore() {
|
|
822
|
+
const store = React.useContext(context);
|
|
823
|
+
if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
|
|
824
|
+
return store;
|
|
793
825
|
}
|
|
794
|
-
function
|
|
795
|
-
|
|
796
|
-
const file = clean.split("/").pop() ?? clean;
|
|
797
|
-
return `${file}:${line}`;
|
|
826
|
+
function useThree(selector = (state) => state, equalityFn) {
|
|
827
|
+
return useStore()(selector, equalityFn);
|
|
798
828
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
829
|
+
|
|
830
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
831
|
+
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
832
|
+
function getLoader$1(Proto) {
|
|
833
|
+
if (isConstructor$1(Proto)) {
|
|
834
|
+
let loader = memoizedLoaders.get(Proto);
|
|
835
|
+
if (!loader) {
|
|
836
|
+
loader = new Proto();
|
|
837
|
+
memoizedLoaders.set(Proto, loader);
|
|
838
|
+
}
|
|
839
|
+
return loader;
|
|
809
840
|
}
|
|
841
|
+
return Proto;
|
|
810
842
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
843
|
+
function loadingFn(extensions, onProgress) {
|
|
844
|
+
return function(Proto, input) {
|
|
845
|
+
const loader = getLoader$1(Proto);
|
|
846
|
+
if (extensions) extensions(loader);
|
|
847
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
848
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
849
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
850
|
+
return data;
|
|
851
|
+
});
|
|
852
|
+
}
|
|
853
|
+
return new Promise(
|
|
854
|
+
(res, reject) => loader.load(
|
|
855
|
+
input,
|
|
856
|
+
(data) => {
|
|
857
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
858
|
+
res(data);
|
|
859
|
+
},
|
|
860
|
+
onProgress,
|
|
861
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
862
|
+
)
|
|
863
|
+
);
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
867
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
868
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
869
|
+
const fn = loadingFn(extensions, onProgress);
|
|
870
|
+
const results = cacheKeys.map(
|
|
871
|
+
(key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
872
|
+
);
|
|
873
|
+
const stableRef = React.useRef(null);
|
|
874
|
+
const previous = stableRef.current;
|
|
875
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
876
|
+
stableRef.current = stable;
|
|
877
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
817
878
|
}
|
|
879
|
+
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
880
|
+
const inputs = Array.isArray(input) ? input : [input];
|
|
881
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
882
|
+
cacheKeys.forEach(
|
|
883
|
+
(key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
|
|
884
|
+
);
|
|
885
|
+
};
|
|
886
|
+
useLoader.clear = function(loader, input, cacheKey) {
|
|
887
|
+
const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
|
|
888
|
+
cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
|
|
889
|
+
};
|
|
890
|
+
useLoader.loader = getLoader$1;
|
|
818
891
|
|
|
819
|
-
|
|
820
|
-
const
|
|
821
|
-
const
|
|
822
|
-
const
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
892
|
+
function useFrame(callback, priorityOrOptions) {
|
|
893
|
+
const store = React__namespace.useContext(context);
|
|
894
|
+
const isInsideCanvas = store !== null;
|
|
895
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
896
|
+
const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
|
|
897
|
+
id: priorityOrOptions.id,
|
|
898
|
+
phase: priorityOrOptions.phase,
|
|
899
|
+
priority: priorityOrOptions.priority,
|
|
900
|
+
fps: priorityOrOptions.fps,
|
|
901
|
+
drop: priorityOrOptions.drop,
|
|
902
|
+
enabled: priorityOrOptions.enabled,
|
|
903
|
+
before: priorityOrOptions.before,
|
|
904
|
+
after: priorityOrOptions.after
|
|
905
|
+
}) : "";
|
|
906
|
+
const options = React__namespace.useMemo(() => {
|
|
907
|
+
return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
|
|
908
|
+
}, [optionsKey]);
|
|
909
|
+
const reactId = React__namespace.useId();
|
|
910
|
+
const id = options.id ?? reactId;
|
|
911
|
+
const callbackRef = useMutableCallback(callback);
|
|
912
|
+
const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
|
|
913
|
+
useIsomorphicLayoutEffect(() => {
|
|
914
|
+
if (!callback) return;
|
|
915
|
+
if (isInsideCanvas) {
|
|
916
|
+
const state = store.getState();
|
|
917
|
+
const rootId = state.internal.rootId;
|
|
918
|
+
if (isLegacyPriority) {
|
|
919
|
+
state.internal.priority++;
|
|
920
|
+
let parentRoot = state.previousRoot;
|
|
921
|
+
while (parentRoot) {
|
|
922
|
+
const parentState = parentRoot.getState();
|
|
923
|
+
if (parentState?.internal) parentState.internal.priority++;
|
|
924
|
+
parentRoot = parentState?.previousRoot;
|
|
925
|
+
}
|
|
926
|
+
notifyDepreciated({
|
|
927
|
+
heading: "useFrame with numeric priority is deprecated",
|
|
928
|
+
body: 'Using useFrame(callback, number) to control render order is deprecated.\n\nFor custom rendering, use: useFrame(callback, { phase: "render" })\nFor execution order within update phase, use: useFrame(callback, { priority: number })',
|
|
929
|
+
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
930
|
+
});
|
|
839
931
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
inspector: null,
|
|
868
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
869
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
870
|
-
textureColorSpace: webgpu.SRGBColorSpace,
|
|
871
|
-
isLegacy: false,
|
|
872
|
-
webGPUSupported: false,
|
|
873
|
-
isNative: false,
|
|
874
|
-
controls: null,
|
|
875
|
-
pointer,
|
|
876
|
-
mouse: pointer,
|
|
877
|
-
frameloop: "always",
|
|
878
|
-
onPointerMissed: void 0,
|
|
879
|
-
onDragOverMissed: void 0,
|
|
880
|
-
onDropMissed: void 0,
|
|
881
|
-
performance: {
|
|
882
|
-
current: 1,
|
|
883
|
-
min: 0.5,
|
|
884
|
-
max: 1,
|
|
885
|
-
debounce: 200,
|
|
886
|
-
regress: () => {
|
|
887
|
-
const state2 = get();
|
|
888
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
889
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
890
|
-
performanceTimeout = setTimeout(
|
|
891
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
892
|
-
state2.performance.debounce
|
|
893
|
-
);
|
|
894
|
-
}
|
|
895
|
-
},
|
|
896
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
897
|
-
viewport: {
|
|
898
|
-
initialDpr: 0,
|
|
899
|
-
dpr: 0,
|
|
900
|
-
width: 0,
|
|
901
|
-
height: 0,
|
|
902
|
-
top: 0,
|
|
903
|
-
left: 0,
|
|
904
|
-
aspect: 0,
|
|
905
|
-
distance: 0,
|
|
906
|
-
factor: 0,
|
|
907
|
-
getCurrentViewport
|
|
908
|
-
},
|
|
909
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
910
|
-
setSize: (width, height, top, left) => {
|
|
911
|
-
const state2 = get();
|
|
912
|
-
if (width === void 0) {
|
|
913
|
-
set({ _sizeImperative: false });
|
|
914
|
-
if (state2._sizeProps) {
|
|
915
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
916
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
917
|
-
const currentSize = state2.size;
|
|
918
|
-
const newSize = {
|
|
919
|
-
width: propW ?? currentSize.width,
|
|
920
|
-
height: propH ?? currentSize.height,
|
|
921
|
-
top: currentSize.top,
|
|
922
|
-
left: currentSize.left
|
|
923
|
-
};
|
|
924
|
-
set((s) => ({
|
|
925
|
-
size: newSize,
|
|
926
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
927
|
-
}));
|
|
928
|
-
scheduler.getScheduler().invalidate();
|
|
932
|
+
const wrappedCallback = (frameState, delta) => {
|
|
933
|
+
const localState = store.getState();
|
|
934
|
+
const mergedState = {
|
|
935
|
+
...localState,
|
|
936
|
+
time: frameState.time,
|
|
937
|
+
delta: frameState.delta,
|
|
938
|
+
elapsed: frameState.elapsed,
|
|
939
|
+
frame: frameState.frame
|
|
940
|
+
};
|
|
941
|
+
callbackRef.current?.(mergedState, delta);
|
|
942
|
+
};
|
|
943
|
+
const unregister = scheduler$1.register(wrappedCallback, {
|
|
944
|
+
id,
|
|
945
|
+
rootId,
|
|
946
|
+
...options
|
|
947
|
+
});
|
|
948
|
+
return () => {
|
|
949
|
+
unregister();
|
|
950
|
+
if (isLegacyPriority) {
|
|
951
|
+
const currentState = store.getState();
|
|
952
|
+
if (currentState.internal) {
|
|
953
|
+
currentState.internal.priority--;
|
|
954
|
+
let parentRoot = currentState.previousRoot;
|
|
955
|
+
while (parentRoot) {
|
|
956
|
+
const parentState = parentRoot.getState();
|
|
957
|
+
if (parentState?.internal) parentState.internal.priority--;
|
|
958
|
+
parentRoot = parentState?.previousRoot;
|
|
929
959
|
}
|
|
930
960
|
}
|
|
931
|
-
return;
|
|
932
961
|
}
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
962
|
+
};
|
|
963
|
+
} else {
|
|
964
|
+
return scheduler$1.register(
|
|
965
|
+
(state, delta) => {
|
|
966
|
+
const frameState = state;
|
|
967
|
+
if (!frameState.renderer) return;
|
|
968
|
+
callbackRef.current?.(frameState, delta);
|
|
969
|
+
},
|
|
970
|
+
{ id, ...options }
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
}, [store, scheduler$1, id, optionsKey, isLegacyPriority, isInsideCanvas]);
|
|
974
|
+
const isPaused = React__namespace.useSyncExternalStore(
|
|
975
|
+
// Subscribe function
|
|
976
|
+
React__namespace.useCallback(
|
|
977
|
+
(onStoreChange) => {
|
|
978
|
+
return scheduler.getScheduler().subscribeJobState(id, onStoreChange);
|
|
944
979
|
},
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
980
|
+
[id]
|
|
981
|
+
),
|
|
982
|
+
// getSnapshot function
|
|
983
|
+
React__namespace.useCallback(() => scheduler.getScheduler().isJobPaused(id), [id]),
|
|
984
|
+
// getServerSnapshot function (SSR)
|
|
985
|
+
React__namespace.useCallback(() => false, [])
|
|
986
|
+
);
|
|
987
|
+
const controls = React__namespace.useMemo(() => {
|
|
988
|
+
const scheduler2 = scheduler.getScheduler();
|
|
989
|
+
return {
|
|
990
|
+
/** The job's unique ID */
|
|
991
|
+
id,
|
|
992
|
+
/**
|
|
993
|
+
* Access to the global scheduler for frame loop control.
|
|
994
|
+
* Use for controlling the entire frame loop, adding phases, etc.
|
|
995
|
+
*/
|
|
996
|
+
scheduler: scheduler2,
|
|
997
|
+
/**
|
|
998
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
999
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1000
|
+
*/
|
|
1001
|
+
get rootId() {
|
|
1002
|
+
return scheduler.getScheduler().getJobRootId(id);
|
|
952
1003
|
},
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
internal.subscribers.push({ ref, priority, store });
|
|
996
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
997
|
-
return () => {
|
|
998
|
-
const internal2 = get().internal;
|
|
999
|
-
if (internal2?.subscribers) {
|
|
1000
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
1001
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
1002
|
-
}
|
|
1003
|
-
};
|
|
1004
|
-
},
|
|
1005
|
-
// Renderer Storage (single source of truth)
|
|
1006
|
-
actualRenderer: null,
|
|
1007
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
1008
|
-
scheduler: null
|
|
1009
|
-
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Manually step this job only.
|
|
1006
|
+
* Bypasses FPS limiting - always runs.
|
|
1007
|
+
* @param timestamp Optional timestamp (defaults to performance.now())
|
|
1008
|
+
*/
|
|
1009
|
+
step: (timestamp) => {
|
|
1010
|
+
scheduler.getScheduler().stepJob(id, timestamp);
|
|
1011
|
+
},
|
|
1012
|
+
/**
|
|
1013
|
+
* Manually step ALL jobs in the scheduler.
|
|
1014
|
+
* Useful for frameloop='never' mode.
|
|
1015
|
+
* @param timestamp Optional timestamp (defaults to performance.now())
|
|
1016
|
+
*/
|
|
1017
|
+
stepAll: (timestamp) => {
|
|
1018
|
+
scheduler.getScheduler().step(timestamp);
|
|
1019
|
+
},
|
|
1020
|
+
/**
|
|
1021
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1022
|
+
*/
|
|
1023
|
+
invalidate: (frames, stackFrames) => {
|
|
1024
|
+
const scheduler3 = scheduler.getScheduler();
|
|
1025
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1026
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1027
|
+
},
|
|
1028
|
+
/**
|
|
1029
|
+
* Pause this job (set enabled=false).
|
|
1030
|
+
* Job remains registered but won't run.
|
|
1031
|
+
*/
|
|
1032
|
+
pause: () => {
|
|
1033
|
+
scheduler.getScheduler().pauseJob(id);
|
|
1034
|
+
},
|
|
1035
|
+
/**
|
|
1036
|
+
* Resume this job (set enabled=true).
|
|
1037
|
+
*/
|
|
1038
|
+
resume: () => {
|
|
1039
|
+
scheduler.getScheduler().resumeJob(id);
|
|
1040
|
+
},
|
|
1041
|
+
/**
|
|
1042
|
+
* Reactive paused state - automatically updates when pause/resume is called.
|
|
1043
|
+
* No need for forceUpdate() in your components.
|
|
1044
|
+
*/
|
|
1045
|
+
isPaused
|
|
1010
1046
|
};
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
Object.defineProperty(state, "gl", {
|
|
1015
|
-
get() {
|
|
1016
|
-
const currentState = rootStore.getState();
|
|
1017
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1018
|
-
const stack = new Error().stack || "";
|
|
1019
|
-
if (!isInternalRendererAccess(stack)) {
|
|
1020
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1021
|
-
notifyDepreciated({
|
|
1022
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
1023
|
-
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
|
|
1024
|
-
});
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
return currentState.internal.actualRenderer;
|
|
1028
|
-
},
|
|
1029
|
-
set(value) {
|
|
1030
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1031
|
-
},
|
|
1032
|
-
enumerable: true,
|
|
1033
|
-
configurable: true
|
|
1034
|
-
});
|
|
1035
|
-
Object.defineProperty(state, "renderer", {
|
|
1036
|
-
get() {
|
|
1037
|
-
return rootStore.getState().internal.actualRenderer;
|
|
1038
|
-
},
|
|
1039
|
-
set(value) {
|
|
1040
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1041
|
-
},
|
|
1042
|
-
enumerable: true,
|
|
1043
|
-
configurable: true
|
|
1044
|
-
});
|
|
1045
|
-
let oldScene = state.scene;
|
|
1046
|
-
rootStore.subscribe(() => {
|
|
1047
|
-
const currentState = rootStore.getState();
|
|
1048
|
-
const { scene, rootScene, set } = currentState;
|
|
1049
|
-
if (scene !== oldScene) {
|
|
1050
|
-
oldScene = scene;
|
|
1051
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
1052
|
-
set({ rootScene: scene });
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
});
|
|
1056
|
-
let oldSize = state.size;
|
|
1057
|
-
let oldDpr = state.viewport.dpr;
|
|
1058
|
-
let oldCamera = state.camera;
|
|
1059
|
-
rootStore.subscribe(() => {
|
|
1060
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
1061
|
-
const actualRenderer = internal.actualRenderer;
|
|
1062
|
-
const canvasTarget = internal.canvasTarget;
|
|
1063
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
1064
|
-
oldSize = size;
|
|
1065
|
-
oldDpr = viewport.dpr;
|
|
1066
|
-
updateCamera(camera, size);
|
|
1067
|
-
if (internal.isSecondary && canvasTarget) {
|
|
1068
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1069
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1070
|
-
} else {
|
|
1071
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1072
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1073
|
-
if (canvasTarget) {
|
|
1074
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1075
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
if (camera !== oldCamera) {
|
|
1080
|
-
oldCamera = camera;
|
|
1081
|
-
const { rootScene } = rootStore.getState();
|
|
1082
|
-
if (camera && rootScene && !camera.parent) {
|
|
1083
|
-
rootScene.add(camera);
|
|
1084
|
-
}
|
|
1085
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
1086
|
-
const currentState = rootStore.getState();
|
|
1087
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
1088
|
-
updateFrustum(camera, currentState.frustum);
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
});
|
|
1092
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
1093
|
-
return rootStore;
|
|
1094
|
-
};
|
|
1047
|
+
}, [id, isPaused]);
|
|
1048
|
+
return controls;
|
|
1049
|
+
}
|
|
1095
1050
|
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1051
|
+
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
1052
|
+
function getUrls(input) {
|
|
1053
|
+
if (typeof input === "string") return [input];
|
|
1054
|
+
if (Array.isArray(input)) return input;
|
|
1055
|
+
return Object.values(input);
|
|
1056
|
+
}
|
|
1057
|
+
function inputSignature(input) {
|
|
1058
|
+
if (typeof input === "string") return input;
|
|
1059
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1060
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1061
|
+
}
|
|
1062
|
+
function allUrlsCached(urls, textureCache) {
|
|
1063
|
+
return urls.every((url) => textureCache.has(url));
|
|
1064
|
+
}
|
|
1065
|
+
function buildFromCache(input, textureCache) {
|
|
1066
|
+
if (typeof input === "string") {
|
|
1067
|
+
return textureCache.get(input);
|
|
1068
|
+
} else if (Array.isArray(input)) {
|
|
1069
|
+
return input.map((url) => textureCache.get(url));
|
|
1070
|
+
} else {
|
|
1071
|
+
const result = {};
|
|
1072
|
+
const objInput = input;
|
|
1073
|
+
for (const key in objInput) {
|
|
1074
|
+
result[key] = textureCache.get(objInput[key]);
|
|
1104
1075
|
}
|
|
1105
|
-
return
|
|
1076
|
+
return result;
|
|
1106
1077
|
}
|
|
1107
|
-
return Proto;
|
|
1108
1078
|
}
|
|
1109
|
-
function
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1079
|
+
function useTexture(input, optionsOrOnLoad) {
|
|
1080
|
+
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
1081
|
+
const store = useStore();
|
|
1082
|
+
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
1083
|
+
const { onLoad, cache = true } = options;
|
|
1084
|
+
const onLoadRef = React.useRef(onLoad);
|
|
1085
|
+
onLoadRef.current = onLoad;
|
|
1086
|
+
const onLoadCalledForRef = React.useRef(null);
|
|
1087
|
+
const inputKey = React.useMemo(() => inputSignature(input), [input]);
|
|
1088
|
+
const stableInput = React.useMemo(() => input, [inputKey]);
|
|
1089
|
+
const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1090
|
+
const cachedResult = React.useMemo(() => {
|
|
1091
|
+
if (!cache) return null;
|
|
1092
|
+
const textures = store.getState().textures;
|
|
1093
|
+
if (!allUrlsCached(urls, textures)) return null;
|
|
1094
|
+
return buildFromCache(stableInput, textures);
|
|
1095
|
+
}, [cache, urls, stableInput, store]);
|
|
1096
|
+
const loadedTextures = useLoader(
|
|
1097
|
+
webgpu.TextureLoader,
|
|
1098
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1099
|
+
);
|
|
1100
|
+
const mappedTextures = React.useMemo(() => {
|
|
1101
|
+
if (cachedResult) return cachedResult;
|
|
1102
|
+
if (IsObject(stableInput)) {
|
|
1103
|
+
const keyed = {};
|
|
1104
|
+
const textureArray = loadedTextures;
|
|
1105
|
+
let i = 0;
|
|
1106
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1107
|
+
return keyed;
|
|
1108
|
+
} else {
|
|
1109
|
+
return loadedTextures;
|
|
1110
|
+
}
|
|
1111
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1112
|
+
React.useLayoutEffect(() => {
|
|
1113
|
+
if (cachedResult) return;
|
|
1114
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
1115
|
+
onLoadCalledForRef.current = inputKey;
|
|
1116
|
+
onLoadRef.current?.(mappedTextures);
|
|
1117
|
+
}, [cachedResult, mappedTextures, inputKey]);
|
|
1118
|
+
React.useEffect(() => {
|
|
1119
|
+
if (cachedResult) return;
|
|
1120
|
+
if ("initTexture" in renderer) {
|
|
1121
|
+
let textureArray = [];
|
|
1122
|
+
if (Array.isArray(loadedTextures)) {
|
|
1123
|
+
textureArray = loadedTextures;
|
|
1124
|
+
} else if (loadedTextures instanceof webgpu.Texture) {
|
|
1125
|
+
textureArray = [loadedTextures];
|
|
1126
|
+
} else if (IsObject(loadedTextures)) {
|
|
1127
|
+
textureArray = Object.values(loadedTextures);
|
|
1128
|
+
}
|
|
1129
|
+
textureArray.forEach((texture) => {
|
|
1130
|
+
if (texture instanceof webgpu.Texture) {
|
|
1131
|
+
renderer.initTexture(texture);
|
|
1132
|
+
}
|
|
1117
1133
|
});
|
|
1118
1134
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1135
|
+
}, [renderer, loadedTextures, cachedResult]);
|
|
1136
|
+
React.useEffect(() => {
|
|
1137
|
+
if (!cache) return;
|
|
1138
|
+
const urlTextureMap = [];
|
|
1139
|
+
if (typeof stableInput === "string") {
|
|
1140
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1141
|
+
} else if (Array.isArray(stableInput)) {
|
|
1142
|
+
const textureArray = mappedTextures;
|
|
1143
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1144
|
+
} else if (IsObject(stableInput)) {
|
|
1145
|
+
const textureRecord = mappedTextures;
|
|
1146
|
+
for (const key in stableInput) {
|
|
1147
|
+
const url = stableInput[key];
|
|
1148
|
+
urlTextureMap.push([url, textureRecord[key]]);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
store.setState((state) => {
|
|
1152
|
+
const refs = new Map(state._textureRefs);
|
|
1153
|
+
let textures = state.textures;
|
|
1154
|
+
let added = false;
|
|
1155
|
+
for (const [url, texture] of urlTextureMap) {
|
|
1156
|
+
if (!textures.has(url)) {
|
|
1157
|
+
if (!added) {
|
|
1158
|
+
textures = new Map(textures);
|
|
1159
|
+
added = true;
|
|
1160
|
+
}
|
|
1161
|
+
textures.set(url, texture);
|
|
1162
|
+
}
|
|
1163
|
+
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
1164
|
+
}
|
|
1165
|
+
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
1166
|
+
});
|
|
1167
|
+
return () => store.setState((state) => {
|
|
1168
|
+
const refs = new Map(state._textureRefs);
|
|
1169
|
+
for (const [url] of urlTextureMap) {
|
|
1170
|
+
const next = (refs.get(url) ?? 0) - 1;
|
|
1171
|
+
if (next <= 0) refs.delete(url);
|
|
1172
|
+
else refs.set(url, next);
|
|
1173
|
+
}
|
|
1174
|
+
return { _textureRefs: refs };
|
|
1175
|
+
});
|
|
1176
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1177
|
+
return mappedTextures;
|
|
1140
1178
|
}
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
};
|
|
1152
|
-
useLoader.loader = getLoader$1;
|
|
1153
|
-
|
|
1154
|
-
function useFrame(callback, priorityOrOptions) {
|
|
1155
|
-
const store = React__namespace.useContext(context);
|
|
1156
|
-
const isInsideCanvas = store !== null;
|
|
1157
|
-
const scheduler$1 = scheduler.getScheduler();
|
|
1158
|
-
const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
|
|
1159
|
-
id: priorityOrOptions.id,
|
|
1160
|
-
phase: priorityOrOptions.phase,
|
|
1161
|
-
priority: priorityOrOptions.priority,
|
|
1162
|
-
fps: priorityOrOptions.fps,
|
|
1163
|
-
drop: priorityOrOptions.drop,
|
|
1164
|
-
enabled: priorityOrOptions.enabled,
|
|
1165
|
-
before: priorityOrOptions.before,
|
|
1166
|
-
after: priorityOrOptions.after
|
|
1167
|
-
}) : "";
|
|
1168
|
-
const options = React__namespace.useMemo(() => {
|
|
1169
|
-
return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
|
|
1170
|
-
}, [optionsKey]);
|
|
1171
|
-
const reactId = React__namespace.useId();
|
|
1172
|
-
const id = options.id ?? reactId;
|
|
1173
|
-
const callbackRef = useMutableCallback(callback);
|
|
1174
|
-
const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
|
|
1175
|
-
useIsomorphicLayoutEffect(() => {
|
|
1176
|
-
if (!callback) return;
|
|
1177
|
-
if (isInsideCanvas) {
|
|
1178
|
-
const state = store.getState();
|
|
1179
|
-
const rootId = state.internal.rootId;
|
|
1180
|
-
if (isLegacyPriority) {
|
|
1181
|
-
state.internal.priority++;
|
|
1182
|
-
let parentRoot = state.previousRoot;
|
|
1183
|
-
while (parentRoot) {
|
|
1184
|
-
const parentState = parentRoot.getState();
|
|
1185
|
-
if (parentState?.internal) parentState.internal.priority++;
|
|
1186
|
-
parentRoot = parentState?.previousRoot;
|
|
1187
|
-
}
|
|
1188
|
-
notifyDepreciated({
|
|
1189
|
-
heading: "useFrame with numeric priority is deprecated",
|
|
1190
|
-
body: 'Using useFrame(callback, number) to control render order is deprecated.\n\nFor custom rendering, use: useFrame(callback, { phase: "render" })\nFor execution order within update phase, use: useFrame(callback, { priority: number })',
|
|
1191
|
-
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
1192
|
-
});
|
|
1193
|
-
}
|
|
1194
|
-
const wrappedCallback = (frameState, delta) => {
|
|
1195
|
-
const localState = store.getState();
|
|
1196
|
-
const mergedState = {
|
|
1197
|
-
...localState,
|
|
1198
|
-
time: frameState.time,
|
|
1199
|
-
delta: frameState.delta,
|
|
1200
|
-
elapsed: frameState.elapsed,
|
|
1201
|
-
frame: frameState.frame
|
|
1202
|
-
};
|
|
1203
|
-
callbackRef.current?.(mergedState, delta);
|
|
1204
|
-
};
|
|
1205
|
-
const unregister = scheduler$1.register(wrappedCallback, {
|
|
1206
|
-
id,
|
|
1207
|
-
rootId,
|
|
1208
|
-
...options
|
|
1209
|
-
});
|
|
1210
|
-
return () => {
|
|
1211
|
-
unregister();
|
|
1212
|
-
if (isLegacyPriority) {
|
|
1213
|
-
const currentState = store.getState();
|
|
1214
|
-
if (currentState.internal) {
|
|
1215
|
-
currentState.internal.priority--;
|
|
1216
|
-
let parentRoot = currentState.previousRoot;
|
|
1217
|
-
while (parentRoot) {
|
|
1218
|
-
const parentState = parentRoot.getState();
|
|
1219
|
-
if (parentState?.internal) parentState.internal.priority--;
|
|
1220
|
-
parentRoot = parentState?.previousRoot;
|
|
1221
|
-
}
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
};
|
|
1225
|
-
} else {
|
|
1226
|
-
return scheduler$1.register(
|
|
1227
|
-
(state, delta) => {
|
|
1228
|
-
const frameState = state;
|
|
1229
|
-
if (!frameState.renderer) return;
|
|
1230
|
-
callbackRef.current?.(frameState, delta);
|
|
1231
|
-
},
|
|
1232
|
-
{ id, ...options }
|
|
1233
|
-
);
|
|
1234
|
-
}
|
|
1235
|
-
}, [store, scheduler$1, id, optionsKey, isLegacyPriority, isInsideCanvas]);
|
|
1236
|
-
const isPaused = React__namespace.useSyncExternalStore(
|
|
1237
|
-
// Subscribe function
|
|
1238
|
-
React__namespace.useCallback(
|
|
1239
|
-
(onStoreChange) => {
|
|
1240
|
-
return scheduler.getScheduler().subscribeJobState(id, onStoreChange);
|
|
1241
|
-
},
|
|
1242
|
-
[id]
|
|
1243
|
-
),
|
|
1244
|
-
// getSnapshot function
|
|
1245
|
-
React__namespace.useCallback(() => scheduler.getScheduler().isJobPaused(id), [id]),
|
|
1246
|
-
// getServerSnapshot function (SSR)
|
|
1247
|
-
React__namespace.useCallback(() => false, [])
|
|
1248
|
-
);
|
|
1249
|
-
const controls = React__namespace.useMemo(() => {
|
|
1250
|
-
const scheduler2 = scheduler.getScheduler();
|
|
1251
|
-
return {
|
|
1252
|
-
/** The job's unique ID */
|
|
1253
|
-
id,
|
|
1254
|
-
/**
|
|
1255
|
-
* Access to the global scheduler for frame loop control.
|
|
1256
|
-
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1257
|
-
*/
|
|
1258
|
-
scheduler: scheduler2,
|
|
1259
|
-
/**
|
|
1260
|
-
* Manually step this job only.
|
|
1261
|
-
* Bypasses FPS limiting - always runs.
|
|
1262
|
-
* @param timestamp Optional timestamp (defaults to performance.now())
|
|
1263
|
-
*/
|
|
1264
|
-
step: (timestamp) => {
|
|
1265
|
-
scheduler.getScheduler().stepJob(id, timestamp);
|
|
1266
|
-
},
|
|
1267
|
-
/**
|
|
1268
|
-
* Manually step ALL jobs in the scheduler.
|
|
1269
|
-
* Useful for frameloop='never' mode.
|
|
1270
|
-
* @param timestamp Optional timestamp (defaults to performance.now())
|
|
1271
|
-
*/
|
|
1272
|
-
stepAll: (timestamp) => {
|
|
1273
|
-
scheduler.getScheduler().step(timestamp);
|
|
1274
|
-
},
|
|
1275
|
-
/**
|
|
1276
|
-
* Pause this job (set enabled=false).
|
|
1277
|
-
* Job remains registered but won't run.
|
|
1278
|
-
*/
|
|
1279
|
-
pause: () => {
|
|
1280
|
-
scheduler.getScheduler().pauseJob(id);
|
|
1281
|
-
},
|
|
1282
|
-
/**
|
|
1283
|
-
* Resume this job (set enabled=true).
|
|
1284
|
-
*/
|
|
1285
|
-
resume: () => {
|
|
1286
|
-
scheduler.getScheduler().resumeJob(id);
|
|
1287
|
-
},
|
|
1288
|
-
/**
|
|
1289
|
-
* Reactive paused state - automatically updates when pause/resume is called.
|
|
1290
|
-
* No need for forceUpdate() in your components.
|
|
1291
|
-
*/
|
|
1292
|
-
isPaused
|
|
1293
|
-
};
|
|
1294
|
-
}, [id, isPaused]);
|
|
1295
|
-
return controls;
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
|
|
1299
|
-
function getUrls(input) {
|
|
1300
|
-
if (typeof input === "string") return [input];
|
|
1301
|
-
if (Array.isArray(input)) return input;
|
|
1302
|
-
return Object.values(input);
|
|
1303
|
-
}
|
|
1304
|
-
function allUrlsCached(urls, textureCache) {
|
|
1305
|
-
return urls.every((url) => textureCache.has(url));
|
|
1306
|
-
}
|
|
1307
|
-
function buildFromCache(input, textureCache) {
|
|
1308
|
-
if (typeof input === "string") {
|
|
1309
|
-
return textureCache.get(input);
|
|
1310
|
-
} else if (Array.isArray(input)) {
|
|
1311
|
-
return input.map((url) => textureCache.get(url));
|
|
1312
|
-
} else {
|
|
1313
|
-
const result = {};
|
|
1314
|
-
const objInput = input;
|
|
1315
|
-
for (const key in objInput) {
|
|
1316
|
-
result[key] = textureCache.get(objInput[key]);
|
|
1317
|
-
}
|
|
1318
|
-
return result;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
function useTexture(input, optionsOrOnLoad) {
|
|
1322
|
-
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
1323
|
-
const store = useStore();
|
|
1324
|
-
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
1325
|
-
const { onLoad, cache = true } = options;
|
|
1326
|
-
const onLoadRef = React.useRef(onLoad);
|
|
1327
|
-
onLoadRef.current = onLoad;
|
|
1328
|
-
const onLoadCalledForRef = React.useRef(null);
|
|
1329
|
-
const urls = React.useMemo(() => getUrls(input), [input]);
|
|
1330
|
-
const cachedResult = React.useMemo(() => {
|
|
1331
|
-
if (!cache) return null;
|
|
1332
|
-
const textures = store.getState().textures;
|
|
1333
|
-
if (!allUrlsCached(urls, textures)) return null;
|
|
1334
|
-
return buildFromCache(input, textures);
|
|
1335
|
-
}, [cache, urls, input, store]);
|
|
1336
|
-
const loadedTextures = useLoader(
|
|
1337
|
-
webgpu.TextureLoader,
|
|
1338
|
-
IsObject(input) ? Object.values(input) : input
|
|
1339
|
-
);
|
|
1340
|
-
const inputKey = urls.join("\0");
|
|
1341
|
-
React.useLayoutEffect(() => {
|
|
1342
|
-
if (cachedResult) return;
|
|
1343
|
-
if (onLoadCalledForRef.current === inputKey) return;
|
|
1344
|
-
onLoadCalledForRef.current = inputKey;
|
|
1345
|
-
onLoadRef.current?.(loadedTextures);
|
|
1346
|
-
}, [cachedResult, loadedTextures, inputKey]);
|
|
1347
|
-
React.useEffect(() => {
|
|
1348
|
-
if (cachedResult) return;
|
|
1349
|
-
if ("initTexture" in renderer) {
|
|
1350
|
-
let textureArray = [];
|
|
1351
|
-
if (Array.isArray(loadedTextures)) {
|
|
1352
|
-
textureArray = loadedTextures;
|
|
1353
|
-
} else if (loadedTextures instanceof webgpu.Texture) {
|
|
1354
|
-
textureArray = [loadedTextures];
|
|
1355
|
-
} else if (IsObject(loadedTextures)) {
|
|
1356
|
-
textureArray = Object.values(loadedTextures);
|
|
1357
|
-
}
|
|
1358
|
-
textureArray.forEach((texture) => {
|
|
1359
|
-
if (texture instanceof webgpu.Texture) {
|
|
1360
|
-
renderer.initTexture(texture);
|
|
1361
|
-
}
|
|
1362
|
-
});
|
|
1363
|
-
}
|
|
1364
|
-
}, [renderer, loadedTextures, cachedResult]);
|
|
1365
|
-
const mappedTextures = React.useMemo(() => {
|
|
1366
|
-
if (cachedResult) return cachedResult;
|
|
1367
|
-
if (IsObject(input)) {
|
|
1368
|
-
const keyed = {};
|
|
1369
|
-
const textureArray = loadedTextures;
|
|
1370
|
-
let i = 0;
|
|
1371
|
-
for (const key in input) keyed[key] = textureArray[i++];
|
|
1372
|
-
return keyed;
|
|
1373
|
-
} else {
|
|
1374
|
-
return loadedTextures;
|
|
1375
|
-
}
|
|
1376
|
-
}, [input, loadedTextures, cachedResult]);
|
|
1377
|
-
React.useEffect(() => {
|
|
1378
|
-
if (!cache) return;
|
|
1379
|
-
const urlTextureMap = [];
|
|
1380
|
-
if (typeof input === "string") {
|
|
1381
|
-
urlTextureMap.push([input, mappedTextures]);
|
|
1382
|
-
} else if (Array.isArray(input)) {
|
|
1383
|
-
const textureArray = mappedTextures;
|
|
1384
|
-
input.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1385
|
-
} else if (IsObject(input)) {
|
|
1386
|
-
const textureRecord = mappedTextures;
|
|
1387
|
-
for (const key in input) {
|
|
1388
|
-
const url = input[key];
|
|
1389
|
-
urlTextureMap.push([url, textureRecord[key]]);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
store.setState((state) => {
|
|
1393
|
-
const refs = new Map(state._textureRefs);
|
|
1394
|
-
let textures = state.textures;
|
|
1395
|
-
let added = false;
|
|
1396
|
-
for (const [url, texture] of urlTextureMap) {
|
|
1397
|
-
if (!textures.has(url)) {
|
|
1398
|
-
if (!added) {
|
|
1399
|
-
textures = new Map(textures);
|
|
1400
|
-
added = true;
|
|
1401
|
-
}
|
|
1402
|
-
textures.set(url, texture);
|
|
1403
|
-
}
|
|
1404
|
-
refs.set(url, (refs.get(url) ?? 0) + 1);
|
|
1405
|
-
}
|
|
1406
|
-
return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
|
|
1407
|
-
});
|
|
1408
|
-
return () => store.setState((state) => {
|
|
1409
|
-
const refs = new Map(state._textureRefs);
|
|
1410
|
-
for (const [url] of urlTextureMap) {
|
|
1411
|
-
const next = (refs.get(url) ?? 0) - 1;
|
|
1412
|
-
if (next <= 0) refs.delete(url);
|
|
1413
|
-
else refs.set(url, next);
|
|
1414
|
-
}
|
|
1415
|
-
return { _textureRefs: refs };
|
|
1416
|
-
});
|
|
1417
|
-
}, [cache, input, mappedTextures, store]);
|
|
1418
|
-
return mappedTextures;
|
|
1419
|
-
}
|
|
1420
|
-
useTexture.preload = (url) => useLoader.preload(webgpu.TextureLoader, url);
|
|
1421
|
-
useTexture.clear = (input) => useLoader.clear(webgpu.TextureLoader, input);
|
|
1422
|
-
const Texture = ({
|
|
1423
|
-
children,
|
|
1424
|
-
input,
|
|
1425
|
-
onLoad,
|
|
1426
|
-
cache
|
|
1427
|
-
}) => {
|
|
1428
|
-
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
1429
|
-
const ret = useTexture(input, options);
|
|
1430
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
1179
|
+
useTexture.preload = (url) => useLoader.preload(webgpu.TextureLoader, url);
|
|
1180
|
+
useTexture.clear = (input) => useLoader.clear(webgpu.TextureLoader, input);
|
|
1181
|
+
const Texture = ({
|
|
1182
|
+
children,
|
|
1183
|
+
input,
|
|
1184
|
+
onLoad,
|
|
1185
|
+
cache
|
|
1186
|
+
}) => {
|
|
1187
|
+
const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
|
|
1188
|
+
const ret = useTexture(input, options);
|
|
1189
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children?.(ret) });
|
|
1431
1190
|
};
|
|
1432
1191
|
|
|
1433
1192
|
function useTextures(selector) {
|
|
@@ -1577,7 +1336,7 @@ function useEnvironment({
|
|
|
1577
1336
|
texture = texture.renderTarget?.texture;
|
|
1578
1337
|
}
|
|
1579
1338
|
texture.mapping = isCubemap ? webgpu.CubeReflectionMapping : webgpu.EquirectangularReflectionMapping;
|
|
1580
|
-
texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
|
|
1339
|
+
texture.colorSpace = colorSpace ?? (isCubemap && extension !== "hdr-cube" ? "srgb" : "srgb-linear");
|
|
1581
1340
|
return texture;
|
|
1582
1341
|
}
|
|
1583
1342
|
const preloadDefaultOptions = {
|
|
@@ -1630,22 +1389,15 @@ function getExtension(files) {
|
|
|
1630
1389
|
const isCubemap = isArray(files) && files.length === 6;
|
|
1631
1390
|
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
|
|
1632
1391
|
const firstEntry = isArray(files) ? files[0] : files;
|
|
1633
|
-
const
|
|
1392
|
+
const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
|
|
1393
|
+
const extension = isCubemap ? firstExtension === "hdr" ? "hdr-cube" : "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : firstExtension;
|
|
1634
1394
|
return { extension, isCubemap, isGainmap };
|
|
1635
1395
|
}
|
|
1636
1396
|
function getLoader(extension) {
|
|
1637
|
-
const loader = extension === "cube" ? webgpu.CubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
|
|
1397
|
+
const loader = extension === "cube" ? webgpu.CubeTextureLoader : extension === "hdr-cube" ? HDRCubeTextureLoader_js.HDRCubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
|
|
1638
1398
|
return loader;
|
|
1639
1399
|
}
|
|
1640
1400
|
|
|
1641
|
-
function useStore() {
|
|
1642
|
-
const store = React.useContext(context);
|
|
1643
|
-
if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
|
|
1644
|
-
return store;
|
|
1645
|
-
}
|
|
1646
|
-
function useThree(selector = (state) => state, equalityFn) {
|
|
1647
|
-
return useStore()(selector, equalityFn);
|
|
1648
|
-
}
|
|
1649
1401
|
function useInstanceHandle(ref) {
|
|
1650
1402
|
const instance = React.useRef(null);
|
|
1651
1403
|
React.useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
|
|
@@ -1685,13 +1437,19 @@ function addTail(callback) {
|
|
|
1685
1437
|
return scheduler.getScheduler().onIdle(callback);
|
|
1686
1438
|
}
|
|
1687
1439
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1688
|
-
|
|
1440
|
+
const rootId = state?.internal?.rootId;
|
|
1441
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1442
|
+
if (rootId) scheduler$1.invalidateRoot(rootId, frames, stackFrames);
|
|
1443
|
+
else scheduler$1.invalidate(frames, stackFrames);
|
|
1689
1444
|
}
|
|
1690
|
-
function advance(timestamp) {
|
|
1691
|
-
|
|
1445
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1446
|
+
const rootId = state?.internal?.rootId;
|
|
1447
|
+
const scheduler$1 = scheduler.getScheduler();
|
|
1448
|
+
if (rootId) scheduler$1.stepRoot(rootId, timestamp);
|
|
1449
|
+
else scheduler$1.step(timestamp);
|
|
1692
1450
|
}
|
|
1693
1451
|
|
|
1694
|
-
const version = "10.0.0-alpha.
|
|
1452
|
+
const version = "10.0.0-alpha.5";
|
|
1695
1453
|
const packageData = {
|
|
1696
1454
|
version: version};
|
|
1697
1455
|
|
|
@@ -13550,7 +13308,10 @@ function extend(objects) {
|
|
|
13550
13308
|
catalogue[Component] = objects;
|
|
13551
13309
|
return Component;
|
|
13552
13310
|
} else {
|
|
13553
|
-
|
|
13311
|
+
for (const name in objects) {
|
|
13312
|
+
const object = objects[name];
|
|
13313
|
+
if (isConstructor(object)) catalogue[name] = object;
|
|
13314
|
+
}
|
|
13554
13315
|
}
|
|
13555
13316
|
}
|
|
13556
13317
|
function validateInstance(type, props) {
|
|
@@ -13898,7 +13659,7 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
13898
13659
|
getRootHostContext: () => NO_CONTEXT,
|
|
13899
13660
|
getChildHostContext: () => NO_CONTEXT,
|
|
13900
13661
|
commitUpdate(instance, type, oldProps, newProps, fiber) {
|
|
13901
|
-
validateInstance(type, newProps);
|
|
13662
|
+
validateInstance(instance.type, newProps);
|
|
13902
13663
|
let reconstruct = false;
|
|
13903
13664
|
if (instance.type === "primitive" && oldProps.object !== newProps.object) reconstruct = true;
|
|
13904
13665
|
else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
|
|
@@ -13913,162 +13674,491 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
13913
13674
|
else delete instance.props.attach;
|
|
13914
13675
|
if (Object.keys(changedProps).length) applyProps(instance.object, changedProps);
|
|
13915
13676
|
}
|
|
13916
|
-
},
|
|
13917
|
-
finalizeInitialChildren: (instance) => {
|
|
13918
|
-
for (const prop in instance.props) {
|
|
13919
|
-
if (isFromRef(instance.props[prop])) return true;
|
|
13677
|
+
},
|
|
13678
|
+
finalizeInitialChildren: (instance) => {
|
|
13679
|
+
for (const prop in instance.props) {
|
|
13680
|
+
if (isFromRef(instance.props[prop])) return true;
|
|
13681
|
+
}
|
|
13682
|
+
return false;
|
|
13683
|
+
},
|
|
13684
|
+
commitMount(instance) {
|
|
13685
|
+
const resolved = {};
|
|
13686
|
+
for (const prop in instance.props) {
|
|
13687
|
+
const value = instance.props[prop];
|
|
13688
|
+
if (isFromRef(value)) {
|
|
13689
|
+
const { [FROM_REF]: ref, transform } = value;
|
|
13690
|
+
if (ref.current != null) resolved[prop] = transform ? transform(ref.current) : ref.current;
|
|
13691
|
+
}
|
|
13692
|
+
}
|
|
13693
|
+
if (Object.keys(resolved).length) applyProps(instance.object, resolved);
|
|
13694
|
+
},
|
|
13695
|
+
getPublicInstance: (instance) => instance?.object,
|
|
13696
|
+
prepareForCommit: () => null,
|
|
13697
|
+
preparePortalMount: (container) => {
|
|
13698
|
+
const target = container.getState().internal.container ?? container.getState().scene;
|
|
13699
|
+
return prepare(target, container, "", {});
|
|
13700
|
+
},
|
|
13701
|
+
// Reconstructed instances are swapped once all mutations are committed,
|
|
13702
|
+
// before layout effects run so refs point to the new objects
|
|
13703
|
+
resetAfterCommit: flushReconstructedInstances,
|
|
13704
|
+
shouldSetTextContent: () => false,
|
|
13705
|
+
clearContainer: () => false,
|
|
13706
|
+
hideInstance,
|
|
13707
|
+
unhideInstance,
|
|
13708
|
+
createTextInstance: handleTextInstance,
|
|
13709
|
+
hideTextInstance: handleTextInstance,
|
|
13710
|
+
unhideTextInstance: handleTextInstance,
|
|
13711
|
+
// Mirrors react-dom, which flushes discrete work in microtasks
|
|
13712
|
+
supportsMicrotasks: true,
|
|
13713
|
+
scheduleMicrotask,
|
|
13714
|
+
scheduleTimeout: typeof setTimeout === "function" ? setTimeout : void 0,
|
|
13715
|
+
cancelTimeout: typeof clearTimeout === "function" ? clearTimeout : void 0,
|
|
13716
|
+
noTimeout: -1,
|
|
13717
|
+
getInstanceFromNode: () => null,
|
|
13718
|
+
beforeActiveInstanceBlur() {
|
|
13719
|
+
},
|
|
13720
|
+
afterActiveInstanceBlur() {
|
|
13721
|
+
},
|
|
13722
|
+
detachDeletedInstance() {
|
|
13723
|
+
},
|
|
13724
|
+
prepareScopeUpdate() {
|
|
13725
|
+
},
|
|
13726
|
+
getInstanceFromScope: () => null,
|
|
13727
|
+
shouldAttemptEagerTransition: () => false,
|
|
13728
|
+
trackSchedulerEvent: () => {
|
|
13729
|
+
},
|
|
13730
|
+
resolveEventType: () => null,
|
|
13731
|
+
resolveEventTimeStamp: () => -1.1,
|
|
13732
|
+
requestPostPaintCallback() {
|
|
13733
|
+
},
|
|
13734
|
+
maySuspendCommit: () => false,
|
|
13735
|
+
preloadInstance: () => true,
|
|
13736
|
+
// true indicates already loaded
|
|
13737
|
+
suspendInstance() {
|
|
13738
|
+
},
|
|
13739
|
+
waitForCommitToBeReady: () => null,
|
|
13740
|
+
NotPendingTransition: null,
|
|
13741
|
+
// The reconciler types use the internal ReactContext with all the hidden properties
|
|
13742
|
+
// so we have to cast from the public React.Context type
|
|
13743
|
+
HostTransitionContext: /* @__PURE__ */ React__namespace.createContext(
|
|
13744
|
+
null
|
|
13745
|
+
),
|
|
13746
|
+
setCurrentUpdatePriority(newPriority) {
|
|
13747
|
+
currentUpdatePriority = newPriority;
|
|
13748
|
+
},
|
|
13749
|
+
getCurrentUpdatePriority() {
|
|
13750
|
+
return currentUpdatePriority;
|
|
13751
|
+
},
|
|
13752
|
+
resolveUpdatePriority() {
|
|
13753
|
+
if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
|
|
13754
|
+
const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
|
|
13755
|
+
if (eventType === void 0) return r;
|
|
13756
|
+
return getEventPriority(eventType);
|
|
13757
|
+
},
|
|
13758
|
+
resetFormInstance() {
|
|
13759
|
+
},
|
|
13760
|
+
// @ts-ignore DefinitelyTyped is not up to date
|
|
13761
|
+
rendererPackageName: "@react-three/fiber",
|
|
13762
|
+
rendererVersion: packageData.version,
|
|
13763
|
+
// 19.2 Reconciler
|
|
13764
|
+
// https://github.com/facebook/react/pull/31975
|
|
13765
|
+
// https://github.com/facebook/react/pull/31999
|
|
13766
|
+
applyViewTransitionName(_instance, _name, _className) {
|
|
13767
|
+
},
|
|
13768
|
+
restoreViewTransitionName(_instance, _props) {
|
|
13769
|
+
},
|
|
13770
|
+
cancelViewTransitionName(_instance, _name, _props) {
|
|
13771
|
+
},
|
|
13772
|
+
cancelRootViewTransitionName(_rootContainer) {
|
|
13773
|
+
},
|
|
13774
|
+
restoreRootViewTransitionName(_rootContainer) {
|
|
13775
|
+
},
|
|
13776
|
+
InstanceMeasurement: null,
|
|
13777
|
+
measureInstance: (_instance) => null,
|
|
13778
|
+
wasInstanceInViewport: (_measurement) => true,
|
|
13779
|
+
hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
|
|
13780
|
+
hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
|
|
13781
|
+
// https://github.com/facebook/react/pull/32002
|
|
13782
|
+
// https://github.com/facebook/react/pull/34486
|
|
13783
|
+
suspendOnActiveViewTransition(_state, _container) {
|
|
13784
|
+
},
|
|
13785
|
+
// https://github.com/facebook/react/pull/32451
|
|
13786
|
+
// https://github.com/facebook/react/pull/32760
|
|
13787
|
+
startGestureTransition: () => null,
|
|
13788
|
+
startViewTransition: () => null,
|
|
13789
|
+
stopViewTransition(_transition) {
|
|
13790
|
+
},
|
|
13791
|
+
// https://github.com/facebook/react/pull/32038
|
|
13792
|
+
createViewTransitionInstance: (_name) => null,
|
|
13793
|
+
// https://github.com/facebook/react/pull/32379
|
|
13794
|
+
// https://github.com/facebook/react/pull/32786
|
|
13795
|
+
getCurrentGestureOffset(_provider) {
|
|
13796
|
+
throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
|
|
13797
|
+
},
|
|
13798
|
+
// https://github.com/facebook/react/pull/32500
|
|
13799
|
+
cloneMutableInstance(instance, _keepChildren) {
|
|
13800
|
+
return instance;
|
|
13801
|
+
},
|
|
13802
|
+
cloneMutableTextInstance(textInstance) {
|
|
13803
|
+
return textInstance;
|
|
13804
|
+
},
|
|
13805
|
+
// React 19.2 added these for root-level view transitions. They only run for hosts that opt into
|
|
13806
|
+
// view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
|
|
13807
|
+
// into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
|
|
13808
|
+
// React never calls them. They stay as no-ops rather than throws: the host config is shared by
|
|
13809
|
+
// every root, and a throw here would turn a React-internal probe into a hard crash for users.
|
|
13810
|
+
// Guarded by a test asserting a full render + unmount never reaches them.
|
|
13811
|
+
cloneRootViewTransitionContainer(_rootContainer) {
|
|
13812
|
+
},
|
|
13813
|
+
removeRootViewTransitionClone(_rootContainer, _clone) {
|
|
13814
|
+
},
|
|
13815
|
+
// https://github.com/facebook/react/pull/32465
|
|
13816
|
+
createFragmentInstance: (_fiber) => null,
|
|
13817
|
+
updateFragmentInstanceFiber(_fiber, _instance) {
|
|
13818
|
+
},
|
|
13819
|
+
commitNewChildToFragmentInstance(_child, _fragmentInstance) {
|
|
13820
|
+
},
|
|
13821
|
+
deleteChildFromFragmentInstance(_child, _fragmentInstance) {
|
|
13822
|
+
},
|
|
13823
|
+
// https://github.com/facebook/react/pull/32653
|
|
13824
|
+
measureClonedInstance: (_instance) => null,
|
|
13825
|
+
// https://github.com/facebook/react/pull/32819
|
|
13826
|
+
maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
|
|
13827
|
+
maySuspendCommitInSyncRender: (_type, _props) => false,
|
|
13828
|
+
// https://github.com/facebook/react/pull/34486
|
|
13829
|
+
startSuspendingCommit: () => null,
|
|
13830
|
+
// https://github.com/facebook/react/pull/34522
|
|
13831
|
+
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
13832
|
+
});
|
|
13833
|
+
|
|
13834
|
+
const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
|
|
13835
|
+
function isInternalRendererAccess(stack, callerDepth = 2) {
|
|
13836
|
+
if (!stack) return false;
|
|
13837
|
+
const caller = stack.split("\n")[callerDepth] ?? "";
|
|
13838
|
+
return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
|
|
13839
|
+
}
|
|
13840
|
+
|
|
13841
|
+
const createStore = (invalidate, advance) => {
|
|
13842
|
+
const rootStore = traditional.createWithEqualityFn((set, get) => {
|
|
13843
|
+
const position = new webgpu.Vector3();
|
|
13844
|
+
const defaultTarget = new webgpu.Vector3();
|
|
13845
|
+
const tempTarget = new webgpu.Vector3();
|
|
13846
|
+
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
13847
|
+
const { width, height, top, left } = size;
|
|
13848
|
+
const aspect = width / height;
|
|
13849
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
13850
|
+
else tempTarget.set(...target);
|
|
13851
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
13852
|
+
if (isOrthographicCamera(camera)) {
|
|
13853
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
13854
|
+
} else {
|
|
13855
|
+
const fov = camera.fov * Math.PI / 180;
|
|
13856
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
13857
|
+
const w = h * (width / height);
|
|
13858
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
13859
|
+
}
|
|
13860
|
+
}
|
|
13861
|
+
let performanceTimeout = void 0;
|
|
13862
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
13863
|
+
const pointer = new webgpu.Vector2();
|
|
13864
|
+
const rootState = {
|
|
13865
|
+
set,
|
|
13866
|
+
get,
|
|
13867
|
+
// Mock objects that have to be configured
|
|
13868
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
13869
|
+
primaryStore: null,
|
|
13870
|
+
gl: null,
|
|
13871
|
+
renderer: null,
|
|
13872
|
+
camera: null,
|
|
13873
|
+
frustum: new webgpu.Frustum(),
|
|
13874
|
+
autoUpdateFrustum: true,
|
|
13875
|
+
raycaster: null,
|
|
13876
|
+
events: {
|
|
13877
|
+
priority: 1,
|
|
13878
|
+
enabled: true,
|
|
13879
|
+
connected: false,
|
|
13880
|
+
frameTimedRaycasts: true,
|
|
13881
|
+
alwaysFireOnScroll: true,
|
|
13882
|
+
updateOnFrame: false
|
|
13883
|
+
},
|
|
13884
|
+
scene: null,
|
|
13885
|
+
rootScene: null,
|
|
13886
|
+
xr: null,
|
|
13887
|
+
inspector: null,
|
|
13888
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
13889
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
13890
|
+
textureColorSpace: webgpu.SRGBColorSpace,
|
|
13891
|
+
isLegacy: false,
|
|
13892
|
+
webGPUSupported: false,
|
|
13893
|
+
isNative: false,
|
|
13894
|
+
controls: null,
|
|
13895
|
+
pointer,
|
|
13896
|
+
mouse: pointer,
|
|
13897
|
+
frameloop: "always",
|
|
13898
|
+
onPointerMissed: void 0,
|
|
13899
|
+
onDragOverMissed: void 0,
|
|
13900
|
+
onDropMissed: void 0,
|
|
13901
|
+
performance: {
|
|
13902
|
+
current: 1,
|
|
13903
|
+
min: 0.5,
|
|
13904
|
+
max: 1,
|
|
13905
|
+
debounce: 200,
|
|
13906
|
+
regress: () => {
|
|
13907
|
+
const state2 = get();
|
|
13908
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
13909
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
13910
|
+
performanceTimeout = setTimeout(
|
|
13911
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
13912
|
+
state2.performance.debounce
|
|
13913
|
+
);
|
|
13914
|
+
}
|
|
13915
|
+
},
|
|
13916
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
13917
|
+
viewport: {
|
|
13918
|
+
initialDpr: 0,
|
|
13919
|
+
dpr: 0,
|
|
13920
|
+
width: 0,
|
|
13921
|
+
height: 0,
|
|
13922
|
+
top: 0,
|
|
13923
|
+
left: 0,
|
|
13924
|
+
aspect: 0,
|
|
13925
|
+
distance: 0,
|
|
13926
|
+
factor: 0,
|
|
13927
|
+
getCurrentViewport
|
|
13928
|
+
},
|
|
13929
|
+
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
13930
|
+
setSize: (width, height, top, left) => {
|
|
13931
|
+
const state2 = get();
|
|
13932
|
+
if (width === void 0) {
|
|
13933
|
+
set({ _sizeImperative: false });
|
|
13934
|
+
if (state2._sizeProps) {
|
|
13935
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
13936
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
13937
|
+
const currentSize = state2.size;
|
|
13938
|
+
const newSize = {
|
|
13939
|
+
width: propW ?? currentSize.width,
|
|
13940
|
+
height: propH ?? currentSize.height,
|
|
13941
|
+
top: currentSize.top,
|
|
13942
|
+
left: currentSize.left
|
|
13943
|
+
};
|
|
13944
|
+
set((s) => ({
|
|
13945
|
+
size: newSize,
|
|
13946
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
13947
|
+
}));
|
|
13948
|
+
get().invalidate();
|
|
13949
|
+
}
|
|
13950
|
+
}
|
|
13951
|
+
return;
|
|
13952
|
+
}
|
|
13953
|
+
const w = width;
|
|
13954
|
+
const h = height ?? width;
|
|
13955
|
+
const t = top ?? state2.size.top;
|
|
13956
|
+
const l = left ?? state2.size.left;
|
|
13957
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
13958
|
+
set((s) => ({
|
|
13959
|
+
size,
|
|
13960
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
13961
|
+
_sizeImperative: true
|
|
13962
|
+
}));
|
|
13963
|
+
get().invalidate();
|
|
13964
|
+
},
|
|
13965
|
+
setDpr: (dpr) => set((state2) => {
|
|
13966
|
+
const resolved = calculateDpr(dpr);
|
|
13967
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
13968
|
+
}),
|
|
13969
|
+
setFrameloop: (frameloop = "always") => {
|
|
13970
|
+
const rootId = get().internal.rootId;
|
|
13971
|
+
if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
|
|
13972
|
+
set(() => ({ frameloop }));
|
|
13973
|
+
},
|
|
13974
|
+
setError: (error) => set(() => ({ error })),
|
|
13975
|
+
error: null,
|
|
13976
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
|
|
13977
|
+
uniforms: {},
|
|
13978
|
+
nodes: {},
|
|
13979
|
+
buffers: {},
|
|
13980
|
+
gpuStorage: {},
|
|
13981
|
+
textures: /* @__PURE__ */ new Map(),
|
|
13982
|
+
_textureRefs: /* @__PURE__ */ new Map(),
|
|
13983
|
+
renderPipeline: null,
|
|
13984
|
+
passes: {},
|
|
13985
|
+
_hmrVersion: 0,
|
|
13986
|
+
_sizeImperative: false,
|
|
13987
|
+
_sizeProps: null,
|
|
13988
|
+
previousRoot: void 0,
|
|
13989
|
+
internal: {
|
|
13990
|
+
// Events
|
|
13991
|
+
interaction: [],
|
|
13992
|
+
subscribers: [],
|
|
13993
|
+
// Per-pointer state (new unified structure)
|
|
13994
|
+
pointerMap: /* @__PURE__ */ new Map(),
|
|
13995
|
+
pointerDirty: /* @__PURE__ */ new Map(),
|
|
13996
|
+
lastEvent: React__namespace.createRef(),
|
|
13997
|
+
// Deprecated but kept for backwards compatibility
|
|
13998
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
13999
|
+
initialClick: [0, 0],
|
|
14000
|
+
initialHits: [],
|
|
14001
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
14002
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
14003
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
14004
|
+
// Occlusion system (WebGPU only)
|
|
14005
|
+
occlusionEnabled: false,
|
|
14006
|
+
occlusionObserver: null,
|
|
14007
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
14008
|
+
helperGroup: null,
|
|
14009
|
+
// Updates
|
|
14010
|
+
active: false,
|
|
14011
|
+
frames: 0,
|
|
14012
|
+
priority: 0,
|
|
14013
|
+
subscribe: (ref, priority, store) => {
|
|
14014
|
+
const internal = get().internal;
|
|
14015
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
14016
|
+
internal.subscribers.push({ ref, priority, store });
|
|
14017
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
14018
|
+
return () => {
|
|
14019
|
+
const internal2 = get().internal;
|
|
14020
|
+
if (internal2?.subscribers) {
|
|
14021
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
14022
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
14023
|
+
}
|
|
14024
|
+
};
|
|
14025
|
+
},
|
|
14026
|
+
// Renderer Storage (single source of truth)
|
|
14027
|
+
actualRenderer: null,
|
|
14028
|
+
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
14029
|
+
scheduler: null,
|
|
14030
|
+
// Replaces the default render call when set (see setRenderOverride)
|
|
14031
|
+
renderOverride: null
|
|
14032
|
+
}
|
|
14033
|
+
};
|
|
14034
|
+
return rootState;
|
|
14035
|
+
});
|
|
14036
|
+
const state = rootStore.getState();
|
|
14037
|
+
Object.defineProperty(state, "gl", {
|
|
14038
|
+
get() {
|
|
14039
|
+
const currentState = rootStore.getState();
|
|
14040
|
+
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
14041
|
+
const stack = new Error().stack || "";
|
|
14042
|
+
if (!isInternalRendererAccess(stack)) {
|
|
14043
|
+
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
14044
|
+
notifyDepreciated({
|
|
14045
|
+
heading: "Accessing state.gl in WebGPU mode",
|
|
14046
|
+
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
|
|
14047
|
+
});
|
|
14048
|
+
}
|
|
14049
|
+
}
|
|
14050
|
+
return currentState.internal.actualRenderer;
|
|
14051
|
+
},
|
|
14052
|
+
set(value) {
|
|
14053
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
14054
|
+
},
|
|
14055
|
+
enumerable: true,
|
|
14056
|
+
configurable: true
|
|
14057
|
+
});
|
|
14058
|
+
Object.defineProperty(state, "renderer", {
|
|
14059
|
+
get() {
|
|
14060
|
+
return rootStore.getState().internal.actualRenderer;
|
|
14061
|
+
},
|
|
14062
|
+
set(value) {
|
|
14063
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
14064
|
+
},
|
|
14065
|
+
enumerable: true,
|
|
14066
|
+
configurable: true
|
|
14067
|
+
});
|
|
14068
|
+
let oldScene = state.scene;
|
|
14069
|
+
rootStore.subscribe(() => {
|
|
14070
|
+
const currentState = rootStore.getState();
|
|
14071
|
+
const { scene, rootScene, set } = currentState;
|
|
14072
|
+
if (scene !== oldScene) {
|
|
14073
|
+
oldScene = scene;
|
|
14074
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
14075
|
+
set({ rootScene: scene });
|
|
14076
|
+
}
|
|
14077
|
+
}
|
|
14078
|
+
});
|
|
14079
|
+
let oldSize = state.size;
|
|
14080
|
+
let oldDpr = state.viewport.dpr;
|
|
14081
|
+
let oldCamera = state.camera;
|
|
14082
|
+
rootStore.subscribe(() => {
|
|
14083
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
14084
|
+
const actualRenderer = internal.actualRenderer;
|
|
14085
|
+
const canvasTarget = internal.canvasTarget;
|
|
14086
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
14087
|
+
oldSize = size;
|
|
14088
|
+
oldDpr = viewport.dpr;
|
|
14089
|
+
updateCamera(camera, size);
|
|
14090
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
14091
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
14092
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
14093
|
+
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
14094
|
+
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
13920
14095
|
}
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
14096
|
+
if (camera !== oldCamera) {
|
|
14097
|
+
oldCamera = camera;
|
|
14098
|
+
const { rootScene } = rootStore.getState();
|
|
14099
|
+
if (camera && rootScene && !camera.parent) {
|
|
14100
|
+
rootScene.add(camera);
|
|
14101
|
+
}
|
|
14102
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
14103
|
+
const currentState = rootStore.getState();
|
|
14104
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
14105
|
+
updateFrustum(camera, currentState.frustum);
|
|
13930
14106
|
}
|
|
13931
14107
|
}
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
|
|
13962
|
-
|
|
13963
|
-
|
|
13964
|
-
|
|
13965
|
-
|
|
13966
|
-
|
|
13967
|
-
|
|
13968
|
-
|
|
13969
|
-
|
|
13970
|
-
|
|
13971
|
-
|
|
13972
|
-
|
|
13973
|
-
|
|
13974
|
-
|
|
13975
|
-
|
|
13976
|
-
|
|
13977
|
-
|
|
13978
|
-
|
|
13979
|
-
|
|
13980
|
-
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
),
|
|
13985
|
-
|
|
13986
|
-
currentUpdatePriority = newPriority;
|
|
13987
|
-
},
|
|
13988
|
-
getCurrentUpdatePriority() {
|
|
13989
|
-
return currentUpdatePriority;
|
|
13990
|
-
},
|
|
13991
|
-
resolveUpdatePriority() {
|
|
13992
|
-
if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
|
|
13993
|
-
const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
|
|
13994
|
-
if (eventType === void 0) return r;
|
|
13995
|
-
return getEventPriority(eventType);
|
|
13996
|
-
},
|
|
13997
|
-
resetFormInstance() {
|
|
13998
|
-
},
|
|
13999
|
-
// @ts-ignore DefinitelyTyped is not up to date
|
|
14000
|
-
rendererPackageName: "@react-three/fiber",
|
|
14001
|
-
rendererVersion: packageData.version,
|
|
14002
|
-
// 19.2 Reconciler
|
|
14003
|
-
// https://github.com/facebook/react/pull/31975
|
|
14004
|
-
// https://github.com/facebook/react/pull/31999
|
|
14005
|
-
applyViewTransitionName(_instance, _name, _className) {
|
|
14006
|
-
},
|
|
14007
|
-
restoreViewTransitionName(_instance, _props) {
|
|
14008
|
-
},
|
|
14009
|
-
cancelViewTransitionName(_instance, _name, _props) {
|
|
14010
|
-
},
|
|
14011
|
-
cancelRootViewTransitionName(_rootContainer) {
|
|
14012
|
-
},
|
|
14013
|
-
restoreRootViewTransitionName(_rootContainer) {
|
|
14014
|
-
},
|
|
14015
|
-
InstanceMeasurement: null,
|
|
14016
|
-
measureInstance: (_instance) => null,
|
|
14017
|
-
wasInstanceInViewport: (_measurement) => true,
|
|
14018
|
-
hasInstanceChanged: (_oldMeasurement, _newMeasurement) => false,
|
|
14019
|
-
hasInstanceAffectedParent: (_oldMeasurement, _newMeasurement) => false,
|
|
14020
|
-
// https://github.com/facebook/react/pull/32002
|
|
14021
|
-
// https://github.com/facebook/react/pull/34486
|
|
14022
|
-
suspendOnActiveViewTransition(_state, _container) {
|
|
14023
|
-
},
|
|
14024
|
-
// https://github.com/facebook/react/pull/32451
|
|
14025
|
-
// https://github.com/facebook/react/pull/32760
|
|
14026
|
-
startGestureTransition: () => null,
|
|
14027
|
-
startViewTransition: () => null,
|
|
14028
|
-
stopViewTransition(_transition) {
|
|
14029
|
-
},
|
|
14030
|
-
// https://github.com/facebook/react/pull/32038
|
|
14031
|
-
createViewTransitionInstance: (_name) => null,
|
|
14032
|
-
// https://github.com/facebook/react/pull/32379
|
|
14033
|
-
// https://github.com/facebook/react/pull/32786
|
|
14034
|
-
getCurrentGestureOffset(_provider) {
|
|
14035
|
-
throw new Error("startGestureTransition is not yet supported in react-three-fiber.");
|
|
14036
|
-
},
|
|
14037
|
-
// https://github.com/facebook/react/pull/32500
|
|
14038
|
-
cloneMutableInstance(instance, _keepChildren) {
|
|
14039
|
-
return instance;
|
|
14040
|
-
},
|
|
14041
|
-
cloneMutableTextInstance(textInstance) {
|
|
14042
|
-
return textInstance;
|
|
14043
|
-
},
|
|
14044
|
-
// React 19.2 added these for root-level view transitions. They only run for hosts that opt into
|
|
14045
|
-
// view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
|
|
14046
|
-
// into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
|
|
14047
|
-
// React never calls them. They stay as no-ops rather than throws: the host config is shared by
|
|
14048
|
-
// every root, and a throw here would turn a React-internal probe into a hard crash for users.
|
|
14049
|
-
// Guarded by a test asserting a full render + unmount never reaches them.
|
|
14050
|
-
cloneRootViewTransitionContainer(_rootContainer) {
|
|
14051
|
-
},
|
|
14052
|
-
removeRootViewTransitionClone(_rootContainer, _clone) {
|
|
14053
|
-
},
|
|
14054
|
-
// https://github.com/facebook/react/pull/32465
|
|
14055
|
-
createFragmentInstance: (_fiber) => null,
|
|
14056
|
-
updateFragmentInstanceFiber(_fiber, _instance) {
|
|
14057
|
-
},
|
|
14058
|
-
commitNewChildToFragmentInstance(_child, _fragmentInstance) {
|
|
14059
|
-
},
|
|
14060
|
-
deleteChildFromFragmentInstance(_child, _fragmentInstance) {
|
|
14061
|
-
},
|
|
14062
|
-
// https://github.com/facebook/react/pull/32653
|
|
14063
|
-
measureClonedInstance: (_instance) => null,
|
|
14064
|
-
// https://github.com/facebook/react/pull/32819
|
|
14065
|
-
maySuspendCommitOnUpdate: (_type, _oldProps, _newProps) => false,
|
|
14066
|
-
maySuspendCommitInSyncRender: (_type, _props) => false,
|
|
14067
|
-
// https://github.com/facebook/react/pull/34486
|
|
14068
|
-
startSuspendingCommit: () => null,
|
|
14069
|
-
// https://github.com/facebook/react/pull/34522
|
|
14070
|
-
getSuspendedCommitReason: (_state, _rootContainer) => null
|
|
14071
|
-
});
|
|
14108
|
+
});
|
|
14109
|
+
rootStore.subscribe((state2) => invalidate(state2));
|
|
14110
|
+
return rootStore;
|
|
14111
|
+
};
|
|
14112
|
+
|
|
14113
|
+
const R3F_EXTENSIONS = Symbol.for("@react-three/fiber.extensions");
|
|
14114
|
+
function getRegistry() {
|
|
14115
|
+
return globalThis[R3F_EXTENSIONS] ?? (globalThis[R3F_EXTENSIONS] = {
|
|
14116
|
+
extensions: /* @__PURE__ */ new Map(),
|
|
14117
|
+
roots: /* @__PURE__ */ new Set(),
|
|
14118
|
+
applied: /* @__PURE__ */ new WeakMap()
|
|
14119
|
+
});
|
|
14120
|
+
}
|
|
14121
|
+
function setupRoot(registry, store, extension) {
|
|
14122
|
+
let applied = registry.applied.get(store);
|
|
14123
|
+
if (!applied) registry.applied.set(store, applied = /* @__PURE__ */ new Map());
|
|
14124
|
+
if (applied.has(extension.name)) return;
|
|
14125
|
+
applied.set(extension.name, extension);
|
|
14126
|
+
const patch = extension.setup?.(store);
|
|
14127
|
+
if (patch) store.setState(patch);
|
|
14128
|
+
}
|
|
14129
|
+
function registerRootExtension(extension) {
|
|
14130
|
+
const registry = getRegistry();
|
|
14131
|
+
registry.extensions.set(extension.name, extension);
|
|
14132
|
+
for (const store of registry.roots) setupRoot(registry, store, extension);
|
|
14133
|
+
return () => {
|
|
14134
|
+
if (registry.extensions.get(extension.name) === extension) registry.extensions.delete(extension.name);
|
|
14135
|
+
};
|
|
14136
|
+
}
|
|
14137
|
+
function setRenderOverride(store, render) {
|
|
14138
|
+
store.getState().internal.renderOverride = render;
|
|
14139
|
+
}
|
|
14140
|
+
function attachRootExtensions(store) {
|
|
14141
|
+
const registry = getRegistry();
|
|
14142
|
+
registry.roots.add(store);
|
|
14143
|
+
for (const extension of registry.extensions.values()) setupRoot(registry, store, extension);
|
|
14144
|
+
}
|
|
14145
|
+
function current(registry, setUpBy) {
|
|
14146
|
+
return registry.extensions.get(setUpBy.name) ?? setUpBy;
|
|
14147
|
+
}
|
|
14148
|
+
function detachRootExtensions(store) {
|
|
14149
|
+
const registry = getRegistry();
|
|
14150
|
+
if (!registry.roots.delete(store)) return;
|
|
14151
|
+
const applied = registry.applied.get(store);
|
|
14152
|
+
registry.applied.delete(store);
|
|
14153
|
+
if (!applied) return;
|
|
14154
|
+
for (const setUpBy of applied.values()) current(registry, setUpBy).dispose?.(store);
|
|
14155
|
+
}
|
|
14156
|
+
function notifyRootExtensionsHmr(store) {
|
|
14157
|
+
const registry = getRegistry();
|
|
14158
|
+
const applied = registry.applied.get(store);
|
|
14159
|
+
if (!applied) return;
|
|
14160
|
+
for (const setUpBy of applied.values()) current(registry, setUpBy).hmr?.(store);
|
|
14161
|
+
}
|
|
14072
14162
|
|
|
14073
14163
|
const isRenderer = (def) => !!def?.render;
|
|
14074
14164
|
const _roots = /* @__PURE__ */ new Map();
|
|
@@ -14225,9 +14315,8 @@ function createRoot(canvas) {
|
|
|
14225
14315
|
if (!renderer.hasInitialized?.()) {
|
|
14226
14316
|
const size2 = computeInitialSize(canvas, propsSize);
|
|
14227
14317
|
if (size2.width > 0 && size2.height > 0) {
|
|
14228
|
-
|
|
14229
|
-
|
|
14230
|
-
canvas.height = size2.height * pixelRatio;
|
|
14318
|
+
renderer.setPixelRatio(calculateDpr(dpr));
|
|
14319
|
+
renderer.setSize(size2.width, size2.height, false);
|
|
14231
14320
|
}
|
|
14232
14321
|
await renderer.init();
|
|
14233
14322
|
}
|
|
@@ -14236,7 +14325,7 @@ function createRoot(canvas) {
|
|
|
14236
14325
|
state.internal.actualRenderer = renderer;
|
|
14237
14326
|
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14238
14327
|
if (canvasId && !state.internal.isSecondary) {
|
|
14239
|
-
const canvasTarget =
|
|
14328
|
+
const canvasTarget = renderer.getCanvasTarget?.();
|
|
14240
14329
|
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14241
14330
|
state.set((prev) => ({
|
|
14242
14331
|
internal: {
|
|
@@ -14350,7 +14439,7 @@ function createRoot(canvas) {
|
|
|
14350
14439
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14351
14440
|
const state2 = store.getState();
|
|
14352
14441
|
if (state2.frameloop === "never") return;
|
|
14353
|
-
advance(timestamp);
|
|
14442
|
+
advance(timestamp, true, state2);
|
|
14354
14443
|
};
|
|
14355
14444
|
const actualRenderer = state.internal.actualRenderer;
|
|
14356
14445
|
const handleSessionChange = () => {
|
|
@@ -14358,7 +14447,7 @@ function createRoot(canvas) {
|
|
|
14358
14447
|
const renderer2 = state2.internal.actualRenderer;
|
|
14359
14448
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14360
14449
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14361
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14450
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14362
14451
|
};
|
|
14363
14452
|
const xr = {
|
|
14364
14453
|
connect() {
|
|
@@ -14440,14 +14529,23 @@ function createRoot(canvas) {
|
|
|
14440
14529
|
const newRootId = canvasId || scheduler$1.generateRootId();
|
|
14441
14530
|
const unregisterRoot = scheduler$1.registerRoot(newRootId, {
|
|
14442
14531
|
getState: () => store.getState(),
|
|
14443
|
-
onError: (err) => store.getState().setError(err)
|
|
14532
|
+
onError: (err) => store.getState().setError(err),
|
|
14533
|
+
frameloop: store.getState().frameloop,
|
|
14534
|
+
before: schedulerConfig?.before,
|
|
14535
|
+
after: schedulerConfig?.after,
|
|
14536
|
+
order: schedulerConfig?.order
|
|
14444
14537
|
});
|
|
14445
14538
|
const unregisterCanvasTarget = scheduler$1.register(
|
|
14446
14539
|
() => {
|
|
14447
14540
|
const state2 = store.getState();
|
|
14448
|
-
|
|
14541
|
+
const canvasTarget = state2.internal.canvasTarget;
|
|
14542
|
+
if (canvasTarget) {
|
|
14449
14543
|
const renderer2 = state2.internal.actualRenderer;
|
|
14450
|
-
renderer2.setCanvasTarget(
|
|
14544
|
+
if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
|
|
14545
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14546
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14547
|
+
renderer2.backend?.updateSize?.();
|
|
14548
|
+
}
|
|
14451
14549
|
}
|
|
14452
14550
|
},
|
|
14453
14551
|
{
|
|
@@ -14503,7 +14601,8 @@ function createRoot(canvas) {
|
|
|
14503
14601
|
const userHandlesRender = scheduler$1.hasUserJobsInPhase("render", newRootId);
|
|
14504
14602
|
if (userHandlesRender || state2.internal.priority) return;
|
|
14505
14603
|
try {
|
|
14506
|
-
|
|
14604
|
+
const renderOverride = state2.internal.renderOverride;
|
|
14605
|
+
if (renderOverride) renderOverride();
|
|
14507
14606
|
else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
|
|
14508
14607
|
} catch (error) {
|
|
14509
14608
|
state2.setError(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -14516,8 +14615,7 @@ function createRoot(canvas) {
|
|
|
14516
14615
|
phase: "render",
|
|
14517
14616
|
system: true,
|
|
14518
14617
|
// Internal flag: this is a system job, not user-controlled
|
|
14519
|
-
//
|
|
14520
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14618
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14521
14619
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14522
14620
|
}
|
|
14523
14621
|
);
|
|
@@ -14536,8 +14634,22 @@ function createRoot(canvas) {
|
|
|
14536
14634
|
scheduler: scheduler$1
|
|
14537
14635
|
}
|
|
14538
14636
|
}));
|
|
14637
|
+
} else {
|
|
14638
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14639
|
+
if (constraintsChanged) {
|
|
14640
|
+
scheduler$1.setRootConstraints(rootId, {
|
|
14641
|
+
before: schedulerConfig?.before,
|
|
14642
|
+
after: schedulerConfig?.after
|
|
14643
|
+
});
|
|
14644
|
+
}
|
|
14645
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14646
|
+
scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14647
|
+
}
|
|
14539
14648
|
}
|
|
14540
|
-
|
|
14649
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14650
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14651
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14652
|
+
attachRootExtensions(store);
|
|
14541
14653
|
onCreated = onCreatedCallback;
|
|
14542
14654
|
configured = true;
|
|
14543
14655
|
resolve();
|
|
@@ -14579,18 +14691,24 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14579
14691
|
const fiber = root?.fiber;
|
|
14580
14692
|
if (fiber) {
|
|
14581
14693
|
const state = root?.store.getState();
|
|
14582
|
-
if (state)
|
|
14694
|
+
if (state) {
|
|
14695
|
+
state.internal.active = false;
|
|
14696
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14697
|
+
if (unregisterRoot) {
|
|
14698
|
+
unregisterRoot();
|
|
14699
|
+
state.internal.unregisterRoot = void 0;
|
|
14700
|
+
}
|
|
14701
|
+
}
|
|
14583
14702
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14703
|
+
if (root?.store) detachRootExtensions(root.store);
|
|
14584
14704
|
if (state) {
|
|
14585
14705
|
setTimeout(() => {
|
|
14586
14706
|
try {
|
|
14587
14707
|
const renderer = state.internal.actualRenderer;
|
|
14588
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14589
|
-
if (unregisterRoot) unregisterRoot();
|
|
14590
14708
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14591
14709
|
if (unregisterPrimary) unregisterPrimary();
|
|
14592
14710
|
const canvasTarget = state.internal.canvasTarget;
|
|
14593
|
-
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14711
|
+
if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
|
|
14594
14712
|
state.events.disconnect?.();
|
|
14595
14713
|
cleanupHelperGroup(root.store);
|
|
14596
14714
|
if (state.isLegacy && renderer) {
|
|
@@ -14660,11 +14778,24 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
14660
14778
|
}
|
|
14661
14779
|
};
|
|
14662
14780
|
}, [portalScene, container, injectScene]);
|
|
14781
|
+
const lastRootState = React.useRef(null);
|
|
14663
14782
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
14783
|
+
const followed = {};
|
|
14784
|
+
const lastRoot = lastRootState.current;
|
|
14785
|
+
if (lastRoot) {
|
|
14786
|
+
for (const key in rootState) {
|
|
14787
|
+
const field = key;
|
|
14788
|
+
const changed = rootState[field] !== lastRoot[field];
|
|
14789
|
+
const inherited = !(key in rest) && injectState[field] === lastRoot[field];
|
|
14790
|
+
if (changed && inherited) followed[field] = rootState[field];
|
|
14791
|
+
}
|
|
14792
|
+
}
|
|
14793
|
+
lastRootState.current = rootState;
|
|
14664
14794
|
const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
|
|
14665
14795
|
let viewport = void 0;
|
|
14666
|
-
|
|
14667
|
-
|
|
14796
|
+
const portalCamera = followed.camera ?? injectState.camera;
|
|
14797
|
+
if (portalCamera && (size || injectState.size)) {
|
|
14798
|
+
const camera = portalCamera;
|
|
14668
14799
|
viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
|
|
14669
14800
|
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14670
14801
|
}
|
|
@@ -14673,6 +14804,7 @@ function PortalInner({ state = {}, children, container }) {
|
|
|
14673
14804
|
// The intersect consists of the previous root state
|
|
14674
14805
|
...rootState,
|
|
14675
14806
|
...injectState,
|
|
14807
|
+
...followed,
|
|
14676
14808
|
// Portals have their own scene - always a real THREE.Scene (injected if needed)
|
|
14677
14809
|
scene: portalScene,
|
|
14678
14810
|
// rootScene always points to the actual THREE.Scene, even inside portals
|
|
@@ -14731,16 +14863,11 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
|
|
|
14731
14863
|
const oldbg = target.background;
|
|
14732
14864
|
const oldenv = target.environment;
|
|
14733
14865
|
const oldSceneProps = {
|
|
14734
|
-
// @ts-ignore
|
|
14735
14866
|
backgroundBlurriness: target.backgroundBlurriness,
|
|
14736
|
-
// @ts-ignore
|
|
14737
14867
|
backgroundIntensity: target.backgroundIntensity,
|
|
14738
|
-
|
|
14739
|
-
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
14740
|
-
// @ts-ignore
|
|
14868
|
+
backgroundRotation: target.backgroundRotation.clone(),
|
|
14741
14869
|
environmentIntensity: target.environmentIntensity,
|
|
14742
|
-
|
|
14743
|
-
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
|
|
14870
|
+
environmentRotation: target.environmentRotation.clone()
|
|
14744
14871
|
};
|
|
14745
14872
|
if (background !== "only") target.environment = texture;
|
|
14746
14873
|
if (background) target.background = texture;
|
|
@@ -14965,38 +15092,6 @@ function parseRendererConfig(rendererProp) {
|
|
|
14965
15092
|
return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
|
|
14966
15093
|
}
|
|
14967
15094
|
|
|
14968
|
-
const RESOURCE_KINDS = ["nodes", "uniforms", "buffers", "gpuStorage"];
|
|
14969
|
-
const registries = /* @__PURE__ */ new WeakMap();
|
|
14970
|
-
function getKindRegistry(store, kind) {
|
|
14971
|
-
let registry = registries.get(store);
|
|
14972
|
-
if (!registry) {
|
|
14973
|
-
registry = {
|
|
14974
|
-
nodes: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14975
|
-
uniforms: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14976
|
-
buffers: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
|
|
14977
|
-
gpuStorage: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() }
|
|
14978
|
-
};
|
|
14979
|
-
registries.set(store, registry);
|
|
14980
|
-
}
|
|
14981
|
-
return registry[kind];
|
|
14982
|
-
}
|
|
14983
|
-
function invalidateResource(store, kind, scopeKey) {
|
|
14984
|
-
const registry = getKindRegistry(store, kind);
|
|
14985
|
-
{
|
|
14986
|
-
registry.valid.clear();
|
|
14987
|
-
registry.staged.clear();
|
|
14988
|
-
}
|
|
14989
|
-
}
|
|
14990
|
-
function invalidateAllResources(store) {
|
|
14991
|
-
for (const kind of RESOURCE_KINDS) invalidateResource(store, kind);
|
|
14992
|
-
}
|
|
14993
|
-
|
|
14994
|
-
function clearHmrCaches(store) {
|
|
14995
|
-
const primary = store.getState().primaryStore ?? store;
|
|
14996
|
-
invalidateAllResources(primary);
|
|
14997
|
-
primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
|
|
14998
|
-
}
|
|
14999
|
-
|
|
15000
15095
|
function CanvasImpl({
|
|
15001
15096
|
ref,
|
|
15002
15097
|
children,
|
|
@@ -15034,9 +15129,9 @@ function CanvasImpl({
|
|
|
15034
15129
|
React__namespace.useMemo(() => extend(THREE), []);
|
|
15035
15130
|
const Bridge = useBridge();
|
|
15036
15131
|
const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
|
|
15037
|
-
const
|
|
15132
|
+
const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
|
|
15038
15133
|
const measureConfig = React__namespace.useMemo(() => {
|
|
15039
|
-
if (!
|
|
15134
|
+
if (!hasInitialSize) {
|
|
15040
15135
|
return {
|
|
15041
15136
|
...resize,
|
|
15042
15137
|
scroll: resize?.scroll ?? true,
|
|
@@ -15048,7 +15143,7 @@ function CanvasImpl({
|
|
|
15048
15143
|
debounce: { scroll: 50, resize: 0 },
|
|
15049
15144
|
...resize
|
|
15050
15145
|
};
|
|
15051
|
-
}, [
|
|
15146
|
+
}, [hasInitialSize, resize]);
|
|
15052
15147
|
const [containerRef, containerRect] = useMeasure__default(measureConfig);
|
|
15053
15148
|
const effectiveSize = React__namespace.useMemo(() => {
|
|
15054
15149
|
let w = width ?? containerRect.width;
|
|
@@ -15064,9 +15159,7 @@ function CanvasImpl({
|
|
|
15064
15159
|
left: containerRect.left
|
|
15065
15160
|
};
|
|
15066
15161
|
}, [width, height, containerRect, forceEven]);
|
|
15067
|
-
if (!
|
|
15068
|
-
hasInitialSizeRef.current = true;
|
|
15069
|
-
}
|
|
15162
|
+
if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
|
|
15070
15163
|
const canvasRef = React__namespace.useRef(null);
|
|
15071
15164
|
const divRef = React__namespace.useRef(null);
|
|
15072
15165
|
React__namespace.useImperativeHandle(ref, () => canvasRef.current);
|
|
@@ -15180,6 +15273,7 @@ function CanvasImpl({
|
|
|
15180
15273
|
const canvas = canvasRef.current;
|
|
15181
15274
|
if (canvas) {
|
|
15182
15275
|
return () => {
|
|
15276
|
+
if (canvas.isConnected) return;
|
|
15183
15277
|
unmountComponentAtNode(canvas);
|
|
15184
15278
|
root.current = null;
|
|
15185
15279
|
};
|
|
@@ -15192,7 +15286,7 @@ function CanvasImpl({
|
|
|
15192
15286
|
const handleHMR = () => {
|
|
15193
15287
|
queueMicrotask(() => {
|
|
15194
15288
|
const rootEntry = _roots.get(canvas);
|
|
15195
|
-
if (rootEntry?.store)
|
|
15289
|
+
if (rootEntry?.store) notifyRootExtensionsHmr(rootEntry.store);
|
|
15196
15290
|
});
|
|
15197
15291
|
};
|
|
15198
15292
|
if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined) {
|
|
@@ -15310,8 +15404,10 @@ exports.prepare = prepare;
|
|
|
15310
15404
|
exports.presetsObj = presetsObj;
|
|
15311
15405
|
exports.reconciler = reconciler;
|
|
15312
15406
|
exports.registerPrimary = registerPrimary;
|
|
15407
|
+
exports.registerRootExtension = registerRootExtension;
|
|
15313
15408
|
exports.removeInteractivity = removeInteractivity;
|
|
15314
15409
|
exports.resolve = resolve;
|
|
15410
|
+
exports.setRenderOverride = setRenderOverride;
|
|
15315
15411
|
exports.swapInteractivity = swapInteractivity;
|
|
15316
15412
|
exports.unmountComponentAtNode = unmountComponentAtNode;
|
|
15317
15413
|
exports.unregisterPrimary = unregisterPrimary;
|