@react-three/fiber 10.0.0-canary.5c62eb9 → 10.0.0-canary.60e7a38

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -56,10 +56,13 @@ const R3F_BUILD_WEBGPU = true;
56
56
 
57
57
  const THREE = /*#__PURE__*/_mergeNamespaces({
58
58
  __proto__: null,
59
+ CubeRenderTarget: webgpu.CubeRenderTarget,
60
+ CubeRenderTargetCompat: webgpu.CubeRenderTarget,
59
61
  Inspector: Inspector_js.Inspector,
60
62
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
61
63
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
62
64
  RenderTargetCompat: webgpu.RenderTarget,
65
+ WebGLCubeRenderTarget: three.WebGLCubeRenderTarget,
63
66
  WebGLRenderTarget: three.WebGLRenderTarget,
64
67
  WebGLRenderer: three.WebGLRenderer
65
68
  }, [webgpu__namespace]);
@@ -333,15 +336,16 @@ function EnvironmentPortal({
333
336
  preset = void 0,
334
337
  extensions
335
338
  }) {
336
- const gl = fiber.useThree((state) => state.gl);
339
+ const renderer = fiber.useThree((state) => state.renderer);
340
+ const isLegacy = fiber.useThree((state) => state.isLegacy);
337
341
  const defaultScene = fiber.useThree((state) => state.scene);
338
342
  const camera = React__namespace.useRef(null);
339
343
  const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
340
344
  const fbo = React__namespace.useMemo(() => {
341
- const fbo2 = new webgpu.WebGLCubeRenderTarget(resolution);
345
+ const fbo2 = isLegacy ? new three.WebGLCubeRenderTarget(resolution) : new webgpu.CubeRenderTarget(resolution);
342
346
  fbo2.texture.type = webgpu.HalfFloatType;
343
347
  return fbo2;
344
- }, [resolution]);
348
+ }, [resolution, isLegacy]);
345
349
  React__namespace.useEffect(() => {
346
350
  return () => {
347
351
  fbo.dispose();
@@ -349,10 +353,10 @@ function EnvironmentPortal({
349
353
  }, [fbo]);
350
354
  React__namespace.useLayoutEffect(() => {
351
355
  if (frames === 1) {
352
- const autoClear = gl.autoClear;
353
- gl.autoClear = true;
354
- camera.current.update(gl, virtualScene);
355
- gl.autoClear = autoClear;
356
+ const autoClear = renderer.autoClear;
357
+ renderer.autoClear = true;
358
+ camera.current.update(renderer, virtualScene);
359
+ renderer.autoClear = autoClear;
356
360
  }
357
361
  return setEnvProps(background, scene, defaultScene, fbo.texture, {
358
362
  backgroundBlurriness: blur ?? backgroundBlurriness,
@@ -369,7 +373,7 @@ function EnvironmentPortal({
369
373
  defaultScene,
370
374
  background,
371
375
  frames,
372
- gl,
376
+ renderer,
373
377
  blur,
374
378
  backgroundBlurriness,
375
379
  backgroundIntensity,
@@ -380,10 +384,10 @@ function EnvironmentPortal({
380
384
  let count = 1;
381
385
  fiber.useFrame(() => {
382
386
  if (frames === Infinity || count < frames) {
383
- const autoClear = gl.autoClear;
384
- gl.autoClear = true;
385
- camera.current.update(gl, virtualScene);
386
- gl.autoClear = autoClear;
387
+ const autoClear = renderer.autoClear;
388
+ renderer.autoClear = true;
389
+ camera.current.update(renderer, virtualScene);
390
+ renderer.autoClear = autoClear;
387
391
  count++;
388
392
  }
389
393
  });
@@ -450,7 +454,6 @@ function Environment(props) {
450
454
  var __defProp = Object.defineProperty;
451
455
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
452
456
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
453
- const act = React__namespace["act"];
454
457
  const useIsomorphicLayoutEffect = /* @__PURE__ */ (() => typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative"))() ? React__namespace.useLayoutEffect : React__namespace.useEffect;
455
458
  function useMutableCallback(fn) {
456
459
  const ref = React__namespace.useRef(fn);
@@ -626,8 +629,7 @@ function prepare(target, root, type, props) {
626
629
  object,
627
630
  eventCount: 0,
628
631
  handlers: {},
629
- isHidden: false,
630
- deferredRefs: []
632
+ isHidden: false
631
633
  };
632
634
  if (object) object.__r3f = instance;
633
635
  }
@@ -784,6 +786,17 @@ function unregisterVisibility(store, object) {
784
786
  internal.visibilityRegistry.delete(object.uuid);
785
787
  internal.occlusionCache.delete(object);
786
788
  }
789
+ function updateVisibilityHandlers(store, object, handlers) {
790
+ const { internal } = store.getState();
791
+ const entry = internal.visibilityRegistry.get(object.uuid);
792
+ if (!entry) return false;
793
+ entry.handlers = handlers;
794
+ if ((handlers.onOccluded || handlers.onVisible) && !internal.occlusionEnabled) {
795
+ object.occlusionTest = true;
796
+ enableOcclusion(store);
797
+ }
798
+ return true;
799
+ }
787
800
  function checkVisibility(state) {
788
801
  const { internal, camera } = state;
789
802
  const registry = internal.visibilityRegistry;
@@ -944,9 +957,9 @@ function diffProps(instance, newProps) {
944
957
  const { root, key } = resolve(instance.object, prop);
945
958
  if (root.constructor && root.constructor.length === 0) {
946
959
  const ctor = getMemoizedPrototype(root);
947
- if (!is.und(ctor)) changedProps[key] = ctor[key];
960
+ if (!is.und(ctor)) changedProps[prop] = ctor[key];
948
961
  } else {
949
- changedProps[key] = 0;
962
+ changedProps[prop] = 0;
950
963
  }
951
964
  }
952
965
  return changedProps;
@@ -971,10 +984,7 @@ function applyProps(object, props) {
971
984
  continue;
972
985
  }
973
986
  if (value === void 0) continue;
974
- if (isFromRef(value)) {
975
- instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
976
- continue;
977
- }
987
+ if (isFromRef(value)) continue;
978
988
  if (isOnce(value)) {
979
989
  if (instance?.appliedOnce?.has(prop)) continue;
980
990
  if (instance) {
@@ -1010,6 +1020,19 @@ function applyProps(object, props) {
1010
1020
  } else if (isVectorLike(target) && is.num(value)) {
1011
1021
  if ("setScalar" in target && typeof target.setScalar === "function") target.setScalar(value);
1012
1022
  else target.set(value);
1023
+ } else if (root instanceof webgpu.ShaderMaterial && key === "uniforms" && is.obj(value)) {
1024
+ if (!is.obj(root.uniforms)) root.uniforms = {};
1025
+ const uniforms = root.uniforms;
1026
+ const nextUniforms = value;
1027
+ for (const name in nextUniforms) {
1028
+ const uniform = nextUniforms[name];
1029
+ const targetUniform = uniforms[name];
1030
+ if (targetUniform) Object.assign(targetUniform, uniform);
1031
+ else {
1032
+ const nextUniform = uniform instanceof webgpu.Uniform ? uniform.clone() : new webgpu.Uniform(uniform.value);
1033
+ uniforms[name] = nextUniform;
1034
+ }
1035
+ }
1013
1036
  } else {
1014
1037
  root[key] = value;
1015
1038
  if (key.endsWith("Node") && root.isMaterial) {
@@ -1028,6 +1051,9 @@ function applyProps(object, props) {
1028
1051
  if (instance.eventCount && object2.raycast !== null) {
1029
1052
  rootState.internal.interaction.push(object2);
1030
1053
  }
1054
+ }
1055
+ if (instance?.parent && rootState?.internal && instance.object?.isObject3D) {
1056
+ const object2 = instance.object;
1031
1057
  const root = findInitialRoot(instance);
1032
1058
  const visibilityHandlers = {
1033
1059
  onFramed: instance.handlers.onFramed,
@@ -1035,7 +1061,9 @@ function applyProps(object, props) {
1035
1061
  onVisible: instance.handlers.onVisible
1036
1062
  };
1037
1063
  if (hasVisibilityHandlers(visibilityHandlers)) {
1038
- registerVisibility(root, object2, visibilityHandlers);
1064
+ if (!updateVisibilityHandlers(root, object2, visibilityHandlers)) {
1065
+ registerVisibility(root, object2, visibilityHandlers);
1066
+ }
1039
1067
  } else {
1040
1068
  unregisterVisibility(root, object2);
1041
1069
  }
@@ -1078,6 +1106,41 @@ function releaseInternalPointerCapture(internal, obj, pointerId) {
1078
1106
  captureData.target.releasePointerCapture(pointerId);
1079
1107
  }
1080
1108
  }
1109
+ function swapInteractivity(store, object, newObject) {
1110
+ const { internal } = store.getState();
1111
+ for (let i = 0; i < internal.interaction.length; i++) {
1112
+ if (internal.interaction[i] === object) internal.interaction[i] = newObject;
1113
+ }
1114
+ for (const pointerState of internal.pointerMap.values()) {
1115
+ for (let i = 0; i < pointerState.initialHits.length; i++) {
1116
+ if (pointerState.initialHits[i] === object) pointerState.initialHits[i] = newObject;
1117
+ }
1118
+ pointerState.hovered.forEach((value, key) => {
1119
+ if (value.eventObject === object || value.object === object) {
1120
+ pointerState.hovered.delete(key);
1121
+ const next = {
1122
+ ...value,
1123
+ eventObject: value.eventObject === object ? newObject : value.eventObject,
1124
+ object: value.object === object ? newObject : value.object
1125
+ };
1126
+ pointerState.hovered.set(makeId(next), next);
1127
+ }
1128
+ });
1129
+ const captureData = pointerState.captured.get(object);
1130
+ if (captureData) {
1131
+ pointerState.captured.delete(object);
1132
+ pointerState.captured.set(newObject, {
1133
+ ...captureData,
1134
+ intersection: {
1135
+ ...captureData.intersection,
1136
+ object: captureData.intersection.object === object ? newObject : captureData.intersection.object,
1137
+ eventObject: captureData.intersection.eventObject === object ? newObject : captureData.intersection.eventObject
1138
+ }
1139
+ });
1140
+ }
1141
+ }
1142
+ unregisterVisibility(store, object);
1143
+ }
1081
1144
  function removeInteractivity(store, object) {
1082
1145
  const { internal } = store.getState();
1083
1146
  internal.interaction = internal.interaction.filter((o) => o !== object);
@@ -1563,6 +1626,7 @@ function createPointerEvents(store) {
1563
1626
  set((state) => ({ events: { ...state.events, connected: void 0 } }));
1564
1627
  }
1565
1628
  },
1629
+ // PREVIEW (A8): the XR pointer registration API may change before stable.
1566
1630
  registerPointer: (config) => {
1567
1631
  const pointerId = nextXRPointerId++;
1568
1632
  xrPointers.set(pointerId, config);
@@ -1650,11 +1714,10 @@ function notifyAlpha({ message, link }) {
1650
1714
  }
1651
1715
 
1652
1716
  const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
1653
- const INTERNAL_FIBER_MARKERS = ["packages/fiber/src", "packages/fiber/dist", "@react-three/fiber", "@react-three_fiber"];
1654
1717
  function isInternalRendererAccess(stack, callerDepth = 2) {
1655
1718
  if (!stack) return false;
1656
1719
  const caller = stack.split("\n")[callerDepth] ?? "";
1657
- return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m)) || INTERNAL_FIBER_MARKERS.some((m) => caller.includes(m));
1720
+ return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
1658
1721
  }
1659
1722
 
1660
1723
  const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
@@ -1789,6 +1852,7 @@ const createStore = (invalidate, advance) => {
1789
1852
  }),
1790
1853
  setFrameloop: (frameloop = "always") => {
1791
1854
  set(() => ({ frameloop }));
1855
+ scheduler.getScheduler().frameloop = frameloop;
1792
1856
  },
1793
1857
  setError: (error) => set(() => ({ error })),
1794
1858
  error: null,
@@ -1969,19 +2033,25 @@ function loadingFn(extensions, onProgress) {
1969
2033
  );
1970
2034
  };
1971
2035
  }
1972
- function useLoader(loader, input, extensions, onProgress) {
1973
- const keys = Array.isArray(input) ? input : [input];
2036
+ function useLoader(loader, input, extensions, onProgress, cacheKey) {
2037
+ const inputs = Array.isArray(input) ? input : [input];
2038
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1974
2039
  const fn = loadingFn(extensions, onProgress);
1975
- const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
2040
+ const results = cacheKeys.map(
2041
+ (key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
2042
+ );
1976
2043
  return Array.isArray(input) ? results : results[0];
1977
2044
  }
1978
- useLoader.preload = function(loader, input, extensions, onProgress) {
1979
- const keys = Array.isArray(input) ? input : [input];
1980
- keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
2045
+ useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
2046
+ const inputs = Array.isArray(input) ? input : [input];
2047
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
2048
+ cacheKeys.forEach(
2049
+ (key, index) => suspendReact.preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
2050
+ );
1981
2051
  };
1982
- useLoader.clear = function(loader, input) {
1983
- const keys = Array.isArray(input) ? input : [input];
1984
- keys.forEach((key) => suspendReact.clear([loader, key]));
2052
+ useLoader.clear = function(loader, input, cacheKey) {
2053
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
2054
+ cacheKeys.forEach((key) => suspendReact.clear([loader, key]));
1985
2055
  };
1986
2056
  useLoader.loader = getLoader;
1987
2057
 
@@ -2403,7 +2473,7 @@ function advance(timestamp) {
2403
2473
  scheduler.getScheduler().step(timestamp);
2404
2474
  }
2405
2475
 
2406
- const version = "10.0.0-alpha.2";
2476
+ const version = "10.0.0-alpha.3";
2407
2477
  const packageData = {
2408
2478
  version: version};
2409
2479
 
@@ -13659,7 +13729,7 @@ function n0() {
13659
13729
  var t0 = n0();
13660
13730
  const r0 = Xb(t0);
13661
13731
 
13662
- const t = 1, o = 8, r = 32, e = 2;
13732
+ const t = 1, o = 8, r = 32, e = 2, i$1 = 268435456;
13663
13733
 
13664
13734
  function createReconciler(config) {
13665
13735
  const reconciler2 = r0(config);
@@ -13824,7 +13894,15 @@ function setFiberRef(fiber, publicInstance) {
13824
13894
  }
13825
13895
  }
13826
13896
  const reconstructed = [];
13827
- function swapInstances() {
13897
+ function flushReconstructedInstances() {
13898
+ if (reconstructed.length === 0) return;
13899
+ try {
13900
+ swapReconstructedInstances();
13901
+ } finally {
13902
+ reconstructed.length = 0;
13903
+ }
13904
+ }
13905
+ function swapReconstructedInstances() {
13828
13906
  for (const [instance] of reconstructed) {
13829
13907
  const parent = instance.parent;
13830
13908
  if (parent) {
@@ -13842,6 +13920,9 @@ function swapInstances() {
13842
13920
  }
13843
13921
  }
13844
13922
  if (instance.isHidden) unhideInstance(instance);
13923
+ if (isObject3D(instance.object) && !instance.parent) {
13924
+ removeInteractivity(findInitialRoot(instance), instance.object);
13925
+ }
13845
13926
  if (instance.object.__r3f) delete instance.object.__r3f;
13846
13927
  if (instance.type !== "primitive") disposeOnIdle(instance.object);
13847
13928
  }
@@ -13850,10 +13931,16 @@ function swapInstances() {
13850
13931
  const parent = instance.parent;
13851
13932
  if (parent) {
13852
13933
  const target = catalogue[toPascalCase(instance.type)];
13934
+ const prevObject = instance.object;
13853
13935
  instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
13854
13936
  instance.object.__r3f = instance;
13855
13937
  setFiberRef(fiber, instance.object);
13938
+ if (isObject3D(prevObject) && isObject3D(instance.object)) {
13939
+ swapInteractivity(findInitialRoot(instance), prevObject, instance.object);
13940
+ }
13856
13941
  delete instance.appliedOnce;
13942
+ instance.eventCount = 0;
13943
+ instance.handlers = {};
13857
13944
  applyProps(instance.object, instance.props);
13858
13945
  if (instance.props.attach) {
13859
13946
  attach(parent, instance);
@@ -13870,14 +13957,114 @@ function swapInstances() {
13870
13957
  invalidateInstance(instance);
13871
13958
  }
13872
13959
  }
13873
- reconstructed.length = 0;
13874
13960
  }
13875
13961
  const handleTextInstance = () => {
13876
13962
  };
13877
13963
  const NO_CONTEXT = {};
13878
13964
  let currentUpdatePriority = NoEventPriority;
13879
- const NoFlags = 0;
13880
- const Update = 4;
13965
+ function getEventPriority(type) {
13966
+ switch (type) {
13967
+ case "beforetoggle":
13968
+ case "cancel":
13969
+ case "click":
13970
+ case "close":
13971
+ case "contextmenu":
13972
+ case "copy":
13973
+ case "cut":
13974
+ case "auxclick":
13975
+ case "dblclick":
13976
+ case "dragend":
13977
+ case "dragstart":
13978
+ case "drop":
13979
+ case "focusin":
13980
+ case "focusout":
13981
+ case "input":
13982
+ case "invalid":
13983
+ case "keydown":
13984
+ case "keypress":
13985
+ case "keyup":
13986
+ case "mousedown":
13987
+ case "mouseup":
13988
+ case "paste":
13989
+ case "pause":
13990
+ case "play":
13991
+ case "pointercancel":
13992
+ case "pointerdown":
13993
+ case "pointerup":
13994
+ case "ratechange":
13995
+ case "reset":
13996
+ case "resize":
13997
+ case "seeked":
13998
+ case "submit":
13999
+ case "touchcancel":
14000
+ case "touchend":
14001
+ case "touchstart":
14002
+ case "volumechange":
14003
+ case "change":
14004
+ case "selectionchange":
14005
+ case "compositionstart":
14006
+ case "compositionend":
14007
+ case "compositionupdate":
14008
+ case "beforeinput":
14009
+ case "blur":
14010
+ case "fullscreenchange":
14011
+ case "focus":
14012
+ case "hashchange":
14013
+ case "popstate":
14014
+ case "select":
14015
+ case "selectstart":
14016
+ return e;
14017
+ case "drag":
14018
+ case "dragenter":
14019
+ case "dragexit":
14020
+ case "dragleave":
14021
+ case "dragover":
14022
+ case "mousemove":
14023
+ case "mouseout":
14024
+ case "mouseover":
14025
+ case "pointermove":
14026
+ case "pointerout":
14027
+ case "pointerover":
14028
+ case "scroll":
14029
+ case "touchmove":
14030
+ case "wheel":
14031
+ case "mouseenter":
14032
+ case "mouseleave":
14033
+ case "pointerenter":
14034
+ case "pointerleave":
14035
+ return o;
14036
+ case "message": {
14037
+ switch (Tb.unstable_getCurrentPriorityLevel()) {
14038
+ case Tb.unstable_ImmediatePriority:
14039
+ return e;
14040
+ case Tb.unstable_UserBlockingPriority:
14041
+ return o;
14042
+ case Tb.unstable_NormalPriority:
14043
+ case Tb.unstable_LowPriority:
14044
+ return r;
14045
+ case Tb.unstable_IdlePriority:
14046
+ return i$1;
14047
+ default:
14048
+ return r;
14049
+ }
14050
+ }
14051
+ default:
14052
+ return r;
14053
+ }
14054
+ }
14055
+ function scheduleMicrotask(callback) {
14056
+ if (typeof queueMicrotask === "function") {
14057
+ queueMicrotask(callback);
14058
+ } else if (typeof Promise !== "undefined") {
14059
+ Promise.resolve().then(callback).catch((error) => {
14060
+ setTimeout(() => {
14061
+ throw error;
14062
+ });
14063
+ });
14064
+ } else {
14065
+ setTimeout(callback);
14066
+ }
14067
+ }
13881
14068
  const reconciler = /* @__PURE__ */ createReconciler({
13882
14069
  isPrimaryRenderer: false,
13883
14070
  warnsIfNotActing: false,
@@ -13916,16 +14103,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
13916
14103
  else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
13917
14104
  else if (newProps.args?.some((value, index) => value !== oldProps.args?.[index])) reconstruct = true;
13918
14105
  if (reconstruct) {
13919
- reconstructed.push([instance, { ...newProps }, fiber]);
14106
+ reconstructed.push([instance, getInstanceProps(newProps), fiber]);
13920
14107
  } else {
13921
14108
  const changedProps = diffProps(instance, newProps);
13922
- if (Object.keys(changedProps).length) {
13923
- Object.assign(instance.props, changedProps);
13924
- applyProps(instance.object, changedProps);
13925
- }
14109
+ const attach2 = instance.props.attach;
14110
+ instance.props = getInstanceProps(newProps);
14111
+ if (attach2 !== void 0) instance.props.attach = attach2;
14112
+ else delete instance.props.attach;
14113
+ if (Object.keys(changedProps).length) applyProps(instance.object, changedProps);
13926
14114
  }
13927
- const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
13928
- if (isTailSibling) swapInstances();
13929
14115
  },
13930
14116
  finalizeInitialChildren: (instance) => {
13931
14117
  for (const prop in instance.props) {
@@ -13950,8 +14136,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13950
14136
  const target = container.getState().internal.container ?? container.getState().scene;
13951
14137
  return prepare(target, container, "", {});
13952
14138
  },
13953
- resetAfterCommit: () => {
13954
- },
14139
+ // Reconstructed instances are swapped once all mutations are committed,
14140
+ // before layout effects run so refs point to the new objects
14141
+ resetAfterCommit: flushReconstructedInstances,
13955
14142
  shouldSetTextContent: () => false,
13956
14143
  clearContainer: () => false,
13957
14144
  hideInstance,
@@ -13959,6 +14146,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13959
14146
  createTextInstance: handleTextInstance,
13960
14147
  hideTextInstance: handleTextInstance,
13961
14148
  unhideTextInstance: handleTextInstance,
14149
+ // Mirrors react-dom, which flushes discrete work in microtasks
14150
+ supportsMicrotasks: true,
14151
+ scheduleMicrotask,
13962
14152
  scheduleTimeout: typeof setTimeout === "function" ? setTimeout : void 0,
13963
14153
  cancelTimeout: typeof clearTimeout === "function" ? clearTimeout : void 0,
13964
14154
  noTimeout: -1,
@@ -13999,28 +14189,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13999
14189
  },
14000
14190
  resolveUpdatePriority() {
14001
14191
  if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
14002
- switch (typeof window !== "undefined" && window.event?.type) {
14003
- case "click":
14004
- case "contextmenu":
14005
- case "dblclick":
14006
- case "dragenter":
14007
- case "dragleave":
14008
- case "drop":
14009
- case "pointercancel":
14010
- case "pointerdown":
14011
- case "pointerup":
14012
- return e;
14013
- case "dragover":
14014
- case "pointermove":
14015
- case "pointerout":
14016
- case "pointerover":
14017
- case "pointerenter":
14018
- case "pointerleave":
14019
- case "wheel":
14020
- return o;
14021
- default:
14022
- return r;
14023
- }
14192
+ const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
14193
+ if (eventType === void 0) return r;
14194
+ return getEventPriority(eventType);
14024
14195
  },
14025
14196
  resetFormInstance() {
14026
14197
  },
@@ -14069,11 +14240,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
14069
14240
  cloneMutableTextInstance(textInstance) {
14070
14241
  return textInstance;
14071
14242
  },
14243
+ // React 19.2 added these for root-level view transitions. They only run for hosts that opt into
14244
+ // view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
14245
+ // into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
14246
+ // React never calls them. They stay as no-ops rather than throws: the host config is shared by
14247
+ // every root, and a throw here would turn a React-internal probe into a hard crash for users.
14248
+ // Guarded by a test asserting a full render + unmount never reaches them.
14072
14249
  cloneRootViewTransitionContainer(_rootContainer) {
14073
- throw new Error("Not implemented.");
14074
14250
  },
14075
14251
  removeRootViewTransitionClone(_rootContainer, _clone) {
14076
- throw new Error("Not implemented.");
14077
14252
  },
14078
14253
  // https://github.com/facebook/react/pull/32465
14079
14254
  createFragmentInstance: (_fiber) => null,
@@ -14158,6 +14333,7 @@ function createRoot(canvas) {
14158
14333
  const lastConfiguredProps = {};
14159
14334
  let configured = false;
14160
14335
  let pending = null;
14336
+ let rendererSetup = null;
14161
14337
  return {
14162
14338
  async configure(props = {}) {
14163
14339
  let resolve;
@@ -14188,7 +14364,7 @@ function createRoot(canvas) {
14188
14364
  forceEven
14189
14365
  } = props;
14190
14366
  const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || webgpu.SRGBColorSpace;
14191
- const state = store.getState();
14367
+ let state = store.getState();
14192
14368
  const defaultGLProps = {
14193
14369
  canvas,
14194
14370
  powerPreference: "high-performance",
@@ -14216,56 +14392,68 @@ function createRoot(canvas) {
14216
14392
  "The `primaryCanvas` prop for multi-canvas rendering cannot be used with WebGL. Remove the `gl` prop or use WebGPU."
14217
14393
  );
14218
14394
  }
14219
- if (wantsGL && !state.internal.actualRenderer) {
14220
- renderer = await resolveRenderer(glConfig, defaultGLProps, three.WebGLRenderer);
14221
- state.internal.actualRenderer = renderer;
14222
- state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14223
- } else if (!wantsGL && primaryCanvas && !state.internal.actualRenderer) {
14224
- const primary = await waitForPrimary(primaryCanvas);
14225
- renderer = primary.renderer;
14226
- state.internal.actualRenderer = renderer;
14227
- const canvasTarget = new webgpu.CanvasTarget(canvas);
14228
- primary.store.setState((prev) => ({
14229
- internal: { ...prev.internal, isMultiCanvas: true }
14230
- }));
14231
- state.set((prev) => ({
14232
- webGPUSupported: primary.store.getState().webGPUSupported,
14233
- renderer,
14234
- primaryStore: primary.store,
14235
- internal: {
14236
- ...prev.internal,
14237
- canvasTarget,
14238
- isMultiCanvas: true,
14239
- isSecondary: true,
14240
- targetId: primaryCanvas
14241
- }
14242
- }));
14243
- } else if (!wantsGL && !state.internal.actualRenderer) {
14244
- renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
14245
- if (!renderer.hasInitialized?.()) {
14246
- const size2 = computeInitialSize(canvas, propsSize);
14247
- if (size2.width > 0 && size2.height > 0) {
14248
- const pixelRatio = calculateDpr(dpr);
14249
- canvas.width = size2.width * pixelRatio;
14250
- canvas.height = size2.height * pixelRatio;
14251
- }
14252
- await renderer.init();
14253
- }
14254
- const backend = renderer.backend;
14255
- const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14256
- state.internal.actualRenderer = renderer;
14257
- state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14258
- if (canvasId && !state.internal.isSecondary) {
14259
- const canvasTarget = new webgpu.CanvasTarget(canvas);
14260
- const unregisterPrimary = registerPrimary(canvasId, renderer, store);
14261
- state.set((prev) => ({
14262
- internal: {
14263
- ...prev.internal,
14264
- canvasTarget,
14265
- unregisterPrimary
14395
+ if (!state.internal.actualRenderer) {
14396
+ if (!rendererSetup) {
14397
+ rendererSetup = (async () => {
14398
+ if (wantsGL) {
14399
+ renderer = await resolveRenderer(glConfig, defaultGLProps, three.WebGLRenderer);
14400
+ state.internal.actualRenderer = renderer;
14401
+ state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14402
+ } else if (!wantsGL && primaryCanvas) {
14403
+ const primary = await waitForPrimary(primaryCanvas);
14404
+ renderer = primary.renderer;
14405
+ state.internal.actualRenderer = renderer;
14406
+ const canvasTarget = new webgpu.CanvasTarget(canvas);
14407
+ primary.store.setState((prev) => ({
14408
+ internal: { ...prev.internal, isMultiCanvas: true }
14409
+ }));
14410
+ state.set((prev) => ({
14411
+ webGPUSupported: primary.store.getState().webGPUSupported,
14412
+ renderer,
14413
+ primaryStore: primary.store,
14414
+ internal: {
14415
+ ...prev.internal,
14416
+ canvasTarget,
14417
+ isMultiCanvas: true,
14418
+ isSecondary: true,
14419
+ targetId: primaryCanvas
14420
+ }
14421
+ }));
14422
+ } else if (!wantsGL) {
14423
+ renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
14424
+ if (!renderer.hasInitialized?.()) {
14425
+ const size2 = computeInitialSize(canvas, propsSize);
14426
+ if (size2.width > 0 && size2.height > 0) {
14427
+ const pixelRatio = calculateDpr(dpr);
14428
+ canvas.width = size2.width * pixelRatio;
14429
+ canvas.height = size2.height * pixelRatio;
14430
+ }
14431
+ await renderer.init();
14432
+ }
14433
+ const backend = renderer.backend;
14434
+ const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14435
+ state.internal.actualRenderer = renderer;
14436
+ state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14437
+ if (canvasId && !state.internal.isSecondary) {
14438
+ const canvasTarget = new webgpu.CanvasTarget(canvas);
14439
+ const unregisterPrimary = registerPrimary(canvasId, renderer, store);
14440
+ state.set((prev) => ({
14441
+ internal: {
14442
+ ...prev.internal,
14443
+ canvasTarget,
14444
+ unregisterPrimary
14445
+ }
14446
+ }));
14447
+ }
14266
14448
  }
14267
- }));
14449
+ })().catch((err) => {
14450
+ rendererSetup = null;
14451
+ throw err;
14452
+ });
14268
14453
  }
14454
+ await rendererSetup;
14455
+ state = store.getState();
14456
+ renderer = state.internal.actualRenderer;
14269
14457
  }
14270
14458
  let raycaster = state.raycaster;
14271
14459
  if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
@@ -14615,7 +14803,8 @@ function unmountComponentAtNode(canvas, callback) {
14615
14803
  dispose(state.scene);
14616
14804
  _roots.delete(canvas);
14617
14805
  if (callback) callback(canvas);
14618
- } catch {
14806
+ } catch (error) {
14807
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
14619
14808
  }
14620
14809
  }, 500);
14621
14810
  }
@@ -14678,6 +14867,7 @@ function PortalInner({ state = {}, children, container }) {
14678
14867
  viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
14679
14868
  if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
14680
14869
  }
14870
+ const set = injectState.set;
14681
14871
  return {
14682
14872
  // The intersect consists of the previous root state
14683
14873
  ...rootState,
@@ -14696,7 +14886,7 @@ function PortalInner({ state = {}, children, container }) {
14696
14886
  size: resolvedSize,
14697
14887
  viewport: { ...rootState.viewport, ...viewport },
14698
14888
  // Layers are allowed to override events
14699
- setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
14889
+ setEvents: (events2) => set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
14700
14890
  // Container for child attachment - the portalScene (injected or container itself)
14701
14891
  internal: { ...rootState.internal, ...injectState.internal, container: portalScene }
14702
14892
  };
@@ -14768,14 +14958,36 @@ function parseRendererConfig(rendererProp) {
14768
14958
  return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
14769
14959
  }
14770
14960
 
14961
+ const RESOURCE_KINDS = ["nodes", "uniforms", "buffers", "gpuStorage"];
14962
+ const registries = /* @__PURE__ */ new WeakMap();
14963
+ function getKindRegistry(store, kind) {
14964
+ let registry = registries.get(store);
14965
+ if (!registry) {
14966
+ registry = {
14967
+ nodes: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14968
+ uniforms: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14969
+ buffers: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14970
+ gpuStorage: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() }
14971
+ };
14972
+ registries.set(store, registry);
14973
+ }
14974
+ return registry[kind];
14975
+ }
14976
+ function invalidateResource(store, kind, scopeKey) {
14977
+ const registry = getKindRegistry(store, kind);
14978
+ {
14979
+ registry.valid.clear();
14980
+ registry.staged.clear();
14981
+ }
14982
+ }
14983
+ function invalidateAllResources(store) {
14984
+ for (const kind of RESOURCE_KINDS) invalidateResource(store, kind);
14985
+ }
14986
+
14771
14987
  function clearHmrCaches(store) {
14772
- store.setState((state) => ({
14773
- nodes: {},
14774
- uniforms: {},
14775
- buffers: {},
14776
- gpuStorage: {},
14777
- _hmrVersion: state._hmrVersion + 1
14778
- }));
14988
+ const primary = store.getState().primaryStore ?? store;
14989
+ invalidateAllResources(primary);
14990
+ primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
14779
14991
  }
14780
14992
 
14781
14993
  function CanvasImpl({
@@ -14856,6 +15068,7 @@ function CanvasImpl({
14856
15068
  const handleDropMissed = useMutableCallback(onDropMissed);
14857
15069
  const [block, setBlock] = React__namespace.useState(false);
14858
15070
  const [error, setError] = React__namespace.useState(false);
15071
+ const [fallbackVisible, setFallbackVisible] = React__namespace.useState(false);
14859
15072
  if (block) throw block;
14860
15073
  if (error) throw error;
14861
15074
  const root = React__namespace.useRef(null);
@@ -14863,6 +15076,7 @@ function CanvasImpl({
14863
15076
  const unsubscribeErrorRef = React__namespace.useRef(null);
14864
15077
  useIsomorphicLayoutEffect(() => {
14865
15078
  effectActiveRef.current = true;
15079
+ if (fallbackVisible) return;
14866
15080
  const canvas = canvasRef.current;
14867
15081
  if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
14868
15082
  if (!root.current) {
@@ -14883,7 +15097,7 @@ function CanvasImpl({
14883
15097
  }
14884
15098
  async function run() {
14885
15099
  if (!effectActiveRef.current || !root.current) return;
14886
- await root.current.configure({
15100
+ const configured = await root.current.configure({
14887
15101
  id,
14888
15102
  primaryCanvas,
14889
15103
  scheduler,
@@ -14924,8 +15138,20 @@ function CanvasImpl({
14924
15138
  }
14925
15139
  onCreated?.(state);
14926
15140
  }
14927
- });
14928
- if (!effectActiveRef.current || !root.current) return;
15141
+ }).then(
15142
+ () => true,
15143
+ // Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
15144
+ // inside <canvas>, which browsers don't display, so surface it as visible DOM
15145
+ // instead; with no fallback, rethrow to an external error boundary. (#3757)
15146
+ (setupError) => {
15147
+ if (effectActiveRef.current) {
15148
+ if (fallback != null) setFallbackVisible(true);
15149
+ else setError(setupError);
15150
+ }
15151
+ return false;
15152
+ }
15153
+ );
15154
+ if (!configured || !effectActiveRef.current || !root.current) return;
14929
15155
  root.current.render(
14930
15156
  /* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: [
14931
15157
  backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
@@ -14988,7 +15214,11 @@ function CanvasImpl({
14988
15214
  ...style
14989
15215
  },
14990
15216
  ...props,
14991
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
15217
+ children: fallbackVisible ? (
15218
+ // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
15219
+ // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
15220
+ fallback
15221
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
14992
15222
  "canvas",
14993
15223
  {
14994
15224
  ref: canvasRef,
@@ -15026,7 +15256,6 @@ exports.REACT_INTERNAL_PROPS = REACT_INTERNAL_PROPS;
15026
15256
  exports.RESERVED_PROPS = RESERVED_PROPS;
15027
15257
  exports.Texture = Texture;
15028
15258
  exports._roots = _roots;
15029
- exports.act = act;
15030
15259
  exports.addAfterEffect = addAfterEffect;
15031
15260
  exports.addEffect = addEffect;
15032
15261
  exports.addTail = addTail;
@@ -15076,6 +15305,7 @@ exports.reconciler = reconciler;
15076
15305
  exports.registerPrimary = registerPrimary;
15077
15306
  exports.removeInteractivity = removeInteractivity;
15078
15307
  exports.resolve = resolve;
15308
+ exports.swapInteractivity = swapInteractivity;
15079
15309
  exports.unmountComponentAtNode = unmountComponentAtNode;
15080
15310
  exports.unregisterPrimary = unregisterPrimary;
15081
15311
  exports.updateCamera = updateCamera;