@react-three/fiber 10.0.0-canary.f046a54 → 10.0.0-canary.f5d9cbd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,22 +1,20 @@
1
1
  import * as webgpu from 'three/webgpu';
2
- import { RenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, ShaderMaterial, Uniform, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer } from 'three/webgpu';
3
- import { WebGLRenderTarget, WebGLRenderer } from 'three';
4
- import { Inspector } from 'three/addons/inspector/Inspector.js';
2
+ import { CubeRenderTarget, RenderTarget, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, ShaderMaterial, Uniform, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, Scene, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer, HalfFloatType, Color } from 'three/webgpu';
3
+ import { WebGLCubeRenderTarget, WebGLRenderTarget, WebGLRenderer } from 'three';
5
4
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
6
5
  import * as React from 'react';
7
- import React__default, { useLayoutEffect, useRef, useMemo, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
6
+ import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
8
7
  import useMeasure from 'react-use-measure';
9
8
  import { useFiber, useContextBridge, traverseFiber, FiberProvider } from 'its-fine';
10
- import { useThree as useThree$1, useLoader as useLoader$1, useFrame as useFrame$1, createPortal as createPortal$1, applyProps as applyProps$1, extend as extend$1 } from '@react-three/fiber';
9
+ import { createWithEqualityFn } from 'zustand/traditional';
10
+ import { getScheduler } from '@pmndrs/scheduler';
11
+ export { Scheduler, getScheduler } from '@pmndrs/scheduler';
12
+ import Tb, { unstable_getCurrentPriorityLevel, unstable_IdlePriority, unstable_LowPriority, unstable_NormalPriority, unstable_UserBlockingPriority, unstable_ImmediatePriority, unstable_scheduleCallback } from 'scheduler';
11
13
  import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
12
14
  import { HDRLoader } from 'three/examples/jsm/loaders/HDRLoader.js';
13
15
  import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
14
16
  import { UltraHDRLoader } from 'three/examples/jsm/loaders/UltraHDRLoader.js';
15
17
  import { GainMapLoader } from '@monogrid/gainmap-js';
16
- import Tb, { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
17
- import { createWithEqualityFn } from 'zustand/traditional';
18
- import { getScheduler } from '@pmndrs/scheduler';
19
- export { Scheduler, getScheduler } from '@pmndrs/scheduler';
20
18
  import { suspend, preload, clear } from 'suspend-react';
21
19
 
22
20
  function _mergeNamespaces(n, m) {
@@ -33,15 +31,22 @@ function _mergeNamespaces(n, m) {
33
31
 
34
32
  const R3F_BUILD_LEGACY = true;
35
33
  const R3F_BUILD_WEBGPU = true;
34
+ async function loadInspector() {
35
+ const { Inspector } = await import('three/addons/inspector/Inspector.js');
36
+ return Inspector;
37
+ }
36
38
 
37
39
  const THREE = /*#__PURE__*/_mergeNamespaces({
38
40
  __proto__: null,
39
- Inspector: Inspector,
41
+ CubeRenderTarget: CubeRenderTarget,
42
+ CubeRenderTargetCompat: CubeRenderTarget,
40
43
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
41
44
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
42
45
  RenderTargetCompat: RenderTarget,
46
+ WebGLCubeRenderTarget: WebGLCubeRenderTarget,
43
47
  WebGLRenderTarget: WebGLRenderTarget,
44
- WebGLRenderer: WebGLRenderer
48
+ WebGLRenderer: WebGLRenderer,
49
+ loadInspector: loadInspector
45
50
  }, [webgpu]);
46
51
 
47
52
  const primaryRegistry = /* @__PURE__ */ new Map();
@@ -102,550 +107,223 @@ function getPrimaryIds() {
102
107
  return Array.from(primaryRegistry.keys());
103
108
  }
104
109
 
105
- const presetsObj = {
106
- apartment: "lebombo_1k.hdr",
107
- city: "potsdamer_platz_1k.hdr",
108
- dawn: "kiara_1_dawn_1k.hdr",
109
- forest: "forest_slope_1k.hdr",
110
- lobby: "st_fagans_interior_1k.hdr",
111
- night: "dikhololo_night_1k.hdr",
112
- park: "rooitou_park_1k.hdr",
113
- studio: "studio_small_03_1k.hdr",
114
- sunset: "venice_sunset_1k.hdr",
115
- warehouse: "empty_warehouse_01_1k.hdr"
116
- };
110
+ var __defProp = Object.defineProperty;
111
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
112
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
113
+ const useIsomorphicLayoutEffect = /* @__PURE__ */ (() => typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative"))() ? React.useLayoutEffect : React.useEffect;
114
+ function useMutableCallback(fn) {
115
+ const ref = React.useRef(fn);
116
+ useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
117
+ return ref;
118
+ }
119
+ function useBridge() {
120
+ const fiber = useFiber();
121
+ const ContextBridge = useContextBridge();
122
+ return React.useMemo(
123
+ () => ({ children }) => {
124
+ const strict = !!traverseFiber(fiber, true, (node) => node.type === React.StrictMode);
125
+ const Root = strict ? React.StrictMode : React.Fragment;
126
+ return /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx(ContextBridge, { children }) });
127
+ },
128
+ [fiber, ContextBridge]
129
+ );
130
+ }
131
+ function Block({ set }) {
132
+ useIsomorphicLayoutEffect(() => {
133
+ set(new Promise(() => null));
134
+ return () => set(false);
135
+ }, [set]);
136
+ return null;
137
+ }
138
+ const ErrorBoundary = /* @__PURE__ */ (() => {
139
+ var _a;
140
+ return _a = class extends React.Component {
141
+ constructor() {
142
+ super(...arguments);
143
+ __publicField(this, "state", { error: false });
144
+ }
145
+ componentDidCatch(err) {
146
+ this.props.set(err);
147
+ }
148
+ render() {
149
+ return this.state.error ? null : this.props.children;
150
+ }
151
+ }, __publicField(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
152
+ })();
117
153
 
118
- const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
119
- const isArray = (arr) => Array.isArray(arr);
120
- const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
121
- function useEnvironment({
122
- files = defaultFiles,
123
- path = "",
124
- preset = void 0,
125
- colorSpace = void 0,
126
- extensions
127
- } = {}) {
128
- if (preset) {
129
- validatePreset(preset);
130
- files = presetsObj[preset];
131
- path = CUBEMAP_ROOT;
132
- }
133
- const multiFile = isArray(files);
134
- const { extension, isCubemap } = getExtension(files);
135
- const loader = getLoader$1(extension);
136
- if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
137
- const renderer = useThree$1((state) => state.renderer);
138
- useLayoutEffect(() => {
139
- if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
140
- function clearGainmapTexture() {
141
- useLoader$1.clear(loader, multiFile ? [files] : files);
154
+ const is = {
155
+ obj: (a) => a === Object(a) && !is.arr(a) && typeof a !== "function",
156
+ fun: (a) => typeof a === "function",
157
+ str: (a) => typeof a === "string",
158
+ num: (a) => typeof a === "number",
159
+ boo: (a) => typeof a === "boolean",
160
+ und: (a) => a === void 0,
161
+ nul: (a) => a === null,
162
+ arr: (a) => Array.isArray(a),
163
+ equ(a, b, { arrays = "shallow", objects = "reference", strict = true } = {}) {
164
+ if (typeof a !== typeof b || !!a !== !!b) return false;
165
+ if (is.str(a) || is.num(a) || is.boo(a)) return a === b;
166
+ const isObj = is.obj(a);
167
+ if (isObj && objects === "reference") return a === b;
168
+ const isArr = is.arr(a);
169
+ if (isArr && arrays === "reference") return a === b;
170
+ if ((isArr || isObj) && a === b) return true;
171
+ let i;
172
+ for (i in a) if (!(i in b)) return false;
173
+ if (isObj && arrays === "shallow" && objects === "shallow") {
174
+ for (i in strict ? b : a) if (!is.equ(a[i], b[i], { strict, objects: "reference" })) return false;
175
+ } else {
176
+ for (i in strict ? b : a) if (a[i] !== b[i]) return false;
142
177
  }
143
- renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
144
- }, [extension, files, loader, multiFile, renderer.domElement]);
145
- const loaderResult = useLoader$1(
146
- loader,
147
- multiFile ? [files] : files,
148
- (loader2) => {
149
- if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
150
- loader2.setRenderer?.(renderer);
151
- }
152
- loader2.setPath?.(path);
153
- if (extensions) extensions(loader2);
178
+ if (is.und(i)) {
179
+ if (isArr && a.length === 0 && b.length === 0) return true;
180
+ if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
181
+ if (a !== b) return false;
154
182
  }
155
- );
156
- let texture = multiFile ? (
157
- // @ts-ignore
158
- loaderResult[0]
159
- ) : loaderResult;
160
- if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
161
- texture = texture.renderTarget?.texture;
162
- }
163
- texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
164
- texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
165
- return texture;
166
- }
167
- const preloadDefaultOptions = {
168
- files: defaultFiles,
169
- path: "",
170
- preset: void 0,
171
- extensions: void 0
172
- };
173
- useEnvironment.preload = (preloadOptions) => {
174
- const options = { ...preloadDefaultOptions, ...preloadOptions };
175
- let { files, path = "" } = options;
176
- const { preset, extensions } = options;
177
- if (preset) {
178
- validatePreset(preset);
179
- files = presetsObj[preset];
180
- path = CUBEMAP_ROOT;
181
- }
182
- const { extension } = getExtension(files);
183
- if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
184
- throw new Error("useEnvironment: Preloading gainmaps is not supported");
185
- }
186
- const loader = getLoader$1(extension);
187
- if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
188
- useLoader$1.preload(loader, isArray(files) ? [files] : files, (loader2) => {
189
- loader2.setPath?.(path);
190
- if (extensions) extensions(loader2);
191
- });
192
- };
193
- const clearDefaultOptins = {
194
- files: defaultFiles,
195
- preset: void 0
196
- };
197
- useEnvironment.clear = (clearOptions) => {
198
- const options = { ...clearDefaultOptins, ...clearOptions };
199
- let { files } = options;
200
- const { preset } = options;
201
- if (preset) {
202
- validatePreset(preset);
203
- files = presetsObj[preset];
183
+ return true;
204
184
  }
205
- const { extension } = getExtension(files);
206
- const loader = getLoader$1(extension);
207
- if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
208
- useLoader$1.clear(loader, isArray(files) ? [files] : files);
209
185
  };
210
- function validatePreset(preset) {
211
- if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
186
+ const isOrthographicCamera = (def) => def && def.isOrthographicCamera;
187
+ const isRef$1 = (obj) => obj !== null && typeof obj === "object" && obj.hasOwnProperty("current");
188
+ const isColorRepresentation = (value) => value != null && (typeof value === "string" || typeof value === "number" || value.isColor);
189
+ const isObject3D = (object) => object?.isObject3D;
190
+ const isTexture = (value) => !!value?.isTexture;
191
+ const isVectorLike = (object) => object !== null && typeof object === "object" && "set" in object && typeof object.set === "function";
192
+ const isCopyable = (object) => isVectorLike(object) && "copy" in object && typeof object.copy === "function";
193
+ const hasConstructor = (object) => !!object?.constructor;
194
+
195
+ function calculateDpr(dpr) {
196
+ const target = typeof window !== "undefined" ? window.devicePixelRatio ?? 2 : 1;
197
+ return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
212
198
  }
213
- function getExtension(files) {
214
- const isCubemap = isArray(files) && files.length === 6;
215
- const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
216
- const firstEntry = isArray(files) ? files[0] : files;
217
- 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();
218
- return { extension, isCubemap, isGainmap };
199
+ function getUuidPrefix(uuid) {
200
+ return uuid.split("-")[0];
219
201
  }
220
- function getLoader$1(extension) {
221
- const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
222
- return loader;
202
+ function updateCamera(camera, size) {
203
+ if (camera.manual) return;
204
+ if (isOrthographicCamera(camera)) {
205
+ camera.left = size.width / -2;
206
+ camera.right = size.width / 2;
207
+ camera.top = size.height / 2;
208
+ camera.bottom = size.height / -2;
209
+ } else {
210
+ camera.aspect = size.width / size.height;
211
+ }
212
+ camera.updateProjectionMatrix();
223
213
  }
224
-
225
- const isRef$1 = (obj) => obj.current && obj.current.isScene;
226
- const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
227
- function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
228
- sceneProps = {
229
- backgroundBlurriness: 0,
230
- backgroundIntensity: 1,
231
- backgroundRotation: [0, 0, 0],
232
- environmentIntensity: 1,
233
- environmentRotation: [0, 0, 0],
234
- ...sceneProps
235
- };
236
- const target = resolveScene(scene || defaultScene);
237
- const oldbg = target.background;
238
- const oldenv = target.environment;
239
- const oldSceneProps = {
240
- // @ts-ignore
241
- backgroundBlurriness: target.backgroundBlurriness,
242
- // @ts-ignore
243
- backgroundIntensity: target.backgroundIntensity,
244
- // @ts-ignore
245
- backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
246
- // @ts-ignore
247
- environmentIntensity: target.environmentIntensity,
248
- // @ts-ignore
249
- environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
250
- };
251
- if (background !== "only") target.environment = texture;
252
- if (background) target.background = texture;
253
- applyProps$1(target, sceneProps);
254
- return () => {
255
- if (background !== "only") target.environment = oldenv;
256
- if (background) target.background = oldbg;
257
- applyProps$1(target, oldSceneProps);
258
- };
214
+ const frustumMatrix = new Matrix4();
215
+ function updateFrustum(camera, frustum) {
216
+ const target = frustum ?? new Frustum();
217
+ frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
218
+ target.setFromProjectionMatrix(frustumMatrix);
219
+ return target;
259
220
  }
260
- function EnvironmentMap({ scene, background = false, map, ...config }) {
261
- const defaultScene = useThree$1((state) => state.scene);
262
- React.useLayoutEffect(() => {
263
- if (map) return setEnvProps(background, scene, defaultScene, map, config);
264
- });
265
- return null;
221
+
222
+ const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
223
+ function findInitialRoot(instance) {
224
+ let root = instance.root;
225
+ while (root.getState().previousRoot) root = root.getState().previousRoot;
226
+ return root;
266
227
  }
267
- function EnvironmentCube({
268
- background = false,
269
- scene,
270
- blur,
271
- backgroundBlurriness,
272
- backgroundIntensity,
273
- backgroundRotation,
274
- environmentIntensity,
275
- environmentRotation,
276
- ...rest
277
- }) {
278
- const texture = useEnvironment(rest);
279
- const defaultScene = useThree$1((state) => state.scene);
280
- React.useLayoutEffect(() => {
281
- return setEnvProps(background, scene, defaultScene, texture, {
282
- backgroundBlurriness: blur ?? backgroundBlurriness,
283
- backgroundIntensity,
284
- backgroundRotation,
285
- environmentIntensity,
286
- environmentRotation
228
+ function getRootState(obj) {
229
+ let state = obj.__r3f?.root.getState();
230
+ if (!state) {
231
+ obj.traverseAncestors((ancestor) => {
232
+ const parentState = ancestor.__r3f?.root.getState();
233
+ if (parentState) {
234
+ state = parentState;
235
+ return false;
236
+ }
287
237
  });
288
- });
289
- React.useEffect(() => {
290
- return () => {
291
- texture.dispose();
292
- };
293
- }, [texture]);
294
- return null;
238
+ }
239
+ return state;
295
240
  }
296
- function EnvironmentPortal({
297
- children,
298
- near = 0.1,
299
- far = 1e3,
300
- resolution = 256,
301
- frames = 1,
302
- map,
303
- background = false,
304
- blur,
305
- backgroundBlurriness,
306
- backgroundIntensity,
307
- backgroundRotation,
308
- environmentIntensity,
309
- environmentRotation,
310
- scene,
311
- files,
312
- path,
313
- preset = void 0,
314
- extensions
315
- }) {
316
- const gl = useThree$1((state) => state.gl);
317
- const defaultScene = useThree$1((state) => state.scene);
318
- const camera = React.useRef(null);
319
- const [virtualScene] = React.useState(() => new Scene());
320
- const fbo = React.useMemo(() => {
321
- const fbo2 = new WebGLCubeRenderTarget(resolution);
322
- fbo2.texture.type = HalfFloatType;
323
- return fbo2;
324
- }, [resolution]);
325
- React.useEffect(() => {
326
- return () => {
327
- fbo.dispose();
328
- };
329
- }, [fbo]);
330
- React.useLayoutEffect(() => {
331
- if (frames === 1) {
332
- const autoClear = gl.autoClear;
333
- gl.autoClear = true;
334
- camera.current.update(gl, virtualScene);
335
- gl.autoClear = autoClear;
336
- }
337
- return setEnvProps(background, scene, defaultScene, fbo.texture, {
338
- backgroundBlurriness: blur ?? backgroundBlurriness,
339
- backgroundIntensity,
340
- backgroundRotation,
341
- environmentIntensity,
342
- environmentRotation
241
+ function buildGraph(object) {
242
+ const data = { nodes: {}, materials: {}, meshes: {} };
243
+ if (object) {
244
+ object.traverse((obj) => {
245
+ if (obj.name) data.nodes[obj.name] = obj;
246
+ if (obj.material) {
247
+ const material = Array.isArray(obj.material) ? obj.material[0] : obj.material;
248
+ const nameAlreadyUsed = data.materials[material.name];
249
+ let materialName = material.name;
250
+ if (nameAlreadyUsed) {
251
+ materialName = materialName + `-${getUuidPrefix(material.uuid)}`;
252
+ material.userData.materialCacheName = materialName;
253
+ }
254
+ data.materials[materialName] = material;
255
+ }
256
+ if (obj.isMesh && !data.meshes[obj.name]) data.meshes[obj.name] = obj;
343
257
  });
344
- }, [
345
- children,
346
- virtualScene,
347
- fbo.texture,
348
- scene,
349
- defaultScene,
350
- background,
351
- frames,
352
- gl,
353
- blur,
354
- backgroundBlurriness,
355
- backgroundIntensity,
356
- backgroundRotation,
357
- environmentIntensity,
358
- environmentRotation
359
- ]);
360
- let count = 1;
361
- useFrame$1(() => {
362
- if (frames === Infinity || count < frames) {
363
- const autoClear = gl.autoClear;
364
- gl.autoClear = true;
365
- camera.current.update(gl, virtualScene);
366
- gl.autoClear = autoClear;
367
- count++;
368
- }
369
- });
370
- return /* @__PURE__ */ jsx(Fragment, { children: createPortal$1(
371
- /* @__PURE__ */ jsxs(Fragment, { children: [
372
- children,
373
- /* @__PURE__ */ jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
374
- files || preset ? /* @__PURE__ */ jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsx(EnvironmentMap, { background: true, map, extensions }) : null
375
- ] }),
376
- virtualScene
377
- ) });
378
- }
379
- function EnvironmentGround(props) {
380
- const textureDefault = useEnvironment(props);
381
- const texture = props.map || textureDefault;
382
- React.useMemo(() => extend$1({ GroundProjectedEnvImpl: GroundedSkybox }), []);
383
- React.useEffect(() => {
384
- return () => {
385
- textureDefault.dispose();
386
- };
387
- }, [textureDefault]);
388
- const height = props.ground?.height ?? 15;
389
- const radius = props.ground?.radius ?? 60;
390
- const scale = props.ground?.scale ?? 1e3;
391
- const args = React.useMemo(
392
- () => [texture, height, radius],
393
- [texture, height, radius]
394
- );
395
- return /* @__PURE__ */ jsxs(Fragment, { children: [
396
- /* @__PURE__ */ jsx(EnvironmentMap, { ...props, map: texture }),
397
- /* @__PURE__ */ jsx("groundProjectedEnvImpl", { args, scale })
398
- ] });
399
- }
400
- function EnvironmentColor({ color, scene }) {
401
- const defaultScene = useThree$1((state) => state.scene);
402
- React.useLayoutEffect(() => {
403
- if (color === void 0) return;
404
- const target = resolveScene(scene || defaultScene);
405
- const oldBg = target.background;
406
- target.background = new Color(color);
407
- return () => {
408
- target.background = oldBg;
409
- };
410
- });
411
- return null;
412
- }
413
- function EnvironmentDualSource(props) {
414
- const { backgroundFiles, ...envProps } = props;
415
- return /* @__PURE__ */ jsxs(Fragment, { children: [
416
- /* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
417
- /* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
418
- ] });
258
+ }
259
+ return data;
419
260
  }
420
- function Environment(props) {
421
- if (props.color && !props.files && !props.preset && !props.map) {
422
- return /* @__PURE__ */ jsx(EnvironmentColor, { ...props });
261
+ function dispose(obj) {
262
+ if (obj.type !== "Scene") obj.dispose?.();
263
+ for (const p in obj) {
264
+ const prop = obj[p];
265
+ if (prop?.type !== "Scene") prop?.dispose?.();
423
266
  }
424
- if (props.backgroundFiles && props.backgroundFiles !== props.files) {
425
- return /* @__PURE__ */ jsx(EnvironmentDualSource, { ...props });
267
+ }
268
+ function getInstanceProps(pendingProps) {
269
+ const props = {};
270
+ for (const key in pendingProps) {
271
+ if (!REACT_INTERNAL_PROPS.includes(key)) props[key] = pendingProps[key];
426
272
  }
427
- return props.ground ? /* @__PURE__ */ jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsx(EnvironmentCube, { ...props });
273
+ return props;
428
274
  }
429
-
430
- var __defProp = Object.defineProperty;
431
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
432
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
433
- const act = React["act"];
434
- const useIsomorphicLayoutEffect = /* @__PURE__ */ (() => typeof window !== "undefined" && (window.document?.createElement || window.navigator?.product === "ReactNative"))() ? React.useLayoutEffect : React.useEffect;
435
- function useMutableCallback(fn) {
436
- const ref = React.useRef(fn);
437
- useIsomorphicLayoutEffect(() => void (ref.current = fn), [fn]);
438
- return ref;
275
+ function prepare(target, root, type, props) {
276
+ const object = target;
277
+ let instance = object?.__r3f;
278
+ if (!instance) {
279
+ instance = {
280
+ root,
281
+ type,
282
+ parent: null,
283
+ children: [],
284
+ props: getInstanceProps(props),
285
+ object,
286
+ eventCount: 0,
287
+ handlers: {},
288
+ isHidden: false
289
+ };
290
+ if (object) object.__r3f = instance;
291
+ }
292
+ return instance;
439
293
  }
440
- function useBridge() {
441
- const fiber = useFiber();
442
- const ContextBridge = useContextBridge();
443
- return React.useMemo(
444
- () => ({ children }) => {
445
- const strict = !!traverseFiber(fiber, true, (node) => node.type === React.StrictMode);
446
- const Root = strict ? React.StrictMode : React.Fragment;
447
- return /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsx(ContextBridge, { children }) });
448
- },
449
- [fiber, ContextBridge]
450
- );
294
+ function invalidateInstance(instance) {
295
+ if (!instance.parent) return;
296
+ instance.props.onUpdate?.(instance.object);
297
+ const state = instance.root?.getState?.();
298
+ if (state && state.internal.frames === 0) state.invalidate();
451
299
  }
452
- function Block({ set }) {
453
- useIsomorphicLayoutEffect(() => {
454
- set(new Promise(() => null));
455
- return () => set(false);
456
- }, [set]);
457
- return null;
300
+
301
+ const tempFrustum = new Frustum();
302
+ let hasWarnedWebGL = false;
303
+ let tslModule = null;
304
+ async function loadTSL() {
305
+ if (tslModule) return tslModule;
306
+ try {
307
+ const tsl = await import('three/tsl');
308
+ tslModule = { uniform: tsl.uniform, nodeObject: tsl.nodeObject };
309
+ return tslModule;
310
+ } catch {
311
+ return null;
312
+ }
458
313
  }
459
- const ErrorBoundary = /* @__PURE__ */ (() => {
460
- var _a;
461
- return _a = class extends React.Component {
462
- constructor() {
463
- super(...arguments);
464
- __publicField(this, "state", { error: false });
465
- }
466
- componentDidCatch(err) {
467
- this.props.set(err);
468
- }
469
- render() {
470
- return this.state.error ? null : this.props.children;
471
- }
472
- }, __publicField(_a, "getDerivedStateFromError", () => ({ error: true })), _a;
473
- })();
474
-
475
- const is = {
476
- obj: (a) => a === Object(a) && !is.arr(a) && typeof a !== "function",
477
- fun: (a) => typeof a === "function",
478
- str: (a) => typeof a === "string",
479
- num: (a) => typeof a === "number",
480
- boo: (a) => typeof a === "boolean",
481
- und: (a) => a === void 0,
482
- nul: (a) => a === null,
483
- arr: (a) => Array.isArray(a),
484
- equ(a, b, { arrays = "shallow", objects = "reference", strict = true } = {}) {
485
- if (typeof a !== typeof b || !!a !== !!b) return false;
486
- if (is.str(a) || is.num(a) || is.boo(a)) return a === b;
487
- const isObj = is.obj(a);
488
- if (isObj && objects === "reference") return a === b;
489
- const isArr = is.arr(a);
490
- if (isArr && arrays === "reference") return a === b;
491
- if ((isArr || isObj) && a === b) return true;
492
- let i;
493
- for (i in a) if (!(i in b)) return false;
494
- if (isObj && arrays === "shallow" && objects === "shallow") {
495
- for (i in strict ? b : a) if (!is.equ(a[i], b[i], { strict, objects: "reference" })) return false;
496
- } else {
497
- for (i in strict ? b : a) if (a[i] !== b[i]) return false;
498
- }
499
- if (is.und(i)) {
500
- if (isArr && a.length === 0 && b.length === 0) return true;
501
- if (isObj && Object.keys(a).length === 0 && Object.keys(b).length === 0) return true;
502
- if (a !== b) return false;
503
- }
504
- return true;
505
- }
506
- };
507
- const isOrthographicCamera = (def) => def && def.isOrthographicCamera;
508
- const isRef = (obj) => obj !== null && typeof obj === "object" && obj.hasOwnProperty("current");
509
- const isColorRepresentation = (value) => value != null && (typeof value === "string" || typeof value === "number" || value.isColor);
510
- const isObject3D = (object) => object?.isObject3D;
511
- const isTexture = (value) => !!value?.isTexture;
512
- const isVectorLike = (object) => object !== null && typeof object === "object" && "set" in object && typeof object.set === "function";
513
- const isCopyable = (object) => isVectorLike(object) && "copy" in object && typeof object.copy === "function";
514
- const hasConstructor = (object) => !!object?.constructor;
515
-
516
- function calculateDpr(dpr) {
517
- const target = typeof window !== "undefined" ? window.devicePixelRatio ?? 2 : 1;
518
- return Array.isArray(dpr) ? Math.min(Math.max(dpr[0], target), dpr[1]) : dpr;
519
- }
520
- function getUuidPrefix(uuid) {
521
- return uuid.split("-")[0];
522
- }
523
- function updateCamera(camera, size) {
524
- if (camera.manual) return;
525
- if (isOrthographicCamera(camera)) {
526
- camera.left = size.width / -2;
527
- camera.right = size.width / 2;
528
- camera.top = size.height / 2;
529
- camera.bottom = size.height / -2;
530
- } else {
531
- camera.aspect = size.width / size.height;
532
- }
533
- camera.updateProjectionMatrix();
534
- }
535
- const frustumMatrix = new Matrix4();
536
- function updateFrustum(camera, frustum) {
537
- const target = frustum ?? new Frustum();
538
- frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse);
539
- target.setFromProjectionMatrix(frustumMatrix);
540
- return target;
541
- }
542
-
543
- const REACT_INTERNAL_PROPS = ["children", "key", "ref"];
544
- function findInitialRoot(instance) {
545
- let root = instance.root;
546
- while (root.getState().previousRoot) root = root.getState().previousRoot;
547
- return root;
548
- }
549
- function getRootState(obj) {
550
- let state = obj.__r3f?.root.getState();
551
- if (!state) {
552
- obj.traverseAncestors((ancestor) => {
553
- const parentState = ancestor.__r3f?.root.getState();
554
- if (parentState) {
555
- state = parentState;
556
- return false;
557
- }
558
- });
559
- }
560
- return state;
561
- }
562
- function buildGraph(object) {
563
- const data = { nodes: {}, materials: {}, meshes: {} };
564
- if (object) {
565
- object.traverse((obj) => {
566
- if (obj.name) data.nodes[obj.name] = obj;
567
- if (obj.material) {
568
- const material = Array.isArray(obj.material) ? obj.material[0] : obj.material;
569
- const nameAlreadyUsed = data.materials[material.name];
570
- let materialName = material.name;
571
- if (nameAlreadyUsed) {
572
- materialName = materialName + `-${getUuidPrefix(material.uuid)}`;
573
- material.userData.materialCacheName = materialName;
574
- }
575
- data.materials[materialName] = material;
576
- }
577
- if (obj.isMesh && !data.meshes[obj.name]) data.meshes[obj.name] = obj;
578
- });
579
- }
580
- return data;
581
- }
582
- function dispose(obj) {
583
- if (obj.type !== "Scene") obj.dispose?.();
584
- for (const p in obj) {
585
- const prop = obj[p];
586
- if (prop?.type !== "Scene") prop?.dispose?.();
587
- }
588
- }
589
- function getInstanceProps(pendingProps) {
590
- const props = {};
591
- for (const key in pendingProps) {
592
- if (!REACT_INTERNAL_PROPS.includes(key)) props[key] = pendingProps[key];
593
- }
594
- return props;
595
- }
596
- function prepare(target, root, type, props) {
597
- const object = target;
598
- let instance = object?.__r3f;
599
- if (!instance) {
600
- instance = {
601
- root,
602
- type,
603
- parent: null,
604
- children: [],
605
- props: getInstanceProps(props),
606
- object,
607
- eventCount: 0,
608
- handlers: {},
609
- isHidden: false,
610
- deferredRefs: []
611
- };
612
- if (object) object.__r3f = instance;
613
- }
614
- return instance;
615
- }
616
- function invalidateInstance(instance) {
617
- if (!instance.parent) return;
618
- instance.props.onUpdate?.(instance.object);
619
- const state = instance.root?.getState?.();
620
- if (state && state.internal.frames === 0) state.invalidate();
621
- }
622
-
623
- const tempFrustum = new Frustum();
624
- let hasWarnedWebGL = false;
625
- let tslModule = null;
626
- async function loadTSL() {
627
- if (tslModule) return tslModule;
628
- try {
629
- const tsl = await import('three/tsl');
630
- tslModule = { uniform: tsl.uniform, nodeObject: tsl.nodeObject };
631
- return tslModule;
632
- } catch {
633
- return null;
634
- }
635
- }
636
- function createOcclusionObserverNode(store, uniform) {
637
- const node = new Node("float");
638
- node.updateType = NodeUpdateType.OBJECT;
639
- node.update = function(frame) {
640
- const { internal } = store.getState();
641
- const registry = internal.visibilityRegistry;
642
- const cache = internal.occlusionCache;
643
- for (const entry of registry.values()) {
644
- const { object, handlers } = entry;
645
- if (handlers.onOccluded || handlers.onVisible) {
646
- const isOccluded = frame.renderer.isOccluded(object);
647
- cache.set(object, isOccluded);
648
- }
314
+ function createOcclusionObserverNode(store, uniform) {
315
+ const node = new Node("float");
316
+ node.updateType = NodeUpdateType.OBJECT;
317
+ node.update = function(frame) {
318
+ const { internal } = store.getState();
319
+ const registry = internal.visibilityRegistry;
320
+ const cache = internal.occlusionCache;
321
+ for (const entry of registry.values()) {
322
+ const { object, handlers } = entry;
323
+ if (handlers.onOccluded || handlers.onVisible) {
324
+ const isOccluded = frame.renderer.isOccluded(object);
325
+ cache.set(object, isOccluded);
326
+ }
649
327
  }
650
328
  };
651
329
  node.setup = function() {
@@ -764,6 +442,17 @@ function unregisterVisibility(store, object) {
764
442
  internal.visibilityRegistry.delete(object.uuid);
765
443
  internal.occlusionCache.delete(object);
766
444
  }
445
+ function updateVisibilityHandlers(store, object, handlers) {
446
+ const { internal } = store.getState();
447
+ const entry = internal.visibilityRegistry.get(object.uuid);
448
+ if (!entry) return false;
449
+ entry.handlers = handlers;
450
+ if ((handlers.onOccluded || handlers.onVisible) && !internal.occlusionEnabled) {
451
+ object.occlusionTest = true;
452
+ enableOcclusion(store);
453
+ }
454
+ return true;
455
+ }
767
456
  function checkVisibility(state) {
768
457
  const { internal, camera } = state;
769
458
  const registry = internal.visibilityRegistry;
@@ -924,9 +613,9 @@ function diffProps(instance, newProps) {
924
613
  const { root, key } = resolve(instance.object, prop);
925
614
  if (root.constructor && root.constructor.length === 0) {
926
615
  const ctor = getMemoizedPrototype(root);
927
- if (!is.und(ctor)) changedProps[key] = ctor[key];
616
+ if (!is.und(ctor)) changedProps[prop] = ctor[key];
928
617
  } else {
929
- changedProps[key] = 0;
618
+ changedProps[prop] = 0;
930
619
  }
931
620
  }
932
621
  return changedProps;
@@ -951,10 +640,7 @@ function applyProps(object, props) {
951
640
  continue;
952
641
  }
953
642
  if (value === void 0) continue;
954
- if (isFromRef(value)) {
955
- instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
956
- continue;
957
- }
643
+ if (isFromRef(value)) continue;
958
644
  if (isOnce(value)) {
959
645
  if (instance?.appliedOnce?.has(prop)) continue;
960
646
  if (instance) {
@@ -1021,6 +707,9 @@ function applyProps(object, props) {
1021
707
  if (instance.eventCount && object2.raycast !== null) {
1022
708
  rootState.internal.interaction.push(object2);
1023
709
  }
710
+ }
711
+ if (instance?.parent && rootState?.internal && instance.object?.isObject3D) {
712
+ const object2 = instance.object;
1024
713
  const root = findInitialRoot(instance);
1025
714
  const visibilityHandlers = {
1026
715
  onFramed: instance.handlers.onFramed,
@@ -1028,7 +717,9 @@ function applyProps(object, props) {
1028
717
  onVisible: instance.handlers.onVisible
1029
718
  };
1030
719
  if (hasVisibilityHandlers(visibilityHandlers)) {
1031
- registerVisibility(root, object2, visibilityHandlers);
720
+ if (!updateVisibilityHandlers(root, object2, visibilityHandlers)) {
721
+ registerVisibility(root, object2, visibilityHandlers);
722
+ }
1032
723
  } else {
1033
724
  unregisterVisibility(root, object2);
1034
725
  }
@@ -1041,1333 +732,904 @@ function applyProps(object, props) {
1041
732
  return object;
1042
733
  }
1043
734
 
1044
- const DEFAULT_POINTER_ID = 0;
1045
- const XR_POINTER_ID_START = 1e3;
1046
- function getPointerState(internal, pointerId) {
1047
- let state = internal.pointerMap.get(pointerId);
1048
- if (!state) {
1049
- state = {
1050
- hovered: /* @__PURE__ */ new Map(),
1051
- captured: /* @__PURE__ */ new Map(),
1052
- initialClick: [0, 0],
1053
- initialHits: []
1054
- };
1055
- internal.pointerMap.set(pointerId, state);
735
+ const shownNotices = /* @__PURE__ */ new Set();
736
+ function notifyDepreciated({ heading, body, link }) {
737
+ if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_DEPRECATION_WARNINGS !== "true") {
738
+ return;
739
+ }
740
+ if (shownNotices.has(heading)) return;
741
+ shownNotices.add(heading);
742
+ const caller = getCallerFrame();
743
+ if (caller) {
744
+ console.log();
745
+ }
746
+ const boxStyle = "background: #ff9800; color: #1a1a1a; padding: 8px 12px; border-radius: 4px; font-weight: 500;";
747
+ if (caller) {
748
+ console.log(`%c\u26A0\uFE0F ${heading}`, boxStyle);
749
+ }
750
+ if (body || link) {
751
+ let message = "";
752
+ if (body) message += body;
753
+ if (link) message += (body ? "\n\n" : "") + `More info: ${link}`;
754
+ console.warn(`%c${message}`, "font-weight: bold;");
1056
755
  }
1057
- return state;
1058
756
  }
1059
- function getPointerId(event) {
1060
- return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
757
+ function getCallerFrame(depth = 3) {
758
+ const stack = new Error().stack;
759
+ if (!stack) return null;
760
+ const lines = stack.split("\n");
761
+ const frame = lines[depth];
762
+ if (!frame) return null;
763
+ let match = frame.match(/^\s*at (?:(.+?) )?\(?(.+?):(\d+):(\d+)\)?$/);
764
+ if (!match) {
765
+ match = frame.match(/^(?:(.+?)@)?(.+?):(\d+):(\d+)$/);
766
+ }
767
+ if (!match) return null;
768
+ const [, fn, url, line] = match;
769
+ return {
770
+ functionName: fn ?? "<anonymous>",
771
+ location: formatLocation(url, Number(line))
772
+ };
1061
773
  }
1062
- function makeId(event) {
1063
- return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
774
+ function formatLocation(url, line) {
775
+ const clean = url.split("?")[0];
776
+ const file = clean.split("/").pop() ?? clean;
777
+ return `${file}:${line}`;
1064
778
  }
1065
- function releaseInternalPointerCapture(internal, obj, pointerId) {
1066
- const pointerState = internal.pointerMap.get(pointerId);
1067
- if (!pointerState) return;
1068
- const captureData = pointerState.captured.get(obj);
1069
- if (captureData) {
1070
- pointerState.captured.delete(obj);
1071
- captureData.target.releasePointerCapture(pointerId);
779
+ function notifyAlpha({ message, link }) {
780
+ if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_ALPHA_WARNINGS !== "true") {
781
+ return;
1072
782
  }
1073
- }
1074
- function removeInteractivity(store, object) {
1075
- const { internal } = store.getState();
1076
- internal.interaction = internal.interaction.filter((o) => o !== object);
1077
- for (const [pointerId, pointerState] of internal.pointerMap) {
1078
- pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
1079
- pointerState.hovered.forEach((value, key) => {
1080
- if (value.eventObject === object || value.object === object) {
1081
- pointerState.hovered.delete(key);
1082
- }
1083
- });
1084
- if (pointerState.captured.has(object)) {
1085
- releaseInternalPointerCapture(internal, object, pointerId);
1086
- }
783
+ if (shownNotices.has(message)) return;
784
+ shownNotices.add(message);
785
+ const boxStyle = "background: #6366f1; color: #ffffff; padding: 6px 10px; border-radius: 4px; font-weight: 500;";
786
+ console.log(`%c\u{1F52C} ${message}`, boxStyle);
787
+ {
788
+ console.log(`%cMore info: ${link}`, "color: #6366f1; font-weight: normal;");
1087
789
  }
1088
- unregisterVisibility(store, object);
1089
790
  }
1090
- function createEvents(store) {
1091
- function calculateDistance(event, pointerId) {
1092
- const { internal } = store.getState();
1093
- const pointerState = internal.pointerMap.get(pointerId);
1094
- if (!pointerState) return 0;
1095
- const [initialX, initialY] = pointerState.initialClick;
1096
- const dx = event.offsetX - initialX;
1097
- const dy = event.offsetY - initialY;
1098
- return Math.round(Math.sqrt(dx * dx + dy * dy));
1099
- }
1100
- function filterPointerEvents(objects) {
1101
- return objects.filter(
1102
- (obj) => ["Move", "Over", "Enter", "Out", "Leave"].some(
1103
- (name) => obj.__r3f?.handlers["onPointer" + name]
1104
- ) || ["OverEnter", "OverLeave", "Over"].some(
1105
- (name) => obj.__r3f?.handlers["onDrag" + name]
1106
- ) || obj.__r3f?.handlers.onDrop
1107
- );
1108
- }
1109
- function intersect(event, filter) {
1110
- const state = store.getState();
1111
- const duplicates = /* @__PURE__ */ new Set();
1112
- const intersections = [];
1113
- const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
1114
- for (let i = 0; i < eventsObjects.length; i++) {
1115
- const state2 = getRootState(eventsObjects[i]);
1116
- if (state2) {
1117
- state2.raycaster.camera = void 0;
1118
- }
1119
- }
1120
- if (!state.previousRoot) {
1121
- state.events.compute?.(event, state);
1122
- }
1123
- function handleRaycast(obj) {
1124
- const state2 = getRootState(obj);
1125
- if (!state2 || !state2.events.enabled || state2.raycaster.camera === null) return [];
1126
- if (state2.raycaster.camera === void 0) {
1127
- state2.events.compute?.(event, state2, state2.previousRoot?.getState());
1128
- if (state2.raycaster.camera === void 0) state2.raycaster.camera = null;
1129
- }
1130
- return state2.raycaster.camera ? state2.raycaster.intersectObject(obj, true) : [];
1131
- }
1132
- let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
1133
- const aInteractivePriority = a.object.userData?.interactivePriority;
1134
- const bInteractivePriority = b.object.userData?.interactivePriority;
1135
- if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
1136
- if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
1137
- if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
1138
- if (aInteractivePriority !== bInteractivePriority) {
1139
- return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
1140
- }
1141
- }
1142
- const aState = getRootState(a.object);
1143
- const bState = getRootState(b.object);
1144
- const aPriority = aState?.events?.priority ?? 1;
1145
- const bPriority = bState?.events?.priority ?? 1;
1146
- return bPriority - aPriority || a.distance - b.distance;
1147
- }).filter((item) => {
1148
- const id = makeId(item);
1149
- if (duplicates.has(id)) return false;
1150
- duplicates.add(id);
1151
- return true;
1152
- });
1153
- if (state.events.filter) hits = state.events.filter(hits, state);
1154
- for (const hit of hits) {
1155
- let eventObject = hit.object;
1156
- while (eventObject) {
1157
- if (eventObject.__r3f?.eventCount) {
1158
- intersections.push({ ...hit, eventObject });
1159
- }
1160
- eventObject = eventObject.parent;
791
+
792
+ const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
793
+ function isInternalRendererAccess(stack, callerDepth = 2) {
794
+ if (!stack) return false;
795
+ const caller = stack.split("\n")[callerDepth] ?? "";
796
+ return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m));
797
+ }
798
+
799
+ const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
800
+ const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React.createContext(null));
801
+ const createStore = (invalidate, advance) => {
802
+ const rootStore = createWithEqualityFn((set, get) => {
803
+ const position = new Vector3();
804
+ const defaultTarget = new Vector3();
805
+ const tempTarget = new Vector3();
806
+ function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
807
+ const { width, height, top, left } = size;
808
+ const aspect = width / height;
809
+ if (target.isVector3) tempTarget.copy(target);
810
+ else tempTarget.set(...target);
811
+ const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
812
+ if (isOrthographicCamera(camera)) {
813
+ return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
814
+ } else {
815
+ const fov = camera.fov * Math.PI / 180;
816
+ const h = 2 * Math.tan(fov / 2) * distance;
817
+ const w = h * (width / height);
818
+ return { width: w, height: h, top, left, factor: width / w, distance, aspect };
1161
819
  }
1162
820
  }
1163
- if ("pointerId" in event) {
1164
- const pointerId = event.pointerId;
1165
- const pointerState = state.internal.pointerMap.get(pointerId);
1166
- if (pointerState?.captured.size) {
1167
- for (const captureData of pointerState.captured.values()) {
1168
- if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
821
+ let performanceTimeout = void 0;
822
+ const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
823
+ const pointer = new Vector2();
824
+ const rootState = {
825
+ set,
826
+ get,
827
+ // Mock objects that have to be configured
828
+ // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
829
+ primaryStore: null,
830
+ gl: null,
831
+ renderer: null,
832
+ camera: null,
833
+ frustum: new Frustum(),
834
+ autoUpdateFrustum: true,
835
+ raycaster: null,
836
+ events: {
837
+ priority: 1,
838
+ enabled: true,
839
+ connected: false,
840
+ frameTimedRaycasts: true,
841
+ alwaysFireOnScroll: true,
842
+ updateOnFrame: false
843
+ },
844
+ scene: null,
845
+ rootScene: null,
846
+ xr: null,
847
+ inspector: null,
848
+ invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
849
+ advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
850
+ textureColorSpace: SRGBColorSpace,
851
+ isLegacy: false,
852
+ webGPUSupported: false,
853
+ isNative: false,
854
+ controls: null,
855
+ pointer,
856
+ mouse: pointer,
857
+ frameloop: "always",
858
+ onPointerMissed: void 0,
859
+ onDragOverMissed: void 0,
860
+ onDropMissed: void 0,
861
+ performance: {
862
+ current: 1,
863
+ min: 0.5,
864
+ max: 1,
865
+ debounce: 200,
866
+ regress: () => {
867
+ const state2 = get();
868
+ if (performanceTimeout) clearTimeout(performanceTimeout);
869
+ if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
870
+ performanceTimeout = setTimeout(
871
+ () => setPerformanceCurrent(get().performance.max),
872
+ state2.performance.debounce
873
+ );
1169
874
  }
1170
- }
1171
- }
1172
- return intersections;
1173
- }
1174
- function handleIntersects(intersections, event, delta, callback) {
1175
- if (intersections.length) {
1176
- const localState = { stopped: false };
1177
- for (const hit of intersections) {
1178
- const state = getRootState(hit.object);
1179
- if (state) {
1180
- const { raycaster, pointer, camera, internal } = state;
1181
- const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
1182
- const hasPointerCapture = (id) => {
1183
- const pointerState = internal.pointerMap.get(id);
1184
- return pointerState?.captured.has(hit.eventObject) ?? false;
1185
- };
1186
- const setPointerCapture = (id) => {
1187
- const captureData = { intersection: hit, target: event.target };
1188
- const pointerState = getPointerState(internal, id);
1189
- pointerState.captured.set(hit.eventObject, captureData);
1190
- event.target.setPointerCapture(id);
1191
- };
1192
- const releasePointerCapture = (id) => {
1193
- releaseInternalPointerCapture(internal, hit.eventObject, id);
1194
- };
1195
- const extractEventProps = {};
1196
- for (const prop in event) {
1197
- const property = event[prop];
1198
- if (typeof property !== "function") extractEventProps[prop] = property;
875
+ },
876
+ size: { width: 0, height: 0, top: 0, left: 0 },
877
+ viewport: {
878
+ initialDpr: 0,
879
+ dpr: 0,
880
+ width: 0,
881
+ height: 0,
882
+ top: 0,
883
+ left: 0,
884
+ aspect: 0,
885
+ distance: 0,
886
+ factor: 0,
887
+ getCurrentViewport
888
+ },
889
+ setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
890
+ setSize: (width, height, top, left) => {
891
+ const state2 = get();
892
+ if (width === void 0) {
893
+ set({ _sizeImperative: false });
894
+ if (state2._sizeProps) {
895
+ const { width: propW, height: propH } = state2._sizeProps;
896
+ if (propW !== void 0 || propH !== void 0) {
897
+ const currentSize = state2.size;
898
+ const newSize = {
899
+ width: propW ?? currentSize.width,
900
+ height: propH ?? currentSize.height,
901
+ top: currentSize.top,
902
+ left: currentSize.left
903
+ };
904
+ set((s) => ({
905
+ size: newSize,
906
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
907
+ }));
908
+ getScheduler().invalidate();
909
+ }
1199
910
  }
1200
- const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
1201
- const raycastEvent = {
1202
- ...hit,
1203
- ...extractEventProps,
1204
- pointer,
1205
- intersections,
1206
- stopped: localState.stopped,
1207
- delta,
1208
- unprojectedPoint,
1209
- ray: raycaster.ray,
1210
- camera,
1211
- pointerId: eventPointerId,
1212
- // Hijack stopPropagation, which just sets a flag
1213
- stopPropagation() {
1214
- const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
1215
- if (
1216
- // ...if this pointer hasn't been captured
1217
- !pointerState?.captured.size || // ... or if the hit object is capturing the pointer
1218
- pointerState.captured.has(hit.eventObject)
1219
- ) {
1220
- raycastEvent.stopped = localState.stopped = true;
1221
- if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
1222
- const higher = intersections.slice(0, intersections.indexOf(hit));
1223
- cancelPointer([...higher, hit], eventPointerId);
1224
- }
1225
- }
1226
- },
1227
- // there should be a distinction between target and currentTarget
1228
- target: { hasPointerCapture, setPointerCapture, releasePointerCapture },
1229
- currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
1230
- nativeEvent: event
1231
- };
1232
- callback(raycastEvent);
1233
- if (localState.stopped === true) break;
911
+ return;
1234
912
  }
913
+ const w = width;
914
+ const h = height ?? width;
915
+ const t = top ?? state2.size.top;
916
+ const l = left ?? state2.size.left;
917
+ const size = { width: w, height: h, top: t, left: l };
918
+ set((s) => ({
919
+ size,
920
+ viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
921
+ _sizeImperative: true
922
+ }));
923
+ getScheduler().invalidate();
924
+ },
925
+ setDpr: (dpr) => set((state2) => {
926
+ const resolved = calculateDpr(dpr);
927
+ return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
928
+ }),
929
+ setFrameloop: (frameloop = "always") => {
930
+ set(() => ({ frameloop }));
931
+ getScheduler().frameloop = frameloop;
932
+ },
933
+ setError: (error) => set(() => ({ error })),
934
+ error: null,
935
+ //* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
936
+ uniforms: {},
937
+ nodes: {},
938
+ buffers: {},
939
+ gpuStorage: {},
940
+ textures: /* @__PURE__ */ new Map(),
941
+ _textureRefs: /* @__PURE__ */ new Map(),
942
+ renderPipeline: null,
943
+ passes: {},
944
+ _hmrVersion: 0,
945
+ _sizeImperative: false,
946
+ _sizeProps: null,
947
+ previousRoot: void 0,
948
+ internal: {
949
+ // Events
950
+ interaction: [],
951
+ subscribers: [],
952
+ // Per-pointer state (new unified structure)
953
+ pointerMap: /* @__PURE__ */ new Map(),
954
+ pointerDirty: /* @__PURE__ */ new Map(),
955
+ lastEvent: React.createRef(),
956
+ // Deprecated but kept for backwards compatibility
957
+ hovered: /* @__PURE__ */ new Map(),
958
+ initialClick: [0, 0],
959
+ initialHits: [],
960
+ capturedMap: /* @__PURE__ */ new Map(),
961
+ // Visibility tracking (onFramed, onOccluded, onVisible)
962
+ visibilityRegistry: /* @__PURE__ */ new Map(),
963
+ // Occlusion system (WebGPU only)
964
+ occlusionEnabled: false,
965
+ occlusionObserver: null,
966
+ occlusionCache: /* @__PURE__ */ new Map(),
967
+ helperGroup: null,
968
+ // Updates
969
+ active: false,
970
+ frames: 0,
971
+ priority: 0,
972
+ subscribe: (ref, priority, store) => {
973
+ const internal = get().internal;
974
+ internal.priority = internal.priority + (priority > 0 ? 1 : 0);
975
+ internal.subscribers.push({ ref, priority, store });
976
+ internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
977
+ return () => {
978
+ const internal2 = get().internal;
979
+ if (internal2?.subscribers) {
980
+ internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
981
+ internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
982
+ }
983
+ };
984
+ },
985
+ // Renderer Storage (single source of truth)
986
+ actualRenderer: null,
987
+ // Scheduler for useFrameNext (initialized in renderer.tsx)
988
+ scheduler: null
1235
989
  }
1236
- }
1237
- return intersections;
1238
- }
1239
- function cancelPointer(intersections, pointerId) {
1240
- const { internal } = store.getState();
1241
- const pid = pointerId ?? DEFAULT_POINTER_ID;
1242
- const pointerState = internal.pointerMap.get(pid);
1243
- if (!pointerState) return;
1244
- for (const [hoveredId, hoveredObj] of pointerState.hovered) {
1245
- if (!intersections.length || !intersections.find(
1246
- (hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
1247
- )) {
1248
- const eventObject = hoveredObj.eventObject;
1249
- const instance = eventObject.__r3f;
1250
- pointerState.hovered.delete(hoveredId);
1251
- if (instance?.eventCount) {
1252
- const handlers = instance.handlers;
1253
- const data = { ...hoveredObj, intersections };
1254
- handlers.onPointerOut?.(data);
1255
- handlers.onPointerLeave?.(data);
1256
- handlers.onDragOverLeave?.(data);
990
+ };
991
+ return rootState;
992
+ });
993
+ const state = rootStore.getState();
994
+ Object.defineProperty(state, "gl", {
995
+ get() {
996
+ const currentState = rootStore.getState();
997
+ if (!currentState.isLegacy && currentState.internal.actualRenderer) {
998
+ const stack = new Error().stack || "";
999
+ if (!isInternalRendererAccess(stack)) {
1000
+ const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
1001
+ notifyDepreciated({
1002
+ heading: "Accessing state.gl in WebGPU mode",
1003
+ 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
1004
+ });
1257
1005
  }
1258
1006
  }
1007
+ return currentState.internal.actualRenderer;
1008
+ },
1009
+ set(value) {
1010
+ rootStore.getState().internal.actualRenderer = value;
1011
+ },
1012
+ enumerable: true,
1013
+ configurable: true
1014
+ });
1015
+ Object.defineProperty(state, "renderer", {
1016
+ get() {
1017
+ return rootStore.getState().internal.actualRenderer;
1018
+ },
1019
+ set(value) {
1020
+ rootStore.getState().internal.actualRenderer = value;
1021
+ },
1022
+ enumerable: true,
1023
+ configurable: true
1024
+ });
1025
+ let oldScene = state.scene;
1026
+ rootStore.subscribe(() => {
1027
+ const currentState = rootStore.getState();
1028
+ const { scene, rootScene, set } = currentState;
1029
+ if (scene !== oldScene) {
1030
+ oldScene = scene;
1031
+ if (scene?.isScene && scene !== rootScene) {
1032
+ set({ rootScene: scene });
1033
+ }
1259
1034
  }
1260
- }
1261
- function pointerMissed(event, objects) {
1262
- for (let i = 0; i < objects.length; i++) {
1263
- const instance = objects[i].__r3f;
1264
- instance?.handlers.onPointerMissed?.(event);
1265
- }
1266
- }
1267
- function dragOverMissed(event, objects) {
1268
- for (let i = 0; i < objects.length; i++) {
1269
- const instance = objects[i].__r3f;
1270
- instance?.handlers.onDragOverMissed?.(event);
1271
- }
1272
- }
1273
- function dropMissed(event, objects) {
1274
- for (let i = 0; i < objects.length; i++) {
1275
- const instance = objects[i].__r3f;
1276
- instance?.handlers.onDropMissed?.(event);
1035
+ });
1036
+ let oldSize = state.size;
1037
+ let oldDpr = state.viewport.dpr;
1038
+ let oldCamera = state.camera;
1039
+ rootStore.subscribe(() => {
1040
+ const { camera, size, viewport, set, internal } = rootStore.getState();
1041
+ const actualRenderer = internal.actualRenderer;
1042
+ const canvasTarget = internal.canvasTarget;
1043
+ if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
1044
+ oldSize = size;
1045
+ oldDpr = viewport.dpr;
1046
+ updateCamera(camera, size);
1047
+ const resizeTarget = canvasTarget ?? actualRenderer;
1048
+ if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
1049
+ resizeTarget.setSize(size.width, size.height, false);
1050
+ internal.canvasTargetSizeDirty = true;
1277
1051
  }
1278
- }
1279
- function cleanupPointer(pointerId) {
1280
- const { internal } = store.getState();
1281
- const pointerState = internal.pointerMap.get(pointerId);
1282
- if (pointerState) {
1283
- for (const [, hoveredObj] of pointerState.hovered) {
1284
- const eventObject = hoveredObj.eventObject;
1285
- const instance = eventObject.__r3f;
1286
- if (instance?.eventCount) {
1287
- const handlers = instance.handlers;
1288
- const data = { ...hoveredObj, intersections: [] };
1289
- handlers.onPointerOut?.(data);
1290
- handlers.onPointerLeave?.(data);
1291
- }
1052
+ if (camera !== oldCamera) {
1053
+ oldCamera = camera;
1054
+ const { rootScene } = rootStore.getState();
1055
+ if (camera && rootScene && !camera.parent) {
1056
+ rootScene.add(camera);
1292
1057
  }
1293
- internal.pointerMap.delete(pointerId);
1294
- }
1295
- internal.pointerDirty.delete(pointerId);
1296
- }
1297
- function processDeferredPointer(event, pointerId) {
1298
- const state = store.getState();
1299
- const { internal } = state;
1300
- if (!state.events.enabled) return;
1301
- const filter = filterPointerEvents;
1302
- const hits = intersect(event, filter);
1303
- cancelPointer(hits, pointerId);
1304
- function onIntersect(data) {
1305
- const eventObject = data.eventObject;
1306
- const instance = eventObject.__r3f;
1307
- if (!instance?.eventCount) return;
1308
- const handlers = instance.handlers;
1309
- if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1310
- const id = makeId(data);
1311
- const pointerState = getPointerState(internal, pointerId);
1312
- const hoveredItem = pointerState.hovered.get(id);
1313
- if (!hoveredItem) {
1314
- pointerState.hovered.set(id, data);
1315
- handlers.onPointerOver?.(data);
1316
- handlers.onPointerEnter?.(data);
1317
- } else if (hoveredItem.stopped) {
1318
- data.stopPropagation();
1319
- }
1058
+ set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
1059
+ const currentState = rootStore.getState();
1060
+ if (currentState.autoUpdateFrustum && camera) {
1061
+ updateFrustum(camera, currentState.frustum);
1320
1062
  }
1321
- handlers.onPointerMove?.(data);
1322
1063
  }
1323
- handleIntersects(hits, event, 0, onIntersect);
1064
+ });
1065
+ rootStore.subscribe((state2) => invalidate(state2));
1066
+ return rootStore;
1067
+ };
1068
+
1069
+ const memoizedLoaders = /* @__PURE__ */ new WeakMap();
1070
+ const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
1071
+ function getLoader$1(Proto) {
1072
+ if (isConstructor$1(Proto)) {
1073
+ let loader = memoizedLoaders.get(Proto);
1074
+ if (!loader) {
1075
+ loader = new Proto();
1076
+ memoizedLoaders.set(Proto, loader);
1077
+ }
1078
+ return loader;
1324
1079
  }
1325
- function handlePointer(name) {
1326
- switch (name) {
1327
- case "onPointerLeave":
1328
- case "onDragLeave":
1329
- return () => cancelPointer([]);
1330
- // Global cancel of these events
1331
- case "onPointerCancel":
1332
- return (event) => {
1333
- const pointerId = getPointerId(event);
1334
- cleanupPointer(pointerId);
1335
- };
1336
- case "onLostPointerCapture":
1337
- return (event) => {
1338
- const { internal } = store.getState();
1339
- const pointerId = getPointerId(event);
1340
- const pointerState = internal.pointerMap.get(pointerId);
1341
- if (pointerState?.captured.size) {
1342
- requestAnimationFrame(() => {
1343
- const pointerState2 = internal.pointerMap.get(pointerId);
1344
- if (pointerState2?.captured.size) {
1345
- pointerState2.captured.clear();
1346
- }
1347
- cancelPointer([], pointerId);
1348
- });
1349
- }
1350
- };
1080
+ return Proto;
1081
+ }
1082
+ function loadingFn(extensions, onProgress) {
1083
+ return function(Proto, input) {
1084
+ const loader = getLoader$1(Proto);
1085
+ if (extensions) extensions(loader);
1086
+ if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
1087
+ return loader.loadAsync(input, onProgress).then((data) => {
1088
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1089
+ return data;
1090
+ });
1351
1091
  }
1352
- return function handleEvent(event) {
1092
+ return new Promise(
1093
+ (res, reject) => loader.load(
1094
+ input,
1095
+ (data) => {
1096
+ if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1097
+ res(data);
1098
+ },
1099
+ onProgress,
1100
+ (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
1101
+ )
1102
+ );
1103
+ };
1104
+ }
1105
+ function useLoader(loader, input, extensions, onProgress, cacheKey) {
1106
+ const inputs = Array.isArray(input) ? input : [input];
1107
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1108
+ const fn = loadingFn(extensions, onProgress);
1109
+ const results = cacheKeys.map(
1110
+ (key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
1111
+ );
1112
+ return Array.isArray(input) ? results : results[0];
1113
+ }
1114
+ useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
1115
+ const inputs = Array.isArray(input) ? input : [input];
1116
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1117
+ cacheKeys.forEach(
1118
+ (key, index) => preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
1119
+ );
1120
+ };
1121
+ useLoader.clear = function(loader, input, cacheKey) {
1122
+ const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1123
+ cacheKeys.forEach((key) => clear([loader, key]));
1124
+ };
1125
+ useLoader.loader = getLoader$1;
1126
+
1127
+ function useFrame(callback, priorityOrOptions) {
1128
+ const store = React.useContext(context);
1129
+ const isInsideCanvas = store !== null;
1130
+ const scheduler = getScheduler();
1131
+ const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
1132
+ id: priorityOrOptions.id,
1133
+ phase: priorityOrOptions.phase,
1134
+ priority: priorityOrOptions.priority,
1135
+ fps: priorityOrOptions.fps,
1136
+ drop: priorityOrOptions.drop,
1137
+ enabled: priorityOrOptions.enabled,
1138
+ before: priorityOrOptions.before,
1139
+ after: priorityOrOptions.after
1140
+ }) : "";
1141
+ const options = React.useMemo(() => {
1142
+ return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
1143
+ }, [optionsKey]);
1144
+ const reactId = React.useId();
1145
+ const id = options.id ?? reactId;
1146
+ const callbackRef = useMutableCallback(callback);
1147
+ const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
1148
+ useIsomorphicLayoutEffect(() => {
1149
+ if (!callback) return;
1150
+ if (isInsideCanvas) {
1353
1151
  const state = store.getState();
1354
- const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
1355
- const pointerId = getPointerId(event);
1356
- internal.lastEvent.current = event;
1357
- if (!events.enabled) return;
1358
- const isPointerMove = name === "onPointerMove";
1359
- const isDragOver = name === "onDragOver";
1360
- const isDrop = name === "onDrop";
1361
- const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
1362
- const isPointerDown = name === "onPointerDown";
1363
- const isPointerUp = name === "onPointerUp";
1364
- const isWheel = name === "onWheel";
1365
- const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
1366
- if (isPointerMove && canDeferRaycasts) {
1367
- events.compute?.(event, state);
1368
- internal.pointerDirty.set(pointerId, event);
1369
- return;
1370
- }
1371
- if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
1372
- events.compute?.(event, state);
1373
- internal.pointerDirty.set(pointerId, event);
1374
- return;
1375
- }
1376
- if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
1377
- const deferredEvent = internal.pointerDirty.get(pointerId);
1378
- internal.pointerDirty.delete(pointerId);
1379
- processDeferredPointer(deferredEvent, pointerId);
1380
- }
1381
- const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
1382
- const hits = intersect(event, filter);
1383
- const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
1384
- if (isPointerDown) {
1385
- const pointerState2 = getPointerState(internal, pointerId);
1386
- pointerState2.initialClick = [event.offsetX, event.offsetY];
1387
- pointerState2.initialHits = hits.map((hit) => hit.eventObject);
1388
- }
1389
- const pointerState = internal.pointerMap.get(pointerId);
1390
- const initialHits = pointerState?.initialHits ?? [];
1391
- if (isClickEvent && !hits.length) {
1392
- if (delta <= 2) {
1393
- pointerMissed(event, internal.interaction);
1394
- if (onPointerMissed) onPointerMissed(event);
1152
+ const rootId = state.internal.rootId;
1153
+ if (isLegacyPriority) {
1154
+ state.internal.priority++;
1155
+ let parentRoot = state.previousRoot;
1156
+ while (parentRoot) {
1157
+ const parentState = parentRoot.getState();
1158
+ if (parentState?.internal) parentState.internal.priority++;
1159
+ parentRoot = parentState?.previousRoot;
1395
1160
  }
1161
+ notifyDepreciated({
1162
+ heading: "useFrame with numeric priority is deprecated",
1163
+ 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 })',
1164
+ link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
1165
+ });
1396
1166
  }
1397
- if (isDragOver && !hits.length) {
1398
- dragOverMissed(event, internal.interaction);
1399
- if (onDragOverMissed) onDragOverMissed(event);
1400
- }
1401
- if (isDrop && !hits.length) {
1402
- dropMissed(event, internal.interaction);
1403
- if (onDropMissed) onDropMissed(event);
1404
- }
1405
- if (isPointerMove || isDragOver) {
1406
- cancelPointer(hits, pointerId);
1407
- }
1408
- function onIntersect(data) {
1409
- const eventObject = data.eventObject;
1410
- const instance = eventObject.__r3f;
1411
- if (!instance?.eventCount) return;
1412
- const handlers = instance.handlers;
1413
- if (isPointerMove) {
1414
- if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
1415
- const id = makeId(data);
1416
- const pointerState2 = getPointerState(internal, pointerId);
1417
- const hoveredItem = pointerState2.hovered.get(id);
1418
- if (!hoveredItem) {
1419
- pointerState2.hovered.set(id, data);
1420
- handlers.onPointerOver?.(data);
1421
- handlers.onPointerEnter?.(data);
1422
- } else if (hoveredItem.stopped) {
1423
- data.stopPropagation();
1424
- }
1425
- }
1426
- handlers.onPointerMove?.(data);
1427
- } else if (isDragOver) {
1428
- const id = makeId(data);
1429
- const pointerState2 = getPointerState(internal, pointerId);
1430
- const hoveredItem = pointerState2.hovered.get(id);
1431
- if (!hoveredItem) {
1432
- pointerState2.hovered.set(id, data);
1433
- handlers.onDragOverEnter?.(data);
1434
- } else if (hoveredItem.stopped) {
1435
- data.stopPropagation();
1436
- }
1437
- handlers.onDragOver?.(data);
1438
- } else if (isDrop) {
1439
- handlers.onDrop?.(data);
1440
- } else {
1441
- const handler = handlers[name];
1442
- if (handler) {
1443
- if (!isClickEvent || initialHits.includes(eventObject)) {
1444
- pointerMissed(
1445
- event,
1446
- internal.interaction.filter((object) => !initialHits.includes(object))
1447
- );
1448
- handler(data);
1449
- }
1450
- } else {
1451
- if (isClickEvent && initialHits.includes(eventObject)) {
1452
- pointerMissed(
1453
- event,
1454
- internal.interaction.filter((object) => !initialHits.includes(object))
1455
- );
1167
+ const wrappedCallback = (frameState, delta) => {
1168
+ const localState = store.getState();
1169
+ const mergedState = {
1170
+ ...localState,
1171
+ time: frameState.time,
1172
+ delta: frameState.delta,
1173
+ elapsed: frameState.elapsed,
1174
+ frame: frameState.frame
1175
+ };
1176
+ callbackRef.current?.(mergedState, delta);
1177
+ };
1178
+ const unregister = scheduler.register(wrappedCallback, {
1179
+ id,
1180
+ rootId,
1181
+ ...options
1182
+ });
1183
+ return () => {
1184
+ unregister();
1185
+ if (isLegacyPriority) {
1186
+ const currentState = store.getState();
1187
+ if (currentState.internal) {
1188
+ currentState.internal.priority--;
1189
+ let parentRoot = currentState.previousRoot;
1190
+ while (parentRoot) {
1191
+ const parentState = parentRoot.getState();
1192
+ if (parentState?.internal) parentState.internal.priority--;
1193
+ parentRoot = parentState?.previousRoot;
1456
1194
  }
1457
1195
  }
1458
1196
  }
1459
- }
1460
- handleIntersects(hits, event, delta, onIntersect);
1461
- };
1462
- }
1463
- function flushDeferredPointers() {
1464
- const { internal, events } = store.getState();
1465
- if (!events.frameTimedRaycasts) return;
1466
- for (const [pointerId, event] of internal.pointerDirty) {
1467
- processDeferredPointer(event, pointerId);
1197
+ };
1198
+ } else {
1199
+ return scheduler.register(
1200
+ (state, delta) => {
1201
+ const frameState = state;
1202
+ if (!frameState.renderer) return;
1203
+ callbackRef.current?.(frameState, delta);
1204
+ },
1205
+ { id, ...options }
1206
+ );
1468
1207
  }
1469
- internal.pointerDirty.clear();
1470
- }
1471
- return { handlePointer, flushDeferredPointers, processDeferredPointer };
1472
- }
1473
- const DOM_EVENTS = {
1474
- onClick: ["click", false],
1475
- onContextMenu: ["contextmenu", false],
1476
- onDoubleClick: ["dblclick", false],
1477
- onDragEnter: ["dragenter", false],
1478
- onDragLeave: ["dragleave", false],
1479
- onDragOver: ["dragover", false],
1480
- onDrop: ["drop", false],
1481
- onWheel: ["wheel", true],
1482
- onPointerDown: ["pointerdown", true],
1483
- onPointerUp: ["pointerup", true],
1484
- onPointerLeave: ["pointerleave", true],
1485
- onPointerMove: ["pointermove", true],
1486
- onPointerCancel: ["pointercancel", true],
1487
- onLostPointerCapture: ["lostpointercapture", true]
1488
- };
1489
- function createPointerEvents(store) {
1490
- const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
1491
- let nextXRPointerId = XR_POINTER_ID_START;
1492
- const xrPointers = /* @__PURE__ */ new Map();
1493
- return {
1494
- priority: 1,
1495
- enabled: true,
1496
- frameTimedRaycasts: true,
1497
- alwaysFireOnScroll: true,
1498
- updateOnFrame: false,
1499
- compute(event, state) {
1500
- state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
1501
- state.raycaster.setFromCamera(state.pointer, state.camera);
1502
- },
1503
- connected: void 0,
1504
- handlers: Object.keys(DOM_EVENTS).reduce(
1505
- (acc, key) => ({ ...acc, [key]: handlePointer(key) }),
1506
- {}
1208
+ }, [store, scheduler, id, optionsKey, isLegacyPriority, isInsideCanvas]);
1209
+ const isPaused = React.useSyncExternalStore(
1210
+ // Subscribe function
1211
+ React.useCallback(
1212
+ (onStoreChange) => {
1213
+ return getScheduler().subscribeJobState(id, onStoreChange);
1214
+ },
1215
+ [id]
1507
1216
  ),
1508
- update: (pointerId) => {
1509
- const { events, internal } = store.getState();
1510
- if (!events.handlers) return;
1511
- if (pointerId !== void 0) {
1512
- const event = internal.pointerDirty.get(pointerId);
1513
- if (event) {
1514
- internal.pointerDirty.delete(pointerId);
1515
- processDeferredPointer(event, pointerId);
1516
- } else if (internal.lastEvent?.current) {
1517
- processDeferredPointer(internal.lastEvent.current, pointerId);
1518
- }
1519
- } else {
1520
- flushDeferredPointers();
1521
- if (internal.lastEvent?.current) {
1522
- events.handlers.onPointerMove(internal.lastEvent.current);
1523
- }
1524
- }
1525
- },
1526
- flush: () => {
1527
- const { events, internal } = store.getState();
1528
- flushDeferredPointers();
1529
- if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
1530
- events.handlers.onPointerMove(internal.lastEvent.current);
1531
- }
1532
- },
1533
- connect: (target) => {
1534
- if (!target) return;
1535
- const { set, events } = store.getState();
1536
- events.disconnect?.();
1537
- set((state) => ({ events: { ...state.events, connected: target } }));
1538
- if (events.handlers) {
1539
- for (const name in events.handlers) {
1540
- const event = events.handlers[name];
1541
- const [eventName, passive] = DOM_EVENTS[name];
1542
- target.addEventListener(eventName, event, { passive });
1543
- }
1544
- }
1545
- },
1546
- disconnect: () => {
1547
- const { set, events } = store.getState();
1548
- if (events.connected) {
1549
- if (events.handlers) {
1550
- for (const name in events.handlers) {
1551
- const event = events.handlers[name];
1552
- const [eventName] = DOM_EVENTS[name];
1553
- events.connected.removeEventListener(eventName, event);
1554
- }
1555
- }
1556
- set((state) => ({ events: { ...state.events, connected: void 0 } }));
1557
- }
1558
- },
1559
- registerPointer: (config) => {
1560
- const pointerId = nextXRPointerId++;
1561
- xrPointers.set(pointerId, config);
1562
- const { internal } = store.getState();
1563
- getPointerState(internal, pointerId);
1564
- return pointerId;
1565
- },
1566
- unregisterPointer: (pointerId) => {
1567
- xrPointers.delete(pointerId);
1568
- const { internal } = store.getState();
1569
- const pointerState = internal.pointerMap.get(pointerId);
1570
- if (pointerState) {
1571
- for (const [, hoveredObj] of pointerState.hovered) {
1572
- const eventObject = hoveredObj.eventObject;
1573
- const instance = eventObject.__r3f;
1574
- if (instance?.eventCount) {
1575
- const handlers = instance.handlers;
1576
- const data = { ...hoveredObj, intersections: [] };
1577
- handlers.onPointerOut?.(data);
1578
- handlers.onPointerLeave?.(data);
1579
- }
1580
- }
1581
- internal.pointerMap.delete(pointerId);
1582
- }
1583
- internal.pointerDirty.delete(pointerId);
1584
- }
1585
- };
1217
+ // getSnapshot function
1218
+ React.useCallback(() => getScheduler().isJobPaused(id), [id]),
1219
+ // getServerSnapshot function (SSR)
1220
+ React.useCallback(() => false, [])
1221
+ );
1222
+ const controls = React.useMemo(() => {
1223
+ const scheduler2 = getScheduler();
1224
+ return {
1225
+ /** The job's unique ID */
1226
+ id,
1227
+ /**
1228
+ * Access to the global scheduler for frame loop control.
1229
+ * Use for controlling the entire frame loop, adding phases, etc.
1230
+ */
1231
+ scheduler: scheduler2,
1232
+ /**
1233
+ * Manually step this job only.
1234
+ * Bypasses FPS limiting - always runs.
1235
+ * @param timestamp Optional timestamp (defaults to performance.now())
1236
+ */
1237
+ step: (timestamp) => {
1238
+ getScheduler().stepJob(id, timestamp);
1239
+ },
1240
+ /**
1241
+ * Manually step ALL jobs in the scheduler.
1242
+ * Useful for frameloop='never' mode.
1243
+ * @param timestamp Optional timestamp (defaults to performance.now())
1244
+ */
1245
+ stepAll: (timestamp) => {
1246
+ getScheduler().step(timestamp);
1247
+ },
1248
+ /**
1249
+ * Pause this job (set enabled=false).
1250
+ * Job remains registered but won't run.
1251
+ */
1252
+ pause: () => {
1253
+ getScheduler().pauseJob(id);
1254
+ },
1255
+ /**
1256
+ * Resume this job (set enabled=true).
1257
+ */
1258
+ resume: () => {
1259
+ getScheduler().resumeJob(id);
1260
+ },
1261
+ /**
1262
+ * Reactive paused state - automatically updates when pause/resume is called.
1263
+ * No need for forceUpdate() in your components.
1264
+ */
1265
+ isPaused
1266
+ };
1267
+ }, [id, isPaused]);
1268
+ return controls;
1586
1269
  }
1587
1270
 
1588
- const shownNotices = /* @__PURE__ */ new Set();
1589
- function notifyDepreciated({ heading, body, link }) {
1590
- if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_DEPRECATION_WARNINGS !== "true") {
1591
- return;
1592
- }
1593
- if (shownNotices.has(heading)) return;
1594
- shownNotices.add(heading);
1595
- const caller = getCallerFrame();
1596
- if (caller) {
1597
- console.log();
1598
- }
1599
- const boxStyle = "background: #ff9800; color: #1a1a1a; padding: 8px 12px; border-radius: 4px; font-weight: 500;";
1600
- if (caller) {
1601
- console.log(`%c\u26A0\uFE0F ${heading}`, boxStyle);
1602
- }
1603
- if (body || link) {
1604
- let message = "";
1605
- if (body) message += body;
1606
- if (link) message += (body ? "\n\n" : "") + `More info: ${link}`;
1607
- console.warn(`%c${message}`, "font-weight: bold;");
1608
- }
1609
- }
1610
- function getCallerFrame(depth = 3) {
1611
- const stack = new Error().stack;
1612
- if (!stack) return null;
1613
- const lines = stack.split("\n");
1614
- const frame = lines[depth];
1615
- if (!frame) return null;
1616
- let match = frame.match(/^\s*at (?:(.+?) )?\(?(.+?):(\d+):(\d+)\)?$/);
1617
- if (!match) {
1618
- match = frame.match(/^(?:(.+?)@)?(.+?):(\d+):(\d+)$/);
1619
- }
1620
- if (!match) return null;
1621
- const [, fn, url, line] = match;
1622
- return {
1623
- functionName: fn ?? "<anonymous>",
1624
- location: formatLocation(url, Number(line))
1625
- };
1271
+ const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
1272
+ function getUrls(input) {
1273
+ if (typeof input === "string") return [input];
1274
+ if (Array.isArray(input)) return input;
1275
+ return Object.values(input);
1626
1276
  }
1627
- function formatLocation(url, line) {
1628
- const clean = url.split("?")[0];
1629
- const file = clean.split("/").pop() ?? clean;
1630
- return `${file}:${line}`;
1277
+ function allUrlsCached(urls, textureCache) {
1278
+ return urls.every((url) => textureCache.has(url));
1631
1279
  }
1632
- function notifyAlpha({ message, link }) {
1633
- if (typeof process !== "undefined" && (process.env.NODE_ENV === "test" || process.env.JEST_WORKER_ID !== void 0) && process.env.R3F_SHOW_ALPHA_WARNINGS !== "true") {
1634
- return;
1635
- }
1636
- if (shownNotices.has(message)) return;
1637
- shownNotices.add(message);
1638
- const boxStyle = "background: #6366f1; color: #ffffff; padding: 6px 10px; border-radius: 4px; font-weight: 500;";
1639
- console.log(`%c\u{1F52C} ${message}`, boxStyle);
1640
- {
1641
- console.log(`%cMore info: ${link}`, "color: #6366f1; font-weight: normal;");
1280
+ function buildFromCache(input, textureCache) {
1281
+ if (typeof input === "string") {
1282
+ return textureCache.get(input);
1283
+ } else if (Array.isArray(input)) {
1284
+ return input.map((url) => textureCache.get(url));
1285
+ } else {
1286
+ const result = {};
1287
+ const objInput = input;
1288
+ for (const key in objInput) {
1289
+ result[key] = textureCache.get(objInput[key]);
1290
+ }
1291
+ return result;
1642
1292
  }
1643
1293
  }
1644
-
1645
- const INTERNAL_LIB_MARKERS = ["zustand", "setState", "Object.assign"];
1646
- const INTERNAL_FIBER_MARKERS = ["packages/fiber/src", "packages/fiber/dist", "@react-three/fiber", "@react-three_fiber"];
1647
- function isInternalRendererAccess(stack, callerDepth = 2) {
1648
- if (!stack) return false;
1649
- const caller = stack.split("\n")[callerDepth] ?? "";
1650
- return INTERNAL_LIB_MARKERS.some((m) => caller.includes(m)) || INTERNAL_FIBER_MARKERS.some((m) => caller.includes(m));
1651
- }
1652
-
1653
- const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
1654
- const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React.createContext(null));
1655
- const createStore = (invalidate, advance) => {
1656
- const rootStore = createWithEqualityFn((set, get) => {
1657
- const position = new Vector3();
1658
- const defaultTarget = new Vector3();
1659
- const tempTarget = new Vector3();
1660
- function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
1661
- const { width, height, top, left } = size;
1662
- const aspect = width / height;
1663
- if (target.isVector3) tempTarget.copy(target);
1664
- else tempTarget.set(...target);
1665
- const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
1666
- if (isOrthographicCamera(camera)) {
1667
- return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
1668
- } else {
1669
- const fov = camera.fov * Math.PI / 180;
1670
- const h = 2 * Math.tan(fov / 2) * distance;
1671
- const w = h * (width / height);
1672
- return { width: w, height: h, top, left, factor: width / w, distance, aspect };
1294
+ function useTexture(input, optionsOrOnLoad) {
1295
+ const renderer = useThree((state) => state.internal.actualRenderer);
1296
+ const store = useStore();
1297
+ const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
1298
+ const { onLoad, cache = true } = options;
1299
+ const onLoadRef = useRef(onLoad);
1300
+ onLoadRef.current = onLoad;
1301
+ const onLoadCalledForRef = useRef(null);
1302
+ const urls = useMemo(() => getUrls(input), [input]);
1303
+ const cachedResult = useMemo(() => {
1304
+ if (!cache) return null;
1305
+ const textures = store.getState().textures;
1306
+ if (!allUrlsCached(urls, textures)) return null;
1307
+ return buildFromCache(input, textures);
1308
+ }, [cache, urls, input, store]);
1309
+ const loadedTextures = useLoader(
1310
+ TextureLoader,
1311
+ IsObject(input) ? Object.values(input) : input
1312
+ );
1313
+ const inputKey = urls.join("\0");
1314
+ useLayoutEffect(() => {
1315
+ if (cachedResult) return;
1316
+ if (onLoadCalledForRef.current === inputKey) return;
1317
+ onLoadCalledForRef.current = inputKey;
1318
+ onLoadRef.current?.(loadedTextures);
1319
+ }, [cachedResult, loadedTextures, inputKey]);
1320
+ useEffect(() => {
1321
+ if (cachedResult) return;
1322
+ if ("initTexture" in renderer) {
1323
+ let textureArray = [];
1324
+ if (Array.isArray(loadedTextures)) {
1325
+ textureArray = loadedTextures;
1326
+ } else if (loadedTextures instanceof Texture$1) {
1327
+ textureArray = [loadedTextures];
1328
+ } else if (IsObject(loadedTextures)) {
1329
+ textureArray = Object.values(loadedTextures);
1673
1330
  }
1331
+ textureArray.forEach((texture) => {
1332
+ if (texture instanceof Texture$1) {
1333
+ renderer.initTexture(texture);
1334
+ }
1335
+ });
1674
1336
  }
1675
- let performanceTimeout = void 0;
1676
- const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
1677
- const pointer = new Vector2();
1678
- const rootState = {
1679
- set,
1680
- get,
1681
- // Mock objects that have to be configured
1682
- // primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
1683
- primaryStore: null,
1684
- gl: null,
1685
- renderer: null,
1686
- camera: null,
1687
- frustum: new Frustum(),
1688
- autoUpdateFrustum: true,
1689
- raycaster: null,
1690
- events: {
1691
- priority: 1,
1692
- enabled: true,
1693
- connected: false,
1694
- frameTimedRaycasts: true,
1695
- alwaysFireOnScroll: true,
1696
- updateOnFrame: false
1697
- },
1698
- scene: null,
1699
- rootScene: null,
1700
- xr: null,
1701
- inspector: null,
1702
- invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
1703
- advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
1704
- textureColorSpace: SRGBColorSpace,
1705
- isLegacy: false,
1706
- webGPUSupported: false,
1707
- isNative: false,
1708
- controls: null,
1709
- pointer,
1710
- mouse: pointer,
1711
- frameloop: "always",
1712
- onPointerMissed: void 0,
1713
- onDragOverMissed: void 0,
1714
- onDropMissed: void 0,
1715
- performance: {
1716
- current: 1,
1717
- min: 0.5,
1718
- max: 1,
1719
- debounce: 200,
1720
- regress: () => {
1721
- const state2 = get();
1722
- if (performanceTimeout) clearTimeout(performanceTimeout);
1723
- if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
1724
- performanceTimeout = setTimeout(
1725
- () => setPerformanceCurrent(get().performance.max),
1726
- state2.performance.debounce
1727
- );
1337
+ }, [renderer, loadedTextures, cachedResult]);
1338
+ const mappedTextures = useMemo(() => {
1339
+ if (cachedResult) return cachedResult;
1340
+ if (IsObject(input)) {
1341
+ const keyed = {};
1342
+ const textureArray = loadedTextures;
1343
+ let i = 0;
1344
+ for (const key in input) keyed[key] = textureArray[i++];
1345
+ return keyed;
1346
+ } else {
1347
+ return loadedTextures;
1348
+ }
1349
+ }, [input, loadedTextures, cachedResult]);
1350
+ useEffect(() => {
1351
+ if (!cache) return;
1352
+ const urlTextureMap = [];
1353
+ if (typeof input === "string") {
1354
+ urlTextureMap.push([input, mappedTextures]);
1355
+ } else if (Array.isArray(input)) {
1356
+ const textureArray = mappedTextures;
1357
+ input.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
1358
+ } else if (IsObject(input)) {
1359
+ const textureRecord = mappedTextures;
1360
+ for (const key in input) {
1361
+ const url = input[key];
1362
+ urlTextureMap.push([url, textureRecord[key]]);
1363
+ }
1364
+ }
1365
+ store.setState((state) => {
1366
+ const refs = new Map(state._textureRefs);
1367
+ let textures = state.textures;
1368
+ let added = false;
1369
+ for (const [url, texture] of urlTextureMap) {
1370
+ if (!textures.has(url)) {
1371
+ if (!added) {
1372
+ textures = new Map(textures);
1373
+ added = true;
1374
+ }
1375
+ textures.set(url, texture);
1728
1376
  }
1377
+ refs.set(url, (refs.get(url) ?? 0) + 1);
1378
+ }
1379
+ return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
1380
+ });
1381
+ return () => store.setState((state) => {
1382
+ const refs = new Map(state._textureRefs);
1383
+ for (const [url] of urlTextureMap) {
1384
+ const next = (refs.get(url) ?? 0) - 1;
1385
+ if (next <= 0) refs.delete(url);
1386
+ else refs.set(url, next);
1387
+ }
1388
+ return { _textureRefs: refs };
1389
+ });
1390
+ }, [cache, input, mappedTextures, store]);
1391
+ return mappedTextures;
1392
+ }
1393
+ useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
1394
+ useTexture.clear = (input) => useLoader.clear(TextureLoader, input);
1395
+ const Texture = ({
1396
+ children,
1397
+ input,
1398
+ onLoad,
1399
+ cache
1400
+ }) => {
1401
+ const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
1402
+ const ret = useTexture(input, options);
1403
+ return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
1404
+ };
1405
+
1406
+ function useTextures(selector) {
1407
+ const store = useStore();
1408
+ const registry = useMemo(() => {
1409
+ const getState = store.getState;
1410
+ const setState = store.setState;
1411
+ const getOne = (key) => getState().textures.get(key);
1412
+ return {
1413
+ get all() {
1414
+ return getState().textures;
1729
1415
  },
1730
- size: { width: 0, height: 0, top: 0, left: 0 },
1731
- viewport: {
1732
- initialDpr: 0,
1733
- dpr: 0,
1734
- width: 0,
1735
- height: 0,
1736
- top: 0,
1737
- left: 0,
1738
- aspect: 0,
1739
- distance: 0,
1740
- factor: 0,
1741
- getCurrentViewport
1416
+ get(input) {
1417
+ if (typeof input === "string") return getOne(input);
1418
+ if (Array.isArray(input)) return input.map(getOne);
1419
+ const out = {};
1420
+ for (const name in input) out[name] = getOne(input[name]);
1421
+ return out;
1742
1422
  },
1743
- setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
1744
- setSize: (width, height, top, left) => {
1745
- const state2 = get();
1746
- if (width === void 0) {
1747
- set({ _sizeImperative: false });
1748
- if (state2._sizeProps) {
1749
- const { width: propW, height: propH } = state2._sizeProps;
1750
- if (propW !== void 0 || propH !== void 0) {
1751
- const currentSize = state2.size;
1752
- const newSize = {
1753
- width: propW ?? currentSize.width,
1754
- height: propH ?? currentSize.height,
1755
- top: currentSize.top,
1756
- left: currentSize.left
1757
- };
1758
- set((s) => ({
1759
- size: newSize,
1760
- viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
1761
- }));
1762
- getScheduler().invalidate();
1763
- }
1423
+ has: (key) => getState().textures.has(key),
1424
+ add(keyOrRecord, texture) {
1425
+ setState((state) => {
1426
+ const textures = new Map(state.textures);
1427
+ if (typeof keyOrRecord === "string") {
1428
+ textures.set(keyOrRecord, texture);
1429
+ } else {
1430
+ for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
1764
1431
  }
1765
- return;
1766
- }
1767
- const w = width;
1768
- const h = height ?? width;
1769
- const t = top ?? state2.size.top;
1770
- const l = left ?? state2.size.left;
1771
- const size = { width: w, height: h, top: t, left: l };
1772
- set((s) => ({
1773
- size,
1774
- viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
1775
- _sizeImperative: true
1776
- }));
1777
- getScheduler().invalidate();
1778
- },
1779
- setDpr: (dpr) => set((state2) => {
1780
- const resolved = calculateDpr(dpr);
1781
- return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
1782
- }),
1783
- setFrameloop: (frameloop = "always") => {
1784
- set(() => ({ frameloop }));
1432
+ return { textures };
1433
+ });
1785
1434
  },
1786
- setError: (error) => set(() => ({ error })),
1787
- error: null,
1788
- //* TSL State (managed via hooks: useUniforms, useNodes, useBuffers, useGPUStorage, useTextures, useRenderPipeline) ==============================
1789
- uniforms: {},
1790
- nodes: {},
1791
- buffers: {},
1792
- gpuStorage: {},
1793
- textures: /* @__PURE__ */ new Map(),
1794
- _textureRefs: /* @__PURE__ */ new Map(),
1795
- renderPipeline: null,
1796
- passes: {},
1797
- _hmrVersion: 0,
1798
- _sizeImperative: false,
1799
- _sizeProps: null,
1800
- previousRoot: void 0,
1801
- internal: {
1802
- // Events
1803
- interaction: [],
1804
- subscribers: [],
1805
- // Per-pointer state (new unified structure)
1806
- pointerMap: /* @__PURE__ */ new Map(),
1807
- pointerDirty: /* @__PURE__ */ new Map(),
1808
- lastEvent: React.createRef(),
1809
- // Deprecated but kept for backwards compatibility
1810
- hovered: /* @__PURE__ */ new Map(),
1811
- initialClick: [0, 0],
1812
- initialHits: [],
1813
- capturedMap: /* @__PURE__ */ new Map(),
1814
- // Visibility tracking (onFramed, onOccluded, onVisible)
1815
- visibilityRegistry: /* @__PURE__ */ new Map(),
1816
- // Occlusion system (WebGPU only)
1817
- occlusionEnabled: false,
1818
- occlusionObserver: null,
1819
- occlusionCache: /* @__PURE__ */ new Map(),
1820
- helperGroup: null,
1821
- // Updates
1822
- active: false,
1823
- frames: 0,
1824
- priority: 0,
1825
- subscribe: (ref, priority, store) => {
1826
- const internal = get().internal;
1827
- internal.priority = internal.priority + (priority > 0 ? 1 : 0);
1828
- internal.subscribers.push({ ref, priority, store });
1829
- internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
1830
- return () => {
1831
- const internal2 = get().internal;
1832
- if (internal2?.subscribers) {
1833
- internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
1834
- internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
1835
- }
1836
- };
1837
- },
1838
- // Renderer Storage (single source of truth)
1839
- actualRenderer: null,
1840
- // Scheduler for useFrameNext (initialized in renderer.tsx)
1841
- scheduler: null
1842
- }
1843
- };
1844
- return rootState;
1845
- });
1846
- const state = rootStore.getState();
1847
- Object.defineProperty(state, "gl", {
1848
- get() {
1849
- const currentState = rootStore.getState();
1850
- if (!currentState.isLegacy && currentState.internal.actualRenderer) {
1851
- const stack = new Error().stack || "";
1852
- if (!isInternalRendererAccess(stack)) {
1853
- const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
1854
- notifyDepreciated({
1855
- heading: "Accessing state.gl in WebGPU mode",
1856
- 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
1857
- });
1858
- }
1859
- }
1860
- return currentState.internal.actualRenderer;
1861
- },
1862
- set(value) {
1863
- rootStore.getState().internal.actualRenderer = value;
1864
- },
1865
- enumerable: true,
1866
- configurable: true
1867
- });
1868
- Object.defineProperty(state, "renderer", {
1869
- get() {
1870
- return rootStore.getState().internal.actualRenderer;
1871
- },
1872
- set(value) {
1873
- rootStore.getState().internal.actualRenderer = value;
1874
- },
1875
- enumerable: true,
1876
- configurable: true
1877
- });
1878
- let oldScene = state.scene;
1879
- rootStore.subscribe(() => {
1880
- const currentState = rootStore.getState();
1881
- const { scene, rootScene, set } = currentState;
1882
- if (scene !== oldScene) {
1883
- oldScene = scene;
1884
- if (scene?.isScene && scene !== rootScene) {
1885
- set({ rootScene: scene });
1886
- }
1887
- }
1888
- });
1889
- let oldSize = state.size;
1890
- let oldDpr = state.viewport.dpr;
1891
- let oldCamera = state.camera;
1892
- rootStore.subscribe(() => {
1893
- const { camera, size, viewport, set, internal } = rootStore.getState();
1894
- const actualRenderer = internal.actualRenderer;
1895
- const canvasTarget = internal.canvasTarget;
1896
- if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
1897
- oldSize = size;
1898
- oldDpr = viewport.dpr;
1899
- updateCamera(camera, size);
1900
- if (internal.isSecondary && canvasTarget) {
1901
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1902
- canvasTarget.setSize(size.width, size.height, false);
1903
- } else {
1904
- if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
1905
- actualRenderer.setSize(size.width, size.height, false);
1906
- if (canvasTarget) {
1907
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1908
- canvasTarget.setSize(size.width, size.height, false);
1435
+ dispose(key, options) {
1436
+ const state = getState();
1437
+ const refs = state._textureRefs.get(key) ?? 0;
1438
+ if (refs > 0 && !options?.force) {
1439
+ console.warn(
1440
+ `[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
1441
+ );
1442
+ return false;
1909
1443
  }
1444
+ state.textures.get(key)?.dispose();
1445
+ setState((s) => {
1446
+ const textures = new Map(s.textures);
1447
+ textures.delete(key);
1448
+ const nextRefs = new Map(s._textureRefs);
1449
+ nextRefs.delete(key);
1450
+ return { textures, _textureRefs: nextRefs };
1451
+ });
1452
+ return true;
1453
+ },
1454
+ disposeAll() {
1455
+ for (const texture of getState().textures.values()) texture.dispose();
1456
+ setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
1910
1457
  }
1911
- }
1912
- if (camera !== oldCamera) {
1913
- oldCamera = camera;
1914
- const { rootScene } = rootStore.getState();
1915
- if (camera && rootScene && !camera.parent) {
1916
- rootScene.add(camera);
1917
- }
1918
- set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
1919
- const currentState = rootStore.getState();
1920
- if (currentState.autoUpdateFrustum && camera) {
1921
- updateFrustum(camera, currentState.frustum);
1922
- }
1923
- }
1924
- });
1925
- rootStore.subscribe((state2) => invalidate(state2));
1926
- return rootStore;
1927
- };
1458
+ };
1459
+ }, [store]);
1460
+ const subscribe = selector ? () => selector(registry) : (state) => state.textures;
1461
+ const selected = useThree(subscribe);
1462
+ return selector ? selected : registry;
1463
+ }
1928
1464
 
1929
- const memoizedLoaders = /* @__PURE__ */ new WeakMap();
1930
- const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
1931
- function getLoader(Proto) {
1932
- if (isConstructor$1(Proto)) {
1933
- let loader = memoizedLoaders.get(Proto);
1934
- if (!loader) {
1935
- loader = new Proto();
1936
- memoizedLoaders.set(Proto, loader);
1465
+ function useRenderTarget(widthOrOptions, heightOrOptions, options) {
1466
+ const isLegacy = useThree((s) => s.isLegacy);
1467
+ const size = useThree((s) => s.size);
1468
+ let width;
1469
+ let height;
1470
+ let opts;
1471
+ if (typeof widthOrOptions === "object") {
1472
+ opts = widthOrOptions;
1473
+ } else if (typeof widthOrOptions === "number") {
1474
+ width = widthOrOptions;
1475
+ if (typeof heightOrOptions === "object") {
1476
+ height = widthOrOptions;
1477
+ opts = heightOrOptions;
1478
+ } else if (typeof heightOrOptions === "number") {
1479
+ height = heightOrOptions;
1480
+ opts = options;
1481
+ } else {
1482
+ height = widthOrOptions;
1937
1483
  }
1938
- return loader;
1939
1484
  }
1940
- return Proto;
1941
- }
1942
- function loadingFn(extensions, onProgress) {
1943
- return function(Proto, input) {
1944
- const loader = getLoader(Proto);
1945
- if (extensions) extensions(loader);
1946
- if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
1947
- return loader.loadAsync(input, onProgress).then((data) => {
1948
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1949
- return data;
1950
- });
1485
+ return useMemo(() => {
1486
+ const w = width ?? size.width;
1487
+ const h = height ?? size.height;
1488
+ {
1489
+ return isLegacy ? new WebGLRenderTarget(w, h, opts) : new RenderTarget(w, h, opts);
1951
1490
  }
1952
- return new Promise(
1953
- (res, reject) => loader.load(
1954
- input,
1955
- (data) => {
1956
- if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
1957
- res(data);
1958
- },
1959
- onProgress,
1960
- (error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
1961
- )
1962
- );
1963
- };
1964
- }
1965
- function useLoader(loader, input, extensions, onProgress, cacheKey) {
1966
- const inputs = Array.isArray(input) ? input : [input];
1967
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1968
- const fn = loadingFn(extensions, onProgress);
1969
- const results = cacheKeys.map(
1970
- (key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
1971
- );
1972
- return Array.isArray(input) ? results : results[0];
1491
+ }, [width, height, size.width, size.height, opts, isLegacy]);
1973
1492
  }
1974
- useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
1975
- const inputs = Array.isArray(input) ? input : [input];
1976
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1977
- cacheKeys.forEach(
1978
- (key, index) => preload(() => loadingFn(extensions, onProgress)(loader, inputs[index]), [loader, key])
1979
- );
1980
- };
1981
- useLoader.clear = function(loader, input, cacheKey) {
1982
- const cacheKeys = Array.isArray(cacheKey ?? input) ? cacheKey ?? input : [cacheKey ?? input];
1983
- cacheKeys.forEach((key) => clear([loader, key]));
1493
+
1494
+ const presetsObj = {
1495
+ apartment: "lebombo_1k.hdr",
1496
+ city: "potsdamer_platz_1k.hdr",
1497
+ dawn: "kiara_1_dawn_1k.hdr",
1498
+ forest: "forest_slope_1k.hdr",
1499
+ lobby: "st_fagans_interior_1k.hdr",
1500
+ night: "dikhololo_night_1k.hdr",
1501
+ park: "rooitou_park_1k.hdr",
1502
+ studio: "studio_small_03_1k.hdr",
1503
+ sunset: "venice_sunset_1k.hdr",
1504
+ warehouse: "empty_warehouse_01_1k.hdr"
1984
1505
  };
1985
- useLoader.loader = getLoader;
1986
1506
 
1987
- function useFrame(callback, priorityOrOptions) {
1988
- const store = React.useContext(context);
1989
- const isInsideCanvas = store !== null;
1990
- const scheduler = getScheduler();
1991
- const optionsKey = typeof priorityOrOptions === "number" ? `p:${priorityOrOptions}` : priorityOrOptions ? JSON.stringify({
1992
- id: priorityOrOptions.id,
1993
- phase: priorityOrOptions.phase,
1994
- priority: priorityOrOptions.priority,
1995
- fps: priorityOrOptions.fps,
1996
- drop: priorityOrOptions.drop,
1997
- enabled: priorityOrOptions.enabled,
1998
- before: priorityOrOptions.before,
1999
- after: priorityOrOptions.after
2000
- }) : "";
2001
- const options = React.useMemo(() => {
2002
- return typeof priorityOrOptions === "number" ? { priority: priorityOrOptions } : priorityOrOptions ?? {};
2003
- }, [optionsKey]);
2004
- const reactId = React.useId();
2005
- const id = options.id ?? reactId;
2006
- const callbackRef = useMutableCallback(callback);
2007
- const isLegacyPriority = typeof priorityOrOptions === "number" && priorityOrOptions > 0;
2008
- useIsomorphicLayoutEffect(() => {
2009
- if (!callback) return;
2010
- if (isInsideCanvas) {
2011
- const state = store.getState();
2012
- const rootId = state.internal.rootId;
2013
- if (isLegacyPriority) {
2014
- state.internal.priority++;
2015
- let parentRoot = state.previousRoot;
2016
- while (parentRoot) {
2017
- const parentState = parentRoot.getState();
2018
- if (parentState?.internal) parentState.internal.priority++;
2019
- parentRoot = parentState?.previousRoot;
2020
- }
2021
- notifyDepreciated({
2022
- heading: "useFrame with numeric priority is deprecated",
2023
- 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 })',
2024
- link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
2025
- });
1507
+ const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
1508
+ const isArray = (arr) => Array.isArray(arr);
1509
+ const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
1510
+ function useEnvironment({
1511
+ files = defaultFiles,
1512
+ path = "",
1513
+ preset = void 0,
1514
+ colorSpace = void 0,
1515
+ extensions
1516
+ } = {}) {
1517
+ if (preset) {
1518
+ validatePreset(preset);
1519
+ files = presetsObj[preset];
1520
+ path = CUBEMAP_ROOT;
1521
+ }
1522
+ const multiFile = isArray(files);
1523
+ const { extension, isCubemap } = getExtension(files);
1524
+ const loader = getLoader(extension);
1525
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1526
+ const renderer = useThree((state) => state.renderer);
1527
+ useLayoutEffect(() => {
1528
+ if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
1529
+ function clearGainmapTexture() {
1530
+ useLoader.clear(loader, multiFile ? [files] : files);
1531
+ }
1532
+ renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
1533
+ }, [extension, files, loader, multiFile, renderer.domElement]);
1534
+ const loaderResult = useLoader(
1535
+ loader,
1536
+ multiFile ? [files] : files,
1537
+ (loader2) => {
1538
+ if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
1539
+ loader2.setRenderer?.(renderer);
2026
1540
  }
2027
- const wrappedCallback = (frameState, delta) => {
2028
- const localState = store.getState();
2029
- const mergedState = {
2030
- ...localState,
2031
- time: frameState.time,
2032
- delta: frameState.delta,
2033
- elapsed: frameState.elapsed,
2034
- frame: frameState.frame
2035
- };
2036
- callbackRef.current?.(mergedState, delta);
2037
- };
2038
- const unregister = scheduler.register(wrappedCallback, {
2039
- id,
2040
- rootId,
2041
- ...options
2042
- });
2043
- return () => {
2044
- unregister();
2045
- if (isLegacyPriority) {
2046
- const currentState = store.getState();
2047
- if (currentState.internal) {
2048
- currentState.internal.priority--;
2049
- let parentRoot = currentState.previousRoot;
2050
- while (parentRoot) {
2051
- const parentState = parentRoot.getState();
2052
- if (parentState?.internal) parentState.internal.priority--;
2053
- parentRoot = parentState?.previousRoot;
2054
- }
2055
- }
2056
- }
2057
- };
2058
- } else {
2059
- return scheduler.register(
2060
- (state, delta) => {
2061
- const frameState = state;
2062
- if (!frameState.renderer) return;
2063
- callbackRef.current?.(frameState, delta);
2064
- },
2065
- { id, ...options }
2066
- );
1541
+ loader2.setPath?.(path);
1542
+ if (extensions) extensions(loader2);
2067
1543
  }
2068
- }, [store, scheduler, id, optionsKey, isLegacyPriority, isInsideCanvas]);
2069
- const isPaused = React.useSyncExternalStore(
2070
- // Subscribe function
2071
- React.useCallback(
2072
- (onStoreChange) => {
2073
- return getScheduler().subscribeJobState(id, onStoreChange);
2074
- },
2075
- [id]
2076
- ),
2077
- // getSnapshot function
2078
- React.useCallback(() => getScheduler().isJobPaused(id), [id]),
2079
- // getServerSnapshot function (SSR)
2080
- React.useCallback(() => false, [])
2081
1544
  );
2082
- const controls = React.useMemo(() => {
2083
- const scheduler2 = getScheduler();
2084
- return {
2085
- /** The job's unique ID */
2086
- id,
2087
- /**
2088
- * Access to the global scheduler for frame loop control.
2089
- * Use for controlling the entire frame loop, adding phases, etc.
2090
- */
2091
- scheduler: scheduler2,
2092
- /**
2093
- * Manually step this job only.
2094
- * Bypasses FPS limiting - always runs.
2095
- * @param timestamp Optional timestamp (defaults to performance.now())
2096
- */
2097
- step: (timestamp) => {
2098
- getScheduler().stepJob(id, timestamp);
2099
- },
2100
- /**
2101
- * Manually step ALL jobs in the scheduler.
2102
- * Useful for frameloop='never' mode.
2103
- * @param timestamp Optional timestamp (defaults to performance.now())
2104
- */
2105
- stepAll: (timestamp) => {
2106
- getScheduler().step(timestamp);
2107
- },
2108
- /**
2109
- * Pause this job (set enabled=false).
2110
- * Job remains registered but won't run.
2111
- */
2112
- pause: () => {
2113
- getScheduler().pauseJob(id);
2114
- },
2115
- /**
2116
- * Resume this job (set enabled=true).
2117
- */
2118
- resume: () => {
2119
- getScheduler().resumeJob(id);
2120
- },
2121
- /**
2122
- * Reactive paused state - automatically updates when pause/resume is called.
2123
- * No need for forceUpdate() in your components.
2124
- */
2125
- isPaused
2126
- };
2127
- }, [id, isPaused]);
2128
- return controls;
1545
+ let texture = multiFile ? (
1546
+ // @ts-ignore
1547
+ loaderResult[0]
1548
+ ) : loaderResult;
1549
+ if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
1550
+ texture = texture.renderTarget?.texture;
1551
+ }
1552
+ texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
1553
+ texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
1554
+ return texture;
1555
+ }
1556
+ const preloadDefaultOptions = {
1557
+ files: defaultFiles,
1558
+ path: "",
1559
+ preset: void 0,
1560
+ extensions: void 0
1561
+ };
1562
+ useEnvironment.preload = (preloadOptions) => {
1563
+ const options = { ...preloadDefaultOptions, ...preloadOptions };
1564
+ let { files, path = "" } = options;
1565
+ const { preset, extensions } = options;
1566
+ if (preset) {
1567
+ validatePreset(preset);
1568
+ files = presetsObj[preset];
1569
+ path = CUBEMAP_ROOT;
1570
+ }
1571
+ const { extension } = getExtension(files);
1572
+ if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
1573
+ throw new Error("useEnvironment: Preloading gainmaps is not supported");
1574
+ }
1575
+ const loader = getLoader(extension);
1576
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1577
+ useLoader.preload(loader, isArray(files) ? [files] : files, (loader2) => {
1578
+ loader2.setPath?.(path);
1579
+ if (extensions) extensions(loader2);
1580
+ });
1581
+ };
1582
+ const clearDefaultOptins = {
1583
+ files: defaultFiles,
1584
+ preset: void 0
1585
+ };
1586
+ useEnvironment.clear = (clearOptions) => {
1587
+ const options = { ...clearDefaultOptins, ...clearOptions };
1588
+ let { files } = options;
1589
+ const { preset } = options;
1590
+ if (preset) {
1591
+ validatePreset(preset);
1592
+ files = presetsObj[preset];
1593
+ }
1594
+ const { extension } = getExtension(files);
1595
+ const loader = getLoader(extension);
1596
+ if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
1597
+ useLoader.clear(loader, isArray(files) ? [files] : files);
1598
+ };
1599
+ function validatePreset(preset) {
1600
+ if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
1601
+ }
1602
+ function getExtension(files) {
1603
+ const isCubemap = isArray(files) && files.length === 6;
1604
+ const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
1605
+ const firstEntry = isArray(files) ? files[0] : files;
1606
+ 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();
1607
+ return { extension, isCubemap, isGainmap };
1608
+ }
1609
+ function getLoader(extension) {
1610
+ const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
1611
+ return loader;
2129
1612
  }
2130
1613
 
2131
- const IsObject = (url) => url === Object(url) && !Array.isArray(url) && typeof url !== "function";
2132
- function getUrls(input) {
2133
- if (typeof input === "string") return [input];
2134
- if (Array.isArray(input)) return input;
2135
- return Object.values(input);
1614
+ function useStore() {
1615
+ const store = useContext(context);
1616
+ if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
1617
+ return store;
2136
1618
  }
2137
- function allUrlsCached(urls, textureCache) {
2138
- return urls.every((url) => textureCache.has(url));
1619
+ function useThree(selector = (state) => state, equalityFn) {
1620
+ return useStore()(selector, equalityFn);
2139
1621
  }
2140
- function buildFromCache(input, textureCache) {
2141
- if (typeof input === "string") {
2142
- return textureCache.get(input);
2143
- } else if (Array.isArray(input)) {
2144
- return input.map((url) => textureCache.get(url));
2145
- } else {
2146
- const result = {};
2147
- const objInput = input;
2148
- for (const key in objInput) {
2149
- result[key] = textureCache.get(objInput[key]);
2150
- }
2151
- return result;
2152
- }
2153
- }
2154
- function useTexture(input, optionsOrOnLoad) {
2155
- const renderer = useThree((state) => state.internal.actualRenderer);
2156
- const store = useStore();
2157
- const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
2158
- const { onLoad, cache = true } = options;
2159
- const onLoadRef = useRef(onLoad);
2160
- onLoadRef.current = onLoad;
2161
- const onLoadCalledForRef = useRef(null);
2162
- const urls = useMemo(() => getUrls(input), [input]);
2163
- const cachedResult = useMemo(() => {
2164
- if (!cache) return null;
2165
- const textures = store.getState().textures;
2166
- if (!allUrlsCached(urls, textures)) return null;
2167
- return buildFromCache(input, textures);
2168
- }, [cache, urls, input, store]);
2169
- const loadedTextures = useLoader(
2170
- TextureLoader,
2171
- IsObject(input) ? Object.values(input) : input
2172
- );
2173
- const inputKey = urls.join("\0");
2174
- useLayoutEffect(() => {
2175
- if (cachedResult) return;
2176
- if (onLoadCalledForRef.current === inputKey) return;
2177
- onLoadCalledForRef.current = inputKey;
2178
- onLoadRef.current?.(loadedTextures);
2179
- }, [cachedResult, loadedTextures, inputKey]);
2180
- useEffect(() => {
2181
- if (cachedResult) return;
2182
- if ("initTexture" in renderer) {
2183
- let textureArray = [];
2184
- if (Array.isArray(loadedTextures)) {
2185
- textureArray = loadedTextures;
2186
- } else if (loadedTextures instanceof Texture$1) {
2187
- textureArray = [loadedTextures];
2188
- } else if (IsObject(loadedTextures)) {
2189
- textureArray = Object.values(loadedTextures);
2190
- }
2191
- textureArray.forEach((texture) => {
2192
- if (texture instanceof Texture$1) {
2193
- renderer.initTexture(texture);
2194
- }
2195
- });
2196
- }
2197
- }, [renderer, loadedTextures, cachedResult]);
2198
- const mappedTextures = useMemo(() => {
2199
- if (cachedResult) return cachedResult;
2200
- if (IsObject(input)) {
2201
- const keyed = {};
2202
- const textureArray = loadedTextures;
2203
- let i = 0;
2204
- for (const key in input) keyed[key] = textureArray[i++];
2205
- return keyed;
2206
- } else {
2207
- return loadedTextures;
2208
- }
2209
- }, [input, loadedTextures, cachedResult]);
2210
- useEffect(() => {
2211
- if (!cache) return;
2212
- const urlTextureMap = [];
2213
- if (typeof input === "string") {
2214
- urlTextureMap.push([input, mappedTextures]);
2215
- } else if (Array.isArray(input)) {
2216
- const textureArray = mappedTextures;
2217
- input.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
2218
- } else if (IsObject(input)) {
2219
- const textureRecord = mappedTextures;
2220
- for (const key in input) {
2221
- const url = input[key];
2222
- urlTextureMap.push([url, textureRecord[key]]);
2223
- }
2224
- }
2225
- store.setState((state) => {
2226
- const refs = new Map(state._textureRefs);
2227
- let textures = state.textures;
2228
- let added = false;
2229
- for (const [url, texture] of urlTextureMap) {
2230
- if (!textures.has(url)) {
2231
- if (!added) {
2232
- textures = new Map(textures);
2233
- added = true;
2234
- }
2235
- textures.set(url, texture);
2236
- }
2237
- refs.set(url, (refs.get(url) ?? 0) + 1);
2238
- }
2239
- return added ? { textures, _textureRefs: refs } : { _textureRefs: refs };
2240
- });
2241
- return () => store.setState((state) => {
2242
- const refs = new Map(state._textureRefs);
2243
- for (const [url] of urlTextureMap) {
2244
- const next = (refs.get(url) ?? 0) - 1;
2245
- if (next <= 0) refs.delete(url);
2246
- else refs.set(url, next);
2247
- }
2248
- return { _textureRefs: refs };
2249
- });
2250
- }, [cache, input, mappedTextures, store]);
2251
- return mappedTextures;
2252
- }
2253
- useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
2254
- useTexture.clear = (input) => useLoader.clear(TextureLoader, input);
2255
- const Texture = ({
2256
- children,
2257
- input,
2258
- onLoad,
2259
- cache
2260
- }) => {
2261
- const options = typeof onLoad === "function" ? { onLoad, cache } : { ...onLoad, cache };
2262
- const ret = useTexture(input, options);
2263
- return /* @__PURE__ */ jsx(Fragment, { children: children?.(ret) });
2264
- };
2265
-
2266
- function useTextures(selector) {
2267
- const store = useStore();
2268
- const registry = useMemo(() => {
2269
- const getState = store.getState;
2270
- const setState = store.setState;
2271
- const getOne = (key) => getState().textures.get(key);
2272
- return {
2273
- get all() {
2274
- return getState().textures;
2275
- },
2276
- get(input) {
2277
- if (typeof input === "string") return getOne(input);
2278
- if (Array.isArray(input)) return input.map(getOne);
2279
- const out = {};
2280
- for (const name in input) out[name] = getOne(input[name]);
2281
- return out;
2282
- },
2283
- has: (key) => getState().textures.has(key),
2284
- add(keyOrRecord, texture) {
2285
- setState((state) => {
2286
- const textures = new Map(state.textures);
2287
- if (typeof keyOrRecord === "string") {
2288
- textures.set(keyOrRecord, texture);
2289
- } else {
2290
- for (const key in keyOrRecord) textures.set(key, keyOrRecord[key]);
2291
- }
2292
- return { textures };
2293
- });
2294
- },
2295
- dispose(key, options) {
2296
- const state = getState();
2297
- const refs = state._textureRefs.get(key) ?? 0;
2298
- if (refs > 0 && !options?.force) {
2299
- console.warn(
2300
- `[useTextures] "${key}" still has ${refs} active reference(s); skipping dispose. Pass { force: true } to override.`
2301
- );
2302
- return false;
2303
- }
2304
- state.textures.get(key)?.dispose();
2305
- setState((s) => {
2306
- const textures = new Map(s.textures);
2307
- textures.delete(key);
2308
- const nextRefs = new Map(s._textureRefs);
2309
- nextRefs.delete(key);
2310
- return { textures, _textureRefs: nextRefs };
2311
- });
2312
- return true;
2313
- },
2314
- disposeAll() {
2315
- for (const texture of getState().textures.values()) texture.dispose();
2316
- setState({ textures: /* @__PURE__ */ new Map(), _textureRefs: /* @__PURE__ */ new Map() });
2317
- }
2318
- };
2319
- }, [store]);
2320
- const subscribe = selector ? () => selector(registry) : (state) => state.textures;
2321
- const selected = useThree(subscribe);
2322
- return selector ? selected : registry;
2323
- }
2324
-
2325
- function useRenderTarget(widthOrOptions, heightOrOptions, options) {
2326
- const isLegacy = useThree((s) => s.isLegacy);
2327
- const size = useThree((s) => s.size);
2328
- let width;
2329
- let height;
2330
- let opts;
2331
- if (typeof widthOrOptions === "object") {
2332
- opts = widthOrOptions;
2333
- } else if (typeof widthOrOptions === "number") {
2334
- width = widthOrOptions;
2335
- if (typeof heightOrOptions === "object") {
2336
- height = widthOrOptions;
2337
- opts = heightOrOptions;
2338
- } else if (typeof heightOrOptions === "number") {
2339
- height = heightOrOptions;
2340
- opts = options;
2341
- } else {
2342
- height = widthOrOptions;
2343
- }
2344
- }
2345
- return useMemo(() => {
2346
- const w = width ?? size.width;
2347
- const h = height ?? size.height;
2348
- {
2349
- return isLegacy ? new WebGLRenderTarget(w, h, opts) : new RenderTarget(w, h, opts);
2350
- }
2351
- }, [width, height, size.width, size.height, opts, isLegacy]);
2352
- }
2353
-
2354
- function useStore() {
2355
- const store = useContext(context);
2356
- if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
2357
- return store;
2358
- }
2359
- function useThree(selector = (state) => state, equalityFn) {
2360
- return useStore()(selector, equalityFn);
2361
- }
2362
- function useInstanceHandle(ref) {
2363
- const instance = useRef(null);
2364
- useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
2365
- return instance;
1622
+ function useInstanceHandle(ref) {
1623
+ const instance = useRef(null);
1624
+ useImperativeHandle(instance, () => ref.current.__r3f, [ref]);
1625
+ return instance;
2366
1626
  }
2367
1627
  function useGraph(object) {
2368
1628
  return useMemo(() => buildGraph(object), [object]);
2369
1629
  }
2370
1630
 
1631
+ const t = 1, o = 8, r = 32, e = 2, i$1 = 268435456;
1632
+
2371
1633
  let effectId = 0;
2372
1634
  function addEffect(callback) {
2373
1635
  notifyDepreciated({
@@ -2402,7 +1664,7 @@ function advance(timestamp) {
2402
1664
  getScheduler().step(timestamp);
2403
1665
  }
2404
1666
 
2405
- const version = "10.0.0-alpha.2";
1667
+ const version = "10.0.0-alpha.3";
2406
1668
  const packageData = {
2407
1669
  version: version};
2408
1670
 
@@ -13459,206 +12721,789 @@ Check the top-level render call using <` + i + ">.");
13459
12721
  var o = 1 << 31 - vn(n);
13460
12722
  e.entanglements[1] |= o, n &= ~o;
13461
12723
  }
13462
- Kn(e), (ye & (Zn | uo)) === Jn && (Pp = me() + Fg, Wa(0));
12724
+ Kn(e), (ye & (Zn | uo)) === Jn && (Pp = me() + Fg, Wa(0));
12725
+ }
12726
+ }
12727
+ break;
12728
+ case 31:
12729
+ case 13:
12730
+ n = On(e, 2), n !== null && We(n, e, 2), Ls(), rl(e, 2);
12731
+ }
12732
+ }, le.batchedUpdates = function(e, n) {
12733
+ return e(n);
12734
+ }, le.createComponentSelector = function(e) {
12735
+ return { $$typeof: pm, value: e };
12736
+ }, le.createContainer = function(e, n, o, i, s, u, f, p, g, S) {
12737
+ return Ka(e, n, false, null, o, i, u, null, f, p, g, S);
12738
+ }, le.createHasPseudoClassSelector = function(e) {
12739
+ return { $$typeof: hm, value: e };
12740
+ }, le.createHydrationContainer = function(e, n, o, i, s, u, f, p, g, S, T, _, I, O) {
12741
+ return e = Ka(o, i, true, e, s, u, p, O, g, S, T, _), e.context = Dh(null), o = e.current, i = Nt(o), i = Xo(i), s = zo(i), s.callback = n ?? null, Mt(o, s, i), ur(i, "hydrateRoot()", null), n = i, e.current.lanes = n, Ci(e, n), Kn(e), e;
12742
+ }, le.createPortal = function(e, n, o) {
12743
+ var i = 3 < arguments.length && arguments[3] !== void 0 ? arguments[3] : null;
12744
+ try {
12745
+ vt(i);
12746
+ var s = false;
12747
+ } catch {
12748
+ s = true;
12749
+ }
12750
+ return s && (console.error("The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", typeof Symbol == "function" && Symbol.toStringTag && i[Symbol.toStringTag] || i.constructor.name || "Object"), vt(i)), { $$typeof: Ao, key: i == null ? null : "" + i, children: e, containerInfo: n, implementation: o };
12751
+ }, le.createRoleSelector = function(e) {
12752
+ return { $$typeof: mm, value: e };
12753
+ }, le.createTestNameSelector = function(e) {
12754
+ return { $$typeof: gm, value: e };
12755
+ }, le.createTextSelector = function(e) {
12756
+ return { $$typeof: ym, value: e };
12757
+ }, le.defaultOnCaughtError = function(e) {
12758
+ var n = bd ? "The above error occurred in the <" + bd + "> component." : "The above error occurred in one of your React components.", o = "React will try to recreate this component tree from scratch using the error boundary you provided, " + ((Cg || "Anonymous") + ".");
12759
+ typeof e == "object" && e !== null && typeof e.environmentName == "string" ? ri("error", [`%o
12760
+
12761
+ %s
12762
+
12763
+ %s
12764
+ `, e, n, o], e.environmentName)() : console.error(`%o
12765
+
12766
+ %s
12767
+
12768
+ %s
12769
+ `, e, n, o);
12770
+ }, le.defaultOnRecoverableError = function(e) {
12771
+ qg(e);
12772
+ }, le.defaultOnUncaughtError = function(e) {
12773
+ qg(e), console.warn(`%s
12774
+
12775
+ %s
12776
+ `, bd ? "An error occurred in the <" + bd + "> component." : "An error occurred in one of your React components.", `Consider adding an error boundary to your tree to customize error handling behavior.
12777
+ Visit https://react.dev/link/error-boundaries to learn more about error boundaries.`);
12778
+ }, le.deferredUpdates = function(e) {
12779
+ var n = x.T, o = wt();
12780
+ try {
12781
+ return an(32), x.T = null, e();
12782
+ } finally {
12783
+ an(o), x.T = n;
12784
+ }
12785
+ }, le.discreteUpdates = function(e, n, o, i, s) {
12786
+ var u = x.T, f = wt();
12787
+ try {
12788
+ return an(2), x.T = null, e(n, o, i, s);
12789
+ } finally {
12790
+ an(f), x.T = u, ye === Jn && (Pp = me() + Fg);
12791
+ }
12792
+ }, le.findAllNodes = kc, le.findBoundingRects = function(e, n) {
12793
+ if (!xr) throw Error("Test selector API is not supported by this renderer.");
12794
+ n = kc(e, n), e = [];
12795
+ for (var o = 0; o < n.length; o++) e.push(ma(n[o]));
12796
+ for (n = e.length - 1; 0 < n; n--) {
12797
+ o = e[n];
12798
+ for (var i = o.x, s = i + o.width, u = o.y, f = u + o.height, p = n - 1; 0 <= p; p--) if (n !== p) {
12799
+ var g = e[p], S = g.x, T = S + g.width, _ = g.y, I = _ + g.height;
12800
+ if (i >= S && u >= _ && s <= T && f <= I) {
12801
+ e.splice(n, 1);
12802
+ break;
12803
+ } else if (i !== S || o.width !== g.width || I < u || _ > f) {
12804
+ if (!(u !== _ || o.height !== g.height || T < i || S > s)) {
12805
+ S > i && (g.width += S - i, g.x = i), T < s && (g.width = s - S), e.splice(n, 1);
12806
+ break;
12807
+ }
12808
+ } else {
12809
+ _ > u && (g.height += _ - u, g.y = u), I < f && (g.height = f - _), e.splice(n, 1);
12810
+ break;
12811
+ }
12812
+ }
12813
+ }
12814
+ return e;
12815
+ }, le.findHostInstance = function(e) {
12816
+ var n = e._reactInternals;
12817
+ if (n === void 0) throw typeof e.render == "function" ? Error("Unable to find node on an unmounted component.") : (e = Object.keys(e).join(","), Error("Argument appears to not be a ReactComponent. Keys: " + e));
12818
+ return e = mu(n), e === null ? null : ot(e.stateNode);
12819
+ }, le.findHostInstanceWithNoPortals = function(e) {
12820
+ return e = Ed(e), e = e !== null ? _p(e) : null, e === null ? null : ot(e.stateNode);
12821
+ }, le.findHostInstanceWithWarning = function(e, n) {
12822
+ var o = e._reactInternals;
12823
+ if (o === void 0) throw typeof e.render == "function" ? Error("Unable to find node on an unmounted component.") : (e = Object.keys(e).join(","), Error("Argument appears to not be a ReactComponent. Keys: " + e));
12824
+ if (e = mu(o), e === null) return null;
12825
+ if (e.mode & 8) {
12826
+ var i = G(o) || "Component";
12827
+ mb[i] || (mb[i] = true, B(e, function() {
12828
+ o.mode & 8 ? console.error("%s is deprecated in StrictMode. %s was passed an instance of %s which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://react.dev/link/strict-mode-find-node", n, n, i) : console.error("%s is deprecated in StrictMode. %s was passed an instance of %s which renders StrictMode children. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://react.dev/link/strict-mode-find-node", n, n, i);
12829
+ }));
12830
+ }
12831
+ return ot(e.stateNode);
12832
+ }, le.flushPassiveEffects = el, le.flushSyncFromReconciler = function(e) {
12833
+ var n = ye;
12834
+ ye |= 1;
12835
+ var o = x.T, i = wt();
12836
+ try {
12837
+ if (an(2), x.T = null, e) return e();
12838
+ } finally {
12839
+ an(i), x.T = o, ye = n, (ye & (Zn | uo)) === Jn && Wa(0);
12840
+ }
12841
+ }, le.flushSyncWork = Ls, le.focusWithin = function(e, n) {
12842
+ if (!xr) throw Error("Test selector API is not supported by this renderer.");
12843
+ for (e = Ef(e), n = hh(e, n), n = Array.from(n), e = 0; e < n.length; ) {
12844
+ var o = n[e++], i = o.tag;
12845
+ if (!Kr(o)) {
12846
+ if ((i === 5 || i === 26 || i === 27) && Ft(o.stateNode)) return true;
12847
+ for (o = o.child; o !== null; ) n.push(o), o = o.sibling;
12848
+ }
12849
+ }
12850
+ return false;
12851
+ }, le.getFindAllNodesFailureDescription = function(e, n) {
12852
+ if (!xr) throw Error("Test selector API is not supported by this renderer.");
12853
+ var o = 0, i = [];
12854
+ e = [Ef(e), 0];
12855
+ for (var s = 0; s < e.length; ) {
12856
+ var u = e[s++], f = u.tag, p = e[s++], g = n[p];
12857
+ if ((f !== 5 && f !== 26 && f !== 27 || !Kr(u)) && (If(u, g) && (i.push(Sc(g)), p++, p > o && (o = p)), p < n.length)) for (u = u.child; u !== null; ) e.push(u, p), u = u.sibling;
12858
+ }
12859
+ if (o < n.length) {
12860
+ for (e = []; o < n.length; o++) e.push(Sc(n[o]));
12861
+ return `findAllNodes was able to match part of the selector:
12862
+ ` + (i.join(" > ") + `
12863
+
12864
+ No matching component was found for:
12865
+ `) + e.join(" > ");
12866
+ }
12867
+ return null;
12868
+ }, le.getPublicRootInstance = function(e) {
12869
+ if (e = e.current, !e.child) return null;
12870
+ switch (e.child.tag) {
12871
+ case 27:
12872
+ case 5:
12873
+ return ot(e.child.stateNode);
12874
+ default:
12875
+ return e.child.stateNode;
12876
+ }
12877
+ }, le.injectIntoDevTools = function() {
12878
+ var e = { bundleType: 1, version: Jt, rendererPackageName: Zt, currentDispatcherRef: x, reconcilerVersion: "19.2.0" };
12879
+ return jo !== null && (e.rendererConfig = jo), e.overrideHookState = gb, e.overrideHookStateDeletePath = yb, e.overrideHookStateRenamePath = bb, e.overrideProps = vb, e.overridePropsDeletePath = Sb, e.overridePropsRenamePath = kb, e.scheduleUpdate = wb, e.scheduleRetry = Pb, e.setErrorHandler = xb, e.setSuspenseHandler = zb, e.scheduleRefresh = hu, e.scheduleRoot = Fl, e.setRefreshHandler = Ir, e.getCurrentFiber = Ic, Ep(e);
12880
+ }, le.isAlreadyRendering = Ns, le.observeVisibleRects = function(e, n, o, i) {
12881
+ function s() {
12882
+ var S = kc(e, n);
12883
+ u.forEach(function(T) {
12884
+ 0 > S.indexOf(T) && g(T);
12885
+ }), S.forEach(function(T) {
12886
+ 0 > u.indexOf(T) && p(T);
12887
+ });
12888
+ }
12889
+ if (!xr) throw Error("Test selector API is not supported by this renderer.");
12890
+ var u = kc(e, n);
12891
+ o = zr(u, o, i);
12892
+ var f = o.disconnect, p = o.observe, g = o.unobserve;
12893
+ return bm.push(s), { disconnect: function() {
12894
+ var S = bm.indexOf(s);
12895
+ 0 <= S && bm.splice(S, 1), f();
12896
+ } };
12897
+ }, le.shouldError = function(e) {
12898
+ return pu(e);
12899
+ }, le.shouldSuspend = function(e) {
12900
+ return fu(e);
12901
+ }, le.startHostTransition = function(e, n, o, i) {
12902
+ if (e.tag !== 5) throw Error("Expected the form instance to be a HostComponent. This is a bug in React.");
12903
+ var s = uf(e).queue;
12904
+ Hp(e), nt(e, s, n, Xt, o === null ? Em : function() {
12905
+ x.T === null && console.error("requestFormReset was called outside a transition or action. To fix, move to an action, or wrap with startTransition.");
12906
+ var u = uf(e);
12907
+ return u.next === null && (u = e.alternate.memoizedState), qi(e, u.next.queue, {}, Nt(e)), o(i);
12908
+ });
12909
+ }, le.updateContainer = function(e, n, o, i) {
12910
+ var s = n.current, u = Nt(s);
12911
+ return As(s, u, e, n, o, i), u;
12912
+ }, le.updateContainerSync = Wh, le;
12913
+ }, Tt.exports.default = Tt.exports, Object.defineProperty(Tt.exports, "__esModule", { value: true }));
12914
+ })(Mg)), Mg.exports;
12915
+ }
12916
+ var Eb;
12917
+ function n0() {
12918
+ return Eb || (Eb = 1, process.env.NODE_ENV === "production" ? Rm.exports = Kb() : Rm.exports = e0()), Rm.exports;
12919
+ }
12920
+ var t0 = n0();
12921
+ const r0 = Xb(t0);
12922
+
12923
+ const DEFAULT_POINTER_ID = 0;
12924
+ const XR_POINTER_ID_START = 1e3;
12925
+ function getPointerState(internal, pointerId) {
12926
+ let state = internal.pointerMap.get(pointerId);
12927
+ if (!state) {
12928
+ state = {
12929
+ hovered: /* @__PURE__ */ new Map(),
12930
+ captured: /* @__PURE__ */ new Map(),
12931
+ initialClick: [0, 0],
12932
+ initialHits: []
12933
+ };
12934
+ internal.pointerMap.set(pointerId, state);
12935
+ }
12936
+ return state;
12937
+ }
12938
+ function getPointerId(event) {
12939
+ return "pointerId" in event ? event.pointerId : DEFAULT_POINTER_ID;
12940
+ }
12941
+ function makeId(event) {
12942
+ return (event.eventObject || event.object).uuid + "/" + event.index + event.instanceId;
12943
+ }
12944
+ function releaseInternalPointerCapture(internal, obj, pointerId) {
12945
+ const pointerState = internal.pointerMap.get(pointerId);
12946
+ if (!pointerState) return;
12947
+ const captureData = pointerState.captured.get(obj);
12948
+ if (captureData) {
12949
+ pointerState.captured.delete(obj);
12950
+ try {
12951
+ captureData.target.releasePointerCapture?.(pointerId);
12952
+ } catch {
12953
+ }
12954
+ }
12955
+ }
12956
+ function swapInteractivity(store, object, newObject) {
12957
+ const { internal } = store.getState();
12958
+ for (let i = 0; i < internal.interaction.length; i++) {
12959
+ if (internal.interaction[i] === object) internal.interaction[i] = newObject;
12960
+ }
12961
+ for (const pointerState of internal.pointerMap.values()) {
12962
+ for (let i = 0; i < pointerState.initialHits.length; i++) {
12963
+ if (pointerState.initialHits[i] === object) pointerState.initialHits[i] = newObject;
12964
+ }
12965
+ pointerState.hovered.forEach((value, key) => {
12966
+ if (value.eventObject === object || value.object === object) {
12967
+ pointerState.hovered.delete(key);
12968
+ const next = {
12969
+ ...value,
12970
+ eventObject: value.eventObject === object ? newObject : value.eventObject,
12971
+ object: value.object === object ? newObject : value.object
12972
+ };
12973
+ pointerState.hovered.set(makeId(next), next);
12974
+ }
12975
+ });
12976
+ const captureData = pointerState.captured.get(object);
12977
+ if (captureData) {
12978
+ pointerState.captured.delete(object);
12979
+ pointerState.captured.set(newObject, {
12980
+ ...captureData,
12981
+ intersection: {
12982
+ ...captureData.intersection,
12983
+ object: captureData.intersection.object === object ? newObject : captureData.intersection.object,
12984
+ eventObject: captureData.intersection.eventObject === object ? newObject : captureData.intersection.eventObject
12985
+ }
12986
+ });
12987
+ }
12988
+ }
12989
+ unregisterVisibility(store, object);
12990
+ }
12991
+ function removeInteractivity(store, object) {
12992
+ const { internal } = store.getState();
12993
+ internal.interaction = internal.interaction.filter((o) => o !== object);
12994
+ for (const [pointerId, pointerState] of internal.pointerMap) {
12995
+ pointerState.initialHits = pointerState.initialHits.filter((o) => o !== object);
12996
+ pointerState.hovered.forEach((value, key) => {
12997
+ if (value.eventObject === object || value.object === object) {
12998
+ pointerState.hovered.delete(key);
12999
+ }
13000
+ });
13001
+ if (pointerState.captured.has(object)) {
13002
+ releaseInternalPointerCapture(internal, object, pointerId);
13003
+ }
13004
+ }
13005
+ unregisterVisibility(store, object);
13006
+ }
13007
+ function createEvents(store) {
13008
+ function calculateDistance(event, pointerId) {
13009
+ const { internal } = store.getState();
13010
+ const pointerState = internal.pointerMap.get(pointerId);
13011
+ if (!pointerState) return 0;
13012
+ const [initialX, initialY] = pointerState.initialClick;
13013
+ const dx = event.offsetX - initialX;
13014
+ const dy = event.offsetY - initialY;
13015
+ return Math.round(Math.sqrt(dx * dx + dy * dy));
13016
+ }
13017
+ function filterPointerEvents(objects) {
13018
+ return objects.filter(
13019
+ (obj) => ["Move", "Over", "Enter", "Out", "Leave"].some(
13020
+ (name) => obj.__r3f?.handlers["onPointer" + name]
13021
+ ) || ["OverEnter", "OverLeave", "Over"].some(
13022
+ (name) => obj.__r3f?.handlers["onDrag" + name]
13023
+ ) || obj.__r3f?.handlers.onDrop
13024
+ );
13025
+ }
13026
+ function intersect(event, filter) {
13027
+ const state = store.getState();
13028
+ const duplicates = /* @__PURE__ */ new Set();
13029
+ const intersections = [];
13030
+ const eventsObjects = filter ? filter(state.internal.interaction) : state.internal.interaction;
13031
+ for (let i = 0; i < eventsObjects.length; i++) {
13032
+ const state2 = getRootState(eventsObjects[i]);
13033
+ if (state2) {
13034
+ state2.raycaster.camera = void 0;
13035
+ }
13036
+ }
13037
+ if (!state.previousRoot) {
13038
+ state.events.compute?.(event, state);
13039
+ }
13040
+ function handleRaycast(obj) {
13041
+ const state2 = getRootState(obj);
13042
+ if (!state2 || !state2.events.enabled || state2.raycaster.camera === null) return [];
13043
+ if (state2.raycaster.camera === void 0) {
13044
+ state2.events.compute?.(event, state2, state2.previousRoot?.getState());
13045
+ if (state2.raycaster.camera === void 0) state2.raycaster.camera = null;
13046
+ }
13047
+ if (!state2.raycaster.camera) return [];
13048
+ obj.updateWorldMatrix(true, true);
13049
+ return state2.raycaster.intersectObject(obj, true);
13050
+ }
13051
+ let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
13052
+ const aInteractivePriority = a.object.userData?.interactivePriority;
13053
+ const bInteractivePriority = b.object.userData?.interactivePriority;
13054
+ if (aInteractivePriority !== void 0 || bInteractivePriority !== void 0) {
13055
+ if (aInteractivePriority !== void 0 && bInteractivePriority === void 0) return -1;
13056
+ if (bInteractivePriority !== void 0 && aInteractivePriority === void 0) return 1;
13057
+ if (aInteractivePriority !== bInteractivePriority) {
13058
+ return (bInteractivePriority ?? 0) - (aInteractivePriority ?? 0);
13059
+ }
13060
+ }
13061
+ const aState = getRootState(a.object);
13062
+ const bState = getRootState(b.object);
13063
+ const aPriority = aState?.events?.priority ?? 1;
13064
+ const bPriority = bState?.events?.priority ?? 1;
13065
+ return bPriority - aPriority || a.distance - b.distance;
13066
+ }).filter((item) => {
13067
+ const id = makeId(item);
13068
+ if (duplicates.has(id)) return false;
13069
+ duplicates.add(id);
13070
+ return true;
13071
+ });
13072
+ if (state.events.filter) hits = state.events.filter(hits, state);
13073
+ for (const hit of hits) {
13074
+ let eventObject = hit.object;
13075
+ while (eventObject) {
13076
+ if (eventObject.__r3f?.eventCount) {
13077
+ intersections.push({ ...hit, eventObject });
13078
+ }
13079
+ eventObject = eventObject.parent;
13080
+ }
13081
+ }
13082
+ if ("pointerId" in event) {
13083
+ const pointerId = event.pointerId;
13084
+ const pointerState = state.internal.pointerMap.get(pointerId);
13085
+ if (pointerState?.captured.size) {
13086
+ for (const captureData of pointerState.captured.values()) {
13087
+ if (!duplicates.has(makeId(captureData.intersection))) intersections.push(captureData.intersection);
13088
+ }
13089
+ }
13090
+ }
13091
+ return intersections;
13092
+ }
13093
+ function handleIntersects(intersections, event, delta, callback) {
13094
+ if (intersections.length) {
13095
+ const localState = { stopped: false };
13096
+ for (const hit of intersections) {
13097
+ const state = getRootState(hit.object);
13098
+ if (state) {
13099
+ const { raycaster, pointer, camera, internal } = state;
13100
+ const unprojectedPoint = new Vector3(pointer.x, pointer.y, 0).unproject(camera);
13101
+ const hasPointerCapture = (id) => {
13102
+ const pointerState = internal.pointerMap.get(id);
13103
+ return pointerState?.captured.has(hit.eventObject) ?? false;
13104
+ };
13105
+ const setPointerCapture = (id) => {
13106
+ const captureData = { intersection: hit, target: event.target };
13107
+ const pointerState = getPointerState(internal, id);
13108
+ pointerState.captured.set(hit.eventObject, captureData);
13109
+ event.target.setPointerCapture(id);
13110
+ };
13111
+ const releasePointerCapture = (id) => {
13112
+ releaseInternalPointerCapture(internal, hit.eventObject, id);
13113
+ };
13114
+ const extractEventProps = {};
13115
+ for (const prop in event) {
13116
+ const property = event[prop];
13117
+ if (typeof property !== "function") extractEventProps[prop] = property;
13118
+ }
13119
+ const eventPointerId = "pointerId" in event ? event.pointerId : void 0;
13120
+ const raycastEvent = {
13121
+ ...hit,
13122
+ ...extractEventProps,
13123
+ pointer,
13124
+ intersections,
13125
+ stopped: localState.stopped,
13126
+ delta,
13127
+ unprojectedPoint,
13128
+ ray: raycaster.ray,
13129
+ camera,
13130
+ pointerId: eventPointerId,
13131
+ // Hijack stopPropagation, which just sets a flag
13132
+ stopPropagation() {
13133
+ const pointerState = eventPointerId !== void 0 ? internal.pointerMap.get(eventPointerId) : void 0;
13134
+ if (
13135
+ // ...if this pointer hasn't been captured
13136
+ !pointerState?.captured.size || // ... or if the hit object is capturing the pointer
13137
+ pointerState.captured.has(hit.eventObject)
13138
+ ) {
13139
+ raycastEvent.stopped = localState.stopped = true;
13140
+ if (pointerState?.hovered.size && Array.from(pointerState.hovered.values()).find((i) => i.eventObject === hit.eventObject)) {
13141
+ const higher = intersections.slice(0, intersections.indexOf(hit));
13142
+ cancelPointer([...higher, hit], eventPointerId);
13143
+ }
13463
13144
  }
13464
- }
13465
- break;
13466
- case 31:
13467
- case 13:
13468
- n = On(e, 2), n !== null && We(n, e, 2), Ls(), rl(e, 2);
13145
+ },
13146
+ // there should be a distinction between target and currentTarget
13147
+ target: { hasPointerCapture, setPointerCapture, releasePointerCapture },
13148
+ currentTarget: { hasPointerCapture, setPointerCapture, releasePointerCapture },
13149
+ nativeEvent: event
13150
+ };
13151
+ callback(raycastEvent);
13152
+ if (localState.stopped === true) break;
13469
13153
  }
13470
- }, le.batchedUpdates = function(e, n) {
13471
- return e(n);
13472
- }, le.createComponentSelector = function(e) {
13473
- return { $$typeof: pm, value: e };
13474
- }, le.createContainer = function(e, n, o, i, s, u, f, p, g, S) {
13475
- return Ka(e, n, false, null, o, i, u, null, f, p, g, S);
13476
- }, le.createHasPseudoClassSelector = function(e) {
13477
- return { $$typeof: hm, value: e };
13478
- }, le.createHydrationContainer = function(e, n, o, i, s, u, f, p, g, S, T, _, I, O) {
13479
- return e = Ka(o, i, true, e, s, u, p, O, g, S, T, _), e.context = Dh(null), o = e.current, i = Nt(o), i = Xo(i), s = zo(i), s.callback = n ?? null, Mt(o, s, i), ur(i, "hydrateRoot()", null), n = i, e.current.lanes = n, Ci(e, n), Kn(e), e;
13480
- }, le.createPortal = function(e, n, o) {
13481
- var i = 3 < arguments.length && arguments[3] !== void 0 ? arguments[3] : null;
13482
- try {
13483
- vt(i);
13484
- var s = false;
13485
- } catch {
13486
- s = true;
13154
+ }
13155
+ }
13156
+ return intersections;
13157
+ }
13158
+ function cancelPointer(intersections, pointerId) {
13159
+ const { internal } = store.getState();
13160
+ const pid = pointerId ?? DEFAULT_POINTER_ID;
13161
+ const pointerState = internal.pointerMap.get(pid);
13162
+ if (!pointerState) return;
13163
+ for (const [hoveredId, hoveredObj] of pointerState.hovered) {
13164
+ if (!intersections.length || !intersections.find(
13165
+ (hit) => hit.object === hoveredObj.object && hit.index === hoveredObj.index && hit.instanceId === hoveredObj.instanceId
13166
+ )) {
13167
+ const eventObject = hoveredObj.eventObject;
13168
+ const instance = eventObject.__r3f;
13169
+ pointerState.hovered.delete(hoveredId);
13170
+ if (instance?.eventCount) {
13171
+ const handlers = instance.handlers;
13172
+ const data = { ...hoveredObj, intersections };
13173
+ handlers.onPointerOut?.(data);
13174
+ handlers.onPointerLeave?.(data);
13175
+ handlers.onDragOverLeave?.(data);
13487
13176
  }
13488
- return s && (console.error("The provided key is an unsupported type %s. This value must be coerced to a string before using it here.", typeof Symbol == "function" && Symbol.toStringTag && i[Symbol.toStringTag] || i.constructor.name || "Object"), vt(i)), { $$typeof: Ao, key: i == null ? null : "" + i, children: e, containerInfo: n, implementation: o };
13489
- }, le.createRoleSelector = function(e) {
13490
- return { $$typeof: mm, value: e };
13491
- }, le.createTestNameSelector = function(e) {
13492
- return { $$typeof: gm, value: e };
13493
- }, le.createTextSelector = function(e) {
13494
- return { $$typeof: ym, value: e };
13495
- }, le.defaultOnCaughtError = function(e) {
13496
- var n = bd ? "The above error occurred in the <" + bd + "> component." : "The above error occurred in one of your React components.", o = "React will try to recreate this component tree from scratch using the error boundary you provided, " + ((Cg || "Anonymous") + ".");
13497
- typeof e == "object" && e !== null && typeof e.environmentName == "string" ? ri("error", [`%o
13498
-
13499
- %s
13500
-
13501
- %s
13502
- `, e, n, o], e.environmentName)() : console.error(`%o
13503
-
13504
- %s
13505
-
13506
- %s
13507
- `, e, n, o);
13508
- }, le.defaultOnRecoverableError = function(e) {
13509
- qg(e);
13510
- }, le.defaultOnUncaughtError = function(e) {
13511
- qg(e), console.warn(`%s
13512
-
13513
- %s
13514
- `, bd ? "An error occurred in the <" + bd + "> component." : "An error occurred in one of your React components.", `Consider adding an error boundary to your tree to customize error handling behavior.
13515
- Visit https://react.dev/link/error-boundaries to learn more about error boundaries.`);
13516
- }, le.deferredUpdates = function(e) {
13517
- var n = x.T, o = wt();
13518
- try {
13519
- return an(32), x.T = null, e();
13520
- } finally {
13521
- an(o), x.T = n;
13177
+ }
13178
+ }
13179
+ }
13180
+ function pointerMissed(event, objects) {
13181
+ for (let i = 0; i < objects.length; i++) {
13182
+ const instance = objects[i].__r3f;
13183
+ instance?.handlers.onPointerMissed?.(event);
13184
+ }
13185
+ }
13186
+ function dragOverMissed(event, objects) {
13187
+ for (let i = 0; i < objects.length; i++) {
13188
+ const instance = objects[i].__r3f;
13189
+ instance?.handlers.onDragOverMissed?.(event);
13190
+ }
13191
+ }
13192
+ function dropMissed(event, objects) {
13193
+ for (let i = 0; i < objects.length; i++) {
13194
+ const instance = objects[i].__r3f;
13195
+ instance?.handlers.onDropMissed?.(event);
13196
+ }
13197
+ }
13198
+ function cleanupPointer(pointerId) {
13199
+ const { internal } = store.getState();
13200
+ const pointerState = internal.pointerMap.get(pointerId);
13201
+ if (pointerState) {
13202
+ for (const [, hoveredObj] of pointerState.hovered) {
13203
+ const eventObject = hoveredObj.eventObject;
13204
+ const instance = eventObject.__r3f;
13205
+ if (instance?.eventCount) {
13206
+ const handlers = instance.handlers;
13207
+ const data = { ...hoveredObj, intersections: [] };
13208
+ handlers.onPointerOut?.(data);
13209
+ handlers.onPointerLeave?.(data);
13522
13210
  }
13523
- }, le.discreteUpdates = function(e, n, o, i, s) {
13524
- var u = x.T, f = wt();
13525
- try {
13526
- return an(2), x.T = null, e(n, o, i, s);
13527
- } finally {
13528
- an(f), x.T = u, ye === Jn && (Pp = me() + Fg);
13211
+ }
13212
+ internal.pointerMap.delete(pointerId);
13213
+ }
13214
+ internal.pointerDirty.delete(pointerId);
13215
+ }
13216
+ function processDeferredPointer(event, pointerId) {
13217
+ const state = store.getState();
13218
+ const { internal } = state;
13219
+ if (!state.events.enabled) return;
13220
+ const filter = filterPointerEvents;
13221
+ const hits = intersect(event, filter);
13222
+ cancelPointer(hits, pointerId);
13223
+ function onIntersect(data) {
13224
+ const eventObject = data.eventObject;
13225
+ const instance = eventObject.__r3f;
13226
+ if (!instance?.eventCount) return;
13227
+ const handlers = instance.handlers;
13228
+ if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
13229
+ const id = makeId(data);
13230
+ const pointerState = getPointerState(internal, pointerId);
13231
+ const hoveredItem = pointerState.hovered.get(id);
13232
+ if (!hoveredItem) {
13233
+ pointerState.hovered.set(id, data);
13234
+ handlers.onPointerOver?.(data);
13235
+ handlers.onPointerEnter?.(data);
13236
+ } else if (hoveredItem.stopped) {
13237
+ data.stopPropagation();
13529
13238
  }
13530
- }, le.findAllNodes = kc, le.findBoundingRects = function(e, n) {
13531
- if (!xr) throw Error("Test selector API is not supported by this renderer.");
13532
- n = kc(e, n), e = [];
13533
- for (var o = 0; o < n.length; o++) e.push(ma(n[o]));
13534
- for (n = e.length - 1; 0 < n; n--) {
13535
- o = e[n];
13536
- for (var i = o.x, s = i + o.width, u = o.y, f = u + o.height, p = n - 1; 0 <= p; p--) if (n !== p) {
13537
- var g = e[p], S = g.x, T = S + g.width, _ = g.y, I = _ + g.height;
13538
- if (i >= S && u >= _ && s <= T && f <= I) {
13539
- e.splice(n, 1);
13540
- break;
13541
- } else if (i !== S || o.width !== g.width || I < u || _ > f) {
13542
- if (!(u !== _ || o.height !== g.height || T < i || S > s)) {
13543
- S > i && (g.width += S - i, g.x = i), T < s && (g.width = s - S), e.splice(n, 1);
13544
- break;
13239
+ }
13240
+ handlers.onPointerMove?.(data);
13241
+ }
13242
+ handleIntersects(hits, event, 0, onIntersect);
13243
+ }
13244
+ function handlePointer(name) {
13245
+ switch (name) {
13246
+ case "onPointerLeave":
13247
+ case "onDragLeave":
13248
+ return () => cancelPointer([]);
13249
+ // Global cancel of these events
13250
+ case "onPointerCancel":
13251
+ return (event) => {
13252
+ const pointerId = getPointerId(event);
13253
+ cleanupPointer(pointerId);
13254
+ };
13255
+ case "onLostPointerCapture":
13256
+ return (event) => {
13257
+ const { internal } = store.getState();
13258
+ const pointerId = getPointerId(event);
13259
+ const pointerState = internal.pointerMap.get(pointerId);
13260
+ if (pointerState?.captured.size) {
13261
+ requestAnimationFrame(() => {
13262
+ const pointerState2 = internal.pointerMap.get(pointerId);
13263
+ if (pointerState2?.captured.size) {
13264
+ pointerState2.captured.clear();
13545
13265
  }
13546
- } else {
13547
- _ > u && (g.height += _ - u, g.y = u), I < f && (g.height = f - _), e.splice(n, 1);
13548
- break;
13266
+ cancelPointer([], pointerId);
13267
+ });
13268
+ }
13269
+ };
13270
+ }
13271
+ return function handleEvent(event) {
13272
+ const state = store.getState();
13273
+ const { onPointerMissed, onDragOverMissed, onDropMissed, internal, events } = state;
13274
+ const pointerId = getPointerId(event);
13275
+ internal.lastEvent.current = event;
13276
+ if (!events.enabled) return;
13277
+ const isPointerMove = name === "onPointerMove";
13278
+ const isDragOver = name === "onDragOver";
13279
+ const isDrop = name === "onDrop";
13280
+ const isClickEvent = name === "onClick" || name === "onContextMenu" || name === "onDoubleClick";
13281
+ const isPointerDown = name === "onPointerDown";
13282
+ const isPointerUp = name === "onPointerUp";
13283
+ const isWheel = name === "onWheel";
13284
+ const canDeferRaycasts = events.frameTimedRaycasts && state.frameloop === "always";
13285
+ if (isPointerMove && canDeferRaycasts) {
13286
+ events.compute?.(event, state);
13287
+ internal.pointerDirty.set(pointerId, event);
13288
+ return;
13289
+ }
13290
+ if (isWheel && canDeferRaycasts && !events.alwaysFireOnScroll) {
13291
+ events.compute?.(event, state);
13292
+ internal.pointerDirty.set(pointerId, event);
13293
+ return;
13294
+ }
13295
+ if ((isClickEvent || isPointerDown || isPointerUp) && internal.pointerDirty.has(pointerId)) {
13296
+ const deferredEvent = internal.pointerDirty.get(pointerId);
13297
+ internal.pointerDirty.delete(pointerId);
13298
+ processDeferredPointer(deferredEvent, pointerId);
13299
+ }
13300
+ const filter = isPointerMove || isDragOver || isDrop ? filterPointerEvents : void 0;
13301
+ const hits = intersect(event, filter);
13302
+ const delta = isClickEvent ? calculateDistance(event, pointerId) : 0;
13303
+ if (isPointerDown) {
13304
+ const pointerState2 = getPointerState(internal, pointerId);
13305
+ pointerState2.initialClick = [event.offsetX, event.offsetY];
13306
+ pointerState2.initialHits = hits.map((hit) => hit.eventObject);
13307
+ }
13308
+ const pointerState = internal.pointerMap.get(pointerId);
13309
+ const initialHits = pointerState?.initialHits ?? [];
13310
+ if (isClickEvent && !hits.length) {
13311
+ if (delta <= 2) {
13312
+ pointerMissed(event, internal.interaction);
13313
+ if (onPointerMissed) onPointerMissed(event);
13314
+ }
13315
+ }
13316
+ if (isDragOver && !hits.length) {
13317
+ dragOverMissed(event, internal.interaction);
13318
+ if (onDragOverMissed) onDragOverMissed(event);
13319
+ }
13320
+ if (isDrop && !hits.length) {
13321
+ dropMissed(event, internal.interaction);
13322
+ if (onDropMissed) onDropMissed(event);
13323
+ }
13324
+ if (isPointerMove || isDragOver) {
13325
+ cancelPointer(hits, pointerId);
13326
+ }
13327
+ function onIntersect(data) {
13328
+ const eventObject = data.eventObject;
13329
+ const instance = eventObject.__r3f;
13330
+ if (!instance?.eventCount) return;
13331
+ const handlers = instance.handlers;
13332
+ if (isPointerMove) {
13333
+ if (handlers.onPointerOver || handlers.onPointerEnter || handlers.onPointerOut || handlers.onPointerLeave) {
13334
+ const id = makeId(data);
13335
+ const pointerState2 = getPointerState(internal, pointerId);
13336
+ const hoveredItem = pointerState2.hovered.get(id);
13337
+ if (!hoveredItem) {
13338
+ pointerState2.hovered.set(id, data);
13339
+ handlers.onPointerOver?.(data);
13340
+ handlers.onPointerEnter?.(data);
13341
+ } else if (hoveredItem.stopped) {
13342
+ data.stopPropagation();
13549
13343
  }
13550
13344
  }
13551
- }
13552
- return e;
13553
- }, le.findHostInstance = function(e) {
13554
- var n = e._reactInternals;
13555
- if (n === void 0) throw typeof e.render == "function" ? Error("Unable to find node on an unmounted component.") : (e = Object.keys(e).join(","), Error("Argument appears to not be a ReactComponent. Keys: " + e));
13556
- return e = mu(n), e === null ? null : ot(e.stateNode);
13557
- }, le.findHostInstanceWithNoPortals = function(e) {
13558
- return e = Ed(e), e = e !== null ? _p(e) : null, e === null ? null : ot(e.stateNode);
13559
- }, le.findHostInstanceWithWarning = function(e, n) {
13560
- var o = e._reactInternals;
13561
- if (o === void 0) throw typeof e.render == "function" ? Error("Unable to find node on an unmounted component.") : (e = Object.keys(e).join(","), Error("Argument appears to not be a ReactComponent. Keys: " + e));
13562
- if (e = mu(o), e === null) return null;
13563
- if (e.mode & 8) {
13564
- var i = G(o) || "Component";
13565
- mb[i] || (mb[i] = true, B(e, function() {
13566
- o.mode & 8 ? console.error("%s is deprecated in StrictMode. %s was passed an instance of %s which is inside StrictMode. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://react.dev/link/strict-mode-find-node", n, n, i) : console.error("%s is deprecated in StrictMode. %s was passed an instance of %s which renders StrictMode children. Instead, add a ref directly to the element you want to reference. Learn more about using refs safely here: https://react.dev/link/strict-mode-find-node", n, n, i);
13567
- }));
13568
- }
13569
- return ot(e.stateNode);
13570
- }, le.flushPassiveEffects = el, le.flushSyncFromReconciler = function(e) {
13571
- var n = ye;
13572
- ye |= 1;
13573
- var o = x.T, i = wt();
13574
- try {
13575
- if (an(2), x.T = null, e) return e();
13576
- } finally {
13577
- an(i), x.T = o, ye = n, (ye & (Zn | uo)) === Jn && Wa(0);
13578
- }
13579
- }, le.flushSyncWork = Ls, le.focusWithin = function(e, n) {
13580
- if (!xr) throw Error("Test selector API is not supported by this renderer.");
13581
- for (e = Ef(e), n = hh(e, n), n = Array.from(n), e = 0; e < n.length; ) {
13582
- var o = n[e++], i = o.tag;
13583
- if (!Kr(o)) {
13584
- if ((i === 5 || i === 26 || i === 27) && Ft(o.stateNode)) return true;
13585
- for (o = o.child; o !== null; ) n.push(o), o = o.sibling;
13345
+ handlers.onPointerMove?.(data);
13346
+ } else if (isDragOver) {
13347
+ const id = makeId(data);
13348
+ const pointerState2 = getPointerState(internal, pointerId);
13349
+ const hoveredItem = pointerState2.hovered.get(id);
13350
+ if (!hoveredItem) {
13351
+ pointerState2.hovered.set(id, data);
13352
+ handlers.onDragOverEnter?.(data);
13353
+ } else if (hoveredItem.stopped) {
13354
+ data.stopPropagation();
13355
+ }
13356
+ handlers.onDragOver?.(data);
13357
+ } else if (isDrop) {
13358
+ handlers.onDrop?.(data);
13359
+ } else {
13360
+ const handler = handlers[name];
13361
+ if (handler) {
13362
+ if (!isClickEvent || initialHits.includes(eventObject)) {
13363
+ pointerMissed(
13364
+ event,
13365
+ internal.interaction.filter((object) => !initialHits.includes(object))
13366
+ );
13367
+ handler(data);
13368
+ }
13369
+ } else {
13370
+ if (isClickEvent && initialHits.includes(eventObject)) {
13371
+ pointerMissed(
13372
+ event,
13373
+ internal.interaction.filter((object) => !initialHits.includes(object))
13374
+ );
13375
+ }
13586
13376
  }
13587
13377
  }
13588
- return false;
13589
- }, le.getFindAllNodesFailureDescription = function(e, n) {
13590
- if (!xr) throw Error("Test selector API is not supported by this renderer.");
13591
- var o = 0, i = [];
13592
- e = [Ef(e), 0];
13593
- for (var s = 0; s < e.length; ) {
13594
- var u = e[s++], f = u.tag, p = e[s++], g = n[p];
13595
- if ((f !== 5 && f !== 26 && f !== 27 || !Kr(u)) && (If(u, g) && (i.push(Sc(g)), p++, p > o && (o = p)), p < n.length)) for (u = u.child; u !== null; ) e.push(u, p), u = u.sibling;
13378
+ }
13379
+ handleIntersects(hits, event, delta, onIntersect);
13380
+ };
13381
+ }
13382
+ function flushDeferredPointers() {
13383
+ const { internal, events } = store.getState();
13384
+ if (!events.frameTimedRaycasts) return;
13385
+ for (const [pointerId, event] of internal.pointerDirty) {
13386
+ processDeferredPointer(event, pointerId);
13387
+ }
13388
+ internal.pointerDirty.clear();
13389
+ }
13390
+ return { handlePointer, flushDeferredPointers, processDeferredPointer };
13391
+ }
13392
+ const DOM_EVENTS = {
13393
+ onClick: ["click", false],
13394
+ onContextMenu: ["contextmenu", false],
13395
+ onDoubleClick: ["dblclick", false],
13396
+ onDragEnter: ["dragenter", false],
13397
+ onDragLeave: ["dragleave", false],
13398
+ onDragOver: ["dragover", false],
13399
+ onDrop: ["drop", false],
13400
+ onWheel: ["wheel", true],
13401
+ onPointerDown: ["pointerdown", true],
13402
+ onPointerUp: ["pointerup", true],
13403
+ onPointerLeave: ["pointerleave", true],
13404
+ onPointerMove: ["pointermove", true],
13405
+ onPointerCancel: ["pointercancel", true],
13406
+ onLostPointerCapture: ["lostpointercapture", true]
13407
+ };
13408
+ function createPointerEvents(store) {
13409
+ const { handlePointer, flushDeferredPointers, processDeferredPointer } = createEvents(store);
13410
+ let nextXRPointerId = XR_POINTER_ID_START;
13411
+ const xrPointers = /* @__PURE__ */ new Map();
13412
+ return {
13413
+ priority: 1,
13414
+ enabled: true,
13415
+ frameTimedRaycasts: true,
13416
+ alwaysFireOnScroll: true,
13417
+ updateOnFrame: false,
13418
+ compute(event, state) {
13419
+ state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
13420
+ state.raycaster.setFromCamera(state.pointer, state.camera);
13421
+ },
13422
+ connected: void 0,
13423
+ handlers: Object.keys(DOM_EVENTS).reduce(
13424
+ (acc, key) => ({ ...acc, [key]: handlePointer(key) }),
13425
+ {}
13426
+ ),
13427
+ update: (pointerId) => {
13428
+ const { events, internal } = store.getState();
13429
+ if (!events.handlers) return;
13430
+ if (pointerId !== void 0) {
13431
+ const event = internal.pointerDirty.get(pointerId);
13432
+ if (event) {
13433
+ internal.pointerDirty.delete(pointerId);
13434
+ processDeferredPointer(event, pointerId);
13435
+ } else if (internal.lastEvent?.current) {
13436
+ processDeferredPointer(internal.lastEvent.current, pointerId);
13596
13437
  }
13597
- if (o < n.length) {
13598
- for (e = []; o < n.length; o++) e.push(Sc(n[o]));
13599
- return `findAllNodes was able to match part of the selector:
13600
- ` + (i.join(" > ") + `
13601
-
13602
- No matching component was found for:
13603
- `) + e.join(" > ");
13438
+ } else {
13439
+ flushDeferredPointers();
13440
+ if (internal.lastEvent?.current) {
13441
+ events.handlers.onPointerMove(internal.lastEvent.current);
13604
13442
  }
13605
- return null;
13606
- }, le.getPublicRootInstance = function(e) {
13607
- if (e = e.current, !e.child) return null;
13608
- switch (e.child.tag) {
13609
- case 27:
13610
- case 5:
13611
- return ot(e.child.stateNode);
13612
- default:
13613
- return e.child.stateNode;
13443
+ }
13444
+ },
13445
+ flush: () => {
13446
+ const { events, internal } = store.getState();
13447
+ flushDeferredPointers();
13448
+ if (events.updateOnFrame && internal.lastEvent?.current && events.handlers) {
13449
+ events.handlers.onPointerMove(internal.lastEvent.current);
13450
+ }
13451
+ },
13452
+ connect: (target) => {
13453
+ if (!target) return;
13454
+ const { set, events } = store.getState();
13455
+ events.disconnect?.();
13456
+ set((state) => ({ events: { ...state.events, connected: target } }));
13457
+ if (events.handlers) {
13458
+ for (const name in events.handlers) {
13459
+ const event = events.handlers[name];
13460
+ const [eventName, passive] = DOM_EVENTS[name];
13461
+ target.addEventListener(eventName, event, { passive });
13614
13462
  }
13615
- }, le.injectIntoDevTools = function() {
13616
- var e = { bundleType: 1, version: Jt, rendererPackageName: Zt, currentDispatcherRef: x, reconcilerVersion: "19.2.0" };
13617
- return jo !== null && (e.rendererConfig = jo), e.overrideHookState = gb, e.overrideHookStateDeletePath = yb, e.overrideHookStateRenamePath = bb, e.overrideProps = vb, e.overridePropsDeletePath = Sb, e.overridePropsRenamePath = kb, e.scheduleUpdate = wb, e.scheduleRetry = Pb, e.setErrorHandler = xb, e.setSuspenseHandler = zb, e.scheduleRefresh = hu, e.scheduleRoot = Fl, e.setRefreshHandler = Ir, e.getCurrentFiber = Ic, Ep(e);
13618
- }, le.isAlreadyRendering = Ns, le.observeVisibleRects = function(e, n, o, i) {
13619
- function s() {
13620
- var S = kc(e, n);
13621
- u.forEach(function(T) {
13622
- 0 > S.indexOf(T) && g(T);
13623
- }), S.forEach(function(T) {
13624
- 0 > u.indexOf(T) && p(T);
13625
- });
13463
+ }
13464
+ },
13465
+ disconnect: () => {
13466
+ const { set, events } = store.getState();
13467
+ if (events.connected) {
13468
+ if (events.handlers) {
13469
+ for (const name in events.handlers) {
13470
+ const event = events.handlers[name];
13471
+ const [eventName] = DOM_EVENTS[name];
13472
+ events.connected.removeEventListener(eventName, event);
13473
+ }
13474
+ }
13475
+ set((state) => ({ events: { ...state.events, connected: void 0 } }));
13476
+ }
13477
+ },
13478
+ // PREVIEW (A8): the XR pointer registration API may change before stable.
13479
+ registerPointer: (config) => {
13480
+ const pointerId = nextXRPointerId++;
13481
+ xrPointers.set(pointerId, config);
13482
+ const { internal } = store.getState();
13483
+ getPointerState(internal, pointerId);
13484
+ return pointerId;
13485
+ },
13486
+ unregisterPointer: (pointerId) => {
13487
+ xrPointers.delete(pointerId);
13488
+ const { internal } = store.getState();
13489
+ const pointerState = internal.pointerMap.get(pointerId);
13490
+ if (pointerState) {
13491
+ for (const [, hoveredObj] of pointerState.hovered) {
13492
+ const eventObject = hoveredObj.eventObject;
13493
+ const instance = eventObject.__r3f;
13494
+ if (instance?.eventCount) {
13495
+ const handlers = instance.handlers;
13496
+ const data = { ...hoveredObj, intersections: [] };
13497
+ handlers.onPointerOut?.(data);
13498
+ handlers.onPointerLeave?.(data);
13499
+ }
13626
13500
  }
13627
- if (!xr) throw Error("Test selector API is not supported by this renderer.");
13628
- var u = kc(e, n);
13629
- o = zr(u, o, i);
13630
- var f = o.disconnect, p = o.observe, g = o.unobserve;
13631
- return bm.push(s), { disconnect: function() {
13632
- var S = bm.indexOf(s);
13633
- 0 <= S && bm.splice(S, 1), f();
13634
- } };
13635
- }, le.shouldError = function(e) {
13636
- return pu(e);
13637
- }, le.shouldSuspend = function(e) {
13638
- return fu(e);
13639
- }, le.startHostTransition = function(e, n, o, i) {
13640
- if (e.tag !== 5) throw Error("Expected the form instance to be a HostComponent. This is a bug in React.");
13641
- var s = uf(e).queue;
13642
- Hp(e), nt(e, s, n, Xt, o === null ? Em : function() {
13643
- x.T === null && console.error("requestFormReset was called outside a transition or action. To fix, move to an action, or wrap with startTransition.");
13644
- var u = uf(e);
13645
- return u.next === null && (u = e.alternate.memoizedState), qi(e, u.next.queue, {}, Nt(e)), o(i);
13646
- });
13647
- }, le.updateContainer = function(e, n, o, i) {
13648
- var s = n.current, u = Nt(s);
13649
- return As(s, u, e, n, o, i), u;
13650
- }, le.updateContainerSync = Wh, le;
13651
- }, Tt.exports.default = Tt.exports, Object.defineProperty(Tt.exports, "__esModule", { value: true }));
13652
- })(Mg)), Mg.exports;
13653
- }
13654
- var Eb;
13655
- function n0() {
13656
- return Eb || (Eb = 1, process.env.NODE_ENV === "production" ? Rm.exports = Kb() : Rm.exports = e0()), Rm.exports;
13501
+ internal.pointerMap.delete(pointerId);
13502
+ }
13503
+ internal.pointerDirty.delete(pointerId);
13504
+ }
13505
+ };
13657
13506
  }
13658
- var t0 = n0();
13659
- const r0 = Xb(t0);
13660
-
13661
- const t = 1, o = 8, r = 32, e = 2;
13662
13507
 
13663
13508
  function createReconciler(config) {
13664
13509
  const reconciler2 = r0(config);
@@ -13823,7 +13668,15 @@ function setFiberRef(fiber, publicInstance) {
13823
13668
  }
13824
13669
  }
13825
13670
  const reconstructed = [];
13826
- function swapInstances() {
13671
+ function flushReconstructedInstances() {
13672
+ if (reconstructed.length === 0) return;
13673
+ try {
13674
+ swapReconstructedInstances();
13675
+ } finally {
13676
+ reconstructed.length = 0;
13677
+ }
13678
+ }
13679
+ function swapReconstructedInstances() {
13827
13680
  for (const [instance] of reconstructed) {
13828
13681
  const parent = instance.parent;
13829
13682
  if (parent) {
@@ -13841,7 +13694,9 @@ function swapInstances() {
13841
13694
  }
13842
13695
  }
13843
13696
  if (instance.isHidden) unhideInstance(instance);
13844
- if (isObject3D(instance.object)) removeInteractivity(findInitialRoot(instance), instance.object);
13697
+ if (isObject3D(instance.object) && !instance.parent) {
13698
+ removeInteractivity(findInitialRoot(instance), instance.object);
13699
+ }
13845
13700
  if (instance.object.__r3f) delete instance.object.__r3f;
13846
13701
  if (instance.type !== "primitive") disposeOnIdle(instance.object);
13847
13702
  }
@@ -13850,9 +13705,13 @@ function swapInstances() {
13850
13705
  const parent = instance.parent;
13851
13706
  if (parent) {
13852
13707
  const target = catalogue[toPascalCase(instance.type)];
13708
+ const prevObject = instance.object;
13853
13709
  instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
13854
13710
  instance.object.__r3f = instance;
13855
13711
  setFiberRef(fiber, instance.object);
13712
+ if (isObject3D(prevObject) && isObject3D(instance.object)) {
13713
+ swapInteractivity(findInitialRoot(instance), prevObject, instance.object);
13714
+ }
13856
13715
  delete instance.appliedOnce;
13857
13716
  instance.eventCount = 0;
13858
13717
  instance.handlers = {};
@@ -13872,14 +13731,114 @@ function swapInstances() {
13872
13731
  invalidateInstance(instance);
13873
13732
  }
13874
13733
  }
13875
- reconstructed.length = 0;
13876
13734
  }
13877
13735
  const handleTextInstance = () => {
13878
13736
  };
13879
13737
  const NO_CONTEXT = {};
13880
13738
  let currentUpdatePriority = NoEventPriority;
13881
- const NoFlags = 0;
13882
- const Update = 4;
13739
+ function getEventPriority(type) {
13740
+ switch (type) {
13741
+ case "beforetoggle":
13742
+ case "cancel":
13743
+ case "click":
13744
+ case "close":
13745
+ case "contextmenu":
13746
+ case "copy":
13747
+ case "cut":
13748
+ case "auxclick":
13749
+ case "dblclick":
13750
+ case "dragend":
13751
+ case "dragstart":
13752
+ case "drop":
13753
+ case "focusin":
13754
+ case "focusout":
13755
+ case "input":
13756
+ case "invalid":
13757
+ case "keydown":
13758
+ case "keypress":
13759
+ case "keyup":
13760
+ case "mousedown":
13761
+ case "mouseup":
13762
+ case "paste":
13763
+ case "pause":
13764
+ case "play":
13765
+ case "pointercancel":
13766
+ case "pointerdown":
13767
+ case "pointerup":
13768
+ case "ratechange":
13769
+ case "reset":
13770
+ case "resize":
13771
+ case "seeked":
13772
+ case "submit":
13773
+ case "touchcancel":
13774
+ case "touchend":
13775
+ case "touchstart":
13776
+ case "volumechange":
13777
+ case "change":
13778
+ case "selectionchange":
13779
+ case "compositionstart":
13780
+ case "compositionend":
13781
+ case "compositionupdate":
13782
+ case "beforeinput":
13783
+ case "blur":
13784
+ case "fullscreenchange":
13785
+ case "focus":
13786
+ case "hashchange":
13787
+ case "popstate":
13788
+ case "select":
13789
+ case "selectstart":
13790
+ return e;
13791
+ case "drag":
13792
+ case "dragenter":
13793
+ case "dragexit":
13794
+ case "dragleave":
13795
+ case "dragover":
13796
+ case "mousemove":
13797
+ case "mouseout":
13798
+ case "mouseover":
13799
+ case "pointermove":
13800
+ case "pointerout":
13801
+ case "pointerover":
13802
+ case "scroll":
13803
+ case "touchmove":
13804
+ case "wheel":
13805
+ case "mouseenter":
13806
+ case "mouseleave":
13807
+ case "pointerenter":
13808
+ case "pointerleave":
13809
+ return o;
13810
+ case "message": {
13811
+ switch (unstable_getCurrentPriorityLevel()) {
13812
+ case unstable_ImmediatePriority:
13813
+ return e;
13814
+ case unstable_UserBlockingPriority:
13815
+ return o;
13816
+ case unstable_NormalPriority:
13817
+ case unstable_LowPriority:
13818
+ return r;
13819
+ case unstable_IdlePriority:
13820
+ return i$1;
13821
+ default:
13822
+ return r;
13823
+ }
13824
+ }
13825
+ default:
13826
+ return r;
13827
+ }
13828
+ }
13829
+ function scheduleMicrotask(callback) {
13830
+ if (typeof queueMicrotask === "function") {
13831
+ queueMicrotask(callback);
13832
+ } else if (typeof Promise !== "undefined") {
13833
+ Promise.resolve().then(callback).catch((error) => {
13834
+ setTimeout(() => {
13835
+ throw error;
13836
+ });
13837
+ });
13838
+ } else {
13839
+ setTimeout(callback);
13840
+ }
13841
+ }
13883
13842
  const reconciler = /* @__PURE__ */ createReconciler({
13884
13843
  isPrimaryRenderer: false,
13885
13844
  warnsIfNotActing: false,
@@ -13918,16 +13877,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
13918
13877
  else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
13919
13878
  else if (newProps.args?.some((value, index) => value !== oldProps.args?.[index])) reconstruct = true;
13920
13879
  if (reconstruct) {
13921
- reconstructed.push([instance, { ...newProps }, fiber]);
13880
+ reconstructed.push([instance, getInstanceProps(newProps), fiber]);
13922
13881
  } else {
13923
13882
  const changedProps = diffProps(instance, newProps);
13924
- if (Object.keys(changedProps).length) {
13925
- Object.assign(instance.props, changedProps);
13926
- applyProps(instance.object, changedProps);
13927
- }
13883
+ const attach2 = instance.props.attach;
13884
+ instance.props = getInstanceProps(newProps);
13885
+ if (attach2 !== void 0) instance.props.attach = attach2;
13886
+ else delete instance.props.attach;
13887
+ if (Object.keys(changedProps).length) applyProps(instance.object, changedProps);
13928
13888
  }
13929
- const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
13930
- if (isTailSibling) swapInstances();
13931
13889
  },
13932
13890
  finalizeInitialChildren: (instance) => {
13933
13891
  for (const prop in instance.props) {
@@ -13952,8 +13910,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13952
13910
  const target = container.getState().internal.container ?? container.getState().scene;
13953
13911
  return prepare(target, container, "", {});
13954
13912
  },
13955
- resetAfterCommit: () => {
13956
- },
13913
+ // Reconstructed instances are swapped once all mutations are committed,
13914
+ // before layout effects run so refs point to the new objects
13915
+ resetAfterCommit: flushReconstructedInstances,
13957
13916
  shouldSetTextContent: () => false,
13958
13917
  clearContainer: () => false,
13959
13918
  hideInstance,
@@ -13961,6 +13920,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
13961
13920
  createTextInstance: handleTextInstance,
13962
13921
  hideTextInstance: handleTextInstance,
13963
13922
  unhideTextInstance: handleTextInstance,
13923
+ // Mirrors react-dom, which flushes discrete work in microtasks
13924
+ supportsMicrotasks: true,
13925
+ scheduleMicrotask,
13964
13926
  scheduleTimeout: typeof setTimeout === "function" ? setTimeout : void 0,
13965
13927
  cancelTimeout: typeof clearTimeout === "function" ? clearTimeout : void 0,
13966
13928
  noTimeout: -1,
@@ -14001,28 +13963,9 @@ const reconciler = /* @__PURE__ */ createReconciler({
14001
13963
  },
14002
13964
  resolveUpdatePriority() {
14003
13965
  if (currentUpdatePriority !== NoEventPriority) return currentUpdatePriority;
14004
- switch (typeof window !== "undefined" && window.event?.type) {
14005
- case "click":
14006
- case "contextmenu":
14007
- case "dblclick":
14008
- case "dragenter":
14009
- case "dragleave":
14010
- case "drop":
14011
- case "pointercancel":
14012
- case "pointerdown":
14013
- case "pointerup":
14014
- return e;
14015
- case "dragover":
14016
- case "pointermove":
14017
- case "pointerout":
14018
- case "pointerover":
14019
- case "pointerenter":
14020
- case "pointerleave":
14021
- case "wheel":
14022
- return o;
14023
- default:
14024
- return r;
14025
- }
13966
+ const eventType = typeof window !== "undefined" ? window.event?.type : void 0;
13967
+ if (eventType === void 0) return r;
13968
+ return getEventPriority(eventType);
14026
13969
  },
14027
13970
  resetFormInstance() {
14028
13971
  },
@@ -14071,11 +14014,15 @@ const reconciler = /* @__PURE__ */ createReconciler({
14071
14014
  cloneMutableTextInstance(textInstance) {
14072
14015
  return textInstance;
14073
14016
  },
14017
+ // React 19.2 added these for root-level view transitions. They only run for hosts that opt into
14018
+ // view transitions by returning a container from cloneRootViewTransitionContainer; R3F renders
14019
+ // into a WebGL/WebGPU canvas, where cloning the root has no meaning, so we never opt in and
14020
+ // React never calls them. They stay as no-ops rather than throws: the host config is shared by
14021
+ // every root, and a throw here would turn a React-internal probe into a hard crash for users.
14022
+ // Guarded by a test asserting a full render + unmount never reaches them.
14074
14023
  cloneRootViewTransitionContainer(_rootContainer) {
14075
- throw new Error("Not implemented.");
14076
14024
  },
14077
14025
  removeRootViewTransitionClone(_rootContainer, _clone) {
14078
- throw new Error("Not implemented.");
14079
14026
  },
14080
14027
  // https://github.com/facebook/react/pull/32465
14081
14028
  createFragmentInstance: (_fiber) => null,
@@ -14474,6 +14421,10 @@ function createRoot(canvas) {
14474
14421
  if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
14475
14422
  const renderer2 = state2.internal.actualRenderer;
14476
14423
  renderer2.setCanvasTarget(state2.internal.canvasTarget);
14424
+ if (state2.internal.canvasTargetSizeDirty) {
14425
+ state2.internal.canvasTargetSizeDirty = false;
14426
+ renderer2.backend?.updateSize?.();
14427
+ }
14477
14428
  }
14478
14429
  },
14479
14430
  {
@@ -14630,7 +14581,8 @@ function unmountComponentAtNode(canvas, callback) {
14630
14581
  dispose(state.scene);
14631
14582
  _roots.delete(canvas);
14632
14583
  if (callback) callback(canvas);
14633
- } catch {
14584
+ } catch (error) {
14585
+ console.warn("[R3F] Error while unmounting root; teardown may be incomplete:", error);
14634
14586
  }
14635
14587
  }, 500);
14636
14588
  }
@@ -14741,6 +14693,212 @@ function flushSync(fn) {
14741
14693
  return reconciler.flushSyncFromReconciler(fn);
14742
14694
  }
14743
14695
 
14696
+ const isRef = (obj) => obj.current && obj.current.isScene;
14697
+ const resolveScene = (scene) => isRef(scene) ? scene.current : scene;
14698
+ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
14699
+ sceneProps = {
14700
+ backgroundBlurriness: 0,
14701
+ backgroundIntensity: 1,
14702
+ backgroundRotation: [0, 0, 0],
14703
+ environmentIntensity: 1,
14704
+ environmentRotation: [0, 0, 0],
14705
+ ...sceneProps
14706
+ };
14707
+ const target = resolveScene(scene || defaultScene);
14708
+ const oldbg = target.background;
14709
+ const oldenv = target.environment;
14710
+ const oldSceneProps = {
14711
+ // @ts-ignore
14712
+ backgroundBlurriness: target.backgroundBlurriness,
14713
+ // @ts-ignore
14714
+ backgroundIntensity: target.backgroundIntensity,
14715
+ // @ts-ignore
14716
+ backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
14717
+ // @ts-ignore
14718
+ environmentIntensity: target.environmentIntensity,
14719
+ // @ts-ignore
14720
+ environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
14721
+ };
14722
+ if (background !== "only") target.environment = texture;
14723
+ if (background) target.background = texture;
14724
+ applyProps(target, sceneProps);
14725
+ return () => {
14726
+ if (background !== "only") target.environment = oldenv;
14727
+ if (background) target.background = oldbg;
14728
+ applyProps(target, oldSceneProps);
14729
+ };
14730
+ }
14731
+ function EnvironmentMap({ scene, background = false, map, ...config }) {
14732
+ const defaultScene = useThree((state) => state.scene);
14733
+ React.useLayoutEffect(() => {
14734
+ if (map) return setEnvProps(background, scene, defaultScene, map, config);
14735
+ });
14736
+ return null;
14737
+ }
14738
+ function EnvironmentCube({
14739
+ background = false,
14740
+ scene,
14741
+ blur,
14742
+ backgroundBlurriness,
14743
+ backgroundIntensity,
14744
+ backgroundRotation,
14745
+ environmentIntensity,
14746
+ environmentRotation,
14747
+ ...rest
14748
+ }) {
14749
+ const texture = useEnvironment(rest);
14750
+ const defaultScene = useThree((state) => state.scene);
14751
+ React.useLayoutEffect(() => {
14752
+ return setEnvProps(background, scene, defaultScene, texture, {
14753
+ backgroundBlurriness: blur ?? backgroundBlurriness,
14754
+ backgroundIntensity,
14755
+ backgroundRotation,
14756
+ environmentIntensity,
14757
+ environmentRotation
14758
+ });
14759
+ });
14760
+ React.useEffect(() => {
14761
+ return () => {
14762
+ texture.dispose();
14763
+ };
14764
+ }, [texture]);
14765
+ return null;
14766
+ }
14767
+ function EnvironmentPortal({
14768
+ children,
14769
+ near = 0.1,
14770
+ far = 1e3,
14771
+ resolution = 256,
14772
+ frames = 1,
14773
+ map,
14774
+ background = false,
14775
+ blur,
14776
+ backgroundBlurriness,
14777
+ backgroundIntensity,
14778
+ backgroundRotation,
14779
+ environmentIntensity,
14780
+ environmentRotation,
14781
+ scene,
14782
+ files,
14783
+ path,
14784
+ preset = void 0,
14785
+ extensions
14786
+ }) {
14787
+ const renderer = useThree((state) => state.renderer);
14788
+ const isLegacy = useThree((state) => state.isLegacy);
14789
+ const defaultScene = useThree((state) => state.scene);
14790
+ const camera = React.useRef(null);
14791
+ const [virtualScene] = React.useState(() => new Scene());
14792
+ const fbo = React.useMemo(() => {
14793
+ const fbo2 = isLegacy ? new WebGLCubeRenderTarget(resolution) : new CubeRenderTarget(resolution);
14794
+ fbo2.texture.type = HalfFloatType;
14795
+ return fbo2;
14796
+ }, [resolution, isLegacy]);
14797
+ React.useEffect(() => {
14798
+ return () => {
14799
+ fbo.dispose();
14800
+ };
14801
+ }, [fbo]);
14802
+ React.useLayoutEffect(() => {
14803
+ if (frames === 1) {
14804
+ const autoClear = renderer.autoClear;
14805
+ renderer.autoClear = true;
14806
+ camera.current.update(renderer, virtualScene);
14807
+ renderer.autoClear = autoClear;
14808
+ }
14809
+ return setEnvProps(background, scene, defaultScene, fbo.texture, {
14810
+ backgroundBlurriness: blur ?? backgroundBlurriness,
14811
+ backgroundIntensity,
14812
+ backgroundRotation,
14813
+ environmentIntensity,
14814
+ environmentRotation
14815
+ });
14816
+ }, [
14817
+ children,
14818
+ virtualScene,
14819
+ fbo.texture,
14820
+ scene,
14821
+ defaultScene,
14822
+ background,
14823
+ frames,
14824
+ renderer,
14825
+ blur,
14826
+ backgroundBlurriness,
14827
+ backgroundIntensity,
14828
+ backgroundRotation,
14829
+ environmentIntensity,
14830
+ environmentRotation
14831
+ ]);
14832
+ let count = 1;
14833
+ useFrame(() => {
14834
+ if (frames === Infinity || count < frames) {
14835
+ const autoClear = renderer.autoClear;
14836
+ renderer.autoClear = true;
14837
+ camera.current.update(renderer, virtualScene);
14838
+ renderer.autoClear = autoClear;
14839
+ count++;
14840
+ }
14841
+ });
14842
+ return /* @__PURE__ */ jsx(Fragment, { children: createPortal(
14843
+ /* @__PURE__ */ jsxs(Fragment, { children: [
14844
+ children,
14845
+ /* @__PURE__ */ jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
14846
+ files || preset ? /* @__PURE__ */ jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsx(EnvironmentMap, { background: true, map, extensions }) : null
14847
+ ] }),
14848
+ virtualScene
14849
+ ) });
14850
+ }
14851
+ function EnvironmentGround(props) {
14852
+ const textureDefault = useEnvironment(props);
14853
+ const texture = props.map || textureDefault;
14854
+ React.useMemo(() => extend({ GroundProjectedEnvImpl: GroundedSkybox }), []);
14855
+ React.useEffect(() => {
14856
+ return () => {
14857
+ textureDefault.dispose();
14858
+ };
14859
+ }, [textureDefault]);
14860
+ const height = props.ground?.height ?? 15;
14861
+ const radius = props.ground?.radius ?? 60;
14862
+ const scale = props.ground?.scale ?? 1e3;
14863
+ const args = React.useMemo(
14864
+ () => [texture, height, radius],
14865
+ [texture, height, radius]
14866
+ );
14867
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
14868
+ /* @__PURE__ */ jsx(EnvironmentMap, { ...props, map: texture }),
14869
+ /* @__PURE__ */ jsx("groundProjectedEnvImpl", { args, scale })
14870
+ ] });
14871
+ }
14872
+ function EnvironmentColor({ color, scene }) {
14873
+ const defaultScene = useThree((state) => state.scene);
14874
+ React.useLayoutEffect(() => {
14875
+ if (color === void 0) return;
14876
+ const target = resolveScene(scene || defaultScene);
14877
+ const oldBg = target.background;
14878
+ target.background = new Color(color);
14879
+ return () => {
14880
+ target.background = oldBg;
14881
+ };
14882
+ });
14883
+ return null;
14884
+ }
14885
+ function EnvironmentDualSource(props) {
14886
+ const { backgroundFiles, ...envProps } = props;
14887
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
14888
+ /* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
14889
+ /* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
14890
+ ] });
14891
+ }
14892
+ function Environment(props) {
14893
+ if (props.color && !props.files && !props.preset && !props.map) {
14894
+ return /* @__PURE__ */ jsx(EnvironmentColor, { ...props });
14895
+ }
14896
+ if (props.backgroundFiles && props.backgroundFiles !== props.files) {
14897
+ return /* @__PURE__ */ jsx(EnvironmentDualSource, { ...props });
14898
+ }
14899
+ return props.ground ? /* @__PURE__ */ jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsx(EnvironmentCube, { ...props });
14900
+ }
14901
+
14744
14902
  function parseBackground(background) {
14745
14903
  if (!background) return null;
14746
14904
  if (typeof background === "object" && !background.isColor) {
@@ -14784,14 +14942,36 @@ function parseRendererConfig(rendererProp) {
14784
14942
  return { primaryCanvas: void 0, scheduler: void 0, renderer: rendererProp };
14785
14943
  }
14786
14944
 
14945
+ const RESOURCE_KINDS = ["nodes", "uniforms", "buffers", "gpuStorage"];
14946
+ const registries = /* @__PURE__ */ new WeakMap();
14947
+ function getKindRegistry(store, kind) {
14948
+ let registry = registries.get(store);
14949
+ if (!registry) {
14950
+ registry = {
14951
+ nodes: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14952
+ uniforms: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14953
+ buffers: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() },
14954
+ gpuStorage: { valid: /* @__PURE__ */ new Set(), staged: /* @__PURE__ */ new Map() }
14955
+ };
14956
+ registries.set(store, registry);
14957
+ }
14958
+ return registry[kind];
14959
+ }
14960
+ function invalidateResource(store, kind, scopeKey) {
14961
+ const registry = getKindRegistry(store, kind);
14962
+ {
14963
+ registry.valid.clear();
14964
+ registry.staged.clear();
14965
+ }
14966
+ }
14967
+ function invalidateAllResources(store) {
14968
+ for (const kind of RESOURCE_KINDS) invalidateResource(store, kind);
14969
+ }
14970
+
14787
14971
  function clearHmrCaches(store) {
14788
- store.setState((state) => ({
14789
- nodes: {},
14790
- uniforms: {},
14791
- buffers: {},
14792
- gpuStorage: {},
14793
- _hmrVersion: state._hmrVersion + 1
14794
- }));
14972
+ const primary = store.getState().primaryStore ?? store;
14973
+ invalidateAllResources(primary);
14974
+ primary.setState((state) => ({ _hmrVersion: state._hmrVersion + 1 }));
14795
14975
  }
14796
14976
 
14797
14977
  function CanvasImpl({
@@ -14928,7 +15108,7 @@ function CanvasImpl({
14928
15108
  onDropMissed: (...args) => handleDropMissed.current?.(...args),
14929
15109
  onCreated: (state) => {
14930
15110
  state.events.connect?.(
14931
- eventSource ? isRef(eventSource) ? eventSource.current : eventSource : divRef.current
15111
+ eventSource ? isRef$1(eventSource) ? eventSource.current : eventSource : divRef.current
14932
15112
  );
14933
15113
  if (eventPrefix) {
14934
15114
  state.setEvents({
@@ -15041,4 +15221,4 @@ function Canvas(props) {
15041
15221
 
15042
15222
  extend(THREE);
15043
15223
 
15044
- export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Texture, _roots, act, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, context, createEvents, createPointerEvents, createPortal, createRoot, createStore, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, reconciler, registerPrimary, removeInteractivity, resolve, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useMutableCallback, useRenderTarget, useStore, useTexture, useTextures, useThree, waitForPrimary };
15224
+ export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Texture, _roots, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, context, createEvents, createPointerEvents, createPortal, createRoot, createStore, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef$1 as isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, reconciler, registerPrimary, removeInteractivity, resolve, swapInteractivity, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useEnvironment, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useMutableCallback, useRenderTarget, useStore, useTexture, useTextures, useThree, waitForPrimary };