@react-three/fiber 10.0.0-canary.164c7be → 10.0.0-canary.1be335a

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/legacy.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as three from 'three';
2
- import { WebGLRenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, Raycaster, OrthographicCamera, PerspectiveCamera, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGLRenderer } from 'three';
2
+ import { WebGLCubeRenderTarget, WebGLRenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, ShaderMaterial, Uniform, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, Raycaster, OrthographicCamera, PerspectiveCamera, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGLRenderer } from 'three';
3
3
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
4
4
  import * as React from 'react';
5
5
  import React__default, { useLayoutEffect, useRef, useMemo, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
@@ -11,7 +11,7 @@ import { HDRLoader } from 'three/examples/jsm/loaders/HDRLoader.js';
11
11
  import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
12
12
  import { UltraHDRLoader } from 'three/examples/jsm/loaders/UltraHDRLoader.js';
13
13
  import { GainMapLoader } from '@monogrid/gainmap-js';
14
- import Tb, { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
14
+ import Tb, { unstable_getCurrentPriorityLevel, unstable_IdlePriority, unstable_LowPriority, unstable_NormalPriority, unstable_UserBlockingPriority, unstable_ImmediatePriority, unstable_scheduleCallback } from 'scheduler';
15
15
  import { createWithEqualityFn } from 'zustand/traditional';
16
16
  import { getScheduler } from '@pmndrs/scheduler';
17
17
  export { Scheduler, getScheduler } from '@pmndrs/scheduler';
@@ -42,9 +42,12 @@ const WebGPURenderer = class WebGPURenderer2 {
42
42
  }
43
43
  };
44
44
  const RenderTarget = null;
45
+ const CubeRenderTarget = null;
45
46
 
46
47
  const THREE = /*#__PURE__*/_mergeNamespaces({
47
48
  __proto__: null,
49
+ CubeRenderTarget: CubeRenderTarget,
50
+ CubeRenderTargetCompat: WebGLCubeRenderTarget,
48
51
  Inspector: Inspector,
49
52
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
50
53
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
@@ -322,15 +325,16 @@ function EnvironmentPortal({
322
325
  preset = void 0,
323
326
  extensions
324
327
  }) {
325
- const gl = useThree$1((state) => state.gl);
328
+ const renderer = useThree$1((state) => state.renderer);
329
+ const isLegacy = useThree$1((state) => state.isLegacy);
326
330
  const defaultScene = useThree$1((state) => state.scene);
327
331
  const camera = React.useRef(null);
328
332
  const [virtualScene] = React.useState(() => new Scene());
329
333
  const fbo = React.useMemo(() => {
330
- const fbo2 = new WebGLCubeRenderTarget(resolution);
334
+ const fbo2 = isLegacy ? new WebGLCubeRenderTarget(resolution) : new CubeRenderTarget(resolution);
331
335
  fbo2.texture.type = HalfFloatType;
332
336
  return fbo2;
333
- }, [resolution]);
337
+ }, [resolution, isLegacy]);
334
338
  React.useEffect(() => {
335
339
  return () => {
336
340
  fbo.dispose();
@@ -338,10 +342,10 @@ function EnvironmentPortal({
338
342
  }, [fbo]);
339
343
  React.useLayoutEffect(() => {
340
344
  if (frames === 1) {
341
- const autoClear = gl.autoClear;
342
- gl.autoClear = true;
343
- camera.current.update(gl, virtualScene);
344
- gl.autoClear = autoClear;
345
+ const autoClear = renderer.autoClear;
346
+ renderer.autoClear = true;
347
+ camera.current.update(renderer, virtualScene);
348
+ renderer.autoClear = autoClear;
345
349
  }
346
350
  return setEnvProps(background, scene, defaultScene, fbo.texture, {
347
351
  backgroundBlurriness: blur ?? backgroundBlurriness,
@@ -358,7 +362,7 @@ function EnvironmentPortal({
358
362
  defaultScene,
359
363
  background,
360
364
  frames,
361
- gl,
365
+ renderer,
362
366
  blur,
363
367
  backgroundBlurriness,
364
368
  backgroundIntensity,
@@ -369,10 +373,10 @@ function EnvironmentPortal({
369
373
  let count = 1;
370
374
  useFrame$1(() => {
371
375
  if (frames === Infinity || count < frames) {
372
- const autoClear = gl.autoClear;
373
- gl.autoClear = true;
374
- camera.current.update(gl, virtualScene);
375
- gl.autoClear = autoClear;
376
+ const autoClear = renderer.autoClear;
377
+ renderer.autoClear = true;
378
+ camera.current.update(renderer, virtualScene);
379
+ renderer.autoClear = autoClear;
376
380
  count++;
377
381
  }
378
382
  });
@@ -615,8 +619,7 @@ function prepare(target, root, type, props) {
615
619
  object,
616
620
  eventCount: 0,
617
621
  handlers: {},
618
- isHidden: false,
619
- deferredRefs: []
622
+ isHidden: false
620
623
  };
621
624
  if (object) object.__r3f = instance;
622
625
  }
@@ -773,6 +776,17 @@ function unregisterVisibility(store, object) {
773
776
  internal.visibilityRegistry.delete(object.uuid);
774
777
  internal.occlusionCache.delete(object);
775
778
  }
779
+ function updateVisibilityHandlers(store, object, handlers) {
780
+ const { internal } = store.getState();
781
+ const entry = internal.visibilityRegistry.get(object.uuid);
782
+ if (!entry) return false;
783
+ entry.handlers = handlers;
784
+ if ((handlers.onOccluded || handlers.onVisible) && !internal.occlusionEnabled) {
785
+ object.occlusionTest = true;
786
+ enableOcclusion(store);
787
+ }
788
+ return true;
789
+ }
776
790
  function checkVisibility(state) {
777
791
  const { internal, camera } = state;
778
792
  const registry = internal.visibilityRegistry;
@@ -933,9 +947,9 @@ function diffProps(instance, newProps) {
933
947
  const { root, key } = resolve(instance.object, prop);
934
948
  if (root.constructor && root.constructor.length === 0) {
935
949
  const ctor = getMemoizedPrototype(root);
936
- if (!is.und(ctor)) changedProps[key] = ctor[key];
950
+ if (!is.und(ctor)) changedProps[prop] = ctor[key];
937
951
  } else {
938
- changedProps[key] = 0;
952
+ changedProps[prop] = 0;
939
953
  }
940
954
  }
941
955
  return changedProps;
@@ -960,10 +974,7 @@ function applyProps(object, props) {
960
974
  continue;
961
975
  }
962
976
  if (value === void 0) continue;
963
- if (isFromRef(value)) {
964
- instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
965
- continue;
966
- }
977
+ if (isFromRef(value)) continue;
967
978
  if (isOnce(value)) {
968
979
  if (instance?.appliedOnce?.has(prop)) continue;
969
980
  if (instance) {
@@ -999,6 +1010,19 @@ function applyProps(object, props) {
999
1010
  } else if (isVectorLike(target) && is.num(value)) {
1000
1011
  if ("setScalar" in target && typeof target.setScalar === "function") target.setScalar(value);
1001
1012
  else target.set(value);
1013
+ } else if (root instanceof ShaderMaterial && key === "uniforms" && is.obj(value)) {
1014
+ if (!is.obj(root.uniforms)) root.uniforms = {};
1015
+ const uniforms = root.uniforms;
1016
+ const nextUniforms = value;
1017
+ for (const name in nextUniforms) {
1018
+ const uniform = nextUniforms[name];
1019
+ const targetUniform = uniforms[name];
1020
+ if (targetUniform) Object.assign(targetUniform, uniform);
1021
+ else {
1022
+ const nextUniform = uniform instanceof Uniform ? uniform.clone() : new Uniform(uniform.value);
1023
+ uniforms[name] = nextUniform;
1024
+ }
1025
+ }
1002
1026
  } else {
1003
1027
  root[key] = value;
1004
1028
  if (key.endsWith("Node") && root.isMaterial) {
@@ -1017,6 +1041,9 @@ function applyProps(object, props) {
1017
1041
  if (instance.eventCount && object2.raycast !== null) {
1018
1042
  rootState.internal.interaction.push(object2);
1019
1043
  }
1044
+ }
1045
+ if (instance?.parent && rootState?.internal && instance.object?.isObject3D) {
1046
+ const object2 = instance.object;
1020
1047
  const root = findInitialRoot(instance);
1021
1048
  const visibilityHandlers = {
1022
1049
  onFramed: instance.handlers.onFramed,
@@ -1024,7 +1051,9 @@ function applyProps(object, props) {
1024
1051
  onVisible: instance.handlers.onVisible
1025
1052
  };
1026
1053
  if (hasVisibilityHandlers(visibilityHandlers)) {
1027
- registerVisibility(root, object2, visibilityHandlers);
1054
+ if (!updateVisibilityHandlers(root, object2, visibilityHandlers)) {
1055
+ registerVisibility(root, object2, visibilityHandlers);
1056
+ }
1028
1057
  } else {
1029
1058
  unregisterVisibility(root, object2);
1030
1059
  }
@@ -1552,6 +1581,7 @@ function createPointerEvents(store) {
1552
1581
  set((state) => ({ events: { ...state.events, connected: void 0 } }));
1553
1582
  }
1554
1583
  },
1584
+ // PREVIEW (A8): the XR pointer registration API may change before stable.
1555
1585
  registerPointer: (config) => {
1556
1586
  const pointerId = nextXRPointerId++;
1557
1587
  xrPointers.set(pointerId, config);
@@ -1638,6 +1668,13 @@ function notifyAlpha({ message, link }) {
1638
1668
  }
1639
1669
  }
1640
1670
 
1671
+ const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
1672
+ function isInternalRendererAccess(stack, callerDepth = 2) {
1673
+ if (!stack) return false;
1674
+ const caller = stack.split("\n")[callerDepth] ?? "";
1675
+ return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
1676
+ }
1677
+
1641
1678
  const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
1642
1679
  const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React.createContext(null));
1643
1680
  const createStore = (invalidate, advance) => {
@@ -1770,6 +1807,7 @@ const createStore = (invalidate, advance) => {
1770
1807
  }),
1771
1808
  setFrameloop: (frameloop = "always") => {
1772
1809
  set(() => ({ frameloop }));
1810
+ getScheduler().frameloop = frameloop;
1773
1811
  },
1774
1812
  setError: (error) => set(() => ({ error })),
1775
1813
  error: null,
@@ -1837,8 +1875,7 @@ const createStore = (invalidate, advance) => {
1837
1875
  const currentState = rootStore.getState();
1838
1876
  if (!currentState.isLegacy && currentState.internal.actualRenderer) {
1839
1877
  const stack = new Error().stack || "";
1840
- const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
1841
- if (!isInternalAccess) {
1878
+ if (!isInternalRendererAccess(stack)) {
1842
1879
  const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
1843
1880
  notifyDepreciated({
1844
1881
  heading: "Accessing state.gl in WebGPU mode",
@@ -1951,19 +1988,25 @@ function loadingFn(extensions, onProgress) {
1951
1988
  );
1952
1989
  };
1953
1990
  }
1954
- function useLoader(loader, input, extensions, onProgress) {
1955
- const keys = Array.isArray(input) ? input : [input];
1991
+ function useLoader(loader, input, extensions, onProgress, cacheKey) {
1992
+ const inputs = Array.isArray(input) ? input : [input];
1993
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1956
1994
  const fn = loadingFn(extensions, onProgress);
1957
- const results = keys.map((key) => suspend(fn, [loader, key], { equal: is.equ }));
1995
+ const results = cacheKeys.map(
1996
+ (key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
1997
+ );
1958
1998
  return Array.isArray(input) ? results : results[0];
1959
1999
  }
1960
- useLoader.preload = function(loader, input, extensions, onProgress) {
1961
- const keys = Array.isArray(input) ? input : [input];
1962
- keys.forEach((key) => preload(loadingFn(extensions, onProgress), [loader, key]));
2000
+ useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
2001
+ const inputs = Array.isArray(input) ? input : [input];
2002
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
2003
+ cacheKeys.forEach(
2004
+ (key, index) => preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
2005
+ );
1963
2006
  };
1964
- useLoader.clear = function(loader, input) {
1965
- const keys = Array.isArray(input) ? input : [input];
1966
- keys.forEach((key) => clear([loader, key]));
2007
+ useLoader.clear = function(loader, input, cacheKey) {
2008
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
2009
+ cacheKeys.forEach((key) => clear([loader, key]));
1967
2010
  };
1968
2011
  useLoader.loader = getLoader;
1969
2012
 
@@ -2383,7 +2426,7 @@ function advance(timestamp) {
2383
2426
  getScheduler().step(timestamp);
2384
2427
  }
2385
2428
 
2386
- const version = "10.0.0-alpha.2";
2429
+ const version = "10.0.0-alpha.3";
2387
2430
  const packageData = {
2388
2431
  version: version};
2389
2432
 
@@ -13639,7 +13682,7 @@ function n0() {
13639
13682
  var t0 = n0();
13640
13683
  const r0 = Xb(t0);
13641
13684
 
13642
- const t = 1, o = 8, r = 32, e = 2;
13685
+ const t = 1, o = 8, r = 32, e = 2, i$1 = 268435456;
13643
13686
 
13644
13687
  function createReconciler(config) {
13645
13688
  const reconciler2 = r0(config);
@@ -13804,7 +13847,15 @@ function setFiberRef(fiber, publicInstance) {
13804
13847
  }
13805
13848
  }
13806
13849
  const reconstructed = [];
13807
- function swapInstances() {
13850
+ function flushReconstructedInstances() {
13851
+ if (reconstructed.length === 0) return;
13852
+ try {
13853
+ swapReconstructedInstances();
13854
+ } finally {
13855
+ reconstructed.length = 0;
13856
+ }
13857
+ }
13858
+ function swapReconstructedInstances() {
13808
13859
  for (const [instance] of reconstructed) {
13809
13860
  const parent = instance.parent;
13810
13861
  if (parent) {
@@ -13822,6 +13873,7 @@ function swapInstances() {
13822
13873
  }
13823
13874
  }
13824
13875
  if (instance.isHidden) unhideInstance(instance);
13876
+ if (isObject3D(instance.object)) removeInteractivity(findInitialRoot(instance), instance.object);
13825
13877
  if (instance.object.__r3f) delete instance.object.__r3f;
13826
13878
  if (instance.type !== "primitive") disposeOnIdle(instance.object);
13827
13879
  }
@@ -13834,6 +13886,8 @@ function swapInstances() {
13834
13886
  instance.object.__r3f = instance;
13835
13887
  setFiberRef(fiber, instance.object);
13836
13888
  delete instance.appliedOnce;
13889
+ instance.eventCount = 0;
13890
+ instance.handlers = {};
13837
13891
  applyProps(instance.object, instance.props);
13838
13892
  if (instance.props.attach) {
13839
13893
  attach(parent, instance);
@@ -13850,14 +13904,114 @@ function swapInstances() {
13850
13904
  invalidateInstance(instance);
13851
13905
  }
13852
13906
  }
13853
- reconstructed.length = 0;
13854
13907
  }
13855
13908
  const handleTextInstance = () => {
13856
13909
  };
13857
13910
  const NO_CONTEXT = {};
13858
13911
  let currentUpdatePriority = NoEventPriority;
13859
- const NoFlags = 0;
13860
- const Update = 4;
13912
+ function getEventPriority(type) {
13913
+ switch (type) {
13914
+ case "beforetoggle":
13915
+ case "cancel":
13916
+ case "click":
13917
+ case "close":
13918
+ case "contextmenu":
13919
+ case "copy":
13920
+ case "cut":
13921
+ case "auxclick":
13922
+ case "dblclick":
13923
+ case "dragend":
13924
+ case "dragstart":
13925
+ case "drop":
13926
+ case "focusin":
13927
+ case "focusout":
13928
+ case "input":
13929
+ case "invalid":
13930
+ case "keydown":
13931
+ case "keypress":
13932
+ case "keyup":
13933
+ case "mousedown":
13934
+ case "mouseup":
13935
+ case "paste":
13936
+ case "pause":
13937
+ case "play":
13938
+ case "pointercancel":
13939
+ case "pointerdown":
13940
+ case "pointerup":
13941
+ case "ratechange":
13942
+ case "reset":
13943
+ case "resize":
13944
+ case "seeked":
13945
+ case "submit":
13946
+ case "touchcancel":
13947
+ case "touchend":
13948
+ case "touchstart":
13949
+ case "volumechange":
13950
+ case "change":
13951
+ case "selectionchange":
13952
+ case "compositionstart":
13953
+ case "compositionend":
13954
+ case "compositionupdate":
13955
+ case "beforeinput":
13956
+ case "blur":
13957
+ case "fullscreenchange":
13958
+ case "focus":
13959
+ case "hashchange":
13960
+ case "popstate":
13961
+ case "select":
13962
+ case "selectstart":
13963
+ return e;
13964
+ case "drag":
13965
+ case "dragenter":
13966
+ case "dragexit":
13967
+ case "dragleave":
13968
+ case "dragover":
13969
+ case "mousemove":
13970
+ case "mouseout":
13971
+ case "mouseover":
13972
+ case "pointermove":
13973
+ case "pointerout":
13974
+ case "pointerover":
13975
+ case "scroll":
13976
+ case "touchmove":
13977
+ case "wheel":
13978
+ case "mouseenter":
13979
+ case "mouseleave":
13980
+ case "pointerenter":
13981
+ case "pointerleave":
13982
+ return o;
13983
+ case "message": {
13984
+ switch (unstable_getCurrentPriorityLevel()) {
13985
+ case unstable_ImmediatePriority:
13986
+ return e;
13987
+ case unstable_UserBlockingPriority:
13988
+ return o;
13989
+ case unstable_NormalPriority:
13990
+ case unstable_LowPriority:
13991
+ return r;
13992
+ case unstable_IdlePriority:
13993
+ return i$1;
13994
+ default:
13995
+ return r;
13996
+ }
13997
+ }
13998
+ default:
13999
+ return r;
14000
+ }
14001
+ }
14002
+ function scheduleMicrotask(callback) {
14003
+ if (typeof queueMicrotask === "function") {
14004
+ queueMicrotask(callback);
14005
+ } else if (typeof Promise !== "undefined") {
14006
+ Promise.resolve().then(callback).catch((error) => {
14007
+ setTimeout(() => {
14008
+ throw error;
14009
+ });
14010
+ });
14011
+ } else {
14012
+ setTimeout(callback);
14013
+ }
14014
+ }
13861
14015
  const reconciler = /* @__PURE__ */ createReconciler({
13862
14016
  isPrimaryRenderer: false,
13863
14017
  warnsIfNotActing: false,
@@ -13896,16 +14050,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
13896
14050
  else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
13897
14051
  else if (newProps.args?.some((value, index) => value !== oldProps.args?.[index])) reconstruct = true;
13898
14052
  if (reconstruct) {
13899
- reconstructed.push([instance, { ...newProps }, fiber]);
14053
+ reconstructed.push([instance, getInstanceProps(newProps), fiber]);
13900
14054
  } else {
13901
14055
  const changedProps = diffProps(instance, newProps);
13902
- if (Object.keys(changedProps).length) {
13903
- Object.assign(instance.props, changedProps);
13904
- applyProps(instance.object, changedProps);
13905
- }
14056
+ const attach2 = instance.props.attach;
14057
+ instance.props = getInstanceProps(newProps);
14058
+ if (attach2 !== void 0) instance.props.attach = attach2;
14059
+ else delete instance.props.attach;
14060
+ if (Object.keys(changedProps).length) applyProps(instance.object, changedProps);
13906
14061
  }
13907
- const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
13908
- if (isTailSibling) swapInstances();
13909
14062
  },
13910
14063
  finalizeInitialChildren: (instance) => {
13911
14064
  for (const prop in instance.props) {
@@ -13930,8 +14083,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13930
14083
  const target = container.getState().internal.container ?? container.getState().scene;
13931
14084
  return prepare(target, container, "", {});
13932
14085
  },
13933
- resetAfterCommit: () => {
13934
- },
14086
+ // Reconstructed instances are swapped once all mutations are committed,
14087
+ // before layout effects run so refs point to the new objects
14088
+ resetAfterCommit: flushReconstructedInstances,
13935
14089
  shouldSetTextContent: () => false,
13936
14090
  clearContainer: () => false,
13937
14091
  hideInstance,
@@ -13939,6 +14093,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13939
14093
  createTextInstance: handleTextInstance,
13940
14094
  hideTextInstance: handleTextInstance,
13941
14095
  unhideTextInstance: handleTextInstance,
14096
+ // Mirrors react-dom, which flushes discrete work in microtasks
14097
+ supportsMicrotasks: true,
14098
+ scheduleMicrotask,
13942
14099
  scheduleTimeout: typeof setTimeout === "function" ? setTimeout : void 0,
13943
14100
  cancelTimeout: typeof clearTimeout === "function" ? clearTimeout : void 0,
13944
14101
  noTimeout: -1,
@@ -13979,28 +14136,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13979
14136
  },
13980
14137
  resolveUpdatePriority() {
13981
14138
  if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
13982
- switch (typeof window !== "undefined" && window.event?.type) {
13983
- case "click":
13984
- case "contextmenu":
13985
- case "dblclick":
13986
- case "dragenter":
13987
- case "dragleave":
13988
- case "drop":
13989
- case "pointercancel":
13990
- case "pointerdown":
13991
- case "pointerup":
13992
- return e;
13993
- case "dragover":
13994
- case "pointermove":
13995
- case "pointerout":
13996
- case "pointerover":
13997
- case "pointerenter":
13998
- case "pointerleave":
13999
- case "wheel":
14000
- return o;
14001
- default:
14002
- return r;
14003
- }
14139
+ const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
14140
+ if (eventType === void 0) return r;
14141
+ return getEventPriority(eventType);
14004
14142
  },
14005
14143
  resetFormInstance() {
14006
14144
  },
@@ -14049,11 +14187,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
14049
14187
  cloneMutableTextInstance(textInstance) {
14050
14188
  return textInstance;
14051
14189
  },
14190
+ // React 19.2 added these for root-level view transitions. They only run for hosts that opt into
14191
+ // view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
14192
+ // into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
14193
+ // React never calls them. They stay as no-ops rather than throws: the host config is shared by
14194
+ // every root, and a throw here would turn a React-internal probe into a hard crash for users.
14195
+ // Guarded by a test asserting a full render + unmount never reaches them.
14052
14196
  cloneRootViewTransitionContainer(_rootContainer) {
14053
- throw new Error("Not implemented.");
14054
14197
  },
14055
14198
  removeRootViewTransitionClone(_rootContainer, _clone) {
14056
- throw new Error("Not implemented.");
14057
14199
  },
14058
14200
  // https://github.com/facebook/react/pull/32465
14059
14201
  createFragmentInstance: (_fiber) => null,
@@ -14138,6 +14280,7 @@ function createRoot(canvas) {
14138
14280
  const lastConfiguredProps = {};
14139
14281
  let configured = false;
14140
14282
  let pending = null;
14283
+ let rendererSetup = null;
14141
14284
  return {
14142
14285
  async configure(props = {}) {
14143
14286
  let resolve;
@@ -14168,7 +14311,7 @@ function createRoot(canvas) {
14168
14311
  forceEven
14169
14312
  } = props;
14170
14313
  const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || SRGBColorSpace;
14171
- const state = store.getState();
14314
+ let state = store.getState();
14172
14315
  const defaultGLProps = {
14173
14316
  canvas,
14174
14317
  powerPreference: "high-performance",
@@ -14196,9 +14339,21 @@ function createRoot(canvas) {
14196
14339
  );
14197
14340
  }
14198
14341
  if (!state.internal.actualRenderer) {
14199
- renderer = await resolveRenderer(glConfig, defaultGLProps, WebGLRenderer);
14200
- state.internal.actualRenderer = renderer;
14201
- state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14342
+ if (!rendererSetup) {
14343
+ rendererSetup = (async () => {
14344
+ {
14345
+ renderer = await resolveRenderer(glConfig, defaultGLProps, WebGLRenderer);
14346
+ state.internal.actualRenderer = renderer;
14347
+ state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
14348
+ }
14349
+ })().catch((err) => {
14350
+ rendererSetup = null;
14351
+ throw err;
14352
+ });
14353
+ }
14354
+ await rendererSetup;
14355
+ state = store.getState();
14356
+ renderer = state.internal.actualRenderer;
14202
14357
  }
14203
14358
  let raycaster = state.raycaster;
14204
14359
  if (!raycaster) state.set({ raycaster: raycaster = new Raycaster() });
@@ -14548,7 +14703,8 @@ function unmountComponentAtNode(canvas, callback) {
14548
14703
  dispose(state.scene);
14549
14704
  _roots.delete(canvas);
14550
14705
  if (callback) callback(canvas);
14551
- } catch {
14706
+ } catch (error) {
14707
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
14552
14708
  }
14553
14709
  }, 500);
14554
14710
  }
@@ -14611,6 +14767,7 @@ function PortalInner({ state = {}, children, container }) {
14611
14767
  viewport = rootState.viewport.getCurrentViewport(camera, new Vector3(), resolvedSize);
14612
14768
  if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
14613
14769
  }
14770
+ const set = injectState.set;
14614
14771
  return {
14615
14772
  // The intersect consists of the previous root state
14616
14773
  ...rootState,
@@ -14629,7 +14786,7 @@ function PortalInner({ state = {}, children, container }) {
14629
14786
  size: resolvedSize,
14630
14787
  viewport: { ...rootState.viewport, ...viewport },
14631
14788
  // Layers are allowed to override events
14632
- setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
14789
+ setEvents: (events2) => set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
14633
14790
  // Container for child attachment - the portalScene (injected or container itself)
14634
14791
  internal: { ...rootState.internal, ...injectState.internal, container: portalScene }
14635
14792
  };
@@ -14688,14 +14845,49 @@ function parseBackground(background) {
14688
14845
  return null;
14689
14846
  }
14690
14847
 
14848
+ function parseRendererConfig(rendererProp) {
14849
+ const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
14850
+ if (isRendererConfig) {
14851
+ const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
14852
+ return {
14853
+ primaryCanvas: pc,
14854
+ scheduler: sc,
14855
+ renderer: Object.keys(rest).length > 0 ? rest : rendererProp
14856
+ };
14857
+ }
14858
+ return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
14859
+ }
14860
+
14861
+ const RESOURCE_KINDS = ["nodes", "uniforms", "buffers", "gpuStorage"];
14862
+ const registries = /* @__PURE__ */ new WeakMap();
14863
+ function getKindRegistry(store, kind) {
14864
+ let registry = registries.get(store);
14865
+ if (!registry) {
14866
+ registry = {
14867
+ nodes: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14868
+ uniforms: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14869
+ buffers: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14870
+ gpuStorage: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() }
14871
+ };
14872
+ registries.set(store, registry);
14873
+ }
14874
+ return registry[kind];
14875
+ }
14876
+ function invalidateResource(store, kind, scopeKey) {
14877
+ const registry = getKindRegistry(store, kind);
14878
+ {
14879
+ registry.valid.clear();
14880
+ registry.staged.clear();
14881
+ }
14882
+ }
14883
+ function invalidateAllResources(store) {
14884
+ for (const kind of RESOURCE_KINDS) invalidateResource(store, kind);
14885
+ }
14886
+
14691
14887
  function clearHmrCaches(store) {
14692
- store.setState((state) => ({
14693
- nodes: {},
14694
- uniforms: {},
14695
- buffers: {},
14696
- gpuStorage: {},
14697
- _hmrVersion: state._hmrVersion + 1
14698
- }));
14888
+ const primary = store.getState().primaryStore ?? store;
14889
+ invalidateAllResources(primary);
14890
+ primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
14699
14891
  }
14700
14892
 
14701
14893
  function CanvasImpl({
@@ -14731,18 +14923,7 @@ function CanvasImpl({
14731
14923
  forceEven,
14732
14924
  ...props
14733
14925
  }) {
14734
- const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
14735
- let primaryCanvas;
14736
- let scheduler;
14737
- let renderer;
14738
- if (isRendererConfig) {
14739
- const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
14740
- primaryCanvas = pc;
14741
- scheduler = sc;
14742
- renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
14743
- } else {
14744
- renderer = rendererProp;
14745
- }
14926
+ const { primaryCanvas, scheduler, renderer } = parseRendererConfig(rendererProp);
14746
14927
  React.useMemo(() => extend(THREE), []);
14747
14928
  const Bridge = useBridge();
14748
14929
  const backgroundProps = React.useMemo(() => parseBackground(background), [background]);
@@ -14787,6 +14968,7 @@ function CanvasImpl({
14787
14968
  const handleDropMissed = useMutableCallback(onDropMissed);
14788
14969
  const [block, setBlock] = React.useState(false);
14789
14970
  const [error, setError] = React.useState(false);
14971
+ const [fallbackVisible, setFallbackVisible] = React.useState(false);
14790
14972
  if (block) throw block;
14791
14973
  if (error) throw error;
14792
14974
  const root = React.useRef(null);
@@ -14794,6 +14976,7 @@ function CanvasImpl({
14794
14976
  const unsubscribeErrorRef = React.useRef(null);
14795
14977
  useIsomorphicLayoutEffect(() => {
14796
14978
  effectActiveRef.current = true;
14979
+ if (fallbackVisible) return;
14797
14980
  const canvas = canvasRef.current;
14798
14981
  if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
14799
14982
  if (!root.current) {
@@ -14814,7 +14997,7 @@ function CanvasImpl({
14814
14997
  }
14815
14998
  async function run() {
14816
14999
  if (!effectActiveRef.current || !root.current) return;
14817
- await root.current.configure({
15000
+ const configured = await root.current.configure({
14818
15001
  id,
14819
15002
  primaryCanvas,
14820
15003
  scheduler,
@@ -14855,8 +15038,20 @@ function CanvasImpl({
14855
15038
  }
14856
15039
  onCreated?.(state);
14857
15040
  }
14858
- });
14859
- if (!effectActiveRef.current || !root.current) return;
15041
+ }).then(
15042
+ () => true,
15043
+ // Renderer setup failed (e.g. no WebGL/WebGPU support). The `fallback` prop lives
15044
+ // inside <canvas>, which browsers don't display, so surface it as visible DOM
15045
+ // instead; with no fallback, rethrow to an external error boundary. (#3757)
15046
+ (setupError) => {
15047
+ if (effectActiveRef.current) {
15048
+ if (fallback != null) setFallbackVisible(true);
15049
+ else setError(setupError);
15050
+ }
15051
+ return false;
15052
+ }
15053
+ );
15054
+ if (!configured || !effectActiveRef.current || !root.current) return;
14860
15055
  root.current.render(
14861
15056
  /* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxs(React.Suspense, { fallback: /* @__PURE__ */ jsx(Block, { set: setBlock }), children: [
14862
15057
  backgroundProps && /* @__PURE__ */ jsx(Environment, { ...backgroundProps }),
@@ -14919,7 +15114,11 @@ function CanvasImpl({
14919
15114
  ...style
14920
15115
  },
14921
15116
  ...props,
14922
- children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
15117
+ children: fallbackVisible ? (
15118
+ // Renderer setup failed: render the fallback as visible DOM. Inside <canvas> (below)
15119
+ // it exists in the tree but browsers never paint it, which is the whole bug (#3757).
15120
+ fallback
15121
+ ) : /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx(
14923
15122
  "canvas",
14924
15123
  {
14925
15124
  ref: canvasRef,