@react-three/fiber 10.0.0-alpha.1 → 10.0.0-canary.1b98c17

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.
@@ -6,6 +6,12 @@ const jsxRuntime = require('react/jsx-runtime');
6
6
  const React = require('react');
7
7
  const useMeasure = require('react-use-measure');
8
8
  const itsFine = require('its-fine');
9
+ const fiber = require('@react-three/fiber');
10
+ const GroundedSkybox_js = require('three/examples/jsm/objects/GroundedSkybox.js');
11
+ const HDRLoader_js = require('three/examples/jsm/loaders/HDRLoader.js');
12
+ const EXRLoader_js = require('three/examples/jsm/loaders/EXRLoader.js');
13
+ const UltraHDRLoader_js = require('three/examples/jsm/loaders/UltraHDRLoader.js');
14
+ const gainmapJs = require('@monogrid/gainmap-js');
9
15
  const Tb = require('scheduler');
10
16
  const traditional = require('zustand/traditional');
11
17
  const suspendReact = require('suspend-react');
@@ -13,6 +19,7 @@ const lite = require('dequal/lite');
13
19
  require('zustand/shallow');
14
20
  const tsl = require('three/tsl');
15
21
 
22
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
16
23
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
17
24
 
18
25
  function _interopNamespaceCompat(e) {
@@ -66,9 +73,392 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
66
73
  WebGLRenderer: WebGLRenderer
67
74
  }, [webgpu__namespace]);
68
75
 
69
- var __defProp$2 = Object.defineProperty;
70
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
71
- var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
76
+ const primaryRegistry = /* @__PURE__ */ new Map();
77
+ const pendingSubscribers = /* @__PURE__ */ new Map();
78
+ function registerPrimary(id, renderer, store) {
79
+ if (primaryRegistry.has(id)) {
80
+ console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
81
+ }
82
+ const entry = { renderer, store };
83
+ primaryRegistry.set(id, entry);
84
+ const subscribers = pendingSubscribers.get(id);
85
+ if (subscribers) {
86
+ subscribers.forEach((callback) => callback(entry));
87
+ pendingSubscribers.delete(id);
88
+ }
89
+ return () => {
90
+ const currentEntry = primaryRegistry.get(id);
91
+ if (currentEntry?.renderer === renderer) {
92
+ primaryRegistry.delete(id);
93
+ }
94
+ };
95
+ }
96
+ function getPrimary(id) {
97
+ return primaryRegistry.get(id);
98
+ }
99
+ function waitForPrimary(id, timeout = 5e3) {
100
+ const existing = primaryRegistry.get(id);
101
+ if (existing) {
102
+ return Promise.resolve(existing);
103
+ }
104
+ return new Promise((resolve, reject) => {
105
+ const timeoutId = setTimeout(() => {
106
+ const subscribers = pendingSubscribers.get(id);
107
+ if (subscribers) {
108
+ const index = subscribers.indexOf(callback);
109
+ if (index !== -1) subscribers.splice(index, 1);
110
+ if (subscribers.length === 0) pendingSubscribers.delete(id);
111
+ }
112
+ reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
113
+ }, timeout);
114
+ const callback = (entry) => {
115
+ clearTimeout(timeoutId);
116
+ resolve(entry);
117
+ };
118
+ if (!pendingSubscribers.has(id)) {
119
+ pendingSubscribers.set(id, []);
120
+ }
121
+ pendingSubscribers.get(id).push(callback);
122
+ });
123
+ }
124
+ function hasPrimary(id) {
125
+ return primaryRegistry.has(id);
126
+ }
127
+ function unregisterPrimary(id) {
128
+ primaryRegistry.delete(id);
129
+ }
130
+ function getPrimaryIds() {
131
+ return Array.from(primaryRegistry.keys());
132
+ }
133
+
134
+ const presetsObj = {
135
+ apartment: "lebombo_1k.hdr",
136
+ city: "potsdamer_platz_1k.hdr",
137
+ dawn: "kiara_1_dawn_1k.hdr",
138
+ forest: "forest_slope_1k.hdr",
139
+ lobby: "st_fagans_interior_1k.hdr",
140
+ night: "dikhololo_night_1k.hdr",
141
+ park: "rooitou_park_1k.hdr",
142
+ studio: "studio_small_03_1k.hdr",
143
+ sunset: "venice_sunset_1k.hdr",
144
+ warehouse: "empty_warehouse_01_1k.hdr"
145
+ };
146
+
147
+ const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
148
+ const isArray = (arr) => Array.isArray(arr);
149
+ const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
150
+ function useEnvironment({
151
+ files = defaultFiles,
152
+ path = "",
153
+ preset = void 0,
154
+ colorSpace = void 0,
155
+ extensions
156
+ } = {}) {
157
+ if (preset) {
158
+ validatePreset(preset);
159
+ files = presetsObj[preset];
160
+ path = CUBEMAP_ROOT;
161
+ }
162
+ const multiFile = isArray(files);
163
+ const { extension, isCubemap } = getExtension(files);
164
+ const loader = getLoader$1(extension);
165
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
166
+ const renderer = fiber.useThree((state) => state.renderer);
167
+ React.useLayoutEffect(() => {
168
+ if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
169
+ function clearGainmapTexture() {
170
+ fiber.useLoader.clear(loader, multiFile ? [files] : files);
171
+ }
172
+ renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
173
+ }, [extension, files, loader, multiFile, renderer.domElement]);
174
+ const loaderResult = fiber.useLoader(
175
+ loader,
176
+ multiFile ? [files] : files,
177
+ (loader2) => {
178
+ if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
179
+ loader2.setRenderer?.(renderer);
180
+ }
181
+ loader2.setPath?.(path);
182
+ if (extensions) extensions(loader2);
183
+ }
184
+ );
185
+ let texture = multiFile ? (
186
+ // @ts-ignore
187
+ loaderResult[0]
188
+ ) : loaderResult;
189
+ if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
190
+ texture = texture.renderTarget?.texture;
191
+ }
192
+ texture.mapping = isCubemap ? webgpu.CubeReflectionMapping : webgpu.EquirectangularReflectionMapping;
193
+ texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
194
+ return texture;
195
+ }
196
+ const preloadDefaultOptions = {
197
+ files: defaultFiles,
198
+ path: "",
199
+ preset: void 0,
200
+ extensions: void 0
201
+ };
202
+ useEnvironment.preload = (preloadOptions) => {
203
+ const options = { ...preloadDefaultOptions, ...preloadOptions };
204
+ let { files, path = "" } = options;
205
+ const { preset, extensions } = options;
206
+ if (preset) {
207
+ validatePreset(preset);
208
+ files = presetsObj[preset];
209
+ path = CUBEMAP_ROOT;
210
+ }
211
+ const { extension } = getExtension(files);
212
+ if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
213
+ throw new Error("useEnvironment: Preloading gainmaps is not supported");
214
+ }
215
+ const loader = getLoader$1(extension);
216
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
217
+ fiber.useLoader.preload(loader, isArray(files) ? [files] : files, (loader2) => {
218
+ loader2.setPath?.(path);
219
+ if (extensions) extensions(loader2);
220
+ });
221
+ };
222
+ const clearDefaultOptins = {
223
+ files: defaultFiles,
224
+ preset: void 0
225
+ };
226
+ useEnvironment.clear = (clearOptions) => {
227
+ const options = { ...clearDefaultOptins, ...clearOptions };
228
+ let { files } = options;
229
+ const { preset } = options;
230
+ if (preset) {
231
+ validatePreset(preset);
232
+ files = presetsObj[preset];
233
+ }
234
+ const { extension } = getExtension(files);
235
+ const loader = getLoader$1(extension);
236
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
237
+ fiber.useLoader.clear(loader, isArray(files) ? [files] : files);
238
+ };
239
+ function validatePreset(preset) {
240
+ if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
241
+ }
242
+ function getExtension(files) {
243
+ const isCubemap = isArray(files) && files.length === 6;
244
+ const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
245
+ const firstEntry = isArray(files) ? files[0] : files;
246
+ const extension = isCubemap ? "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
247
+ return { extension, isCubemap, isGainmap };
248
+ }
249
+ function getLoader$1(extension) {
250
+ const loader = extension === "cube" ? webgpu.CubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
251
+ return loader;
252
+ }
253
+
254
+ const isRef$1 = (obj) => obj.current && obj.current.isScene;
255
+ const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
256
+ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
257
+ sceneProps = {
258
+ backgroundBlurriness: 0,
259
+ backgroundIntensity: 1,
260
+ backgroundRotation: [0, 0, 0],
261
+ environmentIntensity: 1,
262
+ environmentRotation: [0, 0, 0],
263
+ ...sceneProps
264
+ };
265
+ const target = resolveScene(scene || defaultScene);
266
+ const oldbg = target.background;
267
+ const oldenv = target.environment;
268
+ const oldSceneProps = {
269
+ // @ts-ignore
270
+ backgroundBlurriness: target.backgroundBlurriness,
271
+ // @ts-ignore
272
+ backgroundIntensity: target.backgroundIntensity,
273
+ // @ts-ignore
274
+ backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
275
+ // @ts-ignore
276
+ environmentIntensity: target.environmentIntensity,
277
+ // @ts-ignore
278
+ environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
279
+ };
280
+ if (background !== "only") target.environment = texture;
281
+ if (background) target.background = texture;
282
+ fiber.applyProps(target, sceneProps);
283
+ return () => {
284
+ if (background !== "only") target.environment = oldenv;
285
+ if (background) target.background = oldbg;
286
+ fiber.applyProps(target, oldSceneProps);
287
+ };
288
+ }
289
+ function EnvironmentMap({ scene, background = false, map, ...config }) {
290
+ const defaultScene = fiber.useThree((state) => state.scene);
291
+ React__namespace.useLayoutEffect(() => {
292
+ if (map) return setEnvProps(background, scene, defaultScene, map, config);
293
+ });
294
+ return null;
295
+ }
296
+ function EnvironmentCube({
297
+ background = false,
298
+ scene,
299
+ blur,
300
+ backgroundBlurriness,
301
+ backgroundIntensity,
302
+ backgroundRotation,
303
+ environmentIntensity,
304
+ environmentRotation,
305
+ ...rest
306
+ }) {
307
+ const texture = useEnvironment(rest);
308
+ const defaultScene = fiber.useThree((state) => state.scene);
309
+ React__namespace.useLayoutEffect(() => {
310
+ return setEnvProps(background, scene, defaultScene, texture, {
311
+ backgroundBlurriness: blur ?? backgroundBlurriness,
312
+ backgroundIntensity,
313
+ backgroundRotation,
314
+ environmentIntensity,
315
+ environmentRotation
316
+ });
317
+ });
318
+ React__namespace.useEffect(() => {
319
+ return () => {
320
+ texture.dispose();
321
+ };
322
+ }, [texture]);
323
+ return null;
324
+ }
325
+ function EnvironmentPortal({
326
+ children,
327
+ near = 0.1,
328
+ far = 1e3,
329
+ resolution = 256,
330
+ frames = 1,
331
+ map,
332
+ background = false,
333
+ blur,
334
+ backgroundBlurriness,
335
+ backgroundIntensity,
336
+ backgroundRotation,
337
+ environmentIntensity,
338
+ environmentRotation,
339
+ scene,
340
+ files,
341
+ path,
342
+ preset = void 0,
343
+ extensions
344
+ }) {
345
+ const gl = fiber.useThree((state) => state.gl);
346
+ const defaultScene = fiber.useThree((state) => state.scene);
347
+ const camera = React__namespace.useRef(null);
348
+ const [virtualScene] = React__namespace.useState(() => new webgpu.Scene());
349
+ const fbo = React__namespace.useMemo(() => {
350
+ const fbo2 = new webgpu.WebGLCubeRenderTarget(resolution);
351
+ fbo2.texture.type = webgpu.HalfFloatType;
352
+ return fbo2;
353
+ }, [resolution]);
354
+ React__namespace.useEffect(() => {
355
+ return () => {
356
+ fbo.dispose();
357
+ };
358
+ }, [fbo]);
359
+ React__namespace.useLayoutEffect(() => {
360
+ if (frames === 1) {
361
+ const autoClear = gl.autoClear;
362
+ gl.autoClear = true;
363
+ camera.current.update(gl, virtualScene);
364
+ gl.autoClear = autoClear;
365
+ }
366
+ return setEnvProps(background, scene, defaultScene, fbo.texture, {
367
+ backgroundBlurriness: blur ?? backgroundBlurriness,
368
+ backgroundIntensity,
369
+ backgroundRotation,
370
+ environmentIntensity,
371
+ environmentRotation
372
+ });
373
+ }, [
374
+ children,
375
+ virtualScene,
376
+ fbo.texture,
377
+ scene,
378
+ defaultScene,
379
+ background,
380
+ frames,
381
+ gl,
382
+ blur,
383
+ backgroundBlurriness,
384
+ backgroundIntensity,
385
+ backgroundRotation,
386
+ environmentIntensity,
387
+ environmentRotation
388
+ ]);
389
+ let count = 1;
390
+ fiber.useFrame(() => {
391
+ if (frames === Infinity || count < frames) {
392
+ const autoClear = gl.autoClear;
393
+ gl.autoClear = true;
394
+ camera.current.update(gl, virtualScene);
395
+ gl.autoClear = autoClear;
396
+ count++;
397
+ }
398
+ });
399
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fiber.createPortal(
400
+ /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
401
+ children,
402
+ /* @__PURE__ */ jsxRuntime.jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
403
+ files || preset ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { background: true, map, extensions }) : null
404
+ ] }),
405
+ virtualScene
406
+ ) });
407
+ }
408
+ function EnvironmentGround(props) {
409
+ const textureDefault = useEnvironment(props);
410
+ const texture = props.map || textureDefault;
411
+ React__namespace.useMemo(() => fiber.extend({ GroundProjectedEnvImpl: GroundedSkybox_js.GroundedSkybox }), []);
412
+ React__namespace.useEffect(() => {
413
+ return () => {
414
+ textureDefault.dispose();
415
+ };
416
+ }, [textureDefault]);
417
+ const height = props.ground?.height ?? 15;
418
+ const radius = props.ground?.radius ?? 60;
419
+ const scale = props.ground?.scale ?? 1e3;
420
+ const args = React__namespace.useMemo(
421
+ () => [texture, height, radius],
422
+ [texture, height, radius]
423
+ );
424
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
425
+ /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props, map: texture }),
426
+ /* @__PURE__ */ jsxRuntime.jsx("groundProjectedEnvImpl", { args, scale })
427
+ ] });
428
+ }
429
+ function EnvironmentColor({ color, scene }) {
430
+ const defaultScene = fiber.useThree((state) => state.scene);
431
+ React__namespace.useLayoutEffect(() => {
432
+ if (color === void 0) return;
433
+ const target = resolveScene(scene || defaultScene);
434
+ const oldBg = target.background;
435
+ target.background = new webgpu.Color(color);
436
+ return () => {
437
+ target.background = oldBg;
438
+ };
439
+ });
440
+ return null;
441
+ }
442
+ function EnvironmentDualSource(props) {
443
+ const { backgroundFiles, ...envProps } = props;
444
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
445
+ /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...envProps, background: false }),
446
+ /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
447
+ ] });
448
+ }
449
+ function Environment(props) {
450
+ if (props.color && !props.files && !props.preset && !props.map) {
451
+ return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentColor, { ...props });
452
+ }
453
+ if (props.backgroundFiles && props.backgroundFiles !== props.files) {
454
+ return /* @__PURE__ */ jsxRuntime.jsx(EnvironmentDualSource, { ...props });
455
+ }
456
+ return props.ground ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsxRuntime.jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsxRuntime.jsx(EnvironmentCube, { ...props });
457
+ }
458
+
459
+ var __defProp$3 = Object.defineProperty;
460
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
461
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
72
462
  const act = React__namespace["act"];
