@react-three/fiber 10.0.0-alpha.0 → 10.0.0-alpha.2

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.
@@ -13,6 +13,7 @@ const lite = require('dequal/lite');
13
13
  require('zustand/shallow');
14
14
  const tsl = require('three/tsl');
15
15
 
16
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
16
17
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
17
18
 
18
19
  function _interopNamespaceCompat(e) {
@@ -54,18 +55,21 @@ const WebGLRenderer = class WebGLRenderer2 {
54
55
  );
55
56
  }
56
57
  };
58
+ const WebGLRenderTarget = null;
57
59
 
58
60
  const THREE = /*#__PURE__*/_mergeNamespaces({
59
61
  __proto__: null,
60
62
  Inspector: Inspector_js.Inspector,
61
63
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
62
64
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
65
+ RenderTargetCompat: webgpu.RenderTarget,
66
+ WebGLRenderTarget: WebGLRenderTarget,
63
67
  WebGLRenderer: WebGLRenderer
64
68
  }, [webgpu__namespace]);
65
69
 
66
- var __defProp$2 = Object.defineProperty;
67
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
68
- var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
70
+ var __defProp$3 = Object.defineProperty;
71
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
72
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
69
73
  const act = React__namespace["act"];
70
74
  const useIsomorphicLayoutEffect = /* @__PURE__ */ (() => typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative"))() ? React__namespace.useLayoutEffect : React__namespace.useEffect;
71
75
  function useMutableCallback(fn) {
@@ -97,7 +101,7 @@ const ErrorBoundary = /* @__PURE__ */ (() => {
97
101
  return _a = class extends React__namespace.Component {
98
102
  constructor() {
99
103
  super(...arguments);
100
- __publicField$2(this, "state", { error: false });
104
+ __publicField$3(this, "state", { error: false });
101
105
  }
102
106
  componentDidCatch(err) {
103
107
  this.props.set(err);
@@ -105,7 +109,7 @@ const ErrorBoundary = /* @__PURE__ */ (() => {
105
109
  render() {
106
110
  return this.state.error ? null : this.props.children;
107
111
  }
108
- }, __publicField$2(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
112
+ }, __publicField$3(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
109
113
  })();
110
114
 
111
115
  const is = {
@@ -168,6 +172,13 @@ function updateCamera(camera, size) {
168
172
  }
169
173
  camera.updateProjectionMatrix();
170
174
  }
175
+ const frustumMatrix = new webgpu.Matrix4();
176
+ function updateFrustum(camera, frustum) {
177
+ const target = frustum ?? new webgpu.Frustum();
178
+ frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
179
+ target.setFromProjectionMatrix(frustumMatrix);
180
+ return target;
181
+ }
171
182
 
172
183
  const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
173
184
  function findInitialRoot(instance) {
@@ -248,6 +259,205 @@ function invalidateInstance(instance) {
248
259
  if (state && state.internal.frames === 0) state.invalidate();
249
260
  }
250
261
 
262
+ const tempFrustum = new webgpu.Frustum();
263
+ let hasWarnedWebGL = false;
264
+ let tslModule = null;
265
+ async function loadTSL() {
266
+ if (tslModule) return tslModule;
267
+ try {
268
+ const tsl = await import('three/tsl');
269
+ tslModule = { uniform: tsl.uniform, nodeObject: tsl.nodeObject };
270
+ return tslModule;
271
+ } catch {
272
+ return null;
273
+ }
274
+ }
275
+ function createOcclusionObserverNode(store, uniform) {
276
+ const node = new webgpu.Node("float");
277
+ node.updateType = webgpu.NodeUpdateType.OBJECT;
278
+ node.update = function(frame) {
279
+ const { internal } = store.getState();
280
+ const registry = internal.visibilityRegistry;
281
+ const cache = internal.occlusionCache;
282
+ for (const entry of registry.values()) {
283
+ const { object, handlers } = entry;
284
+ if (handlers.onOccluded || handlers.onVisible) {
285
+ const isOccluded = frame.renderer.isOccluded(object);
286
+ cache.set(object, isOccluded);
287
+ }
288
+ }
289
+ };
290
+ node.setup = function() {
291
+ return uniform(0);
292
+ };
293
+ return node;
294
+ }
295
+ let occlusionSetupPromise = null;
296
+ function enableOcclusion(store) {
297
+ const state = store.getState();
298
+ const { internal, renderer, rootScene } = state;
299
+ if (internal.occlusionEnabled || occlusionSetupPromise) return;
300
+ const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
301
+ if (!hasOcclusionSupport) {
302
+ if (!hasWarnedWebGL) {
303
+ console.warn(
304
+ "[R3F] Warning: onOccluded/onVisible occlusion queries require WebGPU renderer. Occlusion events will not fire on WebGL."
305
+ );
306
+ hasWarnedWebGL = true;
307
+ }
308
+ return;
309
+ }
310
+ occlusionSetupPromise = setupOcclusion(store);
311
+ }
312
+ async function setupOcclusion(store) {
313
+ const state = store.getState();
314
+ const { internal, rootScene, set } = state;
315
+ const tsl = await loadTSL();
316
+ if (!tsl) {
317
+ console.warn("[R3F] Warning: TSL module not available. Occlusion queries disabled.");
318
+ occlusionSetupPromise = null;
319
+ return;
320
+ }
321
+ const { uniform, nodeObject } = tsl;
322
+ let helperGroup = internal.helperGroup;
323
+ if (!helperGroup) {
324
+ helperGroup = new webgpu.Group();
325
+ helperGroup.name = "__r3fInternal";
326
+ helperGroup.__r3fInternal = true;
327
+ rootScene.add(helperGroup);
328
+ }
329
+ const geometry = new webgpu.BoxGeometry(1, 1, 1);
330
+ const material = new webgpu.MeshBasicNodeMaterial({
331
+ transparent: true,
332
+ opacity: 0
333
+ });
334
+ const observerNode = nodeObject(createOcclusionObserverNode(store, uniform));
335
+ material.colorNode = observerNode;
336
+ material.needsUpdate = true;
337
+ const mesh = new webgpu.Mesh(geometry, material);
338
+ mesh.name = "__r3fOcclusionObserver";
339
+ mesh.scale.setScalar(1e-4);
340
+ mesh.frustumCulled = false;
341
+ mesh.__r3fInternal = true;
342
+ helperGroup.add(mesh);
343
+ set((state2) => ({
344
+ internal: {
345
+ ...state2.internal,
346
+ helperGroup,
347
+ occlusionObserver: mesh,
348
+ occlusionEnabled: true
349
+ }
350
+ }));
351
+ occlusionSetupPromise = null;
352
+ }
353
+ function disableOcclusion(store) {
354
+ const { internal, set } = store.getState();
355
+ if (!internal.occlusionEnabled) return;
356
+ if (internal.occlusionObserver) {
357
+ internal.occlusionObserver.removeFromParent();
358
+ internal.occlusionObserver.geometry.dispose();
359
+ internal.occlusionObserver.material.dispose();
360
+ }
361
+ internal.occlusionCache.clear();
362
+ set((state) => ({
363
+ internal: {
364
+ ...state.internal,
365
+ occlusionObserver: null,
366
+ occlusionEnabled: false
367
+ }
368
+ }));
369
+ }
370
+ function cleanupHelperGroup(store) {
371
+ const { internal, set } = store.getState();
372
+ disableOcclusion(store);
373
+ if (internal.helperGroup) {
374
+ internal.helperGroup.removeFromParent();
375
+ set((state) => ({
376
+ internal: {
377
+ ...state.internal,
378
+ helperGroup: null
379
+ }
380
+ }));
381
+ }
382
+ }
383
+ function registerVisibility(store, object, handlers) {
384
+ const { internal } = store.getState();
385
+ const registry = internal.visibilityRegistry;
386
+ const entry = {
387
+ object,
388
+ handlers,
389
+ lastFramedState: null,
390
+ lastOccludedState: null,
391
+ lastVisibleState: null
392
+ };
393
+ registry.set(object.uuid, entry);
394
+ if (handlers.onOccluded || handlers.onVisible) {
395
+ object.occlusionTest = true;
396
+ if (!internal.occlusionEnabled) {
397
+ enableOcclusion(store);
398
+ }
399
+ }
400
+ }
401
+ function unregisterVisibility(store, object) {
402
+ const { internal } = store.getState();
403
+ internal.visibilityRegistry.delete(object.uuid);
404
+ internal.occlusionCache.delete(object);
405
+ }
406
+ function checkVisibility(state) {
407
+ const { internal, camera } = state;
408
+ const registry = internal.visibilityRegistry;
409
+ if (registry.size === 0) return;
410
+ updateFrustum(camera, tempFrustum);
411
+ for (const entry of registry.values()) {
412
+ const { object, handlers, lastFramedState, lastOccludedState, lastVisibleState } = entry;
413
+ let inFrustum = null;
414
+ const computeFrustum = () => {
415
+ if (inFrustum === null) {
416
+ if (object.geometry?.boundingSphere === null) {
417
+ object.geometry?.computeBoundingSphere();
418
+ }
419
+ inFrustum = tempFrustum.intersectsObject(object);
420
+ }
421
+ return inFrustum;
422
+ };
423
+ if (handlers.onFramed) {
424
+ const currentInFrustum = computeFrustum();
425
+ if (currentInFrustum !== lastFramedState) {
426
+ entry.lastFramedState = currentInFrustum;
427
+ handlers.onFramed(currentInFrustum);
428
+ }
429
+ }
430
+ let currentOcclusion = null;
431
+ if (handlers.onOccluded && internal.occlusionEnabled) {
432
+ currentOcclusion = internal.occlusionCache.get(object) ?? null;
433
+ if (currentOcclusion !== null && currentOcclusion !== lastOccludedState) {
434
+ entry.lastOccludedState = currentOcclusion;
435
+ handlers.onOccluded(currentOcclusion);
436
+ }
437
+ }
438
+ if (handlers.onVisible) {
439
+ const currentInFrustum = computeFrustum();
440
+ if (!handlers.onFramed && currentInFrustum !== lastFramedState) {
441
+ entry.lastFramedState = currentInFrustum;
442
+ }
443
+ let isOccluded = currentOcclusion;
444
+ if (isOccluded === null && internal.occlusionEnabled) {
445
+ isOccluded = internal.occlusionCache.get(object) ?? null;
446
+ }
447
+ if (isOccluded === null) isOccluded = false;
448
+ const isVisible = currentInFrustum && !isOccluded && object.visible;
449
+ if (isVisible !== lastVisibleState) {
450
+ entry.lastVisibleState = isVisible;
451
+ handlers.onVisible(isVisible);
452
+ }
453
+ }
454
+ }
455
+ }
456
+ function hasVisibilityHandlers(handlers) {
457
+ if (!handlers) return false;
458
+ return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
459
+ }
460
+
251
461
  const RESERVED_PROPS = [
252
462
  "children",
253
463
  "key",
@@ -262,6 +472,7 @@ const RESERVED_PROPS = [
262
472
  "dispose"
263
473
  ];
264
474
  const EVENT_REGEX = /^on(Pointer|Drag|Drop|Click|DoubleClick|ContextMenu|Wheel)/;
475
+ const VISIBILITY_EVENT_REGEX = /^on(Framed|Occluded|Visible)$/;
265
476
  const INDEX_REGEX = /-\d+$/;
266
477
  const MEMOIZED_PROTOTYPES = /* @__PURE__ */ new Map();
267
478
  const colorMaps = ["map", "emissiveMap", "sheenColorMap", "specularColorMap", "envMap"];
@@ -348,7 +559,7 @@ function applyProps(object, props) {
348
559
  const rootState = instance && findInitialRoot(instance).getState();
349
560
  const prevHandlers = instance?.eventCount;
350
561
  for (const prop in props) {
351
- let value = props[prop];
562
+ const value = props[prop];
352
563
  if (RESERVED_PROPS.includes(prop)) continue;
353
564
  if (instance && EVENT_REGEX.test(prop)) {
354
565
  if (typeof value === "function") instance.handlers[prop] = value;
@@ -356,6 +567,12 @@ function applyProps(object, props) {
356
567
  instance.eventCount = Object.keys(instance.handlers).length;
357
568
  continue;
358
569
  }
570
+ if (instance && VISIBILITY_EVENT_REGEX.test(prop)) {
571
+ if (typeof value === "function") instance.handlers[prop] = value;
572
+ else delete instance.handlers[prop];
573
+ instance.eventCount = Object.keys(instance.handlers).length;
574
+ continue;
575
+ }
359
576
  if (value === void 0) continue;
360
577
  let { root, key, target } = resolve(object, prop);
361
578
  if (target === void 0 && (typeof root !== "object" || root === null)) {
@@ -392,6 +609,17 @@ function applyProps(object, props) {
392
609
  if (instance.eventCount && object2.raycast !== null) {
393
610
  rootState.internal.interaction.push(object2);
394
611
  }
612
+ const root = findInitialRoot(instance);
613
+ const visibilityHandlers = {
614
+ onFramed: instance.handlers.onFramed,
615
+ onOccluded: instance.handlers.onOccluded,
616
+ onVisible: instance.handlers.onVisible
617
+ };
618
+ if (hasVisibilityHandlers(visibilityHandlers)) {
619
+ registerVisibility(root, object2, visibilityHandlers);
620
+ } else {
621
+ unregisterVisibility(root, object2);
622
+ }
395
623
  }
396
624
  if (instance && instance.props.attach === void 0) {
397
625
  if (instance.object.isBufferGeometry) instance.props.attach = "geometry";
@@ -426,6 +654,7 @@ function removeInteractivity(store, object) {
426
654
  internal.capturedMap.forEach((captures, pointerId) => {
427
655
  releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
428
656
  });
657
+ unregisterVisibility(store, object);
429
658
  }
430
659
  function createEvents(store) {
431
660
  function calculateDistance(event) {
@@ -482,13 +711,14 @@ function createEvents(store) {
482
711
  for (const hit of hits) {
483
712
  let eventObject = hit.object;
484
713
  while (eventObject) {
485
- if (eventObject.__r3f?.eventCount)
714
+ if (eventObject.__r3f?.eventCount) {
486
715
  intersections.push({ ...hit, eventObject });
716
+ }
487
717
  eventObject = eventObject.parent;
488
718
  }
489
719
  }
490
720
  if ("pointerId" in event && state.internal.capturedMap.has(event.pointerId)) {
491
- for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
721
+ for (const captureData of state.internal.capturedMap.get(event.pointerId).values()) {
492
722
  if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
493
723
  }
494
724
  }
@@ -518,12 +748,12 @@ function createEvents(store) {
518
748
  releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
519
749
  }
520
750
  };
521
- let extractEventProps = {};
522
- for (let prop in event) {
523
- let property = event[prop];
751
+ const extractEventProps = {};
752
+ for (const prop in event) {
753
+ const property = event[prop];
524
754
  if (typeof property !== "function") extractEventProps[prop] = property;
525
755
  }
526
- let raycastEvent = {
756
+ const raycastEvent = {
527
757
  ...hit,
528
758
  ...extractEventProps,
529
759
  pointer,
@@ -808,8 +1038,21 @@ function formatLocation(url, line) {
808
1038
  const file = clean.split("/").pop() ?? clean;
809
1039
  return `${file}:${line}`;
810
1040
  }
1041
+ function notifyAlpha({ message, link }) {
1042
+ if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_ALPHA_WARNINGS !== "true") {
1043
+ return;
1044
+ }
1045
+ if (shownNotices.has(message)) return;
1046
+ shownNotices.add(message);
1047
+ const boxStyle = "background: #6366f1; color: #ffffff; padding: 6px 10px; border-radius: 4px; font-weight: 500;";
1048
+ console.log(`%c\u{1F52C} ${message}`, boxStyle);
1049
+ {
1050
+ console.log(`%cMore info: ${link}`, "color: #6366f1; font-weight: normal;");
1051
+ }
1052
+ }
811
1053
 
812
- const context = /* @__PURE__ */ React__namespace.createContext(null);
1054
+ const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
1055
+ const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
813
1056
  const createStore = (invalidate, advance) => {
814
1057
  const rootStore = traditional.createWithEqualityFn((set, get) => {
815
1058
  const position = new webgpu.Vector3();
@@ -840,6 +1083,8 @@ const createStore = (invalidate, advance) => {
840
1083
  gl: null,
841
1084
  renderer: null,
842
1085
  camera: null,
1086
+ frustum: new webgpu.Frustum(),
1087
+ autoUpdateFrustum: true,
843
1088
  raycaster: null,
844
1089
  events: { priority: 1, enabled: true, connected: false },
845
1090
  scene: null,
@@ -891,10 +1136,38 @@ const createStore = (invalidate, advance) => {
891
1136
  getCurrentViewport
892
1137
  },
893
1138
  setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
894
- setSize: (width, height, top = 0, left = 0) => {
895
- const camera = get().camera;
896
- const size = { width, height, top, left };
897
- set((state2) => ({ size, viewport: { ...state2.viewport, ...getCurrentViewport(camera, defaultTarget, size) } }));
1139
+ setSize: (width, height, top, left) => {
1140
+ const state2 = get();
1141
+ if (width === void 0) {
1142
+ set({ _sizeImperative: false });
1143
+ if (state2._sizeProps) {
1144
+ const { width: propW, height: propH } = state2._sizeProps;
1145
+ if (propW !== void 0 || propH !== void 0) {
1146
+ const currentSize = state2.size;
1147
+ const newSize = {
1148
+ width: propW ?? currentSize.width,
1149
+ height: propH ?? currentSize.height,
1150
+ top: currentSize.top,
1151
+ left: currentSize.left
1152
+ };
1153
+ set((s) => ({
1154
+ size: newSize,
1155
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
1156
+ }));
1157
+ }
1158
+ }
1159
+ return;
1160
+ }
1161
+ const w = width;
1162
+ const h = height ?? width;
1163
+ const t = top ?? state2.size.top;
1164
+ const l = left ?? state2.size.left;
1165
+ const size = { width: w, height: h, top: t, left: l };
1166
+ set((s) => ({
1167
+ size,
1168
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
1169
+ _sizeImperative: true
1170
+ }));
898
1171
  },
899
1172
  setDpr: (dpr) => set((state2) => {
900
1173
  const resolved = calculateDpr(dpr);
@@ -911,6 +1184,9 @@ const createStore = (invalidate, advance) => {
911
1184
  textures: /* @__PURE__ */ new Map(),
912
1185
  postProcessing: null,
913
1186
  passes: {},
1187
+ _hmrVersion: 0,
1188
+ _sizeImperative: false,
1189
+ _sizeProps: null,
914
1190
  previousRoot: void 0,
915
1191
  internal: {
916
1192
  // Events
@@ -921,6 +1197,13 @@ const createStore = (invalidate, advance) => {
921
1197
  initialHits: [],
922
1198
  capturedMap: /* @__PURE__ */ new Map(),
923
1199
  lastEvent: React__namespace.createRef(),
1200
+ // Visibility tracking (onFramed, onOccluded, onVisible)
1201
+ visibilityRegistry: /* @__PURE__ */ new Map(),
1202
+ // Occlusion system (WebGPU only)
1203
+ occlusionEnabled: false,
1204
+ occlusionObserver: null,
1205
+ occlusionCache: /* @__PURE__ */ new Map(),
1206
+ helperGroup: null,
924
1207
  // Updates
925
1208
  active: false,
926
1209
  frames: 0,
@@ -1006,7 +1289,15 @@ const createStore = (invalidate, advance) => {
1006
1289
  }
1007
1290
  if (camera !== oldCamera) {
1008
1291
  oldCamera = camera;
1292
+ const { rootScene } = rootStore.getState();
1293
+ if (camera && rootScene && !camera.parent) {
1294
+ rootScene.add(camera);
1295
+ }
1009
1296
  set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
1297
+ const currentState = rootStore.getState();
1298
+ if (currentState.autoUpdateFrustum && camera) {
1299
+ updateFrustum(camera, currentState.frustum);
1300
+ }
1010
1301
  }
1011
1302
  });
1012
1303
  rootStore.subscribe((state2) => invalidate(state2));
@@ -1065,18 +1356,18 @@ useLoader.clear = function(loader, input) {
1065
1356
  };
1066
1357
  useLoader.loader = getLoader;
1067
1358
 
1068
- var __defProp$1 = Object.defineProperty;
1069
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1070
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1359
+ var __defProp$2 = Object.defineProperty;
1360
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1361
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1071
1362
  const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
1072
1363
  class PhaseGraph {
1073
1364
  constructor() {
1074
1365
  /** Ordered list of phase nodes */
1075
- __publicField$1(this, "phases", []);
1366
+ __publicField$2(this, "phases", []);
1076
1367
  /** Quick lookup by name */
1077
- __publicField$1(this, "phaseMap", /* @__PURE__ */ new Map());
1368
+ __publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
1078
1369
  /** Cached ordered names (invalidated on changes) */
1079
- __publicField$1(this, "orderedNamesCache", null);
1370
+ __publicField$2(this, "orderedNamesCache", null);
1080
1371
  this.initializeDefaultPhases();
1081
1372
  }
1082
1373
  //* Initialization --------------------------------
@@ -1103,8 +1394,9 @@ class PhaseGraph {
1103
1394
  const node = { name, isAutoGenerated: false };
1104
1395
  let insertIndex = this.phases.length;
1105
1396
  const targetIndex = this.getPhaseIndex(before ?? after);
1106
- if (targetIndex !== -1) insertIndex = before ? targetIndex : targetIndex + 1;
1107
- else {
1397
+ if (targetIndex !== -1) {
1398
+ insertIndex = before ? targetIndex : targetIndex + 1;
1399
+ } else {
1108
1400
  const constraintType = before ? "before" : "after";
1109
1401
  console.warn(`[useFrame] Phase "${before ?? after}" not found for '${constraintType}' constraint`);
1110
1402
  }
@@ -1332,9 +1624,9 @@ function resetJobTiming(job) {
1332
1624
  job.lastRun = void 0;
1333
1625
  }
1334
1626
 
1335
- var __defProp = Object.defineProperty;
1336
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1337
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1627
+ var __defProp$1 = Object.defineProperty;
1628
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1629
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1338
1630
  const hmrData = (() => {
1339
1631
  if (typeof process !== "undefined" && process.env.NODE_ENV === "test") return void 0;
1340
1632
  if (typeof import_meta_hot !== "undefined") return import_meta_hot;
@@ -1348,9 +1640,9 @@ const _Scheduler = class _Scheduler {
1348
1640
  //* Constructor ================================
1349
1641
  constructor() {
1350
1642
  //* Critical State ================================
1351
- __publicField(this, "roots", /* @__PURE__ */ new Map());
1352
- __publicField(this, "phaseGraph");
1353
- __publicField(this, "loopState", {
1643
+ __publicField$1(this, "roots", /* @__PURE__ */ new Map());
1644
+ __publicField$1(this, "phaseGraph");
1645
+ __publicField$1(this, "loopState", {
1354
1646
  running: false,
1355
1647
  rafHandle: null,
1356
1648
  lastTime: null,
@@ -1359,17 +1651,21 @@ const _Scheduler = class _Scheduler {
1359
1651
  elapsedTime: 0,
1360
1652
  createdAt: performance.now()
1361
1653
  });
1362
- __publicField(this, "stoppedTime", 0);
1654
+ __publicField$1(this, "stoppedTime", 0);
1363
1655
  //* Private State ================================
1364
- __publicField(this, "nextRootIndex", 0);
1365
- __publicField(this, "globalBeforeJobs", /* @__PURE__ */ new Map());
1366
- __publicField(this, "globalAfterJobs", /* @__PURE__ */ new Map());
1367
- __publicField(this, "nextGlobalIndex", 0);
1368
- __publicField(this, "idleCallbacks", /* @__PURE__ */ new Set());
1369
- __publicField(this, "nextJobIndex", 0);
1370
- __publicField(this, "jobStateListeners", /* @__PURE__ */ new Map());
1371
- __publicField(this, "pendingFrames", 0);
1372
- __publicField(this, "_frameloop", "always");
1656
+ __publicField$1(this, "nextRootIndex", 0);
1657
+ __publicField$1(this, "globalBeforeJobs", /* @__PURE__ */ new Map());
1658
+ __publicField$1(this, "globalAfterJobs", /* @__PURE__ */ new Map());
1659
+ __publicField$1(this, "nextGlobalIndex", 0);
1660
+ __publicField$1(this, "idleCallbacks", /* @__PURE__ */ new Set());
1661
+ __publicField$1(this, "nextJobIndex", 0);
1662
+ __publicField$1(this, "jobStateListeners", /* @__PURE__ */ new Map());
1663
+ __publicField$1(this, "pendingFrames", 0);
1664
+ __publicField$1(this, "_frameloop", "always");
1665
+ //* Independent Mode & Error Handling State ================================
1666
+ __publicField$1(this, "_independent", false);
1667
+ __publicField$1(this, "errorHandler", null);
1668
+ __publicField$1(this, "rootReadyCallbacks", /* @__PURE__ */ new Set());
1373
1669
  //* Core Loop Execution Methods ================================
1374
1670
  /**
1375
1671
  * Main RAF loop callback.
@@ -1378,7 +1674,7 @@ const _Scheduler = class _Scheduler {
1378
1674
  * @returns {void}
1379
1675
  * @private
1380
1676
  */
1381
- __publicField(this, "loop", (timestamp) => {
1677
+ __publicField$1(this, "loop", (timestamp) => {
1382
1678
  if (!this.loopState.running) return;
1383
1679
  this.executeFrame(timestamp);
1384
1680
  if (this._frameloop === "demand") {
@@ -1392,6 +1688,12 @@ const _Scheduler = class _Scheduler {
1392
1688
  });
1393
1689
  this.phaseGraph = new PhaseGraph();
1394
1690
  }
1691
+ static get instance() {
1692
+ return globalThis[_Scheduler.INSTANCE_KEY] ?? null;
1693
+ }
1694
+ static set instance(value) {
1695
+ globalThis[_Scheduler.INSTANCE_KEY] = value;
1696
+ }
1395
1697
  /**
1396
1698
  * Get the global scheduler instance (creates if doesn't exist).
1397
1699
  * Uses HMR data to preserve instance across hot reloads.
@@ -1440,29 +1742,43 @@ const _Scheduler = class _Scheduler {
1440
1742
  get isRunning() {
1441
1743
  return this.loopState.running;
1442
1744
  }
1745
+ get isReady() {
1746
+ return this.roots.size > 0;
1747
+ }
1748
+ get independent() {
1749
+ return this._independent;
1750
+ }
1751
+ set independent(value) {
1752
+ this._independent = value;
1753
+ if (value) this.ensureDefaultRoot();
1754
+ }
1443
1755
  //* Root Management Methods ================================
1444
1756
  /**
1445
1757
  * Register a root (Canvas) with the scheduler.
1446
1758
  * The first root to register starts the RAF loop (if frameloop='always').
1447
1759
  * @param {string} id - Unique identifier for this root
1448
- * @param {() => RootState} getState - Function to get the root's current state
1760
+ * @param {RootOptions} [options] - Optional configuration with getState and onError callbacks
1449
1761
  * @returns {() => void} Unsubscribe function to remove this root
1450
1762
  */
1451
- registerRoot(id, getState) {
1763
+ registerRoot(id, options = {}) {
1452
1764
  if (this.roots.has(id)) {
1453
1765
  console.warn(`[Scheduler] Root "${id}" already registered`);
1454
1766
  return () => this.unregisterRoot(id);
1455
1767
  }
1456
1768
  const entry = {
1457
1769
  id,
1458
- getState,
1770
+ getState: options.getState ?? (() => ({})),
1459
1771
  jobs: /* @__PURE__ */ new Map(),
1460
1772
  sortedJobs: [],
1461
1773
  needsRebuild: false
1462
1774
  };
1775
+ if (options.onError) {
1776
+ this.errorHandler = options.onError;
1777
+ }
1463
1778
  this.roots.set(id, entry);
1464
- if (this.roots.size === 1 && this._frameloop === "always") {
1465
- this.start();
1779
+ if (this.roots.size === 1) {
1780
+ this.notifyRootReady();
1781
+ if (this._frameloop === "always") this.start();
1466
1782
  }
1467
1783
  return () => this.unregisterRoot(id);
1468
1784
  }
@@ -1482,7 +1798,60 @@ const _Scheduler = class _Scheduler {
1482
1798
  this.roots.delete(id);
1483
1799
  if (this.roots.size === 0) {
1484
1800
  this.stop();
1801
+ this.errorHandler = null;
1802
+ }
1803
+ }
1804
+ /**
1805
+ * Subscribe to be notified when a root becomes available.
1806
+ * Fires immediately if a root already exists.
1807
+ * @param {() => void} callback - Function called when first root registers
1808
+ * @returns {() => void} Unsubscribe function
1809
+ */
1810
+ onRootReady(callback) {
1811
+ if (this.roots.size > 0) {
1812
+ callback();
1813
+ return () => {
1814
+ };
1485
1815
  }
1816
+ this.rootReadyCallbacks.add(callback);
1817
+ return () => this.rootReadyCallbacks.delete(callback);
1818
+ }
1819
+ /**
1820
+ * Notify all registered root-ready callbacks.
1821
+ * Called when the first root registers.
1822
+ * @returns {void}
1823
+ * @private
1824
+ */
1825
+ notifyRootReady() {
1826
+ for (const cb of this.rootReadyCallbacks) {
1827
+ try {
1828
+ cb();
1829
+ } catch (error) {
1830
+ console.error("[Scheduler] Error in root-ready callback:", error);
1831
+ }
1832
+ }
1833
+ this.rootReadyCallbacks.clear();
1834
+ }
1835
+ /**
1836
+ * Ensure a default root exists for independent mode.
1837
+ * Creates a minimal root with no state provider.
1838
+ * @returns {void}
1839
+ * @private
1840
+ */
1841
+ ensureDefaultRoot() {
1842
+ if (!this.roots.has("__default__")) {
1843
+ this.registerRoot("__default__");
1844
+ }
1845
+ }
1846
+ /**
1847
+ * Trigger error handling for job errors.
1848
+ * Uses the bound error handler if available, otherwise logs to console.
1849
+ * @param {Error} error - The error to handle
1850
+ * @returns {void}
1851
+ */
1852
+ triggerError(error) {
1853
+ if (this.errorHandler) this.errorHandler(error);
1854
+ else console.error("[Scheduler]", error);
1486
1855
  }
1487
1856
  //* Phase Management Methods ================================
1488
1857
  /**
@@ -1842,9 +2211,9 @@ const _Scheduler = class _Scheduler {
1842
2211
  const deltaMs = this.loopState.lastTime !== null ? now - this.loopState.lastTime : 0;
1843
2212
  const delta = deltaMs / 1e3;
1844
2213
  const elapsed = now - this.loopState.createdAt;
1845
- const rootState = root.getState();
2214
+ const providedState = root.getState?.() ?? {};
1846
2215
  const frameState = {
1847
- ...rootState,
2216
+ ...providedState,
1848
2217
  time: now,
1849
2218
  delta,
1850
2219
  elapsed,
@@ -1854,6 +2223,7 @@ const _Scheduler = class _Scheduler {
1854
2223
  job.callback(frameState, delta);
1855
2224
  } catch (error) {
1856
2225
  console.error(`[Scheduler] Error in job "${job.id}":`, error);
2226
+ this.triggerError(error instanceof Error ? error : new Error(String(error)));
1857
2227
  }
1858
2228
  }
1859
2229
  /**
@@ -1895,7 +2265,7 @@ const _Scheduler = class _Scheduler {
1895
2265
  /**
1896
2266
  * Execute all jobs for a single root in sorted order.
1897
2267
  * Rebuilds sorted job list if needed, then dispatches each job.
1898
- * Errors are caught and propagated to the root's error boundary.
2268
+ * Errors are caught and propagated via triggerError.
1899
2269
  * @param {RootEntry} root - The root entry to tick
1900
2270
  * @param {number} timestamp - RAF timestamp in milliseconds
1901
2271
  * @param {number} delta - Time since last frame in seconds
@@ -1907,10 +2277,9 @@ const _Scheduler = class _Scheduler {
1907
2277
  root.sortedJobs = rebuildSortedJobs(root.jobs, this.phaseGraph);
1908
2278
  root.needsRebuild = false;
1909
2279
  }
1910
- const rootState = root.getState();
1911
- if (!rootState) return;
2280
+ const providedState = root.getState?.() ?? {};
1912
2281
  const frameState = {
1913
- ...rootState,
2282
+ ...providedState,
1914
2283
  time: timestamp,
1915
2284
  delta,
1916
2285
  elapsed: this.loopState.elapsedTime / 1e3,
@@ -1923,7 +2292,7 @@ const _Scheduler = class _Scheduler {
1923
2292
  job.callback(frameState, delta);
1924
2293
  } catch (error) {
1925
2294
  console.error(`[Scheduler] Error in job "${job.id}":`, error);
1926
- rootState.setError(error instanceof Error ? error : new Error(String(error)));
2295
+ this.triggerError(error instanceof Error ? error : new Error(String(error)));
1927
2296
  }
1928
2297
  }
1929
2298
  }
@@ -2008,8 +2377,11 @@ const _Scheduler = class _Scheduler {
2008
2377
  return /* @__PURE__ */ new Set([value]);
2009
2378
  }
2010
2379
  };
2011
- //* Static State & Methods (Singlton Usage) ================================
2012
- __publicField(_Scheduler, "instance", null);
2380
+ //* Static State & Methods (Singleton Usage) ================================
2381
+ //* Cross-Bundle Singleton Key ==============================
2382
+ // Use Symbol.for() to ensure scheduler is shared across bundle boundaries
2383
+ // This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
2384
+ __publicField$1(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
2013
2385
  let Scheduler = _Scheduler;
2014
2386
  const getScheduler = () => Scheduler.get();
2015
2387
  if (hmrData) {
@@ -2017,11 +2389,9 @@ if (hmrData) {
2017
2389
  }
2018
2390
 
2019
2391
  function useFrame(callback, priorityOrOptions) {
2020
- const store = useStore();
2021
- const getRootId = React__namespace.useCallback(() => {
2022
- const state = store.getState();
2023
- return state.internal.rootId;
2024
- }, [store]);
2392
+ const store = React__namespace.useContext(context);
2393
+ const isInsideCanvas = store !== null;
2394
+ const scheduler = getScheduler();
2025
2395
  const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
2026
2396
  id: priorityOrOptions.id,
2027
2397
  phase: priorityOrOptions.phase,
@@ -2041,55 +2411,71 @@ function useFrame(callback, priorityOrOptions) {
2041
2411
  const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
2042
2412
  useIsomorphicLayoutEffect(() => {
2043
2413
  if (!callback) return;
2044
- const scheduler = getScheduler();
2045
- const rootId = getRootId();
2046
- const state = store.getState();
2047
- if (isLegacyPriority) {
2048
- state.internal.priority++;
2049
- let parentRoot = state.previousRoot;
2050
- while (parentRoot) {
2051
- const parentState = parentRoot.getState();
2052
- if (parentState?.internal) parentState.internal.priority++;
2053
- parentRoot = parentState?.previousRoot;
2054
- }
2055
- notifyDepreciated({
2056
- heading: "useFrame with numeric priority is deprecated",
2057
- 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 })',
2058
- link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
2059
- });
2060
- }
2061
- const wrappedCallback = (frameState, delta) => {
2062
- const localState = store.getState();
2063
- const mergedState = {
2064
- ...localState,
2065
- time: frameState.time,
2066
- delta: frameState.delta,
2067
- elapsed: frameState.elapsed,
2068
- frame: frameState.frame
2069
- };
2070
- callbackRef.current?.(mergedState, delta);
2071
- };
2072
- const unregister = scheduler.register(wrappedCallback, {
2073
- id,
2074
- rootId,
2075
- ...options
2076
- });
2077
- return () => {
2078
- unregister();
2414
+ if (isInsideCanvas) {
2415
+ const state = store.getState();
2416
+ const rootId = state.internal.rootId;
2079
2417
  if (isLegacyPriority) {
2080
- const currentState = store.getState();
2081
- if (currentState.internal) {
2082
- currentState.internal.priority--;
2083
- let parentRoot = currentState.previousRoot;
2084
- while (parentRoot) {
2085
- const parentState = parentRoot.getState();
2086
- if (parentState?.internal) parentState.internal.priority--;
2087
- parentRoot = parentState?.previousRoot;
2418
+ state.internal.priority++;
2419
+ let parentRoot = state.previousRoot;
2420
+ while (parentRoot) {
2421
+ const parentState = parentRoot.getState();
2422
+ if (parentState?.internal) parentState.internal.priority++;
2423
+ parentRoot = parentState?.previousRoot;
2424
+ }
2425
+ notifyDepreciated({
2426
+ heading: "useFrame with numeric priority is deprecated",
2427
+ 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 })',
2428
+ link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
2429
+ });
2430
+ }
2431
+ const wrappedCallback = (frameState, delta) => {
2432
+ const localState = store.getState();
2433
+ const mergedState = {
2434
+ ...localState,
2435
+ time: frameState.time,
2436
+ delta: frameState.delta,
2437
+ elapsed: frameState.elapsed,
2438
+ frame: frameState.frame
2439
+ };
2440
+ callbackRef.current?.(mergedState, delta);
2441
+ };
2442
+ const unregister = scheduler.register(wrappedCallback, {
2443
+ id,
2444
+ rootId,
2445
+ ...options
2446
+ });
2447
+ return () => {
2448
+ unregister();
2449
+ if (isLegacyPriority) {
2450
+ const currentState = store.getState();
2451
+ if (currentState.internal) {
2452
+ currentState.internal.priority--;
2453
+ let parentRoot = currentState.previousRoot;
2454
+ while (parentRoot) {
2455
+ const parentState = parentRoot.getState();
2456
+ if (parentState?.internal) parentState.internal.priority--;
2457
+ parentRoot = parentState?.previousRoot;
2458
+ }
2088
2459
  }
2089
2460
  }
2461
+ };
2462
+ } else {
2463
+ const registerOutside = () => {
2464
+ return scheduler.register((state, delta) => callbackRef.current?.(state, delta), { id, ...options });
2465
+ };
2466
+ if (scheduler.independent || scheduler.isReady) {
2467
+ return registerOutside();
2090
2468
  }
2091
- };
2092
- }, [store, id, optionsKey, isLegacyPriority]);
2469
+ let unregisterJob = null;
2470
+ const unsubReady = scheduler.onRootReady(() => {
2471
+ unregisterJob = registerOutside();
2472
+ });
2473
+ return () => {
2474
+ unsubReady();
2475
+ unregisterJob?.();
2476
+ };
2477
+ }
2478
+ }, [store, scheduler, id, optionsKey, isLegacyPriority, isInsideCanvas]);
2093
2479
  const isPaused = React__namespace.useSyncExternalStore(
2094
2480
  // Subscribe function
2095
2481
  React__namespace.useCallback(
@@ -2104,7 +2490,7 @@ function useFrame(callback, priorityOrOptions) {
2104
2490
  React__namespace.useCallback(() => false, [])
2105
2491
  );
2106
2492
  const controls = React__namespace.useMemo(() => {
2107
- const scheduler = getScheduler();
2493
+ const scheduler2 = getScheduler();
2108
2494
  return {
2109
2495
  /** The job's unique ID */
2110
2496
  id,
@@ -2112,7 +2498,7 @@ function useFrame(callback, priorityOrOptions) {
2112
2498
  * Access to the global scheduler for frame loop control.
2113
2499
  * Use for controlling the entire frame loop, adding phases, etc.
2114
2500
  */
2115
- scheduler,
2501
+ scheduler: scheduler2,
2116
2502
  /**
2117
2503
  * Manually step this job only.
2118
2504
  * Bypasses FPS limiting - always runs.
@@ -2360,6 +2746,16 @@ function useTextures() {
2360
2746
  }, [store]);
2361
2747
  }
2362
2748
 
2749
+ function useRenderTarget(width, height, options) {
2750
+ const isLegacy = useThree((s) => s.isLegacy);
2751
+ const size = useThree((s) => s.size);
2752
+ return React.useMemo(() => {
2753
+ const w = width ?? size.width;
2754
+ const h = height ?? size.height;
2755
+ return new webgpu.RenderTarget(w, h, options);
2756
+ }, [width, height, size.width, size.height, options, isLegacy]);
2757
+ }
2758
+
2363
2759
  function useStore() {
2364
2760
  const store = React.useContext(context);
2365
2761
  if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
@@ -2411,24 +2807,14 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
2411
2807
  getScheduler().step(timestamp);
2412
2808
  }
2413
2809
 
2414
- const version = "10.0.0-alpha.0";
2810
+ const version = "10.0.0-alpha.2";
2415
2811
  const packageData = {
2416
2812
  version: version};
2417
2813
 
2418
2814
  function Xb(Tt) {
2419
2815
  return Tt && Tt.__esModule && Object.prototype.hasOwnProperty.call(Tt, "default") ? Tt.default : Tt;
2420
2816
  }
2421
- var Rm = { exports: {} }, Og = { exports: {} };
2422
- /**
2423
- * @license React
2424
- * react-reconciler.production.js
2425
- *
2426
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2427
- *
2428
- * This source code is licensed under the MIT license found in the
2429
- * LICENSE file in the root directory of this source tree.
2430
- */
2431
- var _b;
2817
+ var Rm = { exports: {} }, Og = { exports: {} }, _b;
2432
2818
  function Kb() {
2433
2819
  return _b || (_b = 1, (function(Tt) {
2434
2820
  Tt.exports = function(m) {
@@ -3500,7 +3886,6 @@ Error generating stack: ` + l.message + `
3500
3886
  if (J === cl || J === jc) throw J;
3501
3887
  var Ge = Yn(29, J, null, P.mode);
3502
3888
  return Ge.lanes = H, Ge.return = P, Ge;
3503
- } finally {
3504
3889
  }
3505
3890
  };
3506
3891
  }
@@ -4154,7 +4539,6 @@ Error generating stack: ` + l.message + `
4154
4539
  var h = r.lastRenderedState, y = d(h, a);
4155
4540
  if (c.hasEagerState = true, c.eagerState = y, jn(y, h)) return go(t, r, c, 0), Ne === null && Bn(), false;
4156
4541
  } catch {
4157
- } finally {
4158
4542
  }
4159
4543
  if (a = yo(t, r, c, l), a !== null) return nt(a, t, l), ns(a, r, l), true;
4160
4544
  }
@@ -6575,10 +6959,7 @@ Error generating stack: ` + l.message + `
6575
6959
  function vr(t, r) {
6576
6960
  Sf(t, r), (t = t.alternate) && Sf(t, r);
6577
6961
  }
6578
- var ie = {}, Fm = React__default, tt = Tb__default, Lt = Object.assign, hc = Symbol.for("react.element"), zs = Symbol.for("react.transitional.element"), sa = Symbol.for("react.portal"), $a = Symbol.for("react.fragment"), kf = Symbol.for("react.strict_mode"), Cs = Symbol.for("react.profiler"), mc = Symbol.for("react.consumer"), Io = Symbol.for("react.context"), Zi = Symbol.for("react.forward_ref"), Va = Symbol.for("react.suspense"), Te = Symbol.for("react.suspense_list"), wf = Symbol.for("react.memo"), ua = Symbol.for("react.lazy");
6579
- var gc = Symbol.for("react.activity");
6580
- var $r = Symbol.for("react.memo_cache_sentinel");
6581
- var Pf = Symbol.iterator, xf = Symbol.for("react.client.reference"), ca = Array.isArray, M = Fm.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, Yp = m.rendererVersion, zf = m.rendererPackageName, Cf = m.extraDevToolsConfig, Ts = m.getPublicInstance, Hm = m.getRootHostContext, Xp = m.getChildHostContext, Am = m.prepareForCommit, _s = m.resetAfterCommit, Vr = m.createInstance;
6962
+ var ie = {}, Fm = React__default, tt = Tb__default, Lt = Object.assign, hc = Symbol.for("react.element"), zs = Symbol.for("react.transitional.element"), sa = Symbol.for("react.portal"), $a = Symbol.for("react.fragment"), kf = Symbol.for("react.strict_mode"), Cs = Symbol.for("react.profiler"), mc = Symbol.for("react.consumer"), Io = Symbol.for("react.context"), Zi = Symbol.for("react.forward_ref"), Va = Symbol.for("react.suspense"), Te = Symbol.for("react.suspense_list"), wf = Symbol.for("react.memo"), ua = Symbol.for("react.lazy"), gc = Symbol.for("react.activity"), $r = Symbol.for("react.memo_cache_sentinel"), Pf = Symbol.iterator, xf = Symbol.for("react.client.reference"), ca = Array.isArray, M = Fm.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, Yp = m.rendererVersion, zf = m.rendererPackageName, Cf = m.extraDevToolsConfig, Ts = m.getPublicInstance, Hm = m.getRootHostContext, Xp = m.getChildHostContext, Am = m.prepareForCommit, _s = m.resetAfterCommit, Vr = m.createInstance;
6582
6963
  m.cloneMutableInstance;
6583
6964
  var yc = m.appendInitialChild, Kp = m.finalizeInitialChildren, Rs = m.shouldSetTextContent, bc = m.createTextInstance;
6584
6965
  m.cloneMutableTextInstance;
@@ -6947,17 +7328,7 @@ No matching component was found for:
6947
7328
  }, Tt.exports.default = Tt.exports, Object.defineProperty(Tt.exports, "__esModule", { value: true });
6948
7329
  })(Og)), Og.exports;
6949
7330
  }
6950
- var Mg = { exports: {} };
6951
- /**
6952
- * @license React
6953
- * react-reconciler.development.js
6954
- *
6955
- * Copyright (c) Meta Platforms, Inc. and affiliates.
6956
- *
6957
- * This source code is licensed under the MIT license found in the
6958
- * LICENSE file in the root directory of this source tree.
6959
- */
6960
- var Rb;
7331
+ var Mg = { exports: {} }, Rb;
6961
7332
  function e0() {
6962
7333
  return Rb || (Rb = 1, (function(Tt) {
6963
7334
  process.env.NODE_ENV !== "production" && (Tt.exports = function(m) {
@@ -12724,10 +13095,7 @@ Check the render method of %s.`, G(di) || "Unknown")), i = zo(n), i.payload = {
12724
13095
  function Ic() {
12725
13096
  return di;
12726
13097
  }
12727
- var le = {}, qm = React__default, St = Tb__default, ze = Object.assign, Uh = Symbol.for("react.element"), Ho = Symbol.for("react.transitional.element"), Ao = Symbol.for("react.portal"), ol = Symbol.for("react.fragment"), Lc = Symbol.for("react.strict_mode"), Uf = Symbol.for("react.profiler"), ei = Symbol.for("react.consumer"), on = Symbol.for("react.context"), jn = Symbol.for("react.forward_ref"), Nc = Symbol.for("react.suspense"), Bf = Symbol.for("react.suspense_list"), al = Symbol.for("react.memo"), kt = Symbol.for("react.lazy");
12728
- var Ds = Symbol.for("react.activity");
12729
- var Bh = Symbol.for("react.memo_cache_sentinel");
12730
- var ni = Symbol.iterator, il = Symbol.for("react.client.reference"), fn = Array.isArray, x = qm.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, Jt = m.rendererVersion, Zt = m.rendererPackageName, jo = m.extraDevToolsConfig, ot = m.getPublicInstance, Zr = m.getRootHostContext, Dn = m.getChildHostContext, Ws = m.prepareForCommit, pa = m.resetAfterCommit, Fc = m.createInstance;
13098
+ var le = {}, qm = React__default, St = Tb__default, ze = Object.assign, Uh = Symbol.for("react.element"), Ho = Symbol.for("react.transitional.element"), Ao = Symbol.for("react.portal"), ol = Symbol.for("react.fragment"), Lc = Symbol.for("react.strict_mode"), Uf = Symbol.for("react.profiler"), ei = Symbol.for("react.consumer"), on = Symbol.for("react.context"), jn = Symbol.for("react.forward_ref"), Nc = Symbol.for("react.suspense"), Bf = Symbol.for("react.suspense_list"), al = Symbol.for("react.memo"), kt = Symbol.for("react.lazy"), Ds = Symbol.for("react.activity"), Bh = Symbol.for("react.memo_cache_sentinel"), ni = Symbol.iterator, il = Symbol.for("react.client.reference"), fn = Array.isArray, x = qm.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE, Jt = m.rendererVersion, Zt = m.rendererPackageName, jo = m.extraDevToolsConfig, ot = m.getPublicInstance, Zr = m.getRootHostContext, Dn = m.getChildHostContext, Ws = m.prepareForCommit, pa = m.resetAfterCommit, Fc = m.createInstance;
12731
13099
  m.cloneMutableInstance;
12732
13100
  var bn = m.appendInitialChild, Ue = m.finalizeInitialChildren, ue = m.shouldSetTextContent, Do = m.createTextInstance;
12733
13101
  m.cloneMutableTextInstance;
@@ -13695,15 +14063,6 @@ function n0() {
13695
14063
  var t0 = n0();
13696
14064
  const r0 = Xb(t0);
13697
14065
 
13698
- /**
13699
- * @license React
13700
- * react-reconciler-constants.production.js
13701
- *
13702
- * Copyright (c) Meta Platforms, Inc. and affiliates.
13703
- *
13704
- * This source code is licensed under the MIT license found in the
13705
- * LICENSE file in the root directory of this source tree.
13706
- */
13707
14066
  const t = 1, o = 8, r = 32, e = 2;
13708
14067
 
13709
14068
  function createReconciler(config) {
@@ -13712,7 +14071,8 @@ function createReconciler(config) {
13712
14071
  return reconciler2;
13713
14072
  }
13714
14073
  const NoEventPriority = 0;
13715
- const catalogue = {};
14074
+ const R3F_CATALOGUE = Symbol.for("@react-three/fiber.catalogue");
14075
+ const catalogue = globalThis[R3F_CATALOGUE] ?? (globalThis[R3F_CATALOGUE] = {});
13716
14076
  const PREFIX_REGEX = /^three(?=[A-Z])/;
13717
14077
  const toPascalCase = (type) => `${type[0].toUpperCase()}${type.slice(1)}`;
13718
14078
  let i = 0;
@@ -13729,10 +14089,11 @@ function extend(objects) {
13729
14089
  function validateInstance(type, props) {
13730
14090
  const name = toPascalCase(type);
13731
14091
  const target = catalogue[name];
13732
- if (type !== "primitive" && !target)
14092
+ if (type !== "primitive" && !target) {
13733
14093
  throw new Error(
13734
14094
  `R3F: ${name} is not part of the THREE namespace! Did you forget to extend? See: https://docs.pmnd.rs/react-three-fiber/api/objects#using-3rd-party-objects-declaratively`
13735
14095
  );
14096
+ }
13736
14097
  if (type === "primitive" && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`);
13737
14098
  if (props.args !== void 0 && !Array.isArray(props.args)) throw new Error("R3F: The args prop must be an array!");
13738
14099
  }
@@ -14183,14 +14544,14 @@ function createRoot(canvas) {
14183
14544
  if (!prevRoot) _roots.set(canvas, { fiber, store });
14184
14545
  let onCreated;
14185
14546
  let lastCamera;
14186
- let lastConfiguredProps = {};
14547
+ const lastConfiguredProps = {};
14187
14548
  let configured = false;
14188
14549
  let pending = null;
14189
14550
  return {
14190
14551
  async configure(props = {}) {
14191
14552
  let resolve;
14192
14553
  pending = new Promise((_resolve) => resolve = _resolve);
14193
- let {
14554
+ const {
14194
14555
  gl: glConfig,
14195
14556
  renderer: rendererConfig,
14196
14557
  size: propsSize,
@@ -14210,9 +14571,12 @@ function createRoot(canvas) {
14210
14571
  camera: cameraOptions,
14211
14572
  onPointerMissed,
14212
14573
  onDragOverMissed,
14213
- onDropMissed
14574
+ onDropMissed,
14575
+ autoUpdateFrustum = true,
14576
+ occlusion = false,
14577
+ _sizeProps
14214
14578
  } = props;
14215
- let state = store.getState();
14579
+ const state = store.getState();
14216
14580
  const defaultGPUProps = {
14217
14581
  canvas
14218
14582
  };
@@ -14227,7 +14591,9 @@ function createRoot(canvas) {
14227
14591
  let renderer = state.internal.actualRenderer;
14228
14592
  if (!state.internal.actualRenderer) {
14229
14593
  renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
14230
- await renderer.init();
14594
+ if (!renderer.hasInitialized?.()) {
14595
+ await renderer.init();
14596
+ }
14231
14597
  const backend = renderer.backend;
14232
14598
  const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14233
14599
  state.internal.actualRenderer = renderer;
@@ -14237,8 +14603,9 @@ function createRoot(canvas) {
14237
14603
  if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
14238
14604
  const { params, ...options } = raycastOptions || {};
14239
14605
  if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
14240
- if (!is.equ(params, raycaster.params, shallowLoose))
14606
+ if (!is.equ(params, raycaster.params, shallowLoose)) {
14241
14607
  applyProps(raycaster, { params: { ...raycaster.params, ...params } });
14608
+ }
14242
14609
  if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
14243
14610
  lastCamera = cameraOptions;
14244
14611
  const isCamera = cameraOptions?.isCamera;
@@ -14275,6 +14642,8 @@ function createRoot(canvas) {
14275
14642
  rootScene: scene,
14276
14643
  internal: { ...prev.internal, container: scene }
14277
14644
  }));
14645
+ const camera = state.camera;
14646
+ if (camera && !camera.parent) scene.add(camera);
14278
14647
  }
14279
14648
  if (events && !state.events.handlers) {
14280
14649
  state.set({ events: events(store) });
@@ -14287,9 +14656,14 @@ function createRoot(canvas) {
14287
14656
  wasEnabled = enabled;
14288
14657
  });
14289
14658
  }
14659
+ if (_sizeProps !== void 0) {
14660
+ state.set({ _sizeProps });
14661
+ }
14290
14662
  const size = computeInitialSize(canvas, propsSize);
14291
- if (!is.equ(size, state.size, shallowLoose)) {
14663
+ if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
14664
+ const wasImperative = state._sizeImperative;
14292
14665
  state.setSize(size.width, size.height, size.top, size.left);
14666
+ if (!wasImperative) state.set({ _sizeImperative: false });
14293
14667
  }
14294
14668
  if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
14295
14669
  state.setDpr(dpr);
@@ -14302,6 +14676,10 @@ function createRoot(canvas) {
14302
14676
  if (!state.onPointerMissed) state.set({ onPointerMissed });
14303
14677
  if (!state.onDragOverMissed) state.set({ onDragOverMissed });
14304
14678
  if (!state.onDropMissed) state.set({ onDropMissed });
14679
+ if (state.autoUpdateFrustum !== autoUpdateFrustum) state.set({ autoUpdateFrustum });
14680
+ if (occlusion && !state.internal.occlusionEnabled) {
14681
+ enableOcclusion(store);
14682
+ }
14305
14683
  if (performance && !is.equ(performance, lastConfiguredProps.performance, shallowLoose)) {
14306
14684
  state.set((state2) => ({ performance: { ...state2.performance, ...performance } }));
14307
14685
  lastConfiguredProps.performance = performance;
@@ -14355,15 +14733,17 @@ function createRoot(canvas) {
14355
14733
  } else if (is.obj(shadows)) {
14356
14734
  Object.assign(renderer.shadowMap, shadows);
14357
14735
  }
14358
- if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type)
14736
+ if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
14359
14737
  renderer.shadowMap.needsUpdate = true;
14738
+ }
14360
14739
  }
14361
14740
  if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
14362
14741
  if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
14363
14742
  lastConfiguredProps.textureColorSpace = textureColorSpace;
14364
14743
  }
14365
- if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose))
14744
+ if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
14366
14745
  applyProps(renderer, glConfig);
14746
+ }
14367
14747
  if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
14368
14748
  const currentRenderer = state.renderer;
14369
14749
  if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
@@ -14374,7 +14754,37 @@ function createRoot(canvas) {
14374
14754
  const rootId = state.internal.rootId;
14375
14755
  if (!rootId) {
14376
14756
  const newRootId = scheduler.generateRootId();
14377
- const unregisterRoot = scheduler.registerRoot(newRootId, () => store.getState());
14757
+ const unregisterRoot = scheduler.registerRoot(newRootId, {
14758
+ getState: () => store.getState(),
14759
+ onError: (err) => store.getState().setError(err)
14760
+ });
14761
+ const unregisterFrustum = scheduler.register(
14762
+ () => {
14763
+ const state2 = store.getState();
14764
+ if (state2.autoUpdateFrustum && state2.camera) {
14765
+ updateFrustum(state2.camera, state2.frustum);
14766
+ }
14767
+ },
14768
+ {
14769
+ id: `${newRootId}_frustum`,
14770
+ rootId: newRootId,
14771
+ phase: "preRender",
14772
+ system: true
14773
+ }
14774
+ );
14775
+ const unregisterVisibility = scheduler.register(
14776
+ () => {
14777
+ const state2 = store.getState();
14778
+ checkVisibility(state2);
14779
+ },
14780
+ {
14781
+ id: `${newRootId}_visibility`,
14782
+ rootId: newRootId,
14783
+ phase: "preRender",
14784
+ system: true,
14785
+ after: `${newRootId}_frustum`
14786
+ }
14787
+ );
14378
14788
  const unregisterRender = scheduler.register(
14379
14789
  () => {
14380
14790
  const state2 = store.getState();
@@ -14402,6 +14812,8 @@ function createRoot(canvas) {
14402
14812
  rootId: newRootId,
14403
14813
  unregisterRoot: () => {
14404
14814
  unregisterRoot();
14815
+ unregisterFrustum();
14816
+ unregisterVisibility();
14405
14817
  unregisterRender();
14406
14818
  },
14407
14819
  scheduler
@@ -14459,6 +14871,7 @@ function unmountComponentAtNode(canvas, callback) {
14459
14871
  const unregisterRoot = state.internal.unregisterRoot;
14460
14872
  if (unregisterRoot) unregisterRoot();
14461
14873
  state.events.disconnect?.();
14874
+ cleanupHelperGroup(root.store);
14462
14875
  renderer?.renderLists?.dispose?.();
14463
14876
  renderer?.forceContextLoss?.();
14464
14877
  if (renderer?.xr) state.xr.disconnect();
@@ -14598,6 +15011,9 @@ function CanvasImpl({
14598
15011
  onDragOverMissed,
14599
15012
  onDropMissed,
14600
15013
  onCreated,
15014
+ hmr,
15015
+ width,
15016
+ height,
14601
15017
  ...props
14602
15018
  }) {
14603
15019
  React__namespace.useMemo(() => extend(THREE), []);
@@ -14618,7 +15034,16 @@ function CanvasImpl({
14618
15034
  };
14619
15035
  }, [resize, hasInitialSizeRef.current]);
14620
15036
  const [containerRef, containerRect] = useMeasure__default(measureConfig);
14621
- if (!hasInitialSizeRef.current && containerRect.width > 0 && containerRect.height > 0) {
15037
+ const effectiveSize = React__namespace.useMemo(
15038
+ () => ({
15039
+ width: width ?? containerRect.width,
15040
+ height: height ?? containerRect.height,
15041
+ top: containerRect.top,
15042
+ left: containerRect.left
15043
+ }),
15044
+ [width, height, containerRect]
15045
+ );
15046
+ if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
14622
15047
  hasInitialSizeRef.current = true;
14623
15048
  }
14624
15049
  const canvasRef = React__namespace.useRef(null);
@@ -14637,8 +15062,23 @@ function CanvasImpl({
14637
15062
  useIsomorphicLayoutEffect(() => {
14638
15063
  effectActiveRef.current = true;
14639
15064
  const canvas = canvasRef.current;
14640
- if (containerRect.width > 0 && containerRect.height > 0 && canvas) {
14641
- if (!root.current) root.current = createRoot(canvas);
15065
+ if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
15066
+ if (!root.current) {
15067
+ root.current = createRoot(canvas);
15068
+ notifyAlpha({
15069
+ message: "React Three Fiber v10 is in ALPHA - expect breaking changes",
15070
+ link: "https://github.com/pmndrs/react-three-fiber/discussions"
15071
+ });
15072
+ const rootEntry = _roots.get(canvas);
15073
+ if (rootEntry?.store) {
15074
+ if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
15075
+ unsubscribeErrorRef.current = rootEntry.store.subscribe((state) => {
15076
+ if (state.error && effectActiveRef.current) {
15077
+ setError(state.error);
15078
+ }
15079
+ });
15080
+ }
15081
+ }
14642
15082
  async function run() {
14643
15083
  if (!effectActiveRef.current || !root.current) return;
14644
15084
  await root.current.configure({
@@ -14656,7 +15096,9 @@ function CanvasImpl({
14656
15096
  performance,
14657
15097
  raycaster,
14658
15098
  camera,
14659
- size: containerRect,
15099
+ size: effectiveSize,
15100
+ // Store size props for reset functionality
15101
+ _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
14660
15102
  // Pass mutable reference to onPointerMissed so it's free to update
14661
15103
  onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
14662
15104
  onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
@@ -14679,15 +15121,9 @@ function CanvasImpl({
14679
15121
  }
14680
15122
  });
14681
15123
  if (!effectActiveRef.current || !root.current) return;
14682
- const store = root.current.render(
15124
+ root.current.render(
14683
15125
  /* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsx(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: children ?? null }) }) })
14684
15126
  );
14685
- if (unsubscribeErrorRef.current) unsubscribeErrorRef.current();
14686
- unsubscribeErrorRef.current = store.subscribe((state) => {
14687
- if (state.error && effectActiveRef.current) {
14688
- setError(state.error);
14689
- }
14690
- });
14691
15127
  }
14692
15128
  run();
14693
15129
  }
@@ -14708,6 +15144,33 @@ function CanvasImpl({
14708
15144
  };
14709
15145
  }
14710
15146
  }, []);
15147
+ React__namespace.useEffect(() => {
15148
+ if (hmr === false) return;
15149
+ const canvas = canvasRef.current;
15150
+ if (!canvas) return;
15151
+ const handleHMR = () => {
15152
+ const rootEntry = _roots.get(canvas);
15153
+ if (rootEntry?.store) {
15154
+ rootEntry.store.setState((state) => ({
15155
+ nodes: {},
15156
+ uniforms: {},
15157
+ _hmrVersion: state._hmrVersion + 1
15158
+ }));
15159
+ }
15160
+ };
15161
+ 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) {
15162
+ const hot = undefined;
15163
+ hot.on("vite:afterUpdate", handleHMR);
15164
+ return () => hot.dispose?.(() => {
15165
+ });
15166
+ }
15167
+ if (typeof module !== "undefined" && module.hot) {
15168
+ const hot = module.hot;
15169
+ hot.addStatusHandler((status) => {
15170
+ if (status === "idle") handleHMR();
15171
+ });
15172
+ }
15173
+ }, [hmr]);
14711
15174
  const pointerEvents = eventSource ? "none" : "auto";
14712
15175
  return /* @__PURE__ */ jsxRuntime.jsx(
14713
15176
  "div",
@@ -14730,6 +15193,72 @@ function Canvas(props) {
14730
15193
  return /* @__PURE__ */ jsxRuntime.jsx(itsFine.FiberProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(CanvasImpl, { ...props }) });
14731
15194
  }
14732
15195
 
15196
+ var __defProp = Object.defineProperty;
15197
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
15198
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
15199
+ var _a;
15200
+ const INTERNAL_DATA = Symbol("ScopedStore.data");
15201
+ _a = INTERNAL_DATA;
15202
+ const _ScopedStore = class _ScopedStore {
15203
+ constructor(data) {
15204
+ __publicField(this, _a);
15205
+ this[INTERNAL_DATA] = data;
15206
+ return new Proxy(this, {
15207
+ get(target, prop, receiver) {
15208
+ if (typeof prop === "string") {
15209
+ if (prop === "scope" || prop === "has" || prop === "keys") {
15210
+ return Reflect.get(target, prop, receiver);
15211
+ }
15212
+ return target[INTERNAL_DATA][prop];
15213
+ }
15214
+ return Reflect.get(target, prop, receiver);
15215
+ },
15216
+ has(target, prop) {
15217
+ return typeof prop === "string" ? prop in target[INTERNAL_DATA] : Reflect.has(target, prop);
15218
+ },
15219
+ ownKeys(target) {
15220
+ return Reflect.ownKeys(target[INTERNAL_DATA]);
15221
+ },
15222
+ getOwnPropertyDescriptor(target, prop) {
15223
+ if (typeof prop === "string" && prop in target[INTERNAL_DATA]) {
15224
+ return {
15225
+ configurable: true,
15226
+ enumerable: true,
15227
+ value: target[INTERNAL_DATA][prop]
15228
+ };
15229
+ }
15230
+ return void 0;
15231
+ }
15232
+ });
15233
+ }
15234
+ /**
15235
+ * Access a nested scope by key.
15236
+ * If the key doesn't exist or isn't a scope object, returns an empty ScopedStore.
15237
+ */
15238
+ scope(key) {
15239
+ const data = this[INTERNAL_DATA][key];
15240
+ return new _ScopedStore(
15241
+ data && typeof data === "object" ? data : {}
15242
+ );
15243
+ }
15244
+ /**
15245
+ * Check if a key exists in the store.
15246
+ */
15247
+ has(key) {
15248
+ return key in this[INTERNAL_DATA];
15249
+ }
15250
+ /**
15251
+ * Get all keys in the store.
15252
+ */
15253
+ keys() {
15254
+ return Object.keys(this[INTERNAL_DATA]);
15255
+ }
15256
+ };
15257
+ let ScopedStore = _ScopedStore;
15258
+ function createScopedStore(data) {
15259
+ return new ScopedStore(data);
15260
+ }
15261
+
14733
15262
  function addTexture(set, key, value) {
14734
15263
  set((state) => {
14735
15264
  const newMap = new Map(state.textures);
@@ -14808,21 +15337,87 @@ function useCompareMemoize(value, deep) {
14808
15337
  const isUniformNode$1 = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
14809
15338
  function useUniforms(creatorOrScope, scope) {
14810
15339
  const store = useStore();
15340
+ const removeUniforms2 = React.useCallback(
15341
+ (names, targetScope) => {
15342
+ const nameArray = Array.isArray(names) ? names : [names];
15343
+ store.setState((state) => {
15344
+ if (targetScope) {
15345
+ const currentScope = { ...state.uniforms[targetScope] };
15346
+ for (const name of nameArray) delete currentScope[name];
15347
+ return { uniforms: { ...state.uniforms, [targetScope]: currentScope } };
15348
+ }
15349
+ const uniforms2 = { ...state.uniforms };
15350
+ for (const name of nameArray) if (isUniformNode$1(uniforms2[name])) delete uniforms2[name];
15351
+ return { uniforms: uniforms2 };
15352
+ });
15353
+ },
15354
+ [store]
15355
+ );
15356
+ const clearUniforms = React.useCallback(
15357
+ (targetScope) => {
15358
+ store.setState((state) => {
15359
+ if (targetScope && targetScope !== "root") {
15360
+ const { [targetScope]: _, ...rest } = state.uniforms;
15361
+ return { uniforms: rest };
15362
+ }
15363
+ if (targetScope === "root") {
15364
+ const uniforms2 = {};
15365
+ for (const [key, value] of Object.entries(state.uniforms)) {
15366
+ if (!isUniformNode$1(value)) uniforms2[key] = value;
15367
+ }
15368
+ return { uniforms: uniforms2 };
15369
+ }
15370
+ return { uniforms: {} };
15371
+ });
15372
+ },
15373
+ [store]
15374
+ );
15375
+ const rebuildUniforms = React.useCallback(
15376
+ (targetScope) => {
15377
+ store.setState((state) => {
15378
+ let newUniforms = state.uniforms;
15379
+ if (targetScope && targetScope !== "root") {
15380
+ const { [targetScope]: _, ...rest } = state.uniforms;
15381
+ newUniforms = rest;
15382
+ } else if (targetScope === "root") {
15383
+ newUniforms = {};
15384
+ for (const [key, value] of Object.entries(state.uniforms)) {
15385
+ if (!isUniformNode$1(value)) newUniforms[key] = value;
15386
+ }
15387
+ } else {
15388
+ newUniforms = {};
15389
+ }
15390
+ return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
15391
+ });
15392
+ },
15393
+ [store]
15394
+ );
14811
15395
  const inputForMemoization = React.useMemo(() => {
14812
- return is.fun(creatorOrScope) ? creatorOrScope(store.getState()) : creatorOrScope;
15396
+ if (is.fun(creatorOrScope)) {
15397
+ const state = store.getState();
15398
+ const wrappedState = {
15399
+ ...state,
15400
+ uniforms: createScopedStore(state.uniforms),
15401
+ nodes: createScopedStore(state.nodes)
15402
+ };
15403
+ return creatorOrScope(wrappedState);
15404
+ }
15405
+ return creatorOrScope;
14813
15406
  }, [creatorOrScope, store]);
14814
15407
  const memoizedInput = useCompareMemoize(inputForMemoization);
14815
- return React.useMemo(() => {
14816
- const state = store.getState();
14817
- const set = store.setState;
15408
+ const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
15409
+ const storeUniforms = useThree((s) => s.uniforms);
15410
+ const uniforms = React.useMemo(() => {
14818
15411
  if (memoizedInput === void 0) {
14819
- return state.uniforms;
15412
+ return storeUniforms;
14820
15413
  }
14821
15414
  if (typeof memoizedInput === "string") {
14822
- const scopeData = state.uniforms[memoizedInput];
15415
+ const scopeData = storeUniforms[memoizedInput];
14823
15416
  if (scopeData && !isUniformNode$1(scopeData)) return scopeData;
14824
15417
  return {};
14825
15418
  }
15419
+ const state = store.getState();
15420
+ const set = store.setState;
14826
15421
  if (typeof memoizedInput !== "object" || memoizedInput === null) {
14827
15422
  throw new Error("Invalid uniform input");
14828
15423
  }
@@ -14858,44 +15453,49 @@ function useUniforms(creatorOrScope, scope) {
14858
15453
  set((s) => ({
14859
15454
  uniforms: {
14860
15455
  ...s.uniforms,
14861
- [scope]: {
14862
- ...s.uniforms[scope],
14863
- ...result
14864
- }
15456
+ [scope]: { ...s.uniforms[scope], ...result }
14865
15457
  }
14866
15458
  }));
14867
15459
  } else {
14868
- set((s) => ({
14869
- uniforms: {
14870
- ...s.uniforms,
14871
- ...result
14872
- }
14873
- }));
15460
+ set((s) => ({ uniforms: { ...s.uniforms, ...result } }));
14874
15461
  }
14875
15462
  }
14876
15463
  return result;
14877
- }, [store, memoizedInput, scope]);
15464
+ }, [
15465
+ store,
15466
+ memoizedInput,
15467
+ scope,
15468
+ // Only include storeUniforms in deps for reader modes to enable reactivity
15469
+ isReader ? storeUniforms : null
15470
+ ]);
15471
+ return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
15472
+ }
15473
+ function rebuildAllUniforms(store, scope) {
15474
+ store.setState((state) => {
15475
+ let newUniforms = state.uniforms;
15476
+ if (scope && scope !== "root") {
15477
+ const { [scope]: _, ...rest } = state.uniforms;
15478
+ newUniforms = rest;
15479
+ } else if (scope === "root") {
15480
+ newUniforms = {};
15481
+ for (const [key, value] of Object.entries(state.uniforms)) {
15482
+ if (!isUniformNode$1(value)) newUniforms[key] = value;
15483
+ }
15484
+ } else {
15485
+ newUniforms = {};
15486
+ }
15487
+ return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
15488
+ });
14878
15489
  }
14879
15490
  function removeUniforms(set, names, scope) {
14880
15491
  set((state) => {
14881
15492
  if (scope) {
14882
15493
  const currentScope = { ...state.uniforms[scope] };
14883
- for (const name of names) {
14884
- delete currentScope[name];
14885
- }
14886
- return {
14887
- uniforms: {
14888
- ...state.uniforms,
14889
- [scope]: currentScope
14890
- }
14891
- };
15494
+ for (const name of names) delete currentScope[name];
15495
+ return { uniforms: { ...state.uniforms, [scope]: currentScope } };
14892
15496
  }
14893
15497
  const uniforms = { ...state.uniforms };
14894
- for (const name of names) {
14895
- if (isUniformNode$1(uniforms[name])) {
14896
- delete uniforms[name];
14897
- }
14898
- }
15498
+ for (const name of names) if (isUniformNode$1(uniforms[name])) delete uniforms[name];
14899
15499
  return { uniforms };
14900
15500
  });
14901
15501
  }
@@ -14909,9 +15509,7 @@ function clearRootUniforms(set) {
14909
15509
  set((state) => {
14910
15510
  const uniforms = {};
14911
15511
  for (const [key, value] of Object.entries(state.uniforms)) {
14912
- if (!isUniformNode$1(value)) {
14913
- uniforms[key] = value;
14914
- }
15512
+ if (!isUniformNode$1(value)) uniforms[key] = value;
14915
15513
  }
14916
15514
  return { uniforms };
14917
15515
  });
@@ -14986,21 +15584,82 @@ function useUniform(name, value) {
14986
15584
  const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
14987
15585
  function useNodes(creatorOrScope, scope) {
14988
15586
  const store = useStore();
14989
- return React.useMemo(() => {
14990
- const state = store.getState();
14991
- const set = store.setState;
15587
+ const removeNodes2 = React.useCallback(
15588
+ (names, targetScope) => {
15589
+ const nameArray = Array.isArray(names) ? names : [names];
15590
+ store.setState((state) => {
15591
+ if (targetScope) {
15592
+ const currentScope = { ...state.nodes[targetScope] };
15593
+ for (const name of nameArray) delete currentScope[name];
15594
+ return { nodes: { ...state.nodes, [targetScope]: currentScope } };
15595
+ }
15596
+ const nodes2 = { ...state.nodes };
15597
+ for (const name of nameArray) if (isTSLNode(nodes2[name])) delete nodes2[name];
15598
+ return { nodes: nodes2 };
15599
+ });
15600
+ },
15601
+ [store]
15602
+ );
15603
+ const clearNodes = React.useCallback(
15604
+ (targetScope) => {
15605
+ store.setState((state) => {
15606
+ if (targetScope && targetScope !== "root") {
15607
+ const { [targetScope]: _, ...rest } = state.nodes;
15608
+ return { nodes: rest };
15609
+ }
15610
+ if (targetScope === "root") {
15611
+ const nodes2 = {};
15612
+ for (const [key, value] of Object.entries(state.nodes)) {
15613
+ if (!isTSLNode(value)) nodes2[key] = value;
15614
+ }
15615
+ return { nodes: nodes2 };
15616
+ }
15617
+ return { nodes: {} };
15618
+ });
15619
+ },
15620
+ [store]
15621
+ );
15622
+ const rebuildNodes = React.useCallback(
15623
+ (targetScope) => {
15624
+ store.setState((state) => {
15625
+ let newNodes = state.nodes;
15626
+ if (targetScope && targetScope !== "root") {
15627
+ const { [targetScope]: _, ...rest } = state.nodes;
15628
+ newNodes = rest;
15629
+ } else if (targetScope === "root") {
15630
+ newNodes = {};
15631
+ for (const [key, value] of Object.entries(state.nodes)) {
15632
+ if (!isTSLNode(value)) newNodes[key] = value;
15633
+ }
15634
+ } else {
15635
+ newNodes = {};
15636
+ }
15637
+ return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
15638
+ });
15639
+ },
15640
+ [store]
15641
+ );
15642
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
15643
+ const storeNodes = useThree((s) => s.nodes);
15644
+ const hmrVersion = useThree((s) => s._hmrVersion);
15645
+ const nodes = React.useMemo(() => {
14992
15646
  if (creatorOrScope === void 0) {
14993
- return state.nodes;
15647
+ return storeNodes;
14994
15648
  }
14995
15649
  if (typeof creatorOrScope === "string") {
14996
- const scopeData = state.nodes[creatorOrScope];
14997
- if (scopeData && !isTSLNode(scopeData)) {
14998
- return scopeData;
14999
- }
15650
+ const scopeData = storeNodes[creatorOrScope];
15651
+ if (scopeData && !isTSLNode(scopeData)) return scopeData;
15000
15652
  return {};
15001
15653
  }
15654
+ const state = store.getState();
15655
+ const set = store.setState;
15002
15656
  const creator = creatorOrScope;
15003
- const created = creator(state);
15657
+ const wrappedState = {
15658
+ ...state,
15659
+ uniforms: createScopedStore(state.uniforms),
15660
+ nodes: createScopedStore(state.nodes)
15661
+ };
15662
+ const created = creator(wrappedState);
15004
15663
  const result = {};
15005
15664
  let hasNewNodes = false;
15006
15665
  if (scope) {
@@ -15009,9 +15668,7 @@ function useNodes(creatorOrScope, scope) {
15009
15668
  if (currentScope[name]) {
15010
15669
  result[name] = currentScope[name];
15011
15670
  } else {
15012
- if (typeof node.label === "function") {
15013
- node.setName(`${scope}.${name}`);
15014
- }
15671
+ if (typeof node.label === "function") node.setName(`${scope}.${name}`);
15015
15672
  result[name] = node;
15016
15673
  hasNewNodes = true;
15017
15674
  }
@@ -15020,10 +15677,7 @@ function useNodes(creatorOrScope, scope) {
15020
15677
  set((s) => ({
15021
15678
  nodes: {
15022
15679
  ...s.nodes,
15023
- [scope]: {
15024
- ...s.nodes[scope],
15025
- ...result
15026
- }
15680
+ [scope]: { ...s.nodes[scope], ...result }
15027
15681
  }
15028
15682
  }));
15029
15683
  }
@@ -15034,44 +15688,52 @@ function useNodes(creatorOrScope, scope) {
15034
15688
  if (existing && isTSLNode(existing)) {
15035
15689
  result[name] = existing;
15036
15690
  } else {
15037
- if (typeof node.label === "function") {
15038
- node.setName(name);
15039
- }
15691
+ if (typeof node.label === "function") node.setName(name);
15040
15692
  result[name] = node;
15041
15693
  hasNewNodes = true;
15042
15694
  }
15043
15695
  }
15044
15696
  if (hasNewNodes) {
15045
- set((s) => ({
15046
- nodes: {
15047
- ...s.nodes,
15048
- ...result
15049
- }
15050
- }));
15697
+ set((s) => ({ nodes: { ...s.nodes, ...result } }));
15051
15698
  }
15052
15699
  return result;
15053
- }, [store, typeof creatorOrScope === "string" ? creatorOrScope : scope]);
15700
+ }, [
15701
+ store,
15702
+ typeof creatorOrScope === "string" ? creatorOrScope : scope,
15703
+ // Only include storeNodes in deps for reader modes to enable reactivity
15704
+ // Creator mode intentionally excludes it to avoid re-running creator on unrelated changes
15705
+ isReader ? storeNodes : null,
15706
+ // Include hmrVersion for creator modes to allow rebuildNodes() to bust the cache
15707
+ isReader ? null : hmrVersion
15708
+ ]);
15709
+ return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
15710
+ }
15711
+ function rebuildAllNodes(store, scope) {
15712
+ store.setState((state) => {
15713
+ let newNodes = state.nodes;
15714
+ if (scope && scope !== "root") {
15715
+ const { [scope]: _, ...rest } = state.nodes;
15716
+ newNodes = rest;
15717
+ } else if (scope === "root") {
15718
+ newNodes = {};
15719
+ for (const [key, value] of Object.entries(state.nodes)) {
15720
+ if (!isTSLNode(value)) newNodes[key] = value;
15721
+ }
15722
+ } else {
15723
+ newNodes = {};
15724
+ }
15725
+ return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
15726
+ });
15054
15727
  }
15055
15728
  function removeNodes(set, names, scope) {
15056
15729
  set((state) => {
15057
15730
  if (scope) {
15058
15731
  const currentScope = { ...state.nodes[scope] };
15059
- for (const name of names) {
15060
- delete currentScope[name];
15061
- }
15062
- return {
15063
- nodes: {
15064
- ...state.nodes,
15065
- [scope]: currentScope
15066
- }
15067
- };
15732
+ for (const name of names) delete currentScope[name];
15733
+ return { nodes: { ...state.nodes, [scope]: currentScope } };
15068
15734
  }
15069
15735
  const nodes = { ...state.nodes };
15070
- for (const name of names) {
15071
- if (isTSLNode(nodes[name])) {
15072
- delete nodes[name];
15073
- }
15074
- }
15736
+ for (const name of names) if (isTSLNode(nodes[name])) delete nodes[name];
15075
15737
  return { nodes };
15076
15738
  });
15077
15739
  }
@@ -15085,9 +15747,7 @@ function clearRootNodes(set) {
15085
15747
  set((state) => {
15086
15748
  const nodes = {};
15087
15749
  for (const [key, value] of Object.entries(state.nodes)) {
15088
- if (!isTSLNode(value)) {
15089
- nodes[key] = value;
15090
- }
15750
+ if (!isTSLNode(value)) nodes[key] = value;
15091
15751
  }
15092
15752
  return { nodes };
15093
15753
  });
@@ -15099,7 +15759,12 @@ function useLocalNodes(creator) {
15099
15759
  const textures = useThree((s) => s.textures);
15100
15760
  return React.useMemo(() => {
15101
15761
  const state = store.getState();
15102
- return creator(state);
15762
+ const wrappedState = {
15763
+ ...state,
15764
+ uniforms: createScopedStore(state.uniforms),
15765
+ nodes: createScopedStore(state.nodes)
15766
+ };
15767
+ return creator(wrappedState);
15103
15768
  }, [store, creator, uniforms, nodes, textures]);
15104
15769
  }
15105
15770
 
@@ -15113,6 +15778,10 @@ function usePostProcessing(mainCB, setupCB) {
15113
15778
  mainCBRef.current = mainCB;
15114
15779
  setupCBRef.current = setupCB;
15115
15780
  const [rebuildVersion, setRebuildVersion] = React.useState(0);
15781
+ React.useEffect(() => {
15782
+ callbacksRanRef.current = false;
15783
+ scenePassCacheRef.current = null;
15784
+ }, []);
15116
15785
  const clearPasses = React.useCallback(() => {
15117
15786
  store.setState({ passes: {} });
15118
15787
  }, [store]);
@@ -15223,6 +15892,7 @@ exports.createEvents = createEvents;
15223
15892
  exports.createPointerEvents = createPointerEvents;
15224
15893
  exports.createPortal = createPortal;
15225
15894
  exports.createRoot = createRoot;
15895
+ exports.createScopedStore = createScopedStore;
15226
15896
  exports.createStore = createStore;
15227
15897
  exports.createTextureOperations = createTextureOperations;
15228
15898
  exports.detach = detach;
@@ -15249,6 +15919,8 @@ exports.isRenderer = isRenderer;
15249
15919
  exports.isTexture = isTexture;
15250
15920
  exports.isVectorLike = isVectorLike;
15251
15921
  exports.prepare = prepare;
15922
+ exports.rebuildAllNodes = rebuildAllNodes;
15923
+ exports.rebuildAllUniforms = rebuildAllUniforms;
15252
15924
  exports.reconciler = reconciler;
15253
15925
  exports.removeInteractivity = removeInteractivity;
15254
15926
  exports.removeNodes = removeNodes;
@@ -15256,6 +15928,7 @@ exports.removeUniforms = removeUniforms;
15256
15928
  exports.resolve = resolve;
15257
15929
  exports.unmountComponentAtNode = unmountComponentAtNode;
15258
15930
  exports.updateCamera = updateCamera;
15931
+ exports.updateFrustum = updateFrustum;
15259
15932
  exports.useBridge = useBridge;
15260
15933
  exports.useFrame = useFrame;
15261
15934
  exports.useGraph = useGraph;
@@ -15266,6 +15939,7 @@ exports.useLocalNodes = useLocalNodes;
15266
15939
  exports.useMutableCallback = useMutableCallback;
15267
15940
  exports.useNodes = useNodes;
15268
15941
  exports.usePostProcessing = usePostProcessing;
15942
+ exports.useRenderTarget = useRenderTarget;
15269
15943
  exports.useStore = useStore;
15270
15944
  exports.useTexture = useTexture;
15271
15945
  exports.useTextures = useTextures;