73
463
  const useIsomorphicLayoutEffect = /* @__PURE__ */ (() => typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative"))() ? React__namespace.useLayoutEffect : React__namespace.useEffect;
74
464
  function useMutableCallback(fn) {
@@ -100,7 +490,7 @@ const ErrorBoundary = /* @__PURE__ */ (() => {
100
490
  return _a = class extends React__namespace.Component {
101
491
  constructor() {
102
492
  super(...arguments);
103
- __publicField$2(this, "state", { error: false });
493
+ __publicField$3(this, "state", { error: false });
104
494
  }
105
495
  componentDidCatch(err) {
106
496
  this.props.set(err);
@@ -108,7 +498,7 @@ const ErrorBoundary = /* @__PURE__ */ (() => {
108
498
  render() {
109
499
  return this.state.error ? null : this.props.children;
110
500
  }
111
- }, __publicField$2(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
501
+ }, __publicField$3(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
112
502
  })();
113
503
 
114
504
  const is = {
@@ -245,7 +635,8 @@ function prepare(target, root, type, props) {
245
635
  object,
246
636
  eventCount: 0,
247
637
  handlers: {},
248
- isHidden: false
638
+ isHidden: false,
639
+ deferredRefs: []
249
640
  };
250
641
  if (object) object.__r3f = instance;
251
642
  }
@@ -294,7 +685,7 @@ function createOcclusionObserverNode(store, uniform) {
294
685
  let occlusionSetupPromise = null;
295
686
  function enableOcclusion(store) {
296
687
  const state = store.getState();
297
- const { internal, renderer, rootScene } = state;
688
+ const { internal, renderer } = state;
298
689
  if (internal.occlusionEnabled || occlusionSetupPromise) return;
299
690
  const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
300
691
  if (!hasOcclusionSupport) {
@@ -457,6 +848,22 @@ function hasVisibilityHandlers(handlers) {
457
848
  return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
458
849
  }
459
850
 
851
+ const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
852
+ function fromRef(ref) {
853
+ return { [FROM_REF]: ref };
854
+ }
855
+ function isFromRef(value) {
856
+ return value !== null && typeof value === "object" && FROM_REF in value;
857
+ }
858
+
859
+ const ONCE = Symbol.for("@react-three/fiber.once");
860
+ function once(...args) {
861
+ return { [ONCE]: args.length ? args : true };
862
+ }
863
+ function isOnce(value) {
864
+ return value !== null && typeof value === "object" && ONCE in value;
865
+ }
866
+
460
867
  const RESERVED_PROPS = [
461
868
  "children",
462
869
  "key",
@@ -527,7 +934,7 @@ function getMemoizedPrototype(root) {
527
934
  ctor = new root.constructor();
528
935
  MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
529
936
  }
530
- } catch (e) {
937
+ } catch {
531
938
  }
532
939
  return ctor;
533
940
  }
@@ -558,7 +965,7 @@ function applyProps(object, props) {
558
965
  const rootState = instance && findInitialRoot(instance).getState();
559
966
  const prevHandlers = instance?.eventCount;
560
967
  for (const prop in props) {
561
- let value = props[prop];
968
+ const value = props[prop];
562
969
  if (RESERVED_PROPS.includes(prop)) continue;
563
970
  if (instance && EVENT_REGEX.test(prop)) {
564
971
  if (typeof value === "function") instance.handlers[prop] = value;
@@ -573,6 +980,25 @@ function applyProps(object, props) {
573
980
  continue;
574
981
  }
575
982
  if (value === void 0) continue;
983
+ if (isFromRef(value)) {
984
+ instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
985
+ continue;
986
+ }
987
+ if (isOnce(value)) {
988
+ if (instance?.appliedOnce?.has(prop)) continue;
989
+ if (instance) {
990
+ instance.appliedOnce ?? (instance.appliedOnce = /* @__PURE__ */ new Set());
991
+ instance.appliedOnce.add(prop);
992
+ }
993
+ const { root: targetRoot, key: targetKey } = resolve(object, prop);
994
+ const args = value[ONCE];
995
+ if (typeof targetRoot[targetKey] === "function") {
996
+ targetRoot[targetKey](...args === true ? [] : args);
997
+ } else if (args !== true && args.length > 0) {
998
+ targetRoot[targetKey] = args[0];
999
+ }
1000
+ continue;
1001
+ }
576
1002
  let { root, key, target } = resolve(object, prop);
577
1003
  if (target === void 0 && (typeof root !== "object" || root === null)) {
578
1004
  throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
@@ -595,7 +1021,10 @@ function applyProps(object, props) {
595
1021
  else target.set(value);
596
1022
  } else {
597
1023
  root[key] = value;
598
- if (rootState && !rootState.linear && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
1024
+ if (key.endsWith("Node") && root.isMaterial) {
1025
+ root.needsUpdate = true;
1026
+ }
1027
+ if (rootState && rootState.renderer?.outputColorSpace === webgpu.SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
599
1028
  root[key].format === webgpu.RGBAFormat && root[key].type === webgpu.UnsignedByteType) {
600
1029
  root[key].colorSpace = rootState.textureColorSpace;
601
1030
  }
@@ -628,38 +1057,60 @@ function applyProps(object, props) {
628
1057
  return object;
629
1058
  }
630
1059
 
1060
+ const DEFAULT_POINTER_ID = 0;
1061
+ const XR_POINTER_ID_START = 1e3;
1062
+ function getPointerState(internal, pointerId) {
1063
+ let state = internal.pointerMap.get(pointerId);
1064
+ if (!state) {
1065
+ state = {
1066
+ hovered: /* @__PURE__ */ new Map(),
1067
+ captured: /* @__PURE__ */ new Map(),
1068
+ initialClick: [0, 0],
1069
+ initialHits: []
1070
+ };
1071
+ internal.pointerMap.set(pointerId, state);
1072
+ }
1073
+ return state;
1074
+ }
1075
+ function getPointerId(event) {
1076
+ return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
1077
+ }
631
1078
  function makeId(event) {
632
1079
  return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
633
1080
  }
634
- function releaseInternalPointerCapture(capturedMap, obj, captures, pointerId) {
635
- const captureData = captures.get(obj);
1081
+ function releaseInternalPointerCapture(internal, obj, pointerId) {
1082
+ const pointerState = internal.pointerMap.get(pointerId);
1083
+ if (!pointerState) return;
1084
+ const captureData = pointerState.captured.get(obj);
636
1085
  if (captureData) {
637
- captures.delete(obj);
638
- if (captures.size === 0) {
639
- capturedMap.delete(pointerId);
640
- captureData.target.releasePointerCapture(pointerId);
641
- }
1086
+ pointerState.captured.delete(obj);
1087
+ captureData.target.releasePointerCapture(pointerId);
642
1088
  }
643
1089
  }
644
1090
  function removeInteractivity(store, object) {
645
1091
  const { internal } = store.getState();
646
1092
  internal.interaction = internal.interaction.filter((o) => o !== object);
647
- internal.initialHits = internal.initialHits.filter((o) => o !== object);
648
- internal.hovered.forEach((value, key) => {
649
- if (value.eventObject === object || value.object === object) {
650
- internal.hovered.delete(key);
1093
+ for (const [pointerId, pointerState] of internal.pointerMap) {
1094
+ pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
1095
+ pointerState.hovered.forEach((value, key) => {
1096
+ if (value.eventObject === object || value.object === object) {
1097
+ pointerState.hovered.delete(key);
1098
+ }
1099
+ });
1100
+ if (pointerState.captured.has(object)) {
1101
+ releaseInternalPointerCapture(internal, object, pointerId);
651
1102
  }
652
- });
653
- internal.capturedMap.forEach((captures, pointerId) => {
654
- releaseInternalPointerCapture(internal.capturedMap, object, captures, pointerId);
655
- });
1103
+ }
656
1104
  unregisterVisibility(store, object);
657
1105
  }
658
1106
  function createEvents(store) {
659
- function calculateDistance(event) {
1107
+ function calculateDistance(event, pointerId) {
660
1108
  const { internal } = store.getState();
661
- const dx = event.offsetX - internal.initialClick[0];
662
- const dy = event.offsetY - internal.initialClick[1];
1109
+ const pointerState = internal.pointerMap.get(pointerId);
1110
+ if (!pointerState) return 0;
1111
+ const [initialX, initialY] = pointerState.initialClick;
1112
+ const dx = event.offsetX - initialX;
1113
+ const dy = event.offsetY - initialY;
663
1114
  return Math.round(Math.sqrt(dx * dx + dy * dy));
664
1115
  }
665
1116
  function filterPointerEvents(objects) {
@@ -695,6 +1146,15 @@ function createEvents(store) {
695
1146
  return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
696
1147
  }
697
1148
  let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
1149
+ const aInteractivePriority = a.object.userData?.interactivePriority;
1150
+ const bInteractivePriority = b.object.userData?.interactivePriority;
1151
+ if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
1152
+ if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
1153
+ if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
1154
+ if (aInteractivePriority !== bInteractivePriority) {
1155
+ return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
1156
+ }
1157
+ }
698
1158
  const aState = getRootState(a.object);
699
1159
  const bState = getRootState(b.object);
700
1160
  const aPriority = aState?.events?.priority ?? 1;
@@ -710,14 +1170,19 @@ function createEvents(store) {
710
1170
  for (const hit of hits) {
711
1171
  let eventObject = hit.object;
712
1172
  while (eventObject) {
713
- if (eventObject.__r3f?.eventCount)
1173
+ if (eventObject.__r3f?.eventCount) {
714
1174
  intersections.push({ ...hit, eventObject });
1175
+ }
715
1176
  eventObject = eventObject.parent;
716
1177
  }
717
1178
  }
718
- if ("pointerId" in event && state.internal.capturedMap.has(event.pointerId)) {
719
- for (let captureData of state.internal.capturedMap.get(event.pointerId).values()) {
720
- if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1179
+ if ("pointerId" in event) {
1180
+ const pointerId = event.pointerId;
1181
+ const pointerState = state.internal.pointerMap.get(pointerId);
1182
+ if (pointerState?.captured.size) {
1183
+ for (const captureData of pointerState.captured.values()) {
1184
+ if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
1185
+ }
721
1186
  }
722
1187
  }
723
1188
  return intersections;
@@ -730,28 +1195,26 @@ function createEvents(store) {
730
1195
  if (state) {
731
1196
  const { raycaster, pointer, camera, internal } = state;
732
1197
  const unprojectedPoint = new webgpu.Vector3(pointer.x, pointer.y, 0).unproject(camera);
733
- const hasPointerCapture = (id) => internal.capturedMap.get(id)?.has(hit.eventObject) ?? false;
1198
+ const hasPointerCapture = (id) => {
1199
+ const pointerState = internal.pointerMap.get(id);
1200
+ return pointerState?.captured.has(hit.eventObject) ?? false;
1201
+ };
734
1202
  const setPointerCapture = (id) => {
735
1203
  const captureData = { intersection: hit, target: event.target };
736
- if (internal.capturedMap.has(id)) {
737
- internal.capturedMap.get(id).set(hit.eventObject, captureData);
738
- } else {
739
- internal.capturedMap.set(id, /* @__PURE__ */ new Map([[hit.eventObject, captureData]]));
740
- }
1204
+ const pointerState = getPointerState(internal, id);
1205
+ pointerState.captured.set(hit.eventObject, captureData);
741
1206
  event.target.setPointerCapture(id);
742
1207
  };
743
1208
  const releasePointerCapture = (id) => {
744
- const captures = internal.capturedMap.get(id);
745
- if (captures) {
746
- releaseInternalPointerCapture(internal.capturedMap, hit.eventObject, captures, id);
747
- }
1209
+ releaseInternalPointerCapture(internal, hit.eventObject, id);
748
1210
  };
749
- let extractEventProps = {};
750
- for (let prop in event) {
751
- let property = event[prop];
1211
+ const extractEventProps = {};
1212
+ for (const prop in event) {
1213
+ const property = event[prop];
752
1214
  if (typeof property !== "function") extractEventProps[prop] = property;
753
1215
  }
754
- let raycastEvent = {
1216
+ const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
1217
+ const raycastEvent = {
755
1218
  ...hit,
756
1219
  ...extractEventProps,
757
1220
  pointer,
@@ -761,18 +1224,19 @@ function createEvents(store) {
761
1224
  unprojectedPoint,
762
1225
  ray: raycaster.ray,
763
1226
  camera,
1227
+ pointerId: eventPointerId,
764
1228
  // Hijack stopPropagation, which just sets a flag
765
1229
  stopPropagation() {
766
- const capturesForPointer = "pointerId" in event && internal.capturedMap.get(event.pointerId);
1230
+ const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
767
1231
  if (
768
1232
  // ...if this pointer hasn't been captured
769
- !capturesForPointer || // ... or if the hit object is capturing the pointer
770
- capturesForPointer.has(hit.eventObject)
1233
+ !pointerState?.captured.size || // ... or if the hit object is capturing the pointer
1234
+ pointerState.captured.has(hit.eventObject)
771
1235
  ) {
772
1236
  raycastEvent.stopped = localState.stopped = true;
773
- if (internal.hovered.size && Array.from(internal.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1237
+ if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
774
1238
  const higher = intersections.slice(0, intersections.indexOf(hit));
775
- cancelPointer([...higher, hit]);
1239
+ cancelPointer([...higher, hit], eventPointerId);
776
1240
  }
777
1241
  }
778
1242
  },
@@ -788,15 +1252,18 @@ function createEvents(store) {
788
1252
  }
789
1253
  return intersections;
790
1254
  }
791
- function cancelPointer(intersections) {
1255
+ function cancelPointer(intersections, pointerId) {
792
1256
  const { internal } = store.getState();
793
- for (const hoveredObj of internal.hovered.values()) {
1257
+ const pid = pointerId ?? DEFAULT_POINTER_ID;
1258
+ const pointerState = internal.pointerMap.get(pid);
1259
+ if (!pointerState) return;
1260
+ for (const [hoveredId, hoveredObj] of pointerState.hovered) {
794
1261
  if (!intersections.length || !intersections.find(
795
1262
  (hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
796
1263
  )) {
797
1264
  const eventObject = hoveredObj.eventObject;
798
1265
  const instance = eventObject.__r3f;
799
- internal.hovered.delete(makeId(hoveredObj));
1266
+ pointerState.hovered.delete(hoveredId);
800
1267
  if (instance?.eventCount) {
801
1268
  const handlers = instance.handlers;
802
1269
  const data = { ...hoveredObj, intersections };
@@ -825,41 +1292,118 @@ function createEvents(store) {
825
1292
  instance?.handlers.onDropMissed?.(event);
826
1293
  }
827
1294
  }
1295
+ function cleanupPointer(pointerId) {
1296
+ const { internal } = store.getState();
1297
+ const pointerState = internal.pointerMap.get(pointerId);
1298
+ if (pointerState) {
1299
+ for (const [, hoveredObj] of pointerState.hovered) {
1300
+ const eventObject = hoveredObj.eventObject;
1301
+ const instance = eventObject.__r3f;
1302
+ if (instance?.eventCount) {
1303
+ const handlers = instance.handlers;
1304
+ const data = { ...hoveredObj, intersections: [] };
1305
+ handlers.onPointerOut?.(data);
1306
+ handlers.onPointerLeave?.(data);
1307
+ }
1308
+ }
1309
+ internal.pointerMap.delete(pointerId);
1310
+ }
1311
+ internal.pointerDirty.delete(pointerId);
1312
+ }
1313
+ function processDeferredPointer(event, pointerId) {
1314
+ const state = store.getState();
1315
+ const { internal } = state;
1316
+ if (!state.events.enabled) return;
1317
+ const filter = filterPointerEvents;
1318
+ const hits = intersect(event, filter);
1319
+ cancelPointer(hits, pointerId);
1320
+ function onIntersect(data) {
1321
+ const eventObject = data.eventObject;
1322
+ const instance = eventObject.__r3f;
1323
+ if (!instance?.eventCount) return;
1324
+ const handlers = instance.handlers;
1325
+ if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1326
+ const id = makeId(data);
1327
+ const pointerState = getPointerState(internal, pointerId);
1328
+ const hoveredItem = pointerState.hovered.get(id);
1329
+ if (!hoveredItem) {
1330
+ pointerState.hovered.set(id, data);
1331
+ handlers.onPointerOver?.(data);
1332
+ handlers.onPointerEnter?.(data);
1333
+ } else if (hoveredItem.stopped) {
1334
+ data.stopPropagation();
1335
+ }
1336
+ }
1337
+ handlers.onPointerMove?.(data);
1338
+ }
1339
+ handleIntersects(hits, event, 0, onIntersect);
1340
+ }
828
1341
  function handlePointer(name) {
829
1342
  switch (name) {
830
1343
  case "onPointerLeave":
831
- case "onPointerCancel":
832
1344
  case "onDragLeave":
833
1345
  return () => cancelPointer([]);
1346
+ // Global cancel of these events
1347
+ case "onPointerCancel":
1348
+ return (event) => {
1349
+ const pointerId = getPointerId(event);
1350
+ cleanupPointer(pointerId);
1351
+ };
834
1352
  case "onLostPointerCapture":
835
1353
  return (event) => {
836
1354
  const { internal } = store.getState();
837
- if ("pointerId" in event && internal.capturedMap.has(event.pointerId)) {
1355
+ const pointerId = getPointerId(event);
1356
+ const pointerState = internal.pointerMap.get(pointerId);
1357
+ if (pointerState?.captured.size) {
838
1358
  requestAnimationFrame(() => {
839
- if (internal.capturedMap.has(event.pointerId)) {
840
- internal.capturedMap.delete(event.pointerId);
841
- cancelPointer([]);
1359
+ const pointerState2 = internal.pointerMap.get(pointerId);
1360
+ if (pointerState2?.captured.size) {
1361
+ pointerState2.captured.clear();
842
1362
  }
1363
+ cancelPointer([], pointerId);
843
1364
  });
844
1365
  }
845
1366
  };
846
1367
  }
847
1368
  return function handleEvent(event) {
848
1369
  const state = store.getState();
849
- const { onPointerMissed, onDragOverMissed, onDropMissed, internal } = state;
1370
+ const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
1371
+ const pointerId = getPointerId(event);
850
1372
  internal.lastEvent.current = event;
851
- if (!state.events.enabled) return;
1373
+ if (!events.enabled) return;
852
1374
  const isPointerMove = name === "onPointerMove";
853
1375
  const isDragOver = name === "onDragOver";
854
1376
  const isDrop = name === "onDrop";
855
1377
  const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
1378
+ const isPointerDown = name === "onPointerDown";
1379
+ const isPointerUp = name === "onPointerUp";
1380
+ const isWheel = name === "onWheel";
1381
+ const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
1382
+ if (isPointerMove && canDeferRaycasts) {
1383
+ events.compute?.(event, state);
1384
+ internal.pointerDirty.set(pointerId, event);
1385
+ return;
1386
+ }
1387
+ if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
1388
+ events.compute?.(event, state);
1389
+ internal.pointerDirty.set(pointerId, event);
1390
+ return;
1391
+ }
1392
+ if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
1393
+ const deferredEvent = internal.pointerDirty.get(pointerId);
1394
+ internal.pointerDirty.delete(pointerId);
1395
+ processDeferredPointer(deferredEvent, pointerId);
1396
+ }
856
1397
  const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
857
1398
  const hits = intersect(event, filter);
858
- const delta = isClickEvent ? calculateDistance(event) : 0;
859
- if (name === "onPointerDown") {
860
- internal.initialClick = [event.offsetX, event.offsetY];
861
- internal.initialHits = hits.map((hit) => hit.eventObject);
862
- }
1399
+ const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
1400
+ if (isPointerDown) {
1401
+ const pointerState2 = getPointerState(internal, pointerId);
1402
+ pointerState2.initialClick = [event.offsetX, event.offsetY];
1403
+ pointerState2.initialHits = hits.map((hit) => hit.eventObject);
1404
+ }
1405
+ const pointerState = internal.pointerMap.get(pointerId);
1406
+ const initialHits = pointerState?.initialHits ?? [];
863
1407
  if (isClickEvent && !hits.length) {
864
1408
  if (delta <= 2) {
865
1409
  pointerMissed(event, internal.interaction);
@@ -874,7 +1418,9 @@ function createEvents(store) {
874
1418
  dropMissed(event, internal.interaction);
875
1419
  if (onDropMissed) onDropMissed(event);
876
1420
  }
877
- if (isPointerMove || isDragOver) cancelPointer(hits);
1421
+ if (isPointerMove || isDragOver) {
1422
+ cancelPointer(hits, pointerId);
1423
+ }
878
1424
  function onIntersect(data) {
879
1425
  const eventObject = data.eventObject;
880
1426
  const instance = eventObject.__r3f;
@@ -883,9 +1429,10 @@ function createEvents(store) {
883
1429
  if (isPointerMove) {
884
1430
  if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
885
1431
  const id = makeId(data);
886
- const hoveredItem = internal.hovered.get(id);
1432
+ const pointerState2 = getPointerState(internal, pointerId);
1433
+ const hoveredItem = pointerState2.hovered.get(id);
887
1434
  if (!hoveredItem) {
888
- internal.hovered.set(id, data);
1435
+ pointerState2.hovered.set(id, data);
889
1436
  handlers.onPointerOver?.(data);
890
1437
  handlers.onPointerEnter?.(data);
891
1438
  } else if (hoveredItem.stopped) {
@@ -895,9 +1442,10 @@ function createEvents(store) {
895
1442
  handlers.onPointerMove?.(data);
896
1443
  } else if (isDragOver) {
897
1444
  const id = makeId(data);
898
- const hoveredItem = internal.hovered.get(id);
1445
+ const pointerState2 = getPointerState(internal, pointerId);
1446
+ const hoveredItem = pointerState2.hovered.get(id);
899
1447
  if (!hoveredItem) {
900
- internal.hovered.set(id, data);
1448
+ pointerState2.hovered.set(id, data);
901
1449
  handlers.onDragOverEnter?.(data);
902
1450
  } else if (hoveredItem.stopped) {
903
1451
  data.stopPropagation();
@@ -908,18 +1456,18 @@ function createEvents(store) {
908
1456
  } else {
909
1457
  const handler = handlers[name];
910
1458
  if (handler) {
911
- if (!isClickEvent || internal.initialHits.includes(eventObject)) {
1459
+ if (!isClickEvent || initialHits.includes(eventObject)) {
912
1460
  pointerMissed(
913
1461
  event,
914
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1462
+ internal.interaction.filter((object) => !initialHits.includes(object))
915
1463
  );
916
1464
  handler(data);
917
1465
  }
918
1466
  } else {
919
- if (isClickEvent && internal.initialHits.includes(eventObject)) {
1467
+ if (isClickEvent && initialHits.includes(eventObject)) {
920
1468
  pointerMissed(
921
1469
  event,
922
- internal.interaction.filter((object) => !internal.initialHits.includes(object))
1470
+ internal.interaction.filter((object) => !initialHits.includes(object))
923
1471
  );
924
1472
  }
925
1473
  }
@@ -928,7 +1476,15 @@ function createEvents(store) {
928
1476
  handleIntersects(hits, event, delta, onIntersect);
929
1477
  };
930
1478
  }
931
- return { handlePointer };
1479
+ function flushDeferredPointers() {
1480
+ const { internal, events } = store.getState();
1481
+ if (!events.frameTimedRaycasts) return;
1482
+ for (const [pointerId, event] of internal.pointerDirty) {
1483
+ processDeferredPointer(event, pointerId);
1484
+ }
1485
+ internal.pointerDirty.clear();
1486
+ }
1487
+ return { handlePointer, flushDeferredPointers, processDeferredPointer };
932
1488
  }
933
1489
  const DOM_EVENTS = {
934
1490
  onClick: ["click", false],
@@ -947,11 +1503,16 @@ const DOM_EVENTS = {
947
1503
  onLostPointerCapture: ["lostpointercapture", true]
948
1504
  };
949
1505
  function createPointerEvents(store) {
950
- const { handlePointer } = createEvents(store);
1506
+ const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
1507
+ let nextXRPointerId = XR_POINTER_ID_START;
1508
+ const xrPointers = /* @__PURE__ */ new Map();
951
1509
  return {
952
1510
  priority: 1,
953
1511
  enabled: true,
954
- compute(event, state, previous) {
1512
+ frameTimedRaycasts: true,
1513
+ alwaysFireOnScroll: true,
1514
+ updateOnFrame: false,
1515
+ compute(event, state) {
955
1516
  state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
956
1517
  state.raycaster.setFromCamera(state.pointer, state.camera);
957
1518
  },
@@ -960,11 +1521,33 @@ function createPointerEvents(store) {
960
1521
  (acc, key) => ({ ...acc, [key]: handlePointer(key) }),
961
1522
  {}
962
1523
  ),
963
- update: () => {
1524
+ update: (pointerId) => {
1525
+ const { events, internal } = store.getState();
1526
+ if (!events.handlers) return;
1527
+ if (pointerId !== void 0) {
1528
+ const event = internal.pointerDirty.get(pointerId);
1529
+ if (event) {
1530
+ internal.pointerDirty.delete(pointerId);
1531
+ processDeferredPointer(event, pointerId);
1532
+ } else if (internal.lastEvent?.current) {
1533
+ processDeferredPointer(internal.lastEvent.current, pointerId);
1534
+ }
1535
+ } else {
1536
+ flushDeferredPointers();
1537
+ if (internal.lastEvent?.current) {
1538
+ events.handlers.onPointerMove(internal.lastEvent.current);
1539
+ }
1540
+ }
1541
+ },
1542
+ flush: () => {
964
1543
  const { events, internal } = store.getState();
965
- if (internal.lastEvent?.current && events.handlers) events.handlers.onPointerMove(internal.lastEvent.current);
1544
+ flushDeferredPointers();
1545
+ if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
1546
+ events.handlers.onPointerMove(internal.lastEvent.current);
1547
+ }
966
1548
  },
967
1549
  connect: (target) => {
1550
+ if (!target) return;
968
1551
  const { set, events } = store.getState();
969
1552
  events.disconnect?.();
970
1553
  set((state) => ({ events: { ...state.events, connected: target } }));
@@ -988,6 +1571,32 @@ function createPointerEvents(store) {
988
1571
  }
989
1572
  set((state) => ({ events: { ...state.events, connected: void 0 } }));
990
1573
  }
1574
+ },
1575
+ registerPointer: (config) => {
1576
+ const pointerId = nextXRPointerId++;
1577
+ xrPointers.set(pointerId, config);
1578
+ const { internal } = store.getState();
1579
+ getPointerState(internal, pointerId);
1580
+ return pointerId;
1581
+ },
1582
+ unregisterPointer: (pointerId) => {
1583
+ xrPointers.delete(pointerId);
1584
+ const { internal } = store.getState();
1585
+ const pointerState = internal.pointerMap.get(pointerId);
1586
+ if (pointerState) {
1587
+ for (const [, hoveredObj] of pointerState.hovered) {
1588
+ const eventObject = hoveredObj.eventObject;
1589
+ const instance = eventObject.__r3f;
1590
+ if (instance?.eventCount) {
1591
+ const handlers = instance.handlers;
1592
+ const data = { ...hoveredObj, intersections: [] };
1593
+ handlers.onPointerOut?.(data);
1594
+ handlers.onPointerLeave?.(data);
1595
+ }
1596
+ }
1597
+ internal.pointerMap.delete(pointerId);
1598
+ }
1599
+ internal.pointerDirty.delete(pointerId);
991
1600
  }
992
1601
  };
993
1602
  }
@@ -1049,300 +1658,26 @@ function notifyAlpha({ message, link }) {
1049
1658
  }
1050
1659
  }
1051
1660
 
1052
- const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
1053
- const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
1054
- const createStore = (invalidate, advance) => {
1055
- const rootStore = traditional.createWithEqualityFn((set, get) => {
1056
- const position = new webgpu.Vector3();
1057
- const defaultTarget = new webgpu.Vector3();
1058
- const tempTarget = new webgpu.Vector3();
1059
- function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
1060
- const { width, height, top, left } = size;
1061
- const aspect = width / height;
1062
- if (target.isVector3) tempTarget.copy(target);
1063
- else tempTarget.set(...target);
1064
- const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
1065
- if (isOrthographicCamera(camera)) {
1066
- return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
1067
- } else {
1068
- const fov = camera.fov * Math.PI / 180;
1069
- const h = 2 * Math.tan(fov / 2) * distance;
1070
- const w = h * (width / height);
1071
- return { width: w, height: h, top, left, factor: width / w, distance, aspect };
1072
- }
1073
- }
1074
- let performanceTimeout = void 0;
1075
- const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
1076
- const pointer = new webgpu.Vector2();
1077
- const rootState = {
1078
- set,
1079
- get,
1080
- // Mock objects that have to be configured
1081
- gl: null,
1082
- renderer: null,
1083
- camera: null,
1084
- frustum: new webgpu.Frustum(),
1085
- autoUpdateFrustum: true,
1086
- raycaster: null,
1087
- events: { priority: 1, enabled: true, connected: false },
1088
- scene: null,
1089
- rootScene: null,
1090
- xr: null,
1091
- inspector: null,
1092
- invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
1093
- advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
1094
- legacy: false,
1095
- linear: false,
1096
- flat: false,
1097
- textureColorSpace: "srgb",
1098
- isLegacy: false,
1099
- webGPUSupported: false,
1100
- isNative: false,
1101
- controls: null,
1102
- pointer,
1103
- mouse: pointer,
1104
- frameloop: "always",
1105
- onPointerMissed: void 0,
1106
- onDragOverMissed: void 0,
1107
- onDropMissed: void 0,
1108
- performance: {
1109
- current: 1,
1110
- min: 0.5,
1111
- max: 1,
1112
- debounce: 200,
1113
- regress: () => {
1114
- const state2 = get();
1115
- if (performanceTimeout) clearTimeout(performanceTimeout);
1116
- if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
1117
- performanceTimeout = setTimeout(
1118
- () => setPerformanceCurrent(get().performance.max),
1119
- state2.performance.debounce
1120
- );
1121
- }
1122
- },
1123
- size: { width: 0, height: 0, top: 0, left: 0 },
1124
- viewport: {
1125
- initialDpr: 0,
1126
- dpr: 0,
1127
- width: 0,
1128
- height: 0,
1129
- top: 0,
1130
- left: 0,
1131
- aspect: 0,
1132
- distance: 0,
1133
- factor: 0,
1134
- getCurrentViewport
1135
- },
1136
- setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
1137
- setSize: (width, height, top = 0, left = 0) => {
1138
- const camera = get().camera;
1139
- const size = { width, height, top, left };
1140
- set((state2) => ({ size, viewport: { ...state2.viewport, ...getCurrentViewport(camera, defaultTarget, size) } }));
1141
- },
1142
- setDpr: (dpr) => set((state2) => {
1143
- const resolved = calculateDpr(dpr);
1144
- return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
1145
- }),
1146
- setFrameloop: (frameloop = "always") => {
1147
- set(() => ({ frameloop }));
1148
- },
1149
- setError: (error) => set(() => ({ error })),
1150
- error: null,
1151
- //* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
1152
- uniforms: {},
1153
- nodes: {},
1154
- textures: /* @__PURE__ */ new Map(),
1155
- postProcessing: null,
1156
- passes: {},
1157
- previousRoot: void 0,
1158
- internal: {
1159
- // Events
1160
- interaction: [],
1161
- hovered: /* @__PURE__ */ new Map(),
1162
- subscribers: [],
1163
- initialClick: [0, 0],
1164
- initialHits: [],
1165
- capturedMap: /* @__PURE__ */ new Map(),
1166
- lastEvent: React__namespace.createRef(),
1167
- // Visibility tracking (onFramed, onOccluded, onVisible)
1168
- visibilityRegistry: /* @__PURE__ */ new Map(),
1169
- // Occlusion system (WebGPU only)
1170
- occlusionEnabled: false,
1171
- occlusionObserver: null,
1172
- occlusionCache: /* @__PURE__ */ new Map(),
1173
- helperGroup: null,
1174
- // Updates
1175
- active: false,
1176
- frames: 0,
1177
- priority: 0,
1178
- subscribe: (ref, priority, store) => {
1179
- const internal = get().internal;
1180
- internal.priority = internal.priority + (priority > 0 ? 1 : 0);
1181
- internal.subscribers.push({ ref, priority, store });
1182
- internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
1183
- return () => {
1184
- const internal2 = get().internal;
1185
- if (internal2?.subscribers) {
1186
- internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
1187
- internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
1188
- }
1189
- };
1190
- },
1191
- // Renderer Storage (single source of truth)
1192
- actualRenderer: null,
1193
- // Scheduler for useFrameNext (initialized in renderer.tsx)
1194
- scheduler: null
1195
- }
1196
- };
1197
- return rootState;
1198
- });
1199
- const state = rootStore.getState();
1200
- Object.defineProperty(state, "gl", {
1201
- get() {
1202
- const currentState = rootStore.getState();
1203
- if (!currentState.isLegacy && currentState.internal.actualRenderer) {
1204
- const stack = new Error().stack || "";
1205
- const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
1206
- if (!isInternalAccess) {
1207
- const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
1208
- notifyDepreciated({
1209
- heading: "Accessing state.gl in WebGPU mode",
1210
- body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
1211
- });
1212
- }
1213
- }
1214
- return currentState.internal.actualRenderer;
1215
- },
1216
- set(value) {
1217
- rootStore.getState().internal.actualRenderer = value;
1218
- },
1219
- enumerable: true,
1220
- configurable: true
1221
- });
1222
- Object.defineProperty(state, "renderer", {
1223
- get() {
1224
- return rootStore.getState().internal.actualRenderer;
1225
- },
1226
- set(value) {
1227
- rootStore.getState().internal.actualRenderer = value;
1228
- },
1229
- enumerable: true,
1230
- configurable: true
1231
- });
1232
- let oldScene = state.scene;
1233
- rootStore.subscribe(() => {
1234
- const currentState = rootStore.getState();
1235
- const { scene, rootScene, set } = currentState;
1236
- if (scene !== oldScene) {
1237
- oldScene = scene;
1238
- if (scene?.isScene && scene !== rootScene) {
1239
- set({ rootScene: scene });
1240
- }
1241
- }
1242
- });
1243
- let oldSize = state.size;
1244
- let oldDpr = state.viewport.dpr;
1245
- let oldCamera = state.camera;
1246
- rootStore.subscribe(() => {
1247
- const { camera, size, viewport, set, internal } = rootStore.getState();
1248
- const actualRenderer = internal.actualRenderer;
1249
- if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
1250
- oldSize = size;
1251
- oldDpr = viewport.dpr;
1252
- updateCamera(camera, size);
1253
- if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
1254
- const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
1255
- actualRenderer.setSize(size.width, size.height, updateStyle);
1256
- }
1257
- if (camera !== oldCamera) {
1258
- oldCamera = camera;
1259
- const { rootScene } = rootStore.getState();
1260
- if (camera && rootScene && !camera.parent) {
1261
- rootScene.add(camera);
1262
- }
1263
- set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
1264
- const currentState = rootStore.getState();
1265
- if (currentState.autoUpdateFrustum && camera) {
1266
- updateFrustum(camera, currentState.frustum);
1267
- }
1268
- }
1269
- });
1270
- rootStore.subscribe((state2) => invalidate(state2));
1271
- return rootStore;
1272
- };
1273
-
1274
- const memoizedLoaders = /* @__PURE__ */ new WeakMap();
1275
- const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
1276
- function getLoader(Proto) {
1277
- if (isConstructor$1(Proto)) {
1278
- let loader = memoizedLoaders.get(Proto);
1279
- if (!loader) {
1280
- loader = new Proto();
1281
- memoizedLoaders.set(Proto, loader);
1282
- }
1283
- return loader;
1284
- }
1285
- return Proto;
1286
- }
1287
- function loadingFn(extensions, onProgress) {
1288
- return function(Proto, input) {
1289
- const loader = getLoader(Proto);
1290
- if (extensions) extensions(loader);
1291
- if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
1292
- return loader.loadAsync(input, onProgress).then((data) => {
1293
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1294
- return data;
1295
- });
1296
- }
1297
- return new Promise(
1298
- (res, reject) => loader.load(
1299
- input,
1300
- (data) => {
1301
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1302
- res(data);
1303
- },
1304
- onProgress,
1305
- (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
1306
- )
1307
- );
1308
- };
1309
- }
1310
- function useLoader(loader, input, extensions, onProgress) {
1311
- const keys = Array.isArray(input) ? input : [input];
1312
- const fn = loadingFn(extensions, onProgress);
1313
- const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
1314
- return Array.isArray(input) ? results : results[0];
1315
- }
1316
- useLoader.preload = function(loader, input, extensions, onProgress) {
1317
- const keys = Array.isArray(input) ? input : [input];
1318
- keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
1319
- };
1320
- useLoader.clear = function(loader, input) {
1321
- const keys = Array.isArray(input) ? input : [input];
1322
- keys.forEach((key) => suspendReact.clear([loader, key]));
1323
- };
1324
- useLoader.loader = getLoader;
1325
-
1326
- var __defProp$1 = Object.defineProperty;
1327
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1328
- var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1329
- const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
1330
- class PhaseGraph {
1331
- constructor() {
1332
- /** Ordered list of phase nodes */
1333
- __publicField$1(this, "phases", []);
1334
- /** Quick lookup by name */
1335
- __publicField$1(this, "phaseMap", /* @__PURE__ */ new Map());
1336
- /** Cached ordered names (invalidated on changes) */
1337
- __publicField$1(this, "orderedNamesCache", null);
1338
- this.initializeDefaultPhases();
1339
- }
1340
- //* Initialization --------------------------------
1341
- initializeDefaultPhases() {
1342
- for (const name of DEFAULT_PHASES) {
1343
- const node = { name, isAutoGenerated: false };
1344
- this.phases.push(node);
1345
- this.phaseMap.set(name, node);
1661
+ var __defProp$2 = Object.defineProperty;
1662
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1663
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
1664
+ const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
1665
+ class PhaseGraph {
1666
+ constructor() {
1667
+ /** Ordered list of phase nodes */
1668
+ __publicField$2(this, "phases", []);
1669
+ /** Quick lookup by name */
1670
+ __publicField$2(this, "phaseMap", /* @__PURE__ */ new Map());
1671
+ /** Cached ordered names (invalidated on changes) */
1672
+ __publicField$2(this, "orderedNamesCache", null);
1673
+ this.initializeDefaultPhases();
1674
+ }
1675
+ //* Initialization --------------------------------
1676
+ initializeDefaultPhases() {
1677
+ for (const name of DEFAULT_PHASES) {
1678
+ const node = { name, isAutoGenerated: false };
1679
+ this.phases.push(node);
1680
+ this.phaseMap.set(name, node);
1346
1681
  }
1347
1682
  this.invalidateCache();
1348
1683
  }
@@ -1361,8 +1696,9 @@ class PhaseGraph {
1361
1696
  const node = { name, isAutoGenerated: false };
1362
1697
  let insertIndex = this.phases.length;
1363
1698
  const targetIndex = this.getPhaseIndex(before ?? after);
1364
- if (targetIndex !== -1) insertIndex = before ? targetIndex : targetIndex + 1;
1365
- else {
1699
+ if (targetIndex !== -1) {
1700
+ insertIndex = before ? targetIndex : targetIndex + 1;
1701
+ } else {
1366
1702
  const constraintType = before ? "before" : "after";
1367
1703
  console.warn(`[useFrame] Phase "${before ?? after}" not found for '${constraintType}' constraint`);
1368
1704
  }
@@ -1574,7 +1910,7 @@ function shouldRun(job, now) {
1574
1910
  const minInterval = 1e3 / job.fps;
1575
1911
  const lastRun = job.lastRun ?? 0;
1576
1912
  const elapsed = now - lastRun;
1577
- if (elapsed < minInterval) return false;
1913
+ if (elapsed < minInterval - 1) return false;
1578
1914
  if (job.drop) {
1579
1915
  job.lastRun = now;
1580
1916
  } else {
@@ -1590,9 +1926,9 @@ function resetJobTiming(job) {
1590
1926
  job.lastRun = void 0;
1591
1927
  }
1592
1928
 
1593
- var __defProp = Object.defineProperty;
1594
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1595
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
1929
+ var __defProp$1 = Object.defineProperty;
1930
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
1931
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
1596
1932
  const hmrData = (() => {
1597
1933
  if (typeof process !== "undefined" && process.env.NODE_ENV === "test") return void 0;
1598
1934
  if (typeof import_meta_hot !== "undefined") return import_meta_hot;
@@ -1606,9 +1942,9 @@ const _Scheduler = class _Scheduler {
1606
1942
  //* Constructor ================================
1607
1943
  constructor() {
1608
1944
  //* Critical State ================================
1609
- __publicField(this, "roots", /* @__PURE__ */ new Map());
1610
- __publicField(this, "phaseGraph");
1611
- __publicField(this, "loopState", {
1945
+ __publicField$1(this, "roots", /* @__PURE__ */ new Map());
1946
+ __publicField$1(this, "phaseGraph");
1947
+ __publicField$1(this, "loopState", {
1612
1948
  running: false,
1613
1949
  rafHandle: null,
1614
1950
  lastTime: null,
@@ -1617,21 +1953,21 @@ const _Scheduler = class _Scheduler {
1617
1953
  elapsedTime: 0,
1618
1954
  createdAt: performance.now()
1619
1955
  });
1620
- __publicField(this, "stoppedTime", 0);
1956
+ __publicField$1(this, "stoppedTime", 0);
1621
1957
  //* Private State ================================
1622
- __publicField(this, "nextRootIndex", 0);
1623
- __publicField(this, "globalBeforeJobs", /* @__PURE__ */ new Map());
1624
- __publicField(this, "globalAfterJobs", /* @__PURE__ */ new Map());
1625
- __publicField(this, "nextGlobalIndex", 0);
1626
- __publicField(this, "idleCallbacks", /* @__PURE__ */ new Set());
1627
- __publicField(this, "nextJobIndex", 0);
1628
- __publicField(this, "jobStateListeners", /* @__PURE__ */ new Map());
1629
- __publicField(this, "pendingFrames", 0);
1630
- __publicField(this, "_frameloop", "always");
1958
+ __publicField$1(this, "nextRootIndex", 0);
1959
+ __publicField$1(this, "globalBeforeJobs", /* @__PURE__ */ new Map());
1960
+ __publicField$1(this, "globalAfterJobs", /* @__PURE__ */ new Map());
1961
+ __publicField$1(this, "nextGlobalIndex", 0);
1962
+ __publicField$1(this, "idleCallbacks", /* @__PURE__ */ new Set());
1963
+ __publicField$1(this, "nextJobIndex", 0);
1964
+ __publicField$1(this, "jobStateListeners", /* @__PURE__ */ new Map());
1965
+ __publicField$1(this, "pendingFrames", 0);
1966
+ __publicField$1(this, "_frameloop", "always");
1631
1967
  //* Independent Mode & Error Handling State ================================
1632
- __publicField(this, "_independent", false);
1633
- __publicField(this, "errorHandler", null);
1634
- __publicField(this, "rootReadyCallbacks", /* @__PURE__ */ new Set());
1968
+ __publicField$1(this, "_independent", false);
1969
+ __publicField$1(this, "errorHandler", null);
1970
+ __publicField$1(this, "rootReadyCallbacks", /* @__PURE__ */ new Set());
1635
1971
  //* Core Loop Execution Methods ================================
1636
1972
  /**
1637
1973
  * Main RAF loop callback.
@@ -1640,7 +1976,7 @@ const _Scheduler = class _Scheduler {
1640
1976
  * @returns {void}
1641
1977
  * @private
1642
1978
  */
1643
- __publicField(this, "loop", (timestamp) => {
1979
+ __publicField$1(this, "loop", (timestamp) => {
1644
1980
  if (!this.loopState.running) return;
1645
1981
  this.executeFrame(timestamp);
1646
1982
  if (this._frameloop === "demand") {
@@ -2347,56 +2683,384 @@ const _Scheduler = class _Scheduler {
2347
2683
  //* Cross-Bundle Singleton Key ==============================
2348
2684
  // Use Symbol.for() to ensure scheduler is shared across bundle boundaries
2349
2685
  // This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
2350
- __publicField(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
2686
+ __publicField$1(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
2351
2687
  let Scheduler = _Scheduler;
2352
2688
  const getScheduler = () => Scheduler.get();
2353
2689
  if (hmrData) {
2354
2690
  hmrData.accept?.();
2355
2691
  }
2356
2692
 
2357
- function useFrame(callback, priorityOrOptions) {
2358
- const store = React__namespace.useContext(context);
2359
- const isInsideCanvas = store !== null;
2360
- const scheduler = getScheduler();
2361
- const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
2362
- id: priorityOrOptions.id,
2363
- phase: priorityOrOptions.phase,
2364
- priority: priorityOrOptions.priority,
2365
- fps: priorityOrOptions.fps,
2366
- drop: priorityOrOptions.drop,
2367
- enabled: priorityOrOptions.enabled,
2368
- before: priorityOrOptions.before,
2369
- after: priorityOrOptions.after
2370
- }) : "";
2371
- const options = React__namespace.useMemo(() => {
2372
- return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
2373
- }, [optionsKey]);
2374
- const reactId = React__namespace.useId();
2375
- const id = options.id ?? reactId;
2376
- const callbackRef = useMutableCallback(callback);
2377
- const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
2378
- useIsomorphicLayoutEffect(() => {
2379
- if (!callback) return;
2380
- if (isInsideCanvas) {
2381
- const state = store.getState();
2382
- const rootId = state.internal.rootId;
2383
- if (isLegacyPriority) {
2384
- state.internal.priority++;
2385
- let parentRoot = state.previousRoot;
2386
- while (parentRoot) {
2387
- const parentState = parentRoot.getState();
2388
- if (parentState?.internal) parentState.internal.priority++;
2389
- parentRoot = parentState?.previousRoot;
2390
- }
2391
- notifyDepreciated({
2392
- heading: "useFrame with numeric priority is deprecated",
2393
- 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 })',
2394
- link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
2395
- });
2693
+ const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
2694
+ const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React__namespace.createContext(null));
2695
+ const createStore = (invalidate, advance) => {
2696
+ const rootStore = traditional.createWithEqualityFn((set, get) => {
2697
+ const position = new webgpu.Vector3();
2698
+ const defaultTarget = new webgpu.Vector3();
2699
+ const tempTarget = new webgpu.Vector3();
2700
+ function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
2701
+ const { width, height, top, left } = size;
2702
+ const aspect = width / height;
2703
+ if (target.isVector3) tempTarget.copy(target);
2704
+ else tempTarget.set(...target);
2705
+ const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
2706
+ if (isOrthographicCamera(camera)) {
2707
+ return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
2708
+ } else {
2709
+ const fov = camera.fov * Math.PI / 180;
2710
+ const h = 2 * Math.tan(fov / 2) * distance;
2711
+ const w = h * (width / height);
2712
+ return { width: w, height: h, top, left, factor: width / w, distance, aspect };
2396
2713
  }
2397
- const wrappedCallback = (frameState, delta) => {
2398
- const localState = store.getState();
2399
- const mergedState = {
2714
+ }
2715
+ let performanceTimeout = void 0;
2716
+ const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
2717
+ const pointer = new webgpu.Vector2();
2718
+ const rootState = {
2719
+ set,
2720
+ get,
2721
+ // Mock objects that have to be configured
2722
+ // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
2723
+ primaryStore: null,
2724
+ gl: null,
2725
+ renderer: null,
2726
+ camera: null,
2727
+ frustum: new webgpu.Frustum(),
2728
+ autoUpdateFrustum: true,
2729
+ raycaster: null,
2730
+ events: {
2731
+ priority: 1,
2732
+ enabled: true,
2733
+ connected: false,
2734
+ frameTimedRaycasts: true,
2735
+ alwaysFireOnScroll: true,
2736
+ updateOnFrame: false
2737
+ },
2738
+ scene: null,
2739
+ rootScene: null,
2740
+ xr: null,
2741
+ inspector: null,
2742
+ invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
2743
+ advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
2744
+ textureColorSpace: webgpu.SRGBColorSpace,
2745
+ isLegacy: false,
2746
+ webGPUSupported: false,
2747
+ isNative: false,
2748
+ controls: null,
2749
+ pointer,
2750
+ mouse: pointer,
2751
+ frameloop: "always",
2752
+ onPointerMissed: void 0,
2753
+ onDragOverMissed: void 0,
2754
+ onDropMissed: void 0,
2755
+ performance: {
2756
+ current: 1,
2757
+ min: 0.5,
2758
+ max: 1,
2759
+ debounce: 200,
2760
+ regress: () => {
2761
+ const state2 = get();
2762
+ if (performanceTimeout) clearTimeout(performanceTimeout);
2763
+ if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
2764
+ performanceTimeout = setTimeout(
2765
+ () => setPerformanceCurrent(get().performance.max),
2766
+ state2.performance.debounce
2767
+ );
2768
+ }
2769
+ },
2770
+ size: { width: 0, height: 0, top: 0, left: 0 },
2771
+ viewport: {
2772
+ initialDpr: 0,
2773
+ dpr: 0,
2774
+ width: 0,
2775
+ height: 0,
2776
+ top: 0,
2777
+ left: 0,
2778
+ aspect: 0,
2779
+ distance: 0,
2780
+ factor: 0,
2781
+ getCurrentViewport
2782
+ },
2783
+ setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
2784
+ setSize: (width, height, top, left) => {
2785
+ const state2 = get();
2786
+ if (width === void 0) {
2787
+ set({ _sizeImperative: false });
2788
+ if (state2._sizeProps) {
2789
+ const { width: propW, height: propH } = state2._sizeProps;
2790
+ if (propW !== void 0 || propH !== void 0) {
2791
+ const currentSize = state2.size;
2792
+ const newSize = {
2793
+ width: propW ?? currentSize.width,
2794
+ height: propH ?? currentSize.height,
2795
+ top: currentSize.top,
2796
+ left: currentSize.left
2797
+ };
2798
+ set((s) => ({
2799
+ size: newSize,
2800
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
2801
+ }));
2802
+ getScheduler().invalidate();
2803
+ }
2804
+ }
2805
+ return;
2806
+ }
2807
+ const w = width;
2808
+ const h = height ?? width;
2809
+ const t = top ?? state2.size.top;
2810
+ const l = left ?? state2.size.left;
2811
+ const size = { width: w, height: h, top: t, left: l };
2812
+ set((s) => ({
2813
+ size,
2814
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
2815
+ _sizeImperative: true
2816
+ }));
2817
+ getScheduler().invalidate();
2818
+ },
2819
+ setDpr: (dpr) => set((state2) => {
2820
+ const resolved = calculateDpr(dpr);
2821
+ return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
2822
+ }),
2823
+ setFrameloop: (frameloop = "always") => {
2824
+ set(() => ({ frameloop }));
2825
+ },
2826
+ setError: (error) => set(() => ({ error })),
2827
+ error: null,
2828
+ //* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
2829
+ uniforms: {},
2830
+ nodes: {},
2831
+ buffers: {},
2832
+ gpuStorage: {},
2833
+ textures: /* @__PURE__ */ new Map(),
2834
+ renderPipeline: null,
2835
+ passes: {},
2836
+ _hmrVersion: 0,
2837
+ _sizeImperative: false,
2838
+ _sizeProps: null,
2839
+ previousRoot: void 0,
2840
+ internal: {
2841
+ // Events
2842
+ interaction: [],
2843
+ subscribers: [],
2844
+ // Per-pointer state (new unified structure)
2845
+ pointerMap: /* @__PURE__ */ new Map(),
2846
+ pointerDirty: /* @__PURE__ */ new Map(),
2847
+ lastEvent: React__namespace.createRef(),
2848
+ // Deprecated but kept for backwards compatibility
2849
+ hovered: /* @__PURE__ */ new Map(),
2850
+ initialClick: [0, 0],
2851
+ initialHits: [],
2852
+ capturedMap: /* @__PURE__ */ new Map(),
2853
+ // Visibility tracking (onFramed, onOccluded, onVisible)
2854
+ visibilityRegistry: /* @__PURE__ */ new Map(),
2855
+ // Occlusion system (WebGPU only)
2856
+ occlusionEnabled: false,
2857
+ occlusionObserver: null,
2858
+ occlusionCache: /* @__PURE__ */ new Map(),
2859
+ helperGroup: null,
2860
+ // Updates
2861
+ active: false,
2862
+ frames: 0,
2863
+ priority: 0,
2864
+ subscribe: (ref, priority, store) => {
2865
+ const internal = get().internal;
2866
+ internal.priority = internal.priority + (priority > 0 ? 1 : 0);
2867
+ internal.subscribers.push({ ref, priority, store });
2868
+ internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
2869
+ return () => {
2870
+ const internal2 = get().internal;
2871
+ if (internal2?.subscribers) {
2872
+ internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
2873
+ internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
2874
+ }
2875
+ };
2876
+ },
2877
+ // Renderer Storage (single source of truth)
2878
+ actualRenderer: null,
2879
+ // Scheduler for useFrameNext (initialized in renderer.tsx)
2880
+ scheduler: null
2881
+ }
2882
+ };
2883
+ return rootState;
2884
+ });
2885
+ const state = rootStore.getState();
2886
+ Object.defineProperty(state, "gl", {
2887
+ get() {
2888
+ const currentState = rootStore.getState();
2889
+ if (!currentState.isLegacy && currentState.internal.actualRenderer) {
2890
+ const stack = new Error().stack || "";
2891
+ const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
2892
+ if (!isInternalAccess) {
2893
+ const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
2894
+ notifyDepreciated({
2895
+ heading: "Accessing state.gl in WebGPU mode",
2896
+ body: "Please use state.renderer instead. state.gl is deprecated and will be removed in future versions.\n\nFor backwards compatibility, state.gl currently maps to state.renderer, but this may cause issues with libraries expecting WebGLRenderer.\n\nAccessed from:\n" + cleanedStack
2897
+ });
2898
+ }
2899
+ }
2900
+ return currentState.internal.actualRenderer;
2901
+ },
2902
+ set(value) {
2903
+ rootStore.getState().internal.actualRenderer = value;
2904
+ },
2905
+ enumerable: true,
2906
+ configurable: true
2907
+ });
2908
+ Object.defineProperty(state, "renderer", {
2909
+ get() {
2910
+ return rootStore.getState().internal.actualRenderer;
2911
+ },
2912
+ set(value) {
2913
+ rootStore.getState().internal.actualRenderer = value;
2914
+ },
2915
+ enumerable: true,
2916
+ configurable: true
2917
+ });
2918
+ let oldScene = state.scene;
2919
+ rootStore.subscribe(() => {
2920
+ const currentState = rootStore.getState();
2921
+ const { scene, rootScene, set } = currentState;
2922
+ if (scene !== oldScene) {
2923
+ oldScene = scene;
2924
+ if (scene?.isScene && scene !== rootScene) {
2925
+ set({ rootScene: scene });
2926
+ }
2927
+ }
2928
+ });
2929
+ let oldSize = state.size;
2930
+ let oldDpr = state.viewport.dpr;
2931
+ let oldCamera = state.camera;
2932
+ rootStore.subscribe(() => {
2933
+ const { camera, size, viewport, set, internal } = rootStore.getState();
2934
+ const actualRenderer = internal.actualRenderer;
2935
+ const canvasTarget = internal.canvasTarget;
2936
+ if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
2937
+ oldSize = size;
2938
+ oldDpr = viewport.dpr;
2939
+ updateCamera(camera, size);
2940
+ if (internal.isSecondary && canvasTarget) {
2941
+ if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
2942
+ canvasTarget.setSize(size.width, size.height, false);
2943
+ } else {
2944
+ if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
2945
+ actualRenderer.setSize(size.width, size.height, false);
2946
+ if (canvasTarget) {
2947
+ if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
2948
+ canvasTarget.setSize(size.width, size.height, false);
2949
+ }
2950
+ }
2951
+ }
2952
+ if (camera !== oldCamera) {
2953
+ oldCamera = camera;
2954
+ const { rootScene } = rootStore.getState();
2955
+ if (camera && rootScene && !camera.parent) {
2956
+ rootScene.add(camera);
2957
+ }
2958
+ set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
2959
+ const currentState = rootStore.getState();
2960
+ if (currentState.autoUpdateFrustum && camera) {
2961
+ updateFrustum(camera, currentState.frustum);
2962
+ }
2963
+ }
2964
+ });
2965
+ rootStore.subscribe((state2) => invalidate(state2));
2966
+ return rootStore;
2967
+ };
2968
+
2969
+ const memoizedLoaders = /* @__PURE__ */ new WeakMap();
2970
+ const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
2971
+ function getLoader(Proto) {
2972
+ if (isConstructor$1(Proto)) {
2973
+ let loader = memoizedLoaders.get(Proto);
2974
+ if (!loader) {
2975
+ loader = new Proto();
2976
+ memoizedLoaders.set(Proto, loader);
2977
+ }
2978
+ return loader;
2979
+ }
2980
+ return Proto;
2981
+ }
2982
+ function loadingFn(extensions, onProgress) {
2983
+ return function(Proto, input) {
2984
+ const loader = getLoader(Proto);
2985
+ if (extensions) extensions(loader);
2986
+ if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
2987
+ return loader.loadAsync(input, onProgress).then((data) => {
2988
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
2989
+ return data;
2990
+ });
2991
+ }
2992
+ return new Promise(
2993
+ (res, reject) => loader.load(
2994
+ input,
2995
+ (data) => {
2996
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
2997
+ res(data);
2998
+ },
2999
+ onProgress,
3000
+ (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
3001
+ )
3002
+ );
3003
+ };
3004
+ }
3005
+ function useLoader(loader, input, extensions, onProgress) {
3006
+ const keys = Array.isArray(input) ? input : [input];
3007
+ const fn = loadingFn(extensions, onProgress);
3008
+ const results = keys.map((key) => suspendReact.suspend(fn, [loader, key], { equal: is.equ }));
3009
+ return Array.isArray(input) ? results : results[0];
3010
+ }
3011
+ useLoader.preload = function(loader, input, extensions, onProgress) {
3012
+ const keys = Array.isArray(input) ? input : [input];
3013
+ keys.forEach((key) => suspendReact.preload(loadingFn(extensions, onProgress), [loader, key]));
3014
+ };
3015
+ useLoader.clear = function(loader, input) {
3016
+ const keys = Array.isArray(input) ? input : [input];
3017
+ keys.forEach((key) => suspendReact.clear([loader, key]));
3018
+ };
3019
+ useLoader.loader = getLoader;
3020
+
3021
+ function useFrame(callback, priorityOrOptions) {
3022
+ const store = React__namespace.useContext(context);
3023
+ const isInsideCanvas = store !== null;
3024
+ const scheduler = getScheduler();
3025
+ const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
3026
+ id: priorityOrOptions.id,
3027
+ phase: priorityOrOptions.phase,
3028
+ priority: priorityOrOptions.priority,
3029
+ fps: priorityOrOptions.fps,
3030
+ drop: priorityOrOptions.drop,
3031
+ enabled: priorityOrOptions.enabled,
3032
+ before: priorityOrOptions.before,
3033
+ after: priorityOrOptions.after
3034
+ }) : "";
3035
+ const options = React__namespace.useMemo(() => {
3036
+ return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
3037
+ }, [optionsKey]);
3038
+ const reactId = React__namespace.useId();
3039
+ const id = options.id ?? reactId;
3040
+ const callbackRef = useMutableCallback(callback);
3041
+ const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
3042
+ useIsomorphicLayoutEffect(() => {
3043
+ if (!callback) return;
3044
+ if (isInsideCanvas) {
3045
+ const state = store.getState();
3046
+ const rootId = state.internal.rootId;
3047
+ if (isLegacyPriority) {
3048
+ state.internal.priority++;
3049
+ let parentRoot = state.previousRoot;
3050
+ while (parentRoot) {
3051
+ const parentState = parentRoot.getState();
3052
+ if (parentState?.internal) parentState.internal.priority++;
3053
+ parentRoot = parentState?.previousRoot;
3054
+ }
3055
+ notifyDepreciated({
3056
+ heading: "useFrame with numeric priority is deprecated",
3057
+ 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 })',
3058
+ link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
3059
+ });
3060
+ }
3061
+ const wrappedCallback = (frameState, delta) => {
3062
+ const localState = store.getState();
3063
+ const mergedState = {
2400
3064
  ...localState,
2401
3065
  time: frameState.time,
2402
3066
  delta: frameState.delta,
@@ -2533,6 +3197,9 @@ function useTexture(input, optionsOrOnLoad) {
2533
3197
  const textureCache = useThree((state) => state.textures);
2534
3198
  const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
2535
3199
  const { onLoad, cache = false } = options;
3200
+ const onLoadRef = React.useRef(onLoad);
3201
+ onLoadRef.current = onLoad;
3202
+ const onLoadCalledForRef = React.useRef(null);
2536
3203
  const urls = React.useMemo(() => getUrls(input), [input]);
2537
3204
  const cachedResult = React.useMemo(() => {
2538
3205
  if (!cache) return null;
@@ -2543,9 +3210,13 @@ function useTexture(input, optionsOrOnLoad) {
2543
3210
  webgpu.TextureLoader,
2544
3211
  IsObject(input) ? Object.values(input) : input
2545
3212
  );
3213
+ const inputKey = urls.join("\0");
2546
3214
  React.useLayoutEffect(() => {
2547
- if (!cachedResult) onLoad?.(loadedTextures);
2548
- }, [onLoad, cachedResult, loadedTextures]);
3215
+ if (cachedResult) return;
3216
+ if (onLoadCalledForRef.current === inputKey) return;
3217
+ onLoadCalledForRef.current = inputKey;
3218
+ onLoadRef.current?.(loadedTextures);
3219
+ }, [cachedResult, loadedTextures, inputKey]);
2549
3220
  React.useEffect(() => {
2550
3221
  if (cachedResult) return;
2551
3222
  if ("initTexture" in renderer) {
@@ -2712,14 +3383,31 @@ function useTextures() {
2712
3383
  }, [store]);
2713
3384
  }
2714
3385
 
2715
- function useRenderTarget(width, height, options) {
3386
+ function useRenderTarget(widthOrOptions, heightOrOptions, options) {
2716
3387
  const isLegacy = useThree((s) => s.isLegacy);
2717
3388
  const size = useThree((s) => s.size);
3389
+ let width;
3390
+ let height;
3391
+ let opts;
3392
+ if (typeof widthOrOptions === "object") {
3393
+ opts = widthOrOptions;
3394
+ } else if (typeof widthOrOptions === "number") {
3395
+ width = widthOrOptions;
3396
+ if (typeof heightOrOptions === "object") {
3397
+ height = widthOrOptions;
3398
+ opts = heightOrOptions;
3399
+ } else if (typeof heightOrOptions === "number") {
3400
+ height = heightOrOptions;
3401
+ opts = options;
3402
+ } else {
3403
+ height = widthOrOptions;
3404
+ }
3405
+ }
2718
3406
  return React.useMemo(() => {
2719
3407
  const w = width ?? size.width;
2720
3408
  const h = height ?? size.height;
2721
- return new webgpu.RenderTarget(w, h, options);
2722
- }, [width, height, size.width, size.height, options, isLegacy]);
3409
+ return new webgpu.RenderTarget(w, h, opts);
3410
+ }, [width, height, size.width, size.height, opts, isLegacy]);
2723
3411
  }
2724
3412
 
2725
3413
  function useStore() {
@@ -2769,28 +3457,18 @@ function addTail(callback) {
2769
3457
  function invalidate(state, frames = 1, stackFrames = false) {
2770
3458
  getScheduler().invalidate(frames, stackFrames);
2771
3459
  }
2772
- function advance(timestamp, runGlobalEffects = true, state, frame) {
3460
+ function advance(timestamp) {
2773
3461
  getScheduler().step(timestamp);
2774
3462
  }
2775
3463
 
2776
- const version = "10.0.0-alpha.1";
3464
+ const version = "10.0.0-alpha.2";
2777
3465
  const packageData = {
2778
3466
  version: version};
2779
3467
 
2780
3468
  function Xb(Tt) {
2781
3469
  return Tt && Tt.__esModule && Object.prototype.hasOwnProperty.call(Tt, "default") ? Tt.default : Tt;
2782
3470
  }
2783
- var Rm = { exports: {} }, Og = { exports: {} };
2784
- /**
2785
- * @license React
2786
- * react-reconciler.production.js
2787
- *
2788
- * Copyright (c) Meta Platforms, Inc. and affiliates.
2789
- *
2790
- * This source code is licensed under the MIT license found in the
2791
- * LICENSE file in the root directory of this source tree.
2792
- */
2793
- var _b;
3471
+ var Rm = { exports: {} }, Og = { exports: {} }, _b;
2794
3472
  function Kb() {
2795
3473
  return _b || (_b = 1, (function(Tt) {
2796
3474
  Tt.exports = function(m) {
@@ -3862,7 +4540,6 @@ Error generating stack: ` + l.message + `
3862
4540
  if (J === cl || J === jc) throw J;
3863
4541
  var Ge = Yn(29, J, null, P.mode);
3864
4542
  return Ge.lanes = H, Ge.return = P, Ge;
3865
- } finally {
3866
4543
  }
3867
4544
  };
3868
4545
  }
@@ -4516,7 +5193,6 @@ Error generating stack: ` + l.message + `
4516
5193
  var h = r.lastRenderedState, y = d(h, a);
4517
5194
  if (c.hasEagerState = true, c.eagerState = y, jn(y, h)) return go(t, r, c, 0), Ne === null && Bn(), false;
4518
5195
  } catch {
4519
- } finally {
4520
5196
  }
4521
5197
  if (a = yo(t, r, c, l), a !== null) return nt(a, t, l), ns(a, r, l), true;
4522
5198
  }
@@ -6937,10 +7613,7 @@ Error generating stack: ` + l.message + `
6937
7613
  function vr(t, r) {
6938
7614
  Sf(t, r), (t = t.alternate) && Sf(t, r);
6939
7615
  }
6940
- 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");
6941
- var gc = Symbol.for("react.activity");
6942
- var $r = Symbol.for("react.memo_cache_sentinel");
6943
- 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;
7616
+ 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;
6944
7617
  m.cloneMutableInstance;
6945
7618
  var yc = m.appendInitialChild, Kp = m.finalizeInitialChildren, Rs = m.shouldSetTextContent, bc = m.createTextInstance;
6946
7619
  m.cloneMutableTextInstance;
@@ -7309,17 +7982,7 @@ No matching component was found for:
7309
7982
  }, Tt.exports.default = Tt.exports, Object.defineProperty(Tt.exports, "__esModule", { value: true });
7310
7983
  })(Og)), Og.exports;
7311
7984
  }
7312
- var Mg = { exports: {} };
7313
- /**
7314
- * @license React
7315
- * react-reconciler.development.js
7316
- *
7317
- * Copyright (c) Meta Platforms, Inc. and affiliates.
7318
- *
7319
- * This source code is licensed under the MIT license found in the
7320
- * LICENSE file in the root directory of this source tree.
7321
- */
7322
- var Rb;
7985
+ var Mg = { exports: {} }, Rb;
7323
7986
  function e0() {
7324
7987
  return Rb || (Rb = 1, (function(Tt) {
7325
7988
  process.env.NODE_ENV !== "production" && (Tt.exports = function(m) {
@@ -13086,10 +13749,7 @@ Check the render method of %s.`, G(di) || "Unknown")), i = zo(n), i.payload = {
13086
13749
  function Ic() {
13087
13750
  return di;
13088
13751
  }
13089
- 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");
13090
- var Ds = Symbol.for("react.activity");
13091
- var Bh = Symbol.for("react.memo_cache_sentinel");
13092
- 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;
13752
+ 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;
13093
13753
  m.cloneMutableInstance;
13094
13754
  var bn = m.appendInitialChild, Ue = m.finalizeInitialChildren, ue = m.shouldSetTextContent, Do = m.createTextInstance;
13095
13755
  m.cloneMutableTextInstance;
@@ -14057,15 +14717,6 @@ function n0() {
14057
14717
  var t0 = n0();
14058
14718
  const r0 = Xb(t0);
14059
14719
 
14060
- /**
14061
- * @license React
14062
- * react-reconciler-constants.production.js
14063
- *
14064
- * Copyright (c) Meta Platforms, Inc. and affiliates.
14065
- *
14066
- * This source code is licensed under the MIT license found in the
14067
- * LICENSE file in the root directory of this source tree.
14068
- */
14069
14720
  const t = 1, o = 8, r = 32, e = 2;
14070
14721
 
14071
14722
  function createReconciler(config) {
@@ -14092,10 +14743,11 @@ function extend(objects) {
14092
14743
  function validateInstance(type, props) {
14093
14744
  const name = toPascalCase(type);
14094
14745
  const target = catalogue[name];
14095
- if (type !== "primitive" && !target)
14746
+ if (type !== "primitive" && !target) {
14096
14747
  throw new Error(
14097
14748
  `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`
14098
14749
  );
14750
+ }
14099
14751
  if (type === "primitive" && !props.object) throw new Error(`R3F: Primitives without 'object' are invalid!`);
14100
14752
  if (props.args !== void 0 && !Array.isArray(props.args)) throw new Error("R3F: The args prop must be an array!");
14101
14753
  }
@@ -14259,6 +14911,7 @@ function swapInstances() {
14259
14911
  instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
14260
14912
  instance.object.__r3f = instance;
14261
14913
  setFiberRef(fiber, instance.object);
14914
+ delete instance.appliedOnce;
14262
14915
  applyProps(instance.object, instance.props);
14263
14916
  if (instance.props.attach) {
14264
14917
  attach(parent, instance);
@@ -14332,8 +14985,22 @@ const reconciler = /* @__PURE__ */ createReconciler({
14332
14985
  const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
14333
14986
  if (isTailSibling) swapInstances();
14334
14987
  },
14335
- finalizeInitialChildren: () => false,
14336
- commitMount() {
14988
+ finalizeInitialChildren: (instance) => {
14989
+ for (const prop in instance.props) {
14990
+ if (isFromRef(instance.props[prop])) return true;
14991
+ }
14992
+ return false;
14993
+ },
14994
+ commitMount(instance) {
14995
+ const resolved = {};
14996
+ for (const prop in instance.props) {
14997
+ const value = instance.props[prop];
14998
+ if (isFromRef(value)) {
14999
+ const ref = value[FROM_REF];
15000
+ if (ref.current != null) resolved[prop] = ref.current;
15001
+ }
15002
+ }
15003
+ if (Object.keys(resolved).length) applyProps(instance.object, resolved);
14337
15004
  },
14338
15005
  getPublicInstance: (instance) => instance?.object,
14339
15006
  prepareForCommit: () => null,
@@ -14546,14 +15213,17 @@ function createRoot(canvas) {
14546
15213
  if (!prevRoot) _roots.set(canvas, { fiber, store });
14547
15214
  let onCreated;
14548
15215
  let lastCamera;
14549
- let lastConfiguredProps = {};
15216
+ const lastConfiguredProps = {};
14550
15217
  let configured = false;
14551
15218
  let pending = null;
14552
15219
  return {
14553
15220
  async configure(props = {}) {
14554
15221
  let resolve;
14555
15222
  pending = new Promise((_resolve) => resolve = _resolve);
14556
- let {
15223
+ const {
15224
+ id: canvasId,
15225
+ primaryCanvas,
15226
+ scheduler: schedulerConfig,
14557
15227
  gl: glConfig,
14558
15228
  renderer: rendererConfig,
14559
15229
  size: propsSize,
@@ -14561,10 +15231,6 @@ function createRoot(canvas) {
14561
15231
  events,
14562
15232
  onCreated: onCreatedCallback,
14563
15233
  shadows = false,
14564
- linear = false,
14565
- flat = false,
14566
- textureColorSpace = webgpu.SRGBColorSpace,
14567
- legacy = false,
14568
15234
  orthographic = false,
14569
15235
  frameloop = "always",
14570
15236
  dpr = [1, 2],
@@ -14575,11 +15241,15 @@ function createRoot(canvas) {
14575
15241
  onDragOverMissed,
14576
15242
  onDropMissed,
14577
15243
  autoUpdateFrustum = true,
14578
- occlusion = false
15244
+ occlusion = false,
15245
+ _sizeProps,
15246
+ forceEven
14579
15247
  } = props;
14580
- let state = store.getState();
15248
+ const textureColorSpace = is.obj(glConfig) && !is.fun(glConfig) && !isRenderer(glConfig) && glConfig.textureColorSpace || is.obj(rendererConfig) && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && rendererConfig.textureColorSpace || webgpu.SRGBColorSpace;
15249
+ const state = store.getState();
14581
15250
  const defaultGPUProps = {
14582
- canvas
15251
+ canvas,
15252
+ antialias: true
14583
15253
  };
14584
15254
  if (glConfig && !R3F_BUILD_LEGACY) {
14585
15255
  throw new Error(
@@ -14590,22 +15260,61 @@ function createRoot(canvas) {
14590
15260
  throw new Error("Cannot use both gl and renderer props at the same time");
14591
15261
  }
14592
15262
  let renderer = state.internal.actualRenderer;
14593
- if (!state.internal.actualRenderer) {
15263
+ if (primaryCanvas && !state.internal.actualRenderer) {
15264
+ const primary = await waitForPrimary(primaryCanvas);
15265
+ renderer = primary.renderer;
15266
+ state.internal.actualRenderer = renderer;
15267
+ const canvasTarget = new webgpu.CanvasTarget(canvas);
15268
+ primary.store.setState((prev) => ({
15269
+ internal: { ...prev.internal, isMultiCanvas: true }
15270
+ }));
15271
+ state.set((prev) => ({
15272
+ webGPUSupported: primary.store.getState().webGPUSupported,
15273
+ renderer,
15274
+ primaryStore: primary.store,
15275
+ internal: {
15276
+ ...prev.internal,
15277
+ canvasTarget,
15278
+ isMultiCanvas: true,
15279
+ isSecondary: true,
15280
+ targetId: primaryCanvas
15281
+ }
15282
+ }));
15283
+ } else if (!state.internal.actualRenderer) {
14594
15284
  renderer = await resolveRenderer(rendererConfig, defaultGPUProps, webgpu.WebGPURenderer);
14595
15285
  if (!renderer.hasInitialized?.()) {
15286
+ const size2 = computeInitialSize(canvas, propsSize);
15287
+ if (size2.width > 0 && size2.height > 0) {
15288
+ const pixelRatio = calculateDpr(dpr);
15289
+ canvas.width = size2.width * pixelRatio;
15290
+ canvas.height = size2.height * pixelRatio;
15291
+ }
14596
15292
  await renderer.init();
14597
15293
  }
14598
15294
  const backend = renderer.backend;
14599
15295
  const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
14600
15296
  state.internal.actualRenderer = renderer;
14601
- state.set({ webGPUSupported: isWebGPUBackend, renderer });
15297
+ state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
15298
+ if (canvasId && !state.internal.isSecondary) {
15299
+ const canvasTarget = new webgpu.CanvasTarget(canvas);
15300
+ const unregisterPrimary = registerPrimary(canvasId, renderer, store);
15301
+ state.set((prev) => ({
15302
+ internal: {
15303
+ ...prev.internal,
15304
+ canvasTarget,
15305
+ unregisterPrimary
15306
+ }
15307
+ }));
15308
+ }
14602
15309
  }
14603
15310
  let raycaster = state.raycaster;
14604
15311
  if (!raycaster) state.set({ raycaster: raycaster = new webgpu.Raycaster() });
14605
15312
  const { params, ...options } = raycastOptions || {};
14606
15313
  if (!is.equ(options, raycaster, shallowLoose)) applyProps(raycaster, { ...options });
14607
- if (!is.equ(params, raycaster.params, shallowLoose))
15314
+ if (!is.equ(params, raycaster.params, shallowLoose)) {
14608
15315
  applyProps(raycaster, { params: { ...raycaster.params, ...params } });
15316
+ }
15317
+ let tempCamera = state.camera;
14609
15318
  if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
14610
15319
  lastCamera = cameraOptions;
14611
15320
  const isCamera = cameraOptions?.isCamera;
@@ -14625,6 +15334,7 @@ function createRoot(canvas) {
14625
15334
  if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
14626
15335
  }
14627
15336
  state.set({ camera });
15337
+ tempCamera = camera;
14628
15338
  raycaster.camera = camera;
14629
15339
  }
14630
15340
  if (!state.scene) {
@@ -14642,7 +15352,7 @@ function createRoot(canvas) {
14642
15352
  rootScene: scene,
14643
15353
  internal: { ...prev.internal, container: scene }
14644
15354
  }));
14645
- const camera = state.camera;
15355
+ const camera = tempCamera;
14646
15356
  if (camera && !camera.parent) scene.add(camera);
14647
15357
  }
14648
15358
  if (events && !state.events.handlers) {
@@ -14656,9 +15366,17 @@ function createRoot(canvas) {
14656
15366
  wasEnabled = enabled;
14657
15367
  });
14658
15368
  }
15369
+ if (_sizeProps !== void 0) {
15370
+ state.set({ _sizeProps });
15371
+ }
15372
+ if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
15373
+ state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
15374
+ }
14659
15375
  const size = computeInitialSize(canvas, propsSize);
14660
- if (!is.equ(size, state.size, shallowLoose)) {
15376
+ if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
15377
+ const wasImperative = state._sizeImperative;
14661
15378
  state.setSize(size.width, size.height, size.top, size.left);
15379
+ if (!wasImperative) state.set({ _sizeImperative: false });
14662
15380
  }
14663
15381
  if (dpr !== void 0 && !is.equ(dpr, lastConfiguredProps.dpr, shallowLoose)) {
14664
15382
  state.setDpr(dpr);
@@ -14680,10 +15398,10 @@ function createRoot(canvas) {
14680
15398
  lastConfiguredProps.performance = performance;
14681
15399
  }
14682
15400
  if (!state.xr) {
14683
- const handleXRFrame = (timestamp, frame) => {
15401
+ const handleXRFrame = (timestamp, _frame) => {
14684
15402
  const state2 = store.getState();
14685
15403
  if (state2.frameloop === "never") return;
14686
- advance(timestamp, true);
15404
+ advance(timestamp);
14687
15405
  };
14688
15406
  const actualRenderer = state.internal.actualRenderer;
14689
15407
  const handleSessionChange = () => {
@@ -14695,16 +15413,16 @@ function createRoot(canvas) {
14695
15413
  };
14696
15414
  const xr = {
14697
15415
  connect() {
14698
- const { gl, renderer: renderer2, isLegacy } = store.getState();
14699
- const actualRenderer2 = renderer2 || gl;
14700
- actualRenderer2.xr.addEventListener("sessionstart", handleSessionChange);
14701
- actualRenderer2.xr.addEventListener("sessionend", handleSessionChange);
15416
+ const { gl, renderer: renderer2 } = store.getState();
15417
+ const xrManager = (renderer2 || gl).xr;
15418
+ xrManager.addEventListener("sessionstart", handleSessionChange);
15419
+ xrManager.addEventListener("sessionend", handleSessionChange);
14702
15420
  },
14703
15421
  disconnect() {
14704
- const { gl, renderer: renderer2, isLegacy } = store.getState();
14705
- const actualRenderer2 = renderer2 || gl;
14706
- actualRenderer2.xr.removeEventListener("sessionstart", handleSessionChange);
14707
- actualRenderer2.xr.removeEventListener("sessionend", handleSessionChange);
15422
+ const { gl, renderer: renderer2 } = store.getState();
15423
+ const xrManager = (renderer2 || gl).xr;
15424
+ xrManager.removeEventListener("sessionstart", handleSessionChange);
15425
+ xrManager.removeEventListener("sessionend", handleSessionChange);
14708
15426
  }
14709
15427
  };
14710
15428
  if (typeof renderer.xr?.addEventListener === "function") xr.connect();
@@ -14716,41 +15434,92 @@ function createRoot(canvas) {
14716
15434
  const oldType = renderer.shadowMap.type;
14717
15435
  renderer.shadowMap.enabled = !!shadows;
14718
15436
  if (is.boo(shadows)) {
14719
- renderer.shadowMap.type = webgpu.PCFSoftShadowMap;
15437
+ renderer.shadowMap.type = webgpu.PCFShadowMap;
14720
15438
  } else if (is.str(shadows)) {
15439
+ if (shadows === "soft") {
15440
+ notifyDepreciated({
15441
+ heading: 'shadows="soft" is deprecated',
15442
+ body: "Three has depreciated soft and improved basic PCFShadows, we converted for you.",
15443
+ link: "https://github.com/mrdoob/three.js/wiki/Migration-Guide?utm_source=chatgpt.com#181--182"
15444
+ });
15445
+ }
14721
15446
  const types = {
14722
15447
  basic: webgpu.BasicShadowMap,
14723
15448
  percentage: webgpu.PCFShadowMap,
14724
- soft: webgpu.PCFSoftShadowMap,
15449
+ soft: webgpu.PCFShadowMap,
14725
15450
  variance: webgpu.VSMShadowMap
14726
15451
  };
14727
- renderer.shadowMap.type = types[shadows] ?? webgpu.PCFSoftShadowMap;
15452
+ renderer.shadowMap.type = types[shadows] ?? webgpu.PCFShadowMap;
14728
15453
  } else if (is.obj(shadows)) {
14729
15454
  Object.assign(renderer.shadowMap, shadows);
14730
15455
  }
14731
- if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type)
15456
+ if (oldEnabled !== renderer.shadowMap.enabled || oldType !== renderer.shadowMap.type) {
14732
15457
  renderer.shadowMap.needsUpdate = true;
15458
+ }
15459
+ }
15460
+ if (!configured) {
15461
+ renderer.outputColorSpace = webgpu.SRGBColorSpace;
15462
+ renderer.toneMapping = webgpu.ACESFilmicToneMapping;
14733
15463
  }
14734
15464
  if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
14735
15465
  if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
14736
15466
  lastConfiguredProps.textureColorSpace = textureColorSpace;
14737
15467
  }
14738
- if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose))
14739
- applyProps(renderer, glConfig);
15468
+ const r3fProps = ["textureColorSpace"];
15469
+ const constructorOnlyProps = ["samples", "antialias", "alpha", "canvas", "powerPreference"];
15470
+ const nonApplyProps = [...r3fProps, ...constructorOnlyProps];
15471
+ if (glConfig && !is.fun(glConfig) && !isRenderer(glConfig) && !is.equ(glConfig, renderer, shallowLoose)) {
15472
+ const glProps = {};
15473
+ for (const key in glConfig) {
15474
+ if (!nonApplyProps.includes(key)) glProps[key] = glConfig[key];
15475
+ }
15476
+ applyProps(renderer, glProps);
15477
+ }
14740
15478
  if (rendererConfig && !is.fun(rendererConfig) && !isRenderer(rendererConfig) && state.renderer) {
14741
15479
  const currentRenderer = state.renderer;
14742
15480
  if (!is.equ(rendererConfig, currentRenderer, shallowLoose)) {
14743
- applyProps(currentRenderer, rendererConfig);
15481
+ const rendererProps = {};
15482
+ for (const key in rendererConfig) {
15483
+ if (!nonApplyProps.includes(key)) rendererProps[key] = rendererConfig[key];
15484
+ }
15485
+ applyProps(currentRenderer, rendererProps);
14744
15486
  }
14745
15487
  }
14746
15488
  const scheduler = getScheduler();
14747
15489
  const rootId = state.internal.rootId;
14748
15490
  if (!rootId) {
14749
- const newRootId = scheduler.generateRootId();
15491
+ const newRootId = canvasId || scheduler.generateRootId();
14750
15492
  const unregisterRoot = scheduler.registerRoot(newRootId, {
14751
15493
  getState: () => store.getState(),
14752
15494
  onError: (err) => store.getState().setError(err)
14753
15495
  });
15496
+ const unregisterCanvasTarget = scheduler.register(
15497
+ () => {
15498
+ const state2 = store.getState();
15499
+ if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
15500
+ const renderer2 = state2.internal.actualRenderer;
15501
+ renderer2.setCanvasTarget(state2.internal.canvasTarget);
15502
+ }
15503
+ },
15504
+ {
15505
+ id: `${newRootId}_canvasTarget`,
15506
+ rootId: newRootId,
15507
+ phase: "start",
15508
+ system: true
15509
+ }
15510
+ );
15511
+ const unregisterEventsFlush = scheduler.register(
15512
+ () => {
15513
+ const state2 = store.getState();
15514
+ state2.events.flush?.();
15515
+ },
15516
+ {
15517
+ id: `${newRootId}_events`,
15518
+ rootId: newRootId,
15519
+ phase: "input",
15520
+ system: true
15521
+ }
15522
+ );
14754
15523
  const unregisterFrustum = scheduler.register(
14755
15524
  () => {
14756
15525
  const state2 = store.getState();
@@ -14785,18 +15554,22 @@ function createRoot(canvas) {
14785
15554
  const userHandlesRender = scheduler.hasUserJobsInPhase("render", newRootId);
14786
15555
  if (userHandlesRender || state2.internal.priority) return;
14787
15556
  try {
14788
- if (state2.postProcessing?.render) state2.postProcessing.render();
15557
+ if (state2.renderPipeline?.render) state2.renderPipeline.render();
14789
15558
  else if (renderer2?.render) renderer2.render(state2.scene, state2.camera);
14790
15559
  } catch (error) {
14791
15560
  state2.setError(error instanceof Error ? error : new Error(String(error)));
14792
15561
  }
14793
15562
  },
14794
15563
  {
14795
- id: `${newRootId}_render`,
15564
+ // Use canvas ID directly as job ID if available, otherwise use generated rootId
15565
+ id: canvasId || `${newRootId}_render`,
14796
15566
  rootId: newRootId,
14797
15567
  phase: "render",
14798
- system: true
15568
+ system: true,
14799
15569
  // Internal flag: this is a system job, not user-controlled
15570
+ // Apply scheduler config for render ordering and rate limiting
15571
+ ...schedulerConfig?.after && { after: schedulerConfig.after },
15572
+ ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
14800
15573
  }
14801
15574
  );
14802
15575
  state.set((state2) => ({
@@ -14805,6 +15578,8 @@ function createRoot(canvas) {
14805
15578
  rootId: newRootId,
14806
15579
  unregisterRoot: () => {
14807
15580
  unregisterRoot();
15581
+ unregisterCanvasTarget();
15582
+ unregisterEventsFlush();
14808
15583
  unregisterFrustum();
14809
15584
  unregisterVisibility();
14810
15585
  unregisterRender();
@@ -14863,15 +15638,24 @@ function unmountComponentAtNode(canvas, callback) {
14863
15638
  const renderer = state.internal.actualRenderer;
14864
15639
  const unregisterRoot = state.internal.unregisterRoot;
14865
15640
  if (unregisterRoot) unregisterRoot();
15641
+ const unregisterPrimary = state.internal.unregisterPrimary;
15642
+ if (unregisterPrimary) unregisterPrimary();
15643
+ const canvasTarget = state.internal.canvasTarget;
15644
+ if (canvasTarget?.dispose) canvasTarget.dispose();
14866
15645
  state.events.disconnect?.();
14867
15646
  cleanupHelperGroup(root.store);
14868
- renderer?.renderLists?.dispose?.();
14869
- renderer?.forceContextLoss?.();
14870
- if (renderer?.xr) state.xr.disconnect();
15647
+ if (state.isLegacy && renderer) {
15648
+ ;
15649
+ renderer.renderLists?.dispose?.();
15650
+ renderer.forceContextLoss?.();
15651
+ }
15652
+ if (!state.internal.isSecondary) {
15653
+ if (renderer?.xr) state.xr.disconnect();
15654
+ }
14871
15655
  dispose(state.scene);
14872
15656
  _roots.delete(canvas);
14873
15657
  if (callback) callback(canvas);
14874
- } catch (e) {
15658
+ } catch {
14875
15659
  }
14876
15660
  }, 500);
14877
15661
  }
@@ -14879,36 +15663,34 @@ function unmountComponentAtNode(canvas, callback) {
14879
15663
  }
14880
15664
  }
14881
15665
  function createPortal(children, container, state) {
14882
- return /* @__PURE__ */ jsxRuntime.jsx(PortalWrapper, { children, container, state });
15666
+ return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container, state });
14883
15667
  }
14884
- function PortalWrapper({ children, container, state }) {
15668
+ function Portal({ children, container, state }) {
14885
15669
  const isRef = React.useCallback((obj) => obj && "current" in obj, []);
14886
- const [resolvedContainer, setResolvedContainer] = React.useState(() => {
15670
+ const [resolvedContainer, _setResolvedContainer] = React.useState(() => {
14887
15671
  if (isRef(container)) return container.current ?? null;
14888
15672
  return container;
14889
15673
  });
15674
+ const setResolvedContainer = React.useCallback(
15675
+ (newContainer) => {
15676
+ if (!newContainer || newContainer === resolvedContainer) return;
15677
+ _setResolvedContainer(isRef(newContainer) ? newContainer.current : newContainer);
15678
+ },
15679
+ [resolvedContainer, _setResolvedContainer, isRef]
15680
+ );
14890
15681
  React.useMemo(() => {
14891
- if (isRef(container)) {
14892
- const current = container.current;
14893
- if (!current) {
14894
- queueMicrotask(() => {
14895
- const updated = container.current;
14896
- if (updated && updated !== resolvedContainer) {
14897
- setResolvedContainer(updated);
14898
- }
14899
- });
14900
- } else if (current !== resolvedContainer) {
14901
- setResolvedContainer(current);
14902
- }
14903
- } else if (container !== resolvedContainer) {
14904
- setResolvedContainer(container);
15682
+ if (isRef(container) && !container.current) {
15683
+ return queueMicrotask(() => {
15684
+ setResolvedContainer(container.current);
15685
+ });
14905
15686
  }
14906
- }, [container, resolvedContainer, isRef]);
15687
+ setResolvedContainer(container);
15688
+ }, [container, isRef, setResolvedContainer]);
14907
15689
  if (!resolvedContainer) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
14908
15690
  const portalKey = resolvedContainer.uuid ?? `portal-${resolvedContainer.id ?? "unknown"}`;
14909
- return /* @__PURE__ */ jsxRuntime.jsx(Portal, { children, container: resolvedContainer, state }, portalKey);
15691
+ return /* @__PURE__ */ jsxRuntime.jsx(PortalInner, { children, container: resolvedContainer, state }, portalKey);
14910
15692
  }
14911
- function Portal({ state = {}, children, container }) {
15693
+ function PortalInner({ state = {}, children, container }) {
14912
15694
  const { events, size, injectScene = true, ...rest } = state;
14913
15695
  const previousRoot = useStore();
14914
15696
  const [raycaster] = React.useState(() => new webgpu.Raycaster());
@@ -14929,11 +15711,12 @@ function Portal({ state = {}, children, container }) {
14929
15711
  };
14930
15712
  }, [portalScene, container, injectScene]);
14931
15713
  const inject = useMutableCallback((rootState, injectState) => {
15714
+ const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
14932
15715
  let viewport = void 0;
14933
- if (injectState.camera && size) {
15716
+ if (injectState.camera && (size || injectState.size)) {
14934
15717
  const camera = injectState.camera;
14935
- viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), size);
14936
- if (camera !== rootState.camera) updateCamera(camera, size);
15718
+ viewport = rootState.viewport.getCurrentViewport(camera, new webgpu.Vector3(), resolvedSize);
15719
+ if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
14937
15720
  }
14938
15721
  return {
14939
15722
  // The intersect consists of the previous root state
@@ -14950,7 +15733,7 @@ function Portal({ state = {}, children, container }) {
14950
15733
  previousRoot,
14951
15734
  // Events, size and viewport can be overridden by the inject layer
14952
15735
  events: { ...rootState.events, ...injectState.events, ...events },
14953
- size: { ...rootState.size, ...size },
15736
+ size: resolvedSize,
14954
15737
  viewport: { ...rootState.viewport, ...viewport },
14955
15738
  // Layers are allowed to override events
14956
15739
  setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
@@ -14962,9 +15745,13 @@ function Portal({ state = {}, children, container }) {
14962
15745
  const store = traditional.createWithEqualityFn((set, get) => ({ ...rest, set, get }));
14963
15746
  const onMutate = (prev) => store.setState((state2) => inject.current(prev, state2));
14964
15747
  onMutate(previousRoot.getState());
14965
- previousRoot.subscribe(onMutate);
14966
15748
  return store;
14967
15749
  }, [previousRoot, container]);
15750
+ useIsomorphicLayoutEffect(() => {
15751
+ const onMutate = (prev) => usePortalStore.setState((state2) => inject.current(prev, state2));
15752
+ const unsubscribe = previousRoot.subscribe(onMutate);
15753
+ return unsubscribe;
15754
+ }, [previousRoot, usePortalStore]);
14968
15755
  return (
14969
15756
  // @ts-ignore, reconciler types are not maintained
14970
15757
  /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: reconciler.createPortal(
@@ -14984,15 +15771,13 @@ function CanvasImpl({
14984
15771
  fallback,
14985
15772
  resize,
14986
15773
  style,
15774
+ id,
14987
15775
  gl,
14988
- renderer,
15776
+ renderer: rendererProp,
14989
15777
  events = createPointerEvents,
14990
15778
  eventSource,
14991
15779
  eventPrefix,
14992
15780
  shadows,
14993
- linear,
14994
- flat,
14995
- legacy,
14996
15781
  orthographic,
14997
15782
  frameloop,
14998
15783
  dpr,
@@ -15004,10 +15789,56 @@ function CanvasImpl({
15004
15789
  onDragOverMissed,
15005
15790
  onDropMissed,
15006
15791
  onCreated,
15792
+ hmr,
15793
+ width,
15794
+ height,
15795
+ background,
15796
+ forceEven,
15007
15797
  ...props
15008
15798
  }) {
15799
+ const isRendererConfig = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp);
15800
+ let primaryCanvas;
15801
+ let scheduler;
15802
+ let renderer;
15803
+ if (isRendererConfig) {
15804
+ const { primaryCanvas: pc, scheduler: sc, ...rest } = rendererProp;
15805
+ primaryCanvas = pc;
15806
+ scheduler = sc;
15807
+ renderer = Object.keys(rest).length > 0 ? rest : rendererProp;
15808
+ } else {
15809
+ renderer = rendererProp;
15810
+ }
15009
15811
  React__namespace.useMemo(() => extend(THREE), []);
15010
15812
  const Bridge = useBridge();
15813
+ const backgroundProps = React__namespace.useMemo(() => {
15814
+ if (!background) return null;
15815
+ if (typeof background === "object" && !background.isColor) {
15816
+ const { backgroundMap, envMap, files, preset, ...rest } = background;
15817
+ return {
15818
+ ...rest,
15819
+ preset,
15820
+ files: envMap || files,
15821
+ backgroundFiles: backgroundMap,
15822
+ background: true
15823
+ };
15824
+ }
15825
+ if (typeof background === "number") {
15826
+ return { color: background, background: true };
15827
+ }
15828
+ if (typeof background === "string") {
15829
+ if (background in presetsObj) {
15830
+ return { preset: background, background: true };
15831
+ }
15832
+ if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
15833
+ return { files: background, background: true };
15834
+ }
15835
+ return { color: background, background: true };
15836
+ }
15837
+ if (background.isColor) {
15838
+ return { color: background, background: true };
15839
+ }
15840
+ return null;
15841
+ }, [background]);
15011
15842
  const hasInitialSizeRef = React__namespace.useRef(false);
15012
15843
  const measureConfig = React__namespace.useMemo(() => {
15013
15844
  if (!hasInitialSizeRef.current) {
@@ -15024,7 +15855,21 @@ function CanvasImpl({
15024
15855
  };
15025
15856
  }, [resize, hasInitialSizeRef.current]);
15026
15857
  const [containerRef, containerRect] = useMeasure__default(measureConfig);
15027
- if (!hasInitialSizeRef.current && containerRect.width > 0 && containerRect.height > 0) {
15858
+ const effectiveSize = React__namespace.useMemo(() => {
15859
+ let w = width ?? containerRect.width;
15860
+ let h = height ?? containerRect.height;
15861
+ if (forceEven) {
15862
+ w = Math.ceil(w / 2) * 2;
15863
+ h = Math.ceil(h / 2) * 2;
15864
+ }
15865
+ return {
15866
+ width: w,
15867
+ height: h,
15868
+ top: containerRect.top,
15869
+ left: containerRect.left
15870
+ };
15871
+ }, [width, height, containerRect, forceEven]);
15872
+ if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
15028
15873
  hasInitialSizeRef.current = true;
15029
15874
  }
15030
15875
  const canvasRef = React__namespace.useRef(null);
@@ -15043,7 +15888,7 @@ function CanvasImpl({
15043
15888
  useIsomorphicLayoutEffect(() => {
15044
15889
  effectActiveRef.current = true;
15045
15890
  const canvas = canvasRef.current;
15046
- if (containerRect.width > 0 && containerRect.height > 0 && canvas) {
15891
+ if (effectiveSize.width > 0 && effectiveSize.height > 0 && canvas) {
15047
15892
  if (!root.current) {
15048
15893
  root.current = createRoot(canvas);
15049
15894
  notifyAlpha({
@@ -15063,21 +15908,24 @@ function CanvasImpl({
15063
15908
  async function run() {
15064
15909
  if (!effectActiveRef.current || !root.current) return;
15065
15910
  await root.current.configure({
15911
+ id,
15912
+ primaryCanvas,
15913
+ scheduler,
15066
15914
  gl,
15067
15915
  renderer,
15068
15916
  scene,
15069
15917
  events,
15070
15918
  shadows,
15071
- linear,
15072
- flat,
15073
- legacy,
15074
15919
  orthographic,
15075
15920
  frameloop,
15076
15921
  dpr,
15077
15922
  performance,
15078
15923
  raycaster,
15079
15924
  camera,
15080
- size: containerRect,
15925
+ size: effectiveSize,
15926
+ // Store size props for reset functionality
15927
+ _sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
15928
+ forceEven,
15081
15929
  // Pass mutable reference to onPointerMissed so it's free to update
15082
15930
  onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
15083
15931
  onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
@@ -15101,7 +15949,10 @@ function CanvasImpl({
15101
15949
  });
15102
15950
  if (!effectActiveRef.current || !root.current) return;
15103
15951
  root.current.render(
15104
- /* @__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 }) }) })
15952
+ /* @__PURE__ */ jsxRuntime.jsx(Bridge, { children: /* @__PURE__ */ jsxRuntime.jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx(Block, { set: setBlock }), children: [
15953
+ backgroundProps && /* @__PURE__ */ jsxRuntime.jsx(Environment, { ...backgroundProps }),
15954
+ children ?? null
15955
+ ] }) }) })
15105
15956
  );
15106
15957
  }
15107
15958
  run();
@@ -15122,7 +15973,36 @@ function CanvasImpl({
15122
15973
  root.current = null;
15123
15974
  };
15124
15975
  }
15125
- }, []);
15976
+ }, []);
15977
+ React__namespace.useEffect(() => {
15978
+ if (hmr === false) return;
15979
+ const canvas = canvasRef.current;
15980
+ if (!canvas) return;
15981
+ const handleHMR = () => {
15982
+ queueMicrotask(() => {
15983
+ const rootEntry = _roots.get(canvas);
15984
+ if (rootEntry?.store) {
15985
+ console.log("[R3F] HMR detected \u2014 rebuilding nodes/uniforms");
15986
+ rootEntry.store.setState((state) => ({
15987
+ nodes: {},
15988
+ uniforms: {},
15989
+ _hmrVersion: state._hmrVersion + 1
15990
+ }));
15991
+ }
15992
+ });
15993
+ };
15994
+ 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) {
15995
+ const hot = undefined;
15996
+ hot.on("vite:afterUpdate", handleHMR);
15997
+ return () => hot.off?.("vite:afterUpdate", handleHMR);
15998
+ }
15999
+ if (typeof module !== "undefined" && module.hot) {
16000
+ const hot = module.hot;
16001
+ hot.addStatusHandler((status) => {
16002
+ if (status === "idle") handleHMR();
16003
+ });
16004
+ }
16005
+ }, [hmr]);
15126
16006
  const pointerEvents = eventSource ? "none" : "auto";
15127
16007
  return /* @__PURE__ */ jsxRuntime.jsx(
15128
16008
  "div",
@@ -15137,7 +16017,16 @@ function CanvasImpl({
15137
16017
  ...style
15138
16018
  },
15139
16019
  ...props,
15140
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx("canvas", { ref: canvasRef, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
16020
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsx(
16021
+ "canvas",
16022
+ {
16023
+ ref: canvasRef,
16024
+ id,
16025
+ className: "r3f-canvas",
16026
+ style: { display: "block", width: "100%", height: "100%" },
16027
+ children: fallback
16028
+ }
16029
+ ) })
15141
16030
  }
15142
16031
  );
15143
16032
  }
@@ -15145,6 +16034,100 @@ function Canvas(props) {
15145
16034
  return /* @__PURE__ */ jsxRuntime.jsx(itsFine.FiberProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(CanvasImpl, { ...props }) });
15146
16035
  }
15147
16036
 
16037
+ var __defProp = Object.defineProperty;
16038
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
16039
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
16040
+ var _a;
16041
+ const INTERNAL_DATA = Symbol("ScopedStore.data");
16042
+ _a = INTERNAL_DATA;
16043
+ const _ScopedStore = class _ScopedStore {
16044
+ constructor(data) {
16045
+ __publicField(this, _a);
16046
+ this[INTERNAL_DATA] = data;
16047
+ return new Proxy(this, {
16048
+ get(target, prop, receiver) {
16049
+ if (typeof prop === "string") {
16050
+ if (prop === "scope" || prop === "has" || prop === "keys") {
16051
+ return Reflect.get(target, prop, receiver);
16052
+ }
16053
+ return target[INTERNAL_DATA][prop];
16054
+ }
16055
+ return Reflect.get(target, prop, receiver);
16056
+ },
16057
+ has(target, prop) {
16058
+ return typeof prop === "string" ? prop in target[INTERNAL_DATA] : Reflect.has(target, prop);
16059
+ },
16060
+ ownKeys(target) {
16061
+ return Reflect.ownKeys(target[INTERNAL_DATA]);
16062
+ },
16063
+ getOwnPropertyDescriptor(target, prop) {
16064
+ if (typeof prop === "string" && prop in target[INTERNAL_DATA]) {
16065
+ return {
16066
+ configurable: true,
16067
+ enumerable: true,
16068
+ value: target[INTERNAL_DATA][prop]
16069
+ };
16070
+ }
16071
+ return void 0;
16072
+ }
16073
+ });
16074
+ }
16075
+ /**
16076
+ * Access a nested scope by key.
16077
+ * If the key doesn't exist or isn't a scope object, returns an empty ScopedStore.
16078
+ */
16079
+ scope(key) {
16080
+ const data = this[INTERNAL_DATA][key];
16081
+ return new _ScopedStore(
16082
+ data && typeof data === "object" ? data : {}
16083
+ );
16084
+ }
16085
+ /**
16086
+ * Check if a key exists in the store.
16087
+ */
16088
+ has(key) {
16089
+ return key in this[INTERNAL_DATA];
16090
+ }
16091
+ /**
16092
+ * Get all keys in the store.
16093
+ */
16094
+ keys() {
16095
+ return Object.keys(this[INTERNAL_DATA]);
16096
+ }
16097
+ };
16098
+ let ScopedStore = _ScopedStore;
16099
+ function createScopedStore(data) {
16100
+ return new ScopedStore(data);
16101
+ }
16102
+ function createLazyCreatorState(state) {
16103
+ let _uniforms = null;
16104
+ let _nodes = null;
16105
+ let _buffers = null;
16106
+ let _gpuStorage = null;
16107
+ return Object.create(state, {
16108
+ uniforms: {
16109
+ get() {
16110
+ return _uniforms ?? (_uniforms = createScopedStore(state.uniforms));
16111
+ }
16112
+ },
16113
+ nodes: {
16114
+ get() {
16115
+ return _nodes ?? (_nodes = createScopedStore(state.nodes));
16116
+ }
16117
+ },
16118
+ buffers: {
16119
+ get() {
16120
+ return _buffers ?? (_buffers = createScopedStore(state.buffers));
16121
+ }
16122
+ },
16123
+ gpuStorage: {
16124
+ get() {
16125
+ return _gpuStorage ?? (_gpuStorage = createScopedStore(state.gpuStorage));
16126
+ }
16127
+ }
16128
+ });
16129
+ }
16130
+
15148
16131
  function addTexture(set, key, value) {
15149
16132
  set((state) => {
15150
16133
  const newMap = new Map(state.textures);
@@ -15184,6 +16167,27 @@ function createTextureOperations(set) {
15184
16167
  removeMultiple: (keys) => removeTextures(set, keys)
15185
16168
  };
15186
16169
  }
16170
+ function extractTSLValue(value) {
16171
+ if (value === null || value === void 0) return value;
16172
+ if (typeof value !== "object") return value;
16173
+ const node = value;
16174
+ if (!node.isNode) return value;
16175
+ if (node.isConstNode) {
16176
+ return node.value;
16177
+ }
16178
+ if ("value" in node) {
16179
+ let extractedValue = node.value;
16180
+ if (typeof node.traverse === "function") {
16181
+ node.traverse((n) => {
16182
+ if (n.isConstNode) {
16183
+ extractedValue = n.value;
16184
+ }
16185
+ });
16186
+ }
16187
+ return extractedValue;
16188
+ }
16189
+ return value;
16190
+ }
15187
16191
  function vectorize(inObject) {
15188
16192
  if (inObject === null || inObject === void 0) return inObject;
15189
16193
  if (typeof inObject === "string") {
@@ -15196,9 +16200,16 @@ function vectorize(inObject) {
15196
16200
  }
15197
16201
  if (typeof inObject !== "object") return inObject;
15198
16202
  const obj = inObject;
16203
+ if (obj.isNode) {
16204
+ return extractTSLValue(inObject);
16205
+ }
15199
16206
  if (obj.isVector2 || obj.isVector3 || obj.isVector4) return inObject;
15200
16207
  if (obj.isMatrix3 || obj.isMatrix4) return inObject;
15201
16208
  if (obj.isColor || obj.isEuler || obj.isQuaternion || obj.isSpherical) return inObject;
16209
+ if ("r" in obj && "g" in obj && "b" in obj && typeof obj.r === "number" && typeof obj.g === "number" && typeof obj.b === "number") {
16210
+ const scale = obj.r > 1 || obj.g > 1 || obj.b > 1 ? 1 / 255 : 1;
16211
+ return new webgpu.Color(obj.r * scale, obj.g * scale, obj.b * scale);
16212
+ }
15202
16213
  if ("x" in obj && "y" in obj && typeof obj.x === "number" && typeof obj.y === "number") {
15203
16214
  if ("w" in obj && typeof obj.w === "number" && "z" in obj && typeof obj.z === "number") {
15204
16215
  return new webgpu.Vector4(obj.x, obj.y, obj.z, obj.w);
@@ -15258,21 +16269,55 @@ function useUniforms(creatorOrScope, scope) {
15258
16269
  },
15259
16270
  [store]
15260
16271
  );
16272
+ const rebuildUniforms = React.useCallback(
16273
+ (targetScope) => {
16274
+ store.setState((state) => {
16275
+ let newUniforms = {};
16276
+ if (targetScope && targetScope !== "root") {
16277
+ const { [targetScope]: _, ...rest } = state.uniforms;
16278
+ newUniforms = rest;
16279
+ } else if (targetScope === "root") {
16280
+ for (const [key, value] of Object.entries(state.uniforms)) {
16281
+ if (!isUniformNode$1(value)) newUniforms[key] = value;
16282
+ }
16283
+ }
16284
+ return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
16285
+ });
16286
+ },
16287
+ [store]
16288
+ );
15261
16289
  const inputForMemoization = React.useMemo(() => {
15262
- return is.fun(creatorOrScope) ? creatorOrScope(store.getState()) : creatorOrScope;
16290
+ let raw = creatorOrScope;
16291
+ if (is.fun(creatorOrScope)) {
16292
+ const wrappedState = createLazyCreatorState(store.getState());
16293
+ raw = creatorOrScope(wrappedState);
16294
+ }
16295
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
16296
+ const normalized = {};
16297
+ for (const [key, value] of Object.entries(raw)) {
16298
+ normalized[key] = vectorize(value);
16299
+ }
16300
+ return normalized;
16301
+ }
16302
+ return raw;
15263
16303
  }, [creatorOrScope, store]);
15264
16304
  const memoizedInput = useCompareMemoize(inputForMemoization);
16305
+ const isReader = memoizedInput === void 0 || typeof memoizedInput === "string";
16306
+ const storeUniforms = useThree((s) => s.uniforms);
16307
+ const hmrVersion = useThree((s) => s._hmrVersion);
16308
+ const readerDep = isReader ? storeUniforms : null;
16309
+ const creatorDep = isReader ? null : hmrVersion;
15265
16310
  const uniforms = React.useMemo(() => {
15266
- const state = store.getState();
15267
- const set = store.setState;
15268
16311
  if (memoizedInput === void 0) {
15269
- return state.uniforms;
16312
+ return storeUniforms;
15270
16313
  }
15271
16314
  if (typeof memoizedInput === "string") {
15272
- const scopeData = state.uniforms[memoizedInput];
16315
+ const scopeData = storeUniforms[memoizedInput];
15273
16316
  if (scopeData && !isUniformNode$1(scopeData)) return scopeData;
15274
16317
  return {};
15275
16318
  }
16319
+ const state = store.getState();
16320
+ const set = store.setState;
15276
16321
  if (typeof memoizedInput !== "object" || memoizedInput === null) {
15277
16322
  throw new Error("Invalid uniform input");
15278
16323
  }
@@ -15316,8 +16361,22 @@ function useUniforms(creatorOrScope, scope) {
15316
16361
  }
15317
16362
  }
15318
16363
  return result;
15319
- }, [store, memoizedInput, scope]);
15320
- return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms };
16364
+ }, [store, memoizedInput, scope, readerDep, creatorDep]);
16365
+ return { ...uniforms, removeUniforms: removeUniforms2, clearUniforms, rebuildUniforms };
16366
+ }
16367
+ function rebuildAllUniforms(store, scope) {
16368
+ store.setState((state) => {
16369
+ let newUniforms = {};
16370
+ if (scope && scope !== "root") {
16371
+ const { [scope]: _, ...rest } = state.uniforms;
16372
+ newUniforms = rest;
16373
+ } else if (scope === "root") {
16374
+ for (const [key, value] of Object.entries(state.uniforms)) {
16375
+ if (!isUniformNode$1(value)) newUniforms[key] = value;
16376
+ }
16377
+ }
16378
+ return { uniforms: newUniforms, _hmrVersion: state._hmrVersion + 1 };
16379
+ });
15321
16380
  }
15322
16381
  function removeUniforms(set, names, scope) {
15323
16382
  set((state) => {
@@ -15382,15 +16441,17 @@ function isSameThreeType(a, b) {
15382
16441
  }
15383
16442
 
15384
16443
  const isUniformNode = (value) => value !== null && typeof value === "object" && "value" in value && "uuid" in value;
16444
+ const isTSLNode$1 = (value) => value !== null && typeof value === "object" && "uuid" in value && "nodeType" in value;
15385
16445
  function useUniform(name, value) {
15386
16446
  const store = useStore();
16447
+ const hmrVersion = useThree((s) => s._hmrVersion);
15387
16448
  return React.useMemo(() => {
15388
16449
  const state = store.getState();
15389
16450
  const set = store.setState;
15390
16451
  const existing = state.uniforms[name];
15391
16452
  if (existing && isUniformNode(existing)) {
15392
- if (value !== void 0) {
15393
- existing.value = value;
16453
+ if (value !== void 0 && !isTSLNode$1(value) && !isUniformNode(value)) {
16454
+ existing.value = typeof value === "string" ? new webgpu.Color(value) : value;
15394
16455
  }
15395
16456
  return existing;
15396
16457
  }
@@ -15399,7 +16460,24 @@ function useUniform(name, value) {
15399
16460
  `[useUniform] Uniform "${name}" not found. Create it first with: useUniform('${name}', initialValue)`
15400
16461
  );
15401
16462
  }
15402
- const node = tsl.uniform(value);
16463
+ if (isUniformNode(value)) {
16464
+ const node2 = value;
16465
+ if (typeof node2.setName === "function") {
16466
+ node2.setName(name);
16467
+ }
16468
+ set((s) => ({
16469
+ uniforms: { ...s.uniforms, [name]: node2 }
16470
+ }));
16471
+ return node2;
16472
+ }
16473
+ let node;
16474
+ if (isTSLNode$1(value)) {
16475
+ node = tsl.uniform(value);
16476
+ } else if (typeof value === "string") {
16477
+ node = tsl.uniform(new webgpu.Color(value));
16478
+ } else {
16479
+ node = tsl.uniform(value);
16480
+ }
15403
16481
  if (typeof node.setName === "function") {
15404
16482
  node.setName(name);
15405
16483
  }
@@ -15410,7 +16488,7 @@ function useUniform(name, value) {
15410
16488
  }
15411
16489
  }));
15412
16490
  return node;
15413
- }, [store, name]);
16491
+ }, [store, name, hmrVersion]);
15414
16492
  }
15415
16493
 
15416
16494
  const isTSLNode = (value) => value !== null && typeof value === "object" && ("uuid" in value || "nodeType" in value);
@@ -15451,19 +16529,46 @@ function useNodes(creatorOrScope, scope) {
15451
16529
  },
15452
16530
  [store]
15453
16531
  );
16532
+ const rebuildNodes = React.useCallback(
16533
+ (targetScope) => {
16534
+ store.setState((state) => {
16535
+ let newNodes = state.nodes;
16536
+ if (targetScope && targetScope !== "root") {
16537
+ const { [targetScope]: _, ...rest } = state.nodes;
16538
+ newNodes = rest;
16539
+ } else if (targetScope === "root") {
16540
+ newNodes = {};
16541
+ for (const [key, value] of Object.entries(state.nodes)) {
16542
+ if (!isTSLNode(value)) newNodes[key] = value;
16543
+ }
16544
+ } else {
16545
+ newNodes = {};
16546
+ }
16547
+ return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
16548
+ });
16549
+ },
16550
+ [store]
16551
+ );
16552
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16553
+ const storeNodes = useThree((s) => s.nodes);
16554
+ const hmrVersion = useThree((s) => s._hmrVersion);
16555
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16556
+ const readerDep = isReader ? storeNodes : null;
16557
+ const creatorDep = isReader ? null : hmrVersion;
15454
16558
  const nodes = React.useMemo(() => {
15455
- const state = store.getState();
15456
- const set = store.setState;
15457
16559
  if (creatorOrScope === void 0) {
15458
- return state.nodes;
16560
+ return storeNodes;
15459
16561
  }
15460
16562
  if (typeof creatorOrScope === "string") {
15461
- const scopeData = state.nodes[creatorOrScope];
16563
+ const scopeData = storeNodes[creatorOrScope];
15462
16564
  if (scopeData && !isTSLNode(scopeData)) return scopeData;
15463
16565
  return {};
15464
16566
  }
16567
+ const state = store.getState();
16568
+ const set = store.setState;
15465
16569
  const creator = creatorOrScope;
15466
- const created = creator(state);
16570
+ const wrappedState = createLazyCreatorState(state);
16571
+ const created = creator(wrappedState);
15467
16572
  const result = {};
15468
16573
  let hasNewNodes = false;
15469
16574
  if (scope) {
@@ -15472,7 +16577,7 @@ function useNodes(creatorOrScope, scope) {
15472
16577
  if (currentScope[name]) {
15473
16578
  result[name] = currentScope[name];
15474
16579
  } else {
15475
- if (typeof node.label === "function") node.setName(`${scope}.${name}`);
16580
+ node.setName?.(`${scope}.${name}`);
15476
16581
  result[name] = node;
15477
16582
  hasNewNodes = true;
15478
16583
  }
@@ -15492,7 +16597,7 @@ function useNodes(creatorOrScope, scope) {
15492
16597
  if (existing && isTSLNode(existing)) {
15493
16598
  result[name] = existing;
15494
16599
  } else {
15495
- if (typeof node.label === "function") node.setName(name);
16600
+ node.setName?.(name);
15496
16601
  result[name] = node;
15497
16602
  hasNewNodes = true;
15498
16603
  }
@@ -15501,8 +16606,25 @@ function useNodes(creatorOrScope, scope) {
15501
16606
  set((s) => ({ nodes: { ...s.nodes, ...result } }));
15502
16607
  }
15503
16608
  return result;
15504
- }, [store, typeof creatorOrScope === "string" ? creatorOrScope : scope]);
15505
- return { ...nodes, removeNodes: removeNodes2, clearNodes };
16609
+ }, [store, scopeDep, readerDep, creatorDep]);
16610
+ return { ...nodes, removeNodes: removeNodes2, clearNodes, rebuildNodes };
16611
+ }
16612
+ function rebuildAllNodes(store, scope) {
16613
+ store.setState((state) => {
16614
+ let newNodes = state.nodes;
16615
+ if (scope && scope !== "root") {
16616
+ const { [scope]: _, ...rest } = state.nodes;
16617
+ newNodes = rest;
16618
+ } else if (scope === "root") {
16619
+ newNodes = {};
16620
+ for (const [key, value] of Object.entries(state.nodes)) {
16621
+ if (!isTSLNode(value)) newNodes[key] = value;
16622
+ }
16623
+ } else {
16624
+ newNodes = {};
16625
+ }
16626
+ return { nodes: newNodes, _hmrVersion: state._hmrVersion + 1 };
16627
+ });
15506
16628
  }
15507
16629
  function removeNodes(set, names, scope) {
15508
16630
  set((state) => {
@@ -15536,13 +16658,358 @@ function useLocalNodes(creator) {
15536
16658
  const uniforms = useThree((s) => s.uniforms);
15537
16659
  const nodes = useThree((s) => s.nodes);
15538
16660
  const textures = useThree((s) => s.textures);
16661
+ const hmrVersion = useThree((s) => s._hmrVersion);
15539
16662
  return React.useMemo(() => {
16663
+ const wrappedState = createLazyCreatorState(store.getState());
16664
+ return creator(wrappedState);
16665
+ }, [store, creator, uniforms, nodes, textures, hmrVersion]);
16666
+ }
16667
+
16668
+ const isBufferLike = (value) => {
16669
+ if (value === null || typeof value !== "object") return false;
16670
+ if (ArrayBuffer.isView(value)) return true;
16671
+ if ("isBufferAttribute" in value) return true;
16672
+ if ("uuid" in value || "nodeType" in value) return true;
16673
+ return false;
16674
+ };
16675
+ const disposeBuffer = (buffer) => {
16676
+ if (buffer === null || typeof buffer !== "object") return;
16677
+ if ("dispose" in buffer && typeof buffer.dispose === "function") {
16678
+ buffer.dispose();
16679
+ }
16680
+ };
16681
+ function useBuffers(creatorOrScope, scope) {
16682
+ const store = useStore();
16683
+ const removeBuffers = React.useCallback(
16684
+ (names, targetScope) => {
16685
+ const nameArray = Array.isArray(names) ? names : [names];
16686
+ store.setState((state) => {
16687
+ if (targetScope) {
16688
+ const currentScope = { ...state.buffers[targetScope] };
16689
+ for (const name of nameArray) delete currentScope[name];
16690
+ return { buffers: { ...state.buffers, [targetScope]: currentScope } };
16691
+ }
16692
+ const buffers2 = { ...state.buffers };
16693
+ for (const name of nameArray) if (isBufferLike(buffers2[name])) delete buffers2[name];
16694
+ return { buffers: buffers2 };
16695
+ });
16696
+ },
16697
+ [store]
16698
+ );
16699
+ const clearBuffers = React.useCallback(
16700
+ (targetScope) => {
16701
+ store.setState((state) => {
16702
+ if (targetScope && targetScope !== "root") {
16703
+ const { [targetScope]: _, ...rest } = state.buffers;
16704
+ return { buffers: rest };
16705
+ }
16706
+ if (targetScope === "root") {
16707
+ const buffers2 = {};
16708
+ for (const [key, value] of Object.entries(state.buffers)) {
16709
+ if (!isBufferLike(value)) buffers2[key] = value;
16710
+ }
16711
+ return { buffers: buffers2 };
16712
+ }
16713
+ return { buffers: {} };
16714
+ });
16715
+ },
16716
+ [store]
16717
+ );
16718
+ const rebuildBuffers = React.useCallback(
16719
+ (targetScope) => {
16720
+ store.setState((state) => {
16721
+ let newBuffers = state.buffers;
16722
+ if (targetScope && targetScope !== "root") {
16723
+ const { [targetScope]: _, ...rest } = state.buffers;
16724
+ newBuffers = rest;
16725
+ } else if (targetScope === "root") {
16726
+ newBuffers = {};
16727
+ for (const [key, value] of Object.entries(state.buffers)) {
16728
+ if (!isBufferLike(value)) newBuffers[key] = value;
16729
+ }
16730
+ } else {
16731
+ newBuffers = {};
16732
+ }
16733
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16734
+ });
16735
+ },
16736
+ [store]
16737
+ );
16738
+ const disposeBuffers = React.useCallback(
16739
+ (names, targetScope) => {
16740
+ const nameArray = Array.isArray(names) ? names : [names];
16741
+ const state = store.getState();
16742
+ for (const name of nameArray) {
16743
+ const buffer = targetScope ? state.buffers[targetScope]?.[name] : state.buffers[name];
16744
+ if (buffer && isBufferLike(buffer)) {
16745
+ disposeBuffer(buffer);
16746
+ }
16747
+ }
16748
+ removeBuffers(names, targetScope);
16749
+ },
16750
+ [store, removeBuffers]
16751
+ );
16752
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16753
+ const storeBuffers = useThree((s) => s.buffers);
16754
+ const hmrVersion = useThree((s) => s._hmrVersion);
16755
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16756
+ const readerDep = isReader ? storeBuffers : null;
16757
+ const creatorDep = isReader ? null : hmrVersion;
16758
+ const buffers = React.useMemo(() => {
16759
+ if (creatorOrScope === void 0) {
16760
+ return storeBuffers;
16761
+ }
16762
+ if (typeof creatorOrScope === "string") {
16763
+ const scopeData = storeBuffers[creatorOrScope];
16764
+ if (scopeData && !isBufferLike(scopeData)) return scopeData;
16765
+ return {};
16766
+ }
16767
+ const state = store.getState();
16768
+ const set = store.setState;
16769
+ const creator = creatorOrScope;
16770
+ const wrappedState = createLazyCreatorState(state);
16771
+ const created = creator(wrappedState);
16772
+ const result = {};
16773
+ let hasNewBuffers = false;
16774
+ if (scope) {
16775
+ const currentScope = state.buffers[scope] ?? {};
16776
+ for (const [name, buffer] of Object.entries(created)) {
16777
+ if (currentScope[name]) {
16778
+ result[name] = currentScope[name];
16779
+ } else {
16780
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16781
+ buffer.setName(`${scope}.${name}`);
16782
+ }
16783
+ result[name] = buffer;
16784
+ hasNewBuffers = true;
16785
+ }
16786
+ }
16787
+ if (hasNewBuffers) {
16788
+ set((s) => ({
16789
+ buffers: {
16790
+ ...s.buffers,
16791
+ [scope]: { ...s.buffers[scope], ...result }
16792
+ }
16793
+ }));
16794
+ }
16795
+ return result;
16796
+ }
16797
+ for (const [name, buffer] of Object.entries(created)) {
16798
+ const existing = state.buffers[name];
16799
+ if (existing && isBufferLike(existing)) {
16800
+ result[name] = existing;
16801
+ } else {
16802
+ if ("setName" in buffer && typeof buffer.setName === "function") {
16803
+ buffer.setName(name);
16804
+ }
16805
+ result[name] = buffer;
16806
+ hasNewBuffers = true;
16807
+ }
16808
+ }
16809
+ if (hasNewBuffers) {
16810
+ set((s) => ({ buffers: { ...s.buffers, ...result } }));
16811
+ }
16812
+ return result;
16813
+ }, [store, scopeDep, readerDep, creatorDep]);
16814
+ return { ...buffers, removeBuffers, clearBuffers, rebuildBuffers, disposeBuffers };
16815
+ }
16816
+ function rebuildAllBuffers(store, scope) {
16817
+ store.setState((state) => {
16818
+ let newBuffers = state.buffers;
16819
+ if (scope && scope !== "root") {
16820
+ const { [scope]: _, ...rest } = state.buffers;
16821
+ newBuffers = rest;
16822
+ } else if (scope === "root") {
16823
+ newBuffers = {};
16824
+ for (const [key, value] of Object.entries(state.buffers)) {
16825
+ if (!isBufferLike(value)) newBuffers[key] = value;
16826
+ }
16827
+ } else {
16828
+ newBuffers = {};
16829
+ }
16830
+ return { buffers: newBuffers, _hmrVersion: state._hmrVersion + 1 };
16831
+ });
16832
+ }
16833
+
16834
+ const isStorageLike = (value) => {
16835
+ if (value === null || typeof value !== "object") return false;
16836
+ if ("isTexture" in value) return true;
16837
+ if ("isData3DTexture" in value) return true;
16838
+ if ("uuid" in value || "nodeType" in value) return true;
16839
+ return false;
16840
+ };
16841
+ const disposeStorage = (storage) => {
16842
+ if (storage === null || typeof storage !== "object") return;
16843
+ if ("dispose" in storage && typeof storage.dispose === "function") {
16844
+ storage.dispose();
16845
+ }
16846
+ };
16847
+ function useGPUStorage(creatorOrScope, scope) {
16848
+ const store = useStore();
16849
+ const removeStorage = React.useCallback(
16850
+ (names, targetScope) => {
16851
+ const nameArray = Array.isArray(names) ? names : [names];
16852
+ store.setState((state) => {
16853
+ if (targetScope) {
16854
+ const currentScope = { ...state.gpuStorage[targetScope] };
16855
+ for (const name of nameArray) delete currentScope[name];
16856
+ return { gpuStorage: { ...state.gpuStorage, [targetScope]: currentScope } };
16857
+ }
16858
+ const gpuStorage2 = { ...state.gpuStorage };
16859
+ for (const name of nameArray) if (isStorageLike(gpuStorage2[name])) delete gpuStorage2[name];
16860
+ return { gpuStorage: gpuStorage2 };
16861
+ });
16862
+ },
16863
+ [store]
16864
+ );
16865
+ const clearStorage = React.useCallback(
16866
+ (targetScope) => {
16867
+ store.setState((state) => {
16868
+ if (targetScope && targetScope !== "root") {
16869
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16870
+ return { gpuStorage: rest };
16871
+ }
16872
+ if (targetScope === "root") {
16873
+ const gpuStorage2 = {};
16874
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16875
+ if (!isStorageLike(value)) gpuStorage2[key] = value;
16876
+ }
16877
+ return { gpuStorage: gpuStorage2 };
16878
+ }
16879
+ return { gpuStorage: {} };
16880
+ });
16881
+ },
16882
+ [store]
16883
+ );
16884
+ const rebuildStorage = React.useCallback(
16885
+ (targetScope) => {
16886
+ store.setState((state) => {
16887
+ let newStorage = state.gpuStorage;
16888
+ if (targetScope && targetScope !== "root") {
16889
+ const { [targetScope]: _, ...rest } = state.gpuStorage;
16890
+ newStorage = rest;
16891
+ } else if (targetScope === "root") {
16892
+ newStorage = {};
16893
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
16894
+ if (!isStorageLike(value)) newStorage[key] = value;
16895
+ }
16896
+ } else {
16897
+ newStorage = {};
16898
+ }
16899
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
16900
+ });
16901
+ },
16902
+ [store]
16903
+ );
16904
+ const disposeStorageFn = React.useCallback(
16905
+ (names, targetScope) => {
16906
+ const nameArray = Array.isArray(names) ? names : [names];
16907
+ const state = store.getState();
16908
+ for (const name of nameArray) {
16909
+ const storage = targetScope ? state.gpuStorage[targetScope]?.[name] : state.gpuStorage[name];
16910
+ if (storage && isStorageLike(storage)) {
16911
+ disposeStorage(storage);
16912
+ }
16913
+ }
16914
+ removeStorage(names, targetScope);
16915
+ },
16916
+ [store, removeStorage]
16917
+ );
16918
+ const isReader = creatorOrScope === void 0 || typeof creatorOrScope === "string";
16919
+ const storeStorage = useThree((s) => s.gpuStorage);
16920
+ const hmrVersion = useThree((s) => s._hmrVersion);
16921
+ const scopeDep = typeof creatorOrScope === "string" ? creatorOrScope : scope;
16922
+ const readerDep = isReader ? storeStorage : null;
16923
+ const creatorDep = isReader ? null : hmrVersion;
16924
+ const gpuStorage = React.useMemo(() => {
16925
+ if (creatorOrScope === void 0) {
16926
+ return storeStorage;
16927
+ }
16928
+ if (typeof creatorOrScope === "string") {
16929
+ const scopeData = storeStorage[creatorOrScope];
16930
+ if (scopeData && !isStorageLike(scopeData)) return scopeData;
16931
+ return {};
16932
+ }
15540
16933
  const state = store.getState();
15541
- return creator(state);
15542
- }, [store, creator, uniforms, nodes, textures]);
16934
+ const set = store.setState;
16935
+ const creator = creatorOrScope;
16936
+ const wrappedState = createLazyCreatorState(state);
16937
+ const created = creator(wrappedState);
16938
+ const result = {};
16939
+ let hasNewStorage = false;
16940
+ if (scope) {
16941
+ const currentScope = state.gpuStorage[scope] ?? {};
16942
+ for (const [name, storage] of Object.entries(created)) {
16943
+ if (currentScope[name]) {
16944
+ result[name] = currentScope[name];
16945
+ } else {
16946
+ if ("setName" in storage && typeof storage.setName === "function") {
16947
+ storage.setName(`${scope}.${name}`);
16948
+ }
16949
+ if ("name" in storage && typeof storage.name === "string") {
16950
+ storage.name = `${scope}.${name}`;
16951
+ }
16952
+ result[name] = storage;
16953
+ hasNewStorage = true;
16954
+ }
16955
+ }
16956
+ if (hasNewStorage) {
16957
+ set((s) => ({
16958
+ gpuStorage: {
16959
+ ...s.gpuStorage,
16960
+ [scope]: { ...s.gpuStorage[scope], ...result }
16961
+ }
16962
+ }));
16963
+ }
16964
+ return result;
16965
+ }
16966
+ for (const [name, storage] of Object.entries(created)) {
16967
+ const existing = state.gpuStorage[name];
16968
+ if (existing && isStorageLike(existing)) {
16969
+ result[name] = existing;
16970
+ } else {
16971
+ if ("setName" in storage && typeof storage.setName === "function") {
16972
+ storage.setName(name);
16973
+ }
16974
+ if ("name" in storage && typeof storage.name === "string") {
16975
+ storage.name = name;
16976
+ }
16977
+ result[name] = storage;
16978
+ hasNewStorage = true;
16979
+ }
16980
+ }
16981
+ if (hasNewStorage) {
16982
+ set((s) => ({ gpuStorage: { ...s.gpuStorage, ...result } }));
16983
+ }
16984
+ return result;
16985
+ }, [store, scopeDep, readerDep, creatorDep]);
16986
+ return {
16987
+ ...gpuStorage,
16988
+ removeStorage,
16989
+ clearStorage,
16990
+ rebuildStorage,
16991
+ disposeStorage: disposeStorageFn
16992
+ };
16993
+ }
16994
+ function rebuildAllStorage(store, scope) {
16995
+ store.setState((state) => {
16996
+ let newStorage = state.gpuStorage;
16997
+ if (scope && scope !== "root") {
16998
+ const { [scope]: _, ...rest } = state.gpuStorage;
16999
+ newStorage = rest;
17000
+ } else if (scope === "root") {
17001
+ newStorage = {};
17002
+ for (const [key, value] of Object.entries(state.gpuStorage)) {
17003
+ if (!isStorageLike(value)) newStorage[key] = value;
17004
+ }
17005
+ } else {
17006
+ newStorage = {};
17007
+ }
17008
+ return { gpuStorage: newStorage, _hmrVersion: state._hmrVersion + 1 };
17009
+ });
15543
17010
  }
15544
17011
 
15545
- function usePostProcessing(mainCB, setupCB) {
17012
+ function useRenderPipeline(mainCB, setupCB) {
15546
17013
  const store = useStore();
15547
17014
  const { scene, camera, renderer, isLegacy } = useThree();
15548
17015
  const callbacksRanRef = React.useRef(false);
@@ -15552,12 +17019,16 @@ function usePostProcessing(mainCB, setupCB) {
15552
17019
  mainCBRef.current = mainCB;
15553
17020
  setupCBRef.current = setupCB;
15554
17021
  const [rebuildVersion, setRebuildVersion] = React.useState(0);
17022
+ React.useEffect(() => {
17023
+ callbacksRanRef.current = false;
17024
+ scenePassCacheRef.current = null;
17025
+ }, []);
15555
17026
  const clearPasses = React.useCallback(() => {
15556
17027
  store.setState({ passes: {} });
15557
17028
  }, [store]);
15558
17029
  const reset = React.useCallback(() => {
15559
17030
  store.setState({
15560
- postProcessing: null,
17031
+ renderPipeline: null,
15561
17032
  passes: {}
15562
17033
  });
15563
17034
  callbacksRanRef.current = false;
@@ -15570,13 +17041,13 @@ function usePostProcessing(mainCB, setupCB) {
15570
17041
  }, []);
15571
17042
  React.useLayoutEffect(() => {
15572
17043
  if (isLegacy) {
15573
- throw new Error("usePostProcessing is only available with WebGPU renderer. Set renderer prop on Canvas.");
17044
+ throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
15574
17045
  }
15575
17046
  if (!renderer || !scene || !camera) return;
15576
17047
  const state = store.getState();
15577
17048
  const set = store.setState;
15578
17049
  try {
15579
- let pp = state.postProcessing;
17050
+ let pp = state.renderPipeline;
15580
17051
  let currentPasses = { ...state.passes };
15581
17052
  let justCreatedPP = false;
15582
17053
  if (!pp) {
@@ -15593,7 +17064,7 @@ function usePostProcessing(mainCB, setupCB) {
15593
17064
  }
15594
17065
  currentPasses.scenePass = scenePass;
15595
17066
  if (!pp.outputNode || justCreatedPP) pp.outputNode = scenePass;
15596
- set({ postProcessing: pp, passes: currentPasses });
17067
+ set({ renderPipeline: pp, passes: currentPasses });
15597
17068
  const shouldRunCallbacks = justCreatedPP || !callbacksRanRef.current || !cacheValid;
15598
17069
  if (shouldRunCallbacks) {
15599
17070
  if (setupCBRef.current) {
@@ -15615,19 +17086,19 @@ function usePostProcessing(mainCB, setupCB) {
15615
17086
  callbacksRanRef.current = true;
15616
17087
  }
15617
17088
  } catch (error) {
15618
- console.error("[usePostProcessing] Setup error:", error);
17089
+ console.error("[useRenderPipeline] Setup error:", error);
15619
17090
  }
15620
17091
  }, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
15621
17092
  const passes = useThree((s) => s.passes);
15622
- const postProcessing = useThree((s) => s.postProcessing);
17093
+ const renderPipeline = useThree((s) => s.renderPipeline);
15623
17094
  return {
15624
17095
  passes,
15625
- postProcessing,
17096
+ renderPipeline,
15626
17097
  clearPasses,
15627
17098
  reset,
15628
17099
  rebuild,
15629
- // isReady indicates if PostProcessing is configured and ready for rendering
15630
- isReady: postProcessing !== null
17100
+ // isReady indicates if RenderPipeline is configured and ready for rendering
17101
+ isReady: renderPipeline !== null
15631
17102
  };
15632
17103
  }
15633
17104
 
@@ -15635,8 +17106,15 @@ extend(THREE);
15635
17106
 
15636
17107
  exports.Block = Block;
15637
17108
  exports.Canvas = Canvas;
17109
+ exports.Environment = Environment;
17110
+ exports.EnvironmentCube = EnvironmentCube;
17111
+ exports.EnvironmentMap = EnvironmentMap;
17112
+ exports.EnvironmentPortal = EnvironmentPortal;
15638
17113
  exports.ErrorBoundary = ErrorBoundary;
17114
+ exports.FROM_REF = FROM_REF;
15639
17115
  exports.IsObject = IsObject;
17116
+ exports.ONCE = ONCE;
17117
+ exports.Portal = Portal;
15640
17118
  exports.R3F_BUILD_LEGACY = R3F_BUILD_LEGACY;
15641
17119
  exports.R3F_BUILD_WEBGPU = R3F_BUILD_WEBGPU;
15642
17120
  exports.REACT_INTERNAL_PROPS = REACT_INTERNAL_PROPS;
@@ -15662,6 +17140,7 @@ exports.createEvents = createEvents;
15662
17140
  exports.createPointerEvents = createPointerEvents;
15663
17141
  exports.createPortal = createPortal;
15664
17142
  exports.createRoot = createRoot;
17143
+ exports.createScopedStore = createScopedStore;
15665
17144
  exports.createStore = createStore;
15666
17145
  exports.createTextureOperations = createTextureOperations;
15667
17146
  exports.detach = detach;
@@ -15671,33 +17150,50 @@ exports.events = createPointerEvents;
15671
17150
  exports.extend = extend;
15672
17151
  exports.findInitialRoot = findInitialRoot;
15673
17152
  exports.flushSync = flushSync;
17153
+ exports.fromRef = fromRef;
15674
17154
  exports.getInstanceProps = getInstanceProps;
17155
+ exports.getPrimary = getPrimary;
17156
+ exports.getPrimaryIds = getPrimaryIds;
15675
17157
  exports.getRootState = getRootState;
15676
17158
  exports.getScheduler = getScheduler;
15677
17159
  exports.getUuidPrefix = getUuidPrefix;
15678
17160
  exports.hasConstructor = hasConstructor;
17161
+ exports.hasPrimary = hasPrimary;
15679
17162
  exports.invalidate = invalidate;
15680
17163
  exports.invalidateInstance = invalidateInstance;
15681
17164
  exports.is = is;
15682
17165
  exports.isColorRepresentation = isColorRepresentation;
15683
17166
  exports.isCopyable = isCopyable;
17167
+ exports.isFromRef = isFromRef;
15684
17168
  exports.isObject3D = isObject3D;
17169
+ exports.isOnce = isOnce;
15685
17170
  exports.isOrthographicCamera = isOrthographicCamera;
15686
17171
  exports.isRef = isRef;
15687
17172
  exports.isRenderer = isRenderer;
15688
17173
  exports.isTexture = isTexture;
15689
17174
  exports.isVectorLike = isVectorLike;
17175
+ exports.once = once;
15690
17176
  exports.prepare = prepare;
17177
+ exports.presetsObj = presetsObj;
17178
+ exports.rebuildAllBuffers = rebuildAllBuffers;
17179
+ exports.rebuildAllNodes = rebuildAllNodes;
17180
+ exports.rebuildAllStorage = rebuildAllStorage;
17181
+ exports.rebuildAllUniforms = rebuildAllUniforms;
15691
17182
  exports.reconciler = reconciler;
17183
+ exports.registerPrimary = registerPrimary;
15692
17184
  exports.removeInteractivity = removeInteractivity;
15693
17185
  exports.removeNodes = removeNodes;
15694
17186
  exports.removeUniforms = removeUniforms;
15695
17187
  exports.resolve = resolve;
15696
17188
  exports.unmountComponentAtNode = unmountComponentAtNode;
17189
+ exports.unregisterPrimary = unregisterPrimary;
15697
17190
  exports.updateCamera = updateCamera;
15698
17191
  exports.updateFrustum = updateFrustum;
15699
17192
  exports.useBridge = useBridge;
17193
+ exports.useBuffers = useBuffers;
17194
+ exports.useEnvironment = useEnvironment;
15700
17195
  exports.useFrame = useFrame;
17196
+ exports.useGPUStorage = useGPUStorage;
15701
17197
  exports.useGraph = useGraph;
15702
17198
  exports.useInstanceHandle = useInstanceHandle;
15703
17199
  exports.useIsomorphicLayoutEffect = useIsomorphicLayoutEffect;
@@ -15705,7 +17201,7 @@ exports.useLoader = useLoader;
15705
17201
  exports.useLocalNodes = useLocalNodes;
15706
17202
  exports.useMutableCallback = useMutableCallback;
15707
17203
  exports.useNodes = useNodes;
15708
- exports.usePostProcessing = usePostProcessing;
17204
+ exports.useRenderPipeline = useRenderPipeline;
15709
17205
  exports.useRenderTarget = useRenderTarget;
15710
17206
  exports.useStore = useStore;
15711
17207
  exports.useTexture = useTexture;
@@ -15713,3 +17209,4 @@ exports.useTextures = useTextures;
15713
17209
  exports.useThree = useThree;
15714
17210
  exports.useUniform = useUniform;
15715
17211
  exports.useUniforms = useUniforms;
17212
+ exports.waitForPrimary = waitForPrimary;