@react-three/fiber 10.0.0-alpha.2 → 10.0.0-canary.b0fafc8
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/LICENSE +21 -21
- package/dist/index.cjs +1122 -558
- package/dist/index.d.cts +2001 -1285
- package/dist/index.d.mts +2001 -1285
- package/dist/index.d.ts +2001 -1285
- package/dist/index.mjs +1107 -562
- package/dist/legacy.cjs +1093 -547
- package/dist/legacy.d.cts +2002 -1286
- package/dist/legacy.d.mts +2002 -1286
- package/dist/legacy.d.ts +2002 -1286
- package/dist/legacy.mjs +1078 -551
- package/dist/webgpu/index.cjs +1176 -548
- package/dist/webgpu/index.d.cts +2097 -1300
- package/dist/webgpu/index.d.mts +2097 -1300
- package/dist/webgpu/index.d.ts +2097 -1300
- package/dist/webgpu/index.mjs +1161 -552
- package/package.json +3 -1
- package/readme.md +244 -318
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import * as webgpu from 'three/webgpu';
|
|
2
|
-
import { RenderTarget, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1,
|
|
2
|
+
import { RenderTarget, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, Scene, WebGLCubeRenderTarget, HalfFloatType, Color, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, PCFSoftShadowMap, VSMShadowMap, PCFShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer } from 'three/webgpu';
|
|
3
3
|
import { WebGLRenderTarget, WebGLRenderer } from 'three';
|
|
4
4
|
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
5
|
-
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
5
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
-
import React__default, {
|
|
7
|
+
import React__default, { useLayoutEffect, useRef, useMemo, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
|
|
8
8
|
import useMeasure from 'react-use-measure';
|
|
9
9
|
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';
|
|
11
|
+
import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
|
|
12
|
+
import { HDRLoader } from 'three/examples/jsm/loaders/HDRLoader.js';
|
|
13
|
+
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
|
|
14
|
+
import { UltraHDRLoader } from 'three/examples/jsm/loaders/UltraHDRLoader.js';
|
|
15
|
+
import { GainMapLoader } from '@monogrid/gainmap-js';
|
|
10
16
|
import Tb, { unstable_scheduleCallback, unstable_IdlePriority } from 'scheduler';
|
|
11
17
|
import { createWithEqualityFn } from 'zustand/traditional';
|
|
12
18
|
import { suspend, preload, clear } from 'suspend-react';
|
|
@@ -36,6 +42,374 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
|
36
42
|
WebGLRenderer: WebGLRenderer
|
|
37
43
|
}, [webgpu]);
|
|
38
44
|
|
|
45
|
+
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
46
|
+
const pendingSubscribers = /* @__PURE__ */ new Map();
|
|
47
|
+
function registerPrimary(id, renderer, store) {
|
|
48
|
+
if (primaryRegistry.has(id)) {
|
|
49
|
+
console.warn(`Canvas with id="${id}" already registered. Overwriting.`);
|
|
50
|
+
}
|
|
51
|
+
const entry = { renderer, store };
|
|
52
|
+
primaryRegistry.set(id, entry);
|
|
53
|
+
const subscribers = pendingSubscribers.get(id);
|
|
54
|
+
if (subscribers) {
|
|
55
|
+
subscribers.forEach((callback) => callback(entry));
|
|
56
|
+
pendingSubscribers.delete(id);
|
|
57
|
+
}
|
|
58
|
+
return () => {
|
|
59
|
+
const currentEntry = primaryRegistry.get(id);
|
|
60
|
+
if (currentEntry?.renderer === renderer) {
|
|
61
|
+
primaryRegistry.delete(id);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function getPrimary(id) {
|
|
66
|
+
return primaryRegistry.get(id);
|
|
67
|
+
}
|
|
68
|
+
function waitForPrimary(id, timeout = 5e3) {
|
|
69
|
+
const existing = primaryRegistry.get(id);
|
|
70
|
+
if (existing) {
|
|
71
|
+
return Promise.resolve(existing);
|
|
72
|
+
}
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const timeoutId = setTimeout(() => {
|
|
75
|
+
const subscribers = pendingSubscribers.get(id);
|
|
76
|
+
if (subscribers) {
|
|
77
|
+
const index = subscribers.indexOf(callback);
|
|
78
|
+
if (index !== -1) subscribers.splice(index, 1);
|
|
79
|
+
if (subscribers.length === 0) pendingSubscribers.delete(id);
|
|
80
|
+
}
|
|
81
|
+
reject(new Error(`Timeout waiting for canvas with id="${id}". Make sure a <Canvas id="${id}"> is mounted.`));
|
|
82
|
+
}, timeout);
|
|
83
|
+
const callback = (entry) => {
|
|
84
|
+
clearTimeout(timeoutId);
|
|
85
|
+
resolve(entry);
|
|
86
|
+
};
|
|
87
|
+
if (!pendingSubscribers.has(id)) {
|
|
88
|
+
pendingSubscribers.set(id, []);
|
|
89
|
+
}
|
|
90
|
+
pendingSubscribers.get(id).push(callback);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function hasPrimary(id) {
|
|
94
|
+
return primaryRegistry.has(id);
|
|
95
|
+
}
|
|
96
|
+
function unregisterPrimary(id) {
|
|
97
|
+
primaryRegistry.delete(id);
|
|
98
|
+
}
|
|
99
|
+
function getPrimaryIds() {
|
|
100
|
+
return Array.from(primaryRegistry.keys());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const presetsObj = {
|
|
104
|
+
apartment: "lebombo_1k.hdr",
|
|
105
|
+
city: "potsdamer_platz_1k.hdr",
|
|
106
|
+
dawn: "kiara_1_dawn_1k.hdr",
|
|
107
|
+
forest: "forest_slope_1k.hdr",
|
|
108
|
+
lobby: "st_fagans_interior_1k.hdr",
|
|
109
|
+
night: "dikhololo_night_1k.hdr",
|
|
110
|
+
park: "rooitou_park_1k.hdr",
|
|
111
|
+
studio: "studio_small_03_1k.hdr",
|
|
112
|
+
sunset: "venice_sunset_1k.hdr",
|
|
113
|
+
warehouse: "empty_warehouse_01_1k.hdr"
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const CUBEMAP_ROOT = "https://raw.githack.com/pmndrs/drei-assets/456060a26bbeb8fdf79326f224b6d99b8bcce736/hdri/";
|
|
117
|
+
const isArray = (arr) => Array.isArray(arr);
|
|
118
|
+
const defaultFiles = ["/px.png", "/nx.png", "/py.png", "/ny.png", "/pz.png", "/nz.png"];
|
|
119
|
+
function useEnvironment({
|
|
120
|
+
files = defaultFiles,
|
|
121
|
+
path = "",
|
|
122
|
+
preset = void 0,
|
|
123
|
+
colorSpace = void 0,
|
|
124
|
+
extensions
|
|
125
|
+
} = {}) {
|
|
126
|
+
if (preset) {
|
|
127
|
+
validatePreset(preset);
|
|
128
|
+
files = presetsObj[preset];
|
|
129
|
+
path = CUBEMAP_ROOT;
|
|
130
|
+
}
|
|
131
|
+
const multiFile = isArray(files);
|
|
132
|
+
const { extension, isCubemap } = getExtension(files);
|
|
133
|
+
const loader = getLoader$1(extension);
|
|
134
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
135
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
136
|
+
useLayoutEffect(() => {
|
|
137
|
+
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
138
|
+
function clearGainmapTexture() {
|
|
139
|
+
useLoader$1.clear(loader, multiFile ? [files] : files);
|
|
140
|
+
}
|
|
141
|
+
renderer.domElement.addEventListener("webglcontextlost", clearGainmapTexture, { once: true });
|
|
142
|
+
}, [files, renderer.domElement]);
|
|
143
|
+
const loaderResult = useLoader$1(
|
|
144
|
+
loader,
|
|
145
|
+
multiFile ? [files] : files,
|
|
146
|
+
(loader2) => {
|
|
147
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
148
|
+
loader2.setRenderer?.(renderer);
|
|
149
|
+
}
|
|
150
|
+
loader2.setPath?.(path);
|
|
151
|
+
if (extensions) extensions(loader2);
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
let texture = multiFile ? (
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
loaderResult[0]
|
|
157
|
+
) : loaderResult;
|
|
158
|
+
if (extension === "jpg" || extension === "jpeg" || extension === "webp") {
|
|
159
|
+
texture = texture.renderTarget?.texture;
|
|
160
|
+
}
|
|
161
|
+
texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
|
|
162
|
+
texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
|
|
163
|
+
return texture;
|
|
164
|
+
}
|
|
165
|
+
const preloadDefaultOptions = {
|
|
166
|
+
files: defaultFiles,
|
|
167
|
+
path: "",
|
|
168
|
+
preset: void 0,
|
|
169
|
+
extensions: void 0
|
|
170
|
+
};
|
|
171
|
+
useEnvironment.preload = (preloadOptions) => {
|
|
172
|
+
const options = { ...preloadDefaultOptions, ...preloadOptions };
|
|
173
|
+
let { files, path = "" } = options;
|
|
174
|
+
const { preset, extensions } = options;
|
|
175
|
+
if (preset) {
|
|
176
|
+
validatePreset(preset);
|
|
177
|
+
files = presetsObj[preset];
|
|
178
|
+
path = CUBEMAP_ROOT;
|
|
179
|
+
}
|
|
180
|
+
const { extension } = getExtension(files);
|
|
181
|
+
if (extension === "webp" || extension === "jpg" || extension === "jpeg") {
|
|
182
|
+
throw new Error("useEnvironment: Preloading gainmaps is not supported");
|
|
183
|
+
}
|
|
184
|
+
const loader = getLoader$1(extension);
|
|
185
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
186
|
+
useLoader$1.preload(loader, isArray(files) ? [files] : files, (loader2) => {
|
|
187
|
+
loader2.setPath?.(path);
|
|
188
|
+
if (extensions) extensions(loader2);
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
const clearDefaultOptins = {
|
|
192
|
+
files: defaultFiles,
|
|
193
|
+
preset: void 0
|
|
194
|
+
};
|
|
195
|
+
useEnvironment.clear = (clearOptions) => {
|
|
196
|
+
const options = { ...clearDefaultOptins, ...clearOptions };
|
|
197
|
+
let { files } = options;
|
|
198
|
+
const { preset } = options;
|
|
199
|
+
if (preset) {
|
|
200
|
+
validatePreset(preset);
|
|
201
|
+
files = presetsObj[preset];
|
|
202
|
+
}
|
|
203
|
+
const { extension } = getExtension(files);
|
|
204
|
+
const loader = getLoader$1(extension);
|
|
205
|
+
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
206
|
+
useLoader$1.clear(loader, isArray(files) ? [files] : files);
|
|
207
|
+
};
|
|
208
|
+
function validatePreset(preset) {
|
|
209
|
+
if (!(preset in presetsObj)) throw new Error("Preset must be one of: " + Object.keys(presetsObj).join(", "));
|
|
210
|
+
}
|
|
211
|
+
function getExtension(files) {
|
|
212
|
+
const isCubemap = isArray(files) && files.length === 6;
|
|
213
|
+
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
|
|
214
|
+
const firstEntry = isArray(files) ? files[0] : files;
|
|
215
|
+
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();
|
|
216
|
+
return { extension, isCubemap, isGainmap };
|
|
217
|
+
}
|
|
218
|
+
function getLoader$1(extension) {
|
|
219
|
+
const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
|
|
220
|
+
return loader;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const isRef$1 = (obj) => obj.current && obj.current.isScene;
|
|
224
|
+
const resolveScene = (scene) => isRef$1(scene) ? scene.current : scene;
|
|
225
|
+
function setEnvProps(background, scene, defaultScene, texture, sceneProps = {}) {
|
|
226
|
+
sceneProps = {
|
|
227
|
+
backgroundBlurriness: 0,
|
|
228
|
+
backgroundIntensity: 1,
|
|
229
|
+
backgroundRotation: [0, 0, 0],
|
|
230
|
+
environmentIntensity: 1,
|
|
231
|
+
environmentRotation: [0, 0, 0],
|
|
232
|
+
...sceneProps
|
|
233
|
+
};
|
|
234
|
+
const target = resolveScene(scene || defaultScene);
|
|
235
|
+
const oldbg = target.background;
|
|
236
|
+
const oldenv = target.environment;
|
|
237
|
+
const oldSceneProps = {
|
|
238
|
+
// @ts-ignore
|
|
239
|
+
backgroundBlurriness: target.backgroundBlurriness,
|
|
240
|
+
// @ts-ignore
|
|
241
|
+
backgroundIntensity: target.backgroundIntensity,
|
|
242
|
+
// @ts-ignore
|
|
243
|
+
backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
|
|
244
|
+
// @ts-ignore
|
|
245
|
+
environmentIntensity: target.environmentIntensity,
|
|
246
|
+
// @ts-ignore
|
|
247
|
+
environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
|
|
248
|
+
};
|
|
249
|
+
if (background !== "only") target.environment = texture;
|
|
250
|
+
if (background) target.background = texture;
|
|
251
|
+
applyProps$1(target, sceneProps);
|
|
252
|
+
return () => {
|
|
253
|
+
if (background !== "only") target.environment = oldenv;
|
|
254
|
+
if (background) target.background = oldbg;
|
|
255
|
+
applyProps$1(target, oldSceneProps);
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
259
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
260
|
+
React.useLayoutEffect(() => {
|
|
261
|
+
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
262
|
+
});
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
function EnvironmentCube({
|
|
266
|
+
background = false,
|
|
267
|
+
scene,
|
|
268
|
+
blur,
|
|
269
|
+
backgroundBlurriness,
|
|
270
|
+
backgroundIntensity,
|
|
271
|
+
backgroundRotation,
|
|
272
|
+
environmentIntensity,
|
|
273
|
+
environmentRotation,
|
|
274
|
+
...rest
|
|
275
|
+
}) {
|
|
276
|
+
const texture = useEnvironment(rest);
|
|
277
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
278
|
+
React.useLayoutEffect(() => {
|
|
279
|
+
return setEnvProps(background, scene, defaultScene, texture, {
|
|
280
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
281
|
+
backgroundIntensity,
|
|
282
|
+
backgroundRotation,
|
|
283
|
+
environmentIntensity,
|
|
284
|
+
environmentRotation
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
React.useEffect(() => {
|
|
288
|
+
return () => {
|
|
289
|
+
texture.dispose();
|
|
290
|
+
};
|
|
291
|
+
}, [texture]);
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
function EnvironmentPortal({
|
|
295
|
+
children,
|
|
296
|
+
near = 0.1,
|
|
297
|
+
far = 1e3,
|
|
298
|
+
resolution = 256,
|
|
299
|
+
frames = 1,
|
|
300
|
+
map,
|
|
301
|
+
background = false,
|
|
302
|
+
blur,
|
|
303
|
+
backgroundBlurriness,
|
|
304
|
+
backgroundIntensity,
|
|
305
|
+
backgroundRotation,
|
|
306
|
+
environmentIntensity,
|
|
307
|
+
environmentRotation,
|
|
308
|
+
scene,
|
|
309
|
+
files,
|
|
310
|
+
path,
|
|
311
|
+
preset = void 0,
|
|
312
|
+
extensions
|
|
313
|
+
}) {
|
|
314
|
+
const gl = useThree$1((state) => state.gl);
|
|
315
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
316
|
+
const camera = React.useRef(null);
|
|
317
|
+
const [virtualScene] = React.useState(() => new Scene());
|
|
318
|
+
const fbo = React.useMemo(() => {
|
|
319
|
+
const fbo2 = new WebGLCubeRenderTarget(resolution);
|
|
320
|
+
fbo2.texture.type = HalfFloatType;
|
|
321
|
+
return fbo2;
|
|
322
|
+
}, [resolution]);
|
|
323
|
+
React.useEffect(() => {
|
|
324
|
+
return () => {
|
|
325
|
+
fbo.dispose();
|
|
326
|
+
};
|
|
327
|
+
}, [fbo]);
|
|
328
|
+
React.useLayoutEffect(() => {
|
|
329
|
+
if (frames === 1) {
|
|
330
|
+
const autoClear = gl.autoClear;
|
|
331
|
+
gl.autoClear = true;
|
|
332
|
+
camera.current.update(gl, virtualScene);
|
|
333
|
+
gl.autoClear = autoClear;
|
|
334
|
+
}
|
|
335
|
+
return setEnvProps(background, scene, defaultScene, fbo.texture, {
|
|
336
|
+
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
337
|
+
backgroundIntensity,
|
|
338
|
+
backgroundRotation,
|
|
339
|
+
environmentIntensity,
|
|
340
|
+
environmentRotation
|
|
341
|
+
});
|
|
342
|
+
}, [children, virtualScene, fbo.texture, scene, defaultScene, background, frames, gl]);
|
|
343
|
+
let count = 1;
|
|
344
|
+
useFrame$1(() => {
|
|
345
|
+
if (frames === Infinity || count < frames) {
|
|
346
|
+
const autoClear = gl.autoClear;
|
|
347
|
+
gl.autoClear = true;
|
|
348
|
+
camera.current.update(gl, virtualScene);
|
|
349
|
+
gl.autoClear = autoClear;
|
|
350
|
+
count++;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
return /* @__PURE__ */ jsx(Fragment, { children: createPortal$1(
|
|
354
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
355
|
+
children,
|
|
356
|
+
/* @__PURE__ */ jsx("cubeCamera", { ref: camera, args: [near, far, fbo] }),
|
|
357
|
+
files || preset ? /* @__PURE__ */ jsx(EnvironmentCube, { background: true, files, preset, path, extensions }) : map ? /* @__PURE__ */ jsx(EnvironmentMap, { background: true, map, extensions }) : null
|
|
358
|
+
] }),
|
|
359
|
+
virtualScene
|
|
360
|
+
) });
|
|
361
|
+
}
|
|
362
|
+
function EnvironmentGround(props) {
|
|
363
|
+
const textureDefault = useEnvironment(props);
|
|
364
|
+
const texture = props.map || textureDefault;
|
|
365
|
+
React.useMemo(() => extend$1({ GroundProjectedEnvImpl: GroundedSkybox }), []);
|
|
366
|
+
React.useEffect(() => {
|
|
367
|
+
return () => {
|
|
368
|
+
textureDefault.dispose();
|
|
369
|
+
};
|
|
370
|
+
}, [textureDefault]);
|
|
371
|
+
const height = props.ground?.height ?? 15;
|
|
372
|
+
const radius = props.ground?.radius ?? 60;
|
|
373
|
+
const scale = props.ground?.scale ?? 1e3;
|
|
374
|
+
const args = React.useMemo(
|
|
375
|
+
() => [texture, height, radius],
|
|
376
|
+
[texture, height, radius]
|
|
377
|
+
);
|
|
378
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
379
|
+
/* @__PURE__ */ jsx(EnvironmentMap, { ...props, map: texture }),
|
|
380
|
+
/* @__PURE__ */ jsx("groundProjectedEnvImpl", { args, scale })
|
|
381
|
+
] });
|
|
382
|
+
}
|
|
383
|
+
function EnvironmentColor({ color, scene }) {
|
|
384
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
385
|
+
React.useLayoutEffect(() => {
|
|
386
|
+
if (color === void 0) return;
|
|
387
|
+
const target = resolveScene(scene || defaultScene);
|
|
388
|
+
const oldBg = target.background;
|
|
389
|
+
target.background = new Color(color);
|
|
390
|
+
return () => {
|
|
391
|
+
target.background = oldBg;
|
|
392
|
+
};
|
|
393
|
+
});
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
function EnvironmentDualSource(props) {
|
|
397
|
+
const { backgroundFiles, ...envProps } = props;
|
|
398
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
399
|
+
/* @__PURE__ */ jsx(EnvironmentCube, { ...envProps, background: false }),
|
|
400
|
+
/* @__PURE__ */ jsx(EnvironmentCube, { ...props, files: backgroundFiles, background: "only" })
|
|
401
|
+
] });
|
|
402
|
+
}
|
|
403
|
+
function Environment(props) {
|
|
404
|
+
if (props.color && !props.files && !props.preset && !props.map) {
|
|
405
|
+
return /* @__PURE__ */ jsx(EnvironmentColor, { ...props });
|
|
406
|
+
}
|
|
407
|
+
if (props.backgroundFiles && props.backgroundFiles !== props.files) {
|
|
408
|
+
return /* @__PURE__ */ jsx(EnvironmentDualSource, { ...props });
|
|
409
|
+
}
|
|
410
|
+
return props.ground ? /* @__PURE__ */ jsx(EnvironmentGround, { ...props }) : props.map ? /* @__PURE__ */ jsx(EnvironmentMap, { ...props }) : props.children ? /* @__PURE__ */ jsx(EnvironmentPortal, { ...props }) : /* @__PURE__ */ jsx(EnvironmentCube, { ...props });
|
|
411
|
+
}
|
|
412
|
+
|
|
39
413
|
var __defProp$2 = Object.defineProperty;
|
|
40
414
|
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
41
415
|
var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
@@ -215,7 +589,8 @@ function prepare(target, root, type, props) {
|
|
|
215
589
|
object,
|
|
216
590
|
eventCount: 0,
|
|
217
591
|
handlers: {},
|
|
218
|
-
isHidden: false
|
|
592
|
+
isHidden: false,
|
|
593
|
+
deferredRefs: []
|
|
219
594
|
};
|
|
220
595
|
if (object) object.__r3f = instance;
|
|
221
596
|
}
|
|
@@ -264,7 +639,7 @@ function createOcclusionObserverNode(store, uniform) {
|
|
|
264
639
|
let occlusionSetupPromise = null;
|
|
265
640
|
function enableOcclusion(store) {
|
|
266
641
|
const state = store.getState();
|
|
267
|
-
const { internal, renderer
|
|
642
|
+
const { internal, renderer } = state;
|
|
268
643
|
if (internal.occlusionEnabled || occlusionSetupPromise) return;
|
|
269
644
|
const hasOcclusionSupport = typeof renderer?.isOccluded === "function";
|
|
270
645
|
if (!hasOcclusionSupport) {
|
|
@@ -427,6 +802,22 @@ function hasVisibilityHandlers(handlers) {
|
|
|
427
802
|
return !!(handlers.onFramed || handlers.onOccluded || handlers.onVisible);
|
|
428
803
|
}
|
|
429
804
|
|
|
805
|
+
const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
|
|
806
|
+
function fromRef(ref) {
|
|
807
|
+
return { [FROM_REF]: ref };
|
|
808
|
+
}
|
|
809
|
+
function isFromRef(value) {
|
|
810
|
+
return value !== null && typeof value === "object" && FROM_REF in value;
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const ONCE = Symbol.for("@react-three/fiber.once");
|
|
814
|
+
function once(...args) {
|
|
815
|
+
return { [ONCE]: args.length ? args : true };
|
|
816
|
+
}
|
|
817
|
+
function isOnce(value) {
|
|
818
|
+
return value !== null && typeof value === "object" && ONCE in value;
|
|
819
|
+
}
|
|
820
|
+
|
|
430
821
|
const RESERVED_PROPS = [
|
|
431
822
|
"children",
|
|
432
823
|
"key",
|
|
@@ -497,7 +888,7 @@ function getMemoizedPrototype(root) {
|
|
|
497
888
|
ctor = new root.constructor();
|
|
498
889
|
MEMOIZED_PROTOTYPES.set(root.constructor, ctor);
|
|
499
890
|
}
|
|
500
|
-
} catch
|
|
891
|
+
} catch {
|
|
501
892
|
}
|
|
502
893
|
return ctor;
|
|
503
894
|
}
|
|
@@ -543,6 +934,25 @@ function applyProps(object, props) {
|
|
|
543
934
|
continue;
|
|
544
935
|
}
|
|
545
936
|
if (value === void 0) continue;
|
|
937
|
+
if (isFromRef(value)) {
|
|
938
|
+
instance?.deferredRefs?.push({ prop, ref: value[FROM_REF] });
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
if (isOnce(value)) {
|
|
942
|
+
if (instance?.appliedOnce?.has(prop)) continue;
|
|
943
|
+
if (instance) {
|
|
944
|
+
instance.appliedOnce ?? (instance.appliedOnce = /* @__PURE__ */ new Set());
|
|
945
|
+
instance.appliedOnce.add(prop);
|
|
946
|
+
}
|
|
947
|
+
const { root: targetRoot, key: targetKey } = resolve(object, prop);
|
|
948
|
+
const args = value[ONCE];
|
|
949
|
+
if (typeof targetRoot[targetKey] === "function") {
|
|
950
|
+
targetRoot[targetKey](...args === true ? [] : args);
|
|
951
|
+
} else if (args !== true && args.length > 0) {
|
|
952
|
+
targetRoot[targetKey] = args[0];
|
|
953
|
+
}
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
546
956
|
let { root, key, target } = resolve(object, prop);
|
|
547
957
|
if (target === void 0 && (typeof root !== "object" || root === null)) {
|
|
548
958
|
throw Error(`R3F: Cannot set "${prop}". Ensure it is an object before setting "${key}".`);
|
|
@@ -565,7 +975,7 @@ function applyProps(object, props) {
|
|
|
565
975
|
else target.set(value);
|
|
566
976
|
} else {
|
|
567
977
|
root[key] = value;
|
|
568
|
-
if (rootState &&
|
|
978
|
+
if (rootState && rootState.renderer?.outputColorSpace === SRGBColorSpace && colorMaps.includes(key) && isTexture(value) && root[key]?.isTexture && // sRGB textures must be RGBA8 since r137 https://github.com/mrdoob/three.js/pull/23129
|
|
569
979
|
root[key].format === RGBAFormat && root[key].type === UnsignedByteType) {
|
|
570
980
|
root[key].colorSpace = rootState.textureColorSpace;
|
|
571
981
|
}
|
|
@@ -922,7 +1332,7 @@ function createPointerEvents(store) {
|
|
|
922
1332
|
return {
|
|
923
1333
|
priority: 1,
|
|
924
1334
|
enabled: true,
|
|
925
|
-
compute(event, state
|
|
1335
|
+
compute(event, state) {
|
|
926
1336
|
state.pointer.set(event.offsetX / state.size.width * 2 - 1, -(event.offsetY / state.size.height) * 2 + 1);
|
|
927
1337
|
state.raycaster.setFromCamera(state.pointer, state.camera);
|
|
928
1338
|
},
|
|
@@ -1020,331 +1430,26 @@ function notifyAlpha({ message, link }) {
|
|
|
1020
1430
|
}
|
|
1021
1431
|
}
|
|
1022
1432
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
let performanceTimeout = void 0;
|
|
1046
|
-
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
1047
|
-
const pointer = new Vector2();
|
|
1048
|
-
const rootState = {
|
|
1049
|
-
set,
|
|
1050
|
-
get,
|
|
1051
|
-
// Mock objects that have to be configured
|
|
1052
|
-
gl: null,
|
|
1053
|
-
renderer: null,
|
|
1054
|
-
camera: null,
|
|
1055
|
-
frustum: new Frustum(),
|
|
1056
|
-
autoUpdateFrustum: true,
|
|
1057
|
-
raycaster: null,
|
|
1058
|
-
events: { priority: 1, enabled: true, connected: false },
|
|
1059
|
-
scene: null,
|
|
1060
|
-
rootScene: null,
|
|
1061
|
-
xr: null,
|
|
1062
|
-
inspector: null,
|
|
1063
|
-
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
1064
|
-
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
1065
|
-
legacy: false,
|
|
1066
|
-
linear: false,
|
|
1067
|
-
flat: false,
|
|
1068
|
-
textureColorSpace: "srgb",
|
|
1069
|
-
isLegacy: false,
|
|
1070
|
-
webGPUSupported: false,
|
|
1071
|
-
isNative: false,
|
|
1072
|
-
controls: null,
|
|
1073
|
-
pointer,
|
|
1074
|
-
mouse: pointer,
|
|
1075
|
-
frameloop: "always",
|
|
1076
|
-
onPointerMissed: void 0,
|
|
1077
|
-
onDragOverMissed: void 0,
|
|
1078
|
-
onDropMissed: void 0,
|
|
1079
|
-
performance: {
|
|
1080
|
-
current: 1,
|
|
1081
|
-
min: 0.5,
|
|
1082
|
-
max: 1,
|
|
1083
|
-
debounce: 200,
|
|
1084
|
-
regress: () => {
|
|
1085
|
-
const state2 = get();
|
|
1086
|
-
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
1087
|
-
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
1088
|
-
performanceTimeout = setTimeout(
|
|
1089
|
-
() => setPerformanceCurrent(get().performance.max),
|
|
1090
|
-
state2.performance.debounce
|
|
1091
|
-
);
|
|
1092
|
-
}
|
|
1093
|
-
},
|
|
1094
|
-
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
1095
|
-
viewport: {
|
|
1096
|
-
initialDpr: 0,
|
|
1097
|
-
dpr: 0,
|
|
1098
|
-
width: 0,
|
|
1099
|
-
height: 0,
|
|
1100
|
-
top: 0,
|
|
1101
|
-
left: 0,
|
|
1102
|
-
aspect: 0,
|
|
1103
|
-
distance: 0,
|
|
1104
|
-
factor: 0,
|
|
1105
|
-
getCurrentViewport
|
|
1106
|
-
},
|
|
1107
|
-
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
1108
|
-
setSize: (width, height, top, left) => {
|
|
1109
|
-
const state2 = get();
|
|
1110
|
-
if (width === void 0) {
|
|
1111
|
-
set({ _sizeImperative: false });
|
|
1112
|
-
if (state2._sizeProps) {
|
|
1113
|
-
const { width: propW, height: propH } = state2._sizeProps;
|
|
1114
|
-
if (propW !== void 0 || propH !== void 0) {
|
|
1115
|
-
const currentSize = state2.size;
|
|
1116
|
-
const newSize = {
|
|
1117
|
-
width: propW ?? currentSize.width,
|
|
1118
|
-
height: propH ?? currentSize.height,
|
|
1119
|
-
top: currentSize.top,
|
|
1120
|
-
left: currentSize.left
|
|
1121
|
-
};
|
|
1122
|
-
set((s) => ({
|
|
1123
|
-
size: newSize,
|
|
1124
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
1125
|
-
}));
|
|
1126
|
-
}
|
|
1127
|
-
}
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
const w = width;
|
|
1131
|
-
const h = height ?? width;
|
|
1132
|
-
const t = top ?? state2.size.top;
|
|
1133
|
-
const l = left ?? state2.size.left;
|
|
1134
|
-
const size = { width: w, height: h, top: t, left: l };
|
|
1135
|
-
set((s) => ({
|
|
1136
|
-
size,
|
|
1137
|
-
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
1138
|
-
_sizeImperative: true
|
|
1139
|
-
}));
|
|
1140
|
-
},
|
|
1141
|
-
setDpr: (dpr) => set((state2) => {
|
|
1142
|
-
const resolved = calculateDpr(dpr);
|
|
1143
|
-
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
1144
|
-
}),
|
|
1145
|
-
setFrameloop: (frameloop = "always") => {
|
|
1146
|
-
set(() => ({ frameloop }));
|
|
1147
|
-
},
|
|
1148
|
-
setError: (error) => set(() => ({ error })),
|
|
1149
|
-
error: null,
|
|
1150
|
-
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
1151
|
-
uniforms: {},
|
|
1152
|
-
nodes: {},
|
|
1153
|
-
textures: /* @__PURE__ */ new Map(),
|
|
1154
|
-
postProcessing: null,
|
|
1155
|
-
passes: {},
|
|
1156
|
-
_hmrVersion: 0,
|
|
1157
|
-
_sizeImperative: false,
|
|
1158
|
-
_sizeProps: null,
|
|
1159
|
-
previousRoot: void 0,
|
|
1160
|
-
internal: {
|
|
1161
|
-
// Events
|
|
1162
|
-
interaction: [],
|
|
1163
|
-
hovered: /* @__PURE__ */ new Map(),
|
|
1164
|
-
subscribers: [],
|
|
1165
|
-
initialClick: [0, 0],
|
|
1166
|
-
initialHits: [],
|
|
1167
|
-
capturedMap: /* @__PURE__ */ new Map(),
|
|
1168
|
-
lastEvent: React.createRef(),
|
|
1169
|
-
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
1170
|
-
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
1171
|
-
// Occlusion system (WebGPU only)
|
|
1172
|
-
occlusionEnabled: false,
|
|
1173
|
-
occlusionObserver: null,
|
|
1174
|
-
occlusionCache: /* @__PURE__ */ new Map(),
|
|
1175
|
-
helperGroup: null,
|
|
1176
|
-
// Updates
|
|
1177
|
-
active: false,
|
|
1178
|
-
frames: 0,
|
|
1179
|
-
priority: 0,
|
|
1180
|
-
subscribe: (ref, priority, store) => {
|
|
1181
|
-
const internal = get().internal;
|
|
1182
|
-
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1183
|
-
internal.subscribers.push({ ref, priority, store });
|
|
1184
|
-
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1185
|
-
return () => {
|
|
1186
|
-
const internal2 = get().internal;
|
|
1187
|
-
if (internal2?.subscribers) {
|
|
1188
|
-
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
1189
|
-
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
1190
|
-
}
|
|
1191
|
-
};
|
|
1192
|
-
},
|
|
1193
|
-
// Renderer Storage (single source of truth)
|
|
1194
|
-
actualRenderer: null,
|
|
1195
|
-
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
1196
|
-
scheduler: null
|
|
1197
|
-
}
|
|
1198
|
-
};
|
|
1199
|
-
return rootState;
|
|
1200
|
-
});
|
|
1201
|
-
const state = rootStore.getState();
|
|
1202
|
-
Object.defineProperty(state, "gl", {
|
|
1203
|
-
get() {
|
|
1204
|
-
const currentState = rootStore.getState();
|
|
1205
|
-
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
1206
|
-
const stack = new Error().stack || "";
|
|
1207
|
-
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
1208
|
-
if (!isInternalAccess) {
|
|
1209
|
-
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
1210
|
-
notifyDepreciated({
|
|
1211
|
-
heading: "Accessing state.gl in WebGPU mode",
|
|
1212
|
-
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
|
|
1213
|
-
});
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
return currentState.internal.actualRenderer;
|
|
1217
|
-
},
|
|
1218
|
-
set(value) {
|
|
1219
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1220
|
-
},
|
|
1221
|
-
enumerable: true,
|
|
1222
|
-
configurable: true
|
|
1223
|
-
});
|
|
1224
|
-
Object.defineProperty(state, "renderer", {
|
|
1225
|
-
get() {
|
|
1226
|
-
return rootStore.getState().internal.actualRenderer;
|
|
1227
|
-
},
|
|
1228
|
-
set(value) {
|
|
1229
|
-
rootStore.getState().internal.actualRenderer = value;
|
|
1230
|
-
},
|
|
1231
|
-
enumerable: true,
|
|
1232
|
-
configurable: true
|
|
1233
|
-
});
|
|
1234
|
-
let oldScene = state.scene;
|
|
1235
|
-
rootStore.subscribe(() => {
|
|
1236
|
-
const currentState = rootStore.getState();
|
|
1237
|
-
const { scene, rootScene, set } = currentState;
|
|
1238
|
-
if (scene !== oldScene) {
|
|
1239
|
-
oldScene = scene;
|
|
1240
|
-
if (scene?.isScene && scene !== rootScene) {
|
|
1241
|
-
set({ rootScene: scene });
|
|
1242
|
-
}
|
|
1243
|
-
}
|
|
1244
|
-
});
|
|
1245
|
-
let oldSize = state.size;
|
|
1246
|
-
let oldDpr = state.viewport.dpr;
|
|
1247
|
-
let oldCamera = state.camera;
|
|
1248
|
-
rootStore.subscribe(() => {
|
|
1249
|
-
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
1250
|
-
const actualRenderer = internal.actualRenderer;
|
|
1251
|
-
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
1252
|
-
oldSize = size;
|
|
1253
|
-
oldDpr = viewport.dpr;
|
|
1254
|
-
updateCamera(camera, size);
|
|
1255
|
-
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
1256
|
-
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
1257
|
-
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
1258
|
-
}
|
|
1259
|
-
if (camera !== oldCamera) {
|
|
1260
|
-
oldCamera = camera;
|
|
1261
|
-
const { rootScene } = rootStore.getState();
|
|
1262
|
-
if (camera && rootScene && !camera.parent) {
|
|
1263
|
-
rootScene.add(camera);
|
|
1264
|
-
}
|
|
1265
|
-
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
1266
|
-
const currentState = rootStore.getState();
|
|
1267
|
-
if (currentState.autoUpdateFrustum && camera) {
|
|
1268
|
-
updateFrustum(camera, currentState.frustum);
|
|
1269
|
-
}
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
rootStore.subscribe((state2) => invalidate(state2));
|
|
1273
|
-
return rootStore;
|
|
1274
|
-
};
|
|
1275
|
-
|
|
1276
|
-
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
1277
|
-
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
1278
|
-
function getLoader(Proto) {
|
|
1279
|
-
if (isConstructor$1(Proto)) {
|
|
1280
|
-
let loader = memoizedLoaders.get(Proto);
|
|
1281
|
-
if (!loader) {
|
|
1282
|
-
loader = new Proto();
|
|
1283
|
-
memoizedLoaders.set(Proto, loader);
|
|
1284
|
-
}
|
|
1285
|
-
return loader;
|
|
1286
|
-
}
|
|
1287
|
-
return Proto;
|
|
1288
|
-
}
|
|
1289
|
-
function loadingFn(extensions, onProgress) {
|
|
1290
|
-
return function(Proto, input) {
|
|
1291
|
-
const loader = getLoader(Proto);
|
|
1292
|
-
if (extensions) extensions(loader);
|
|
1293
|
-
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
1294
|
-
return loader.loadAsync(input, onProgress).then((data) => {
|
|
1295
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1296
|
-
return data;
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
return new Promise(
|
|
1300
|
-
(res, reject) => loader.load(
|
|
1301
|
-
input,
|
|
1302
|
-
(data) => {
|
|
1303
|
-
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
1304
|
-
res(data);
|
|
1305
|
-
},
|
|
1306
|
-
onProgress,
|
|
1307
|
-
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
1308
|
-
)
|
|
1309
|
-
);
|
|
1310
|
-
};
|
|
1311
|
-
}
|
|
1312
|
-
function useLoader(loader, input, extensions, onProgress) {
|
|
1313
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1314
|
-
const fn = loadingFn(extensions, onProgress);
|
|
1315
|
-
const results = keys.map((key) => suspend(fn, [loader, key], { equal: is.equ }));
|
|
1316
|
-
return Array.isArray(input) ? results : results[0];
|
|
1317
|
-
}
|
|
1318
|
-
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
1319
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1320
|
-
keys.forEach((key) => preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
1321
|
-
};
|
|
1322
|
-
useLoader.clear = function(loader, input) {
|
|
1323
|
-
const keys = Array.isArray(input) ? input : [input];
|
|
1324
|
-
keys.forEach((key) => clear([loader, key]));
|
|
1325
|
-
};
|
|
1326
|
-
useLoader.loader = getLoader;
|
|
1327
|
-
|
|
1328
|
-
var __defProp$1 = Object.defineProperty;
|
|
1329
|
-
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1330
|
-
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1331
|
-
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1332
|
-
class PhaseGraph {
|
|
1333
|
-
constructor() {
|
|
1334
|
-
/** Ordered list of phase nodes */
|
|
1335
|
-
__publicField$1(this, "phases", []);
|
|
1336
|
-
/** Quick lookup by name */
|
|
1337
|
-
__publicField$1(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1338
|
-
/** Cached ordered names (invalidated on changes) */
|
|
1339
|
-
__publicField$1(this, "orderedNamesCache", null);
|
|
1340
|
-
this.initializeDefaultPhases();
|
|
1341
|
-
}
|
|
1342
|
-
//* Initialization --------------------------------
|
|
1343
|
-
initializeDefaultPhases() {
|
|
1344
|
-
for (const name of DEFAULT_PHASES) {
|
|
1345
|
-
const node = { name, isAutoGenerated: false };
|
|
1346
|
-
this.phases.push(node);
|
|
1347
|
-
this.phaseMap.set(name, node);
|
|
1433
|
+
var __defProp$1 = Object.defineProperty;
|
|
1434
|
+
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
1435
|
+
var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
1436
|
+
const DEFAULT_PHASES = ["start", "input", "physics", "update", "render", "finish"];
|
|
1437
|
+
class PhaseGraph {
|
|
1438
|
+
constructor() {
|
|
1439
|
+
/** Ordered list of phase nodes */
|
|
1440
|
+
__publicField$1(this, "phases", []);
|
|
1441
|
+
/** Quick lookup by name */
|
|
1442
|
+
__publicField$1(this, "phaseMap", /* @__PURE__ */ new Map());
|
|
1443
|
+
/** Cached ordered names (invalidated on changes) */
|
|
1444
|
+
__publicField$1(this, "orderedNamesCache", null);
|
|
1445
|
+
this.initializeDefaultPhases();
|
|
1446
|
+
}
|
|
1447
|
+
//* Initialization --------------------------------
|
|
1448
|
+
initializeDefaultPhases() {
|
|
1449
|
+
for (const name of DEFAULT_PHASES) {
|
|
1450
|
+
const node = { name, isAutoGenerated: false };
|
|
1451
|
+
this.phases.push(node);
|
|
1452
|
+
this.phaseMap.set(name, node);
|
|
1348
1453
|
}
|
|
1349
1454
|
this.invalidateCache();
|
|
1350
1455
|
}
|
|
@@ -2230,132 +2335,445 @@ const _Scheduler = class _Scheduler {
|
|
|
2230
2335
|
console.error(`[Scheduler] Error in global job "${job.id}":`, error);
|
|
2231
2336
|
}
|
|
2232
2337
|
}
|
|
2233
|
-
}
|
|
2234
|
-
/**
|
|
2235
|
-
* Execute all jobs for a single root in sorted order.
|
|
2236
|
-
* Rebuilds sorted job list if needed, then dispatches each job.
|
|
2237
|
-
* Errors are caught and propagated via triggerError.
|
|
2238
|
-
* @param {RootEntry} root - The root entry to tick
|
|
2239
|
-
* @param {number} timestamp - RAF timestamp in milliseconds
|
|
2240
|
-
* @param {number} delta - Time since last frame in seconds
|
|
2241
|
-
* @returns {void}
|
|
2242
|
-
* @private
|
|
2243
|
-
*/
|
|
2244
|
-
tickRoot(root, timestamp, delta) {
|
|
2245
|
-
if (root.needsRebuild) {
|
|
2246
|
-
root.sortedJobs = rebuildSortedJobs(root.jobs, this.phaseGraph);
|
|
2247
|
-
root.needsRebuild = false;
|
|
2248
|
-
}
|
|
2249
|
-
const providedState = root.getState?.() ?? {};
|
|
2250
|
-
const frameState = {
|
|
2251
|
-
...providedState,
|
|
2252
|
-
time: timestamp,
|
|
2253
|
-
delta,
|
|
2254
|
-
elapsed: this.loopState.elapsedTime / 1e3,
|
|
2255
|
-
// Convert ms to seconds
|
|
2256
|
-
frame: this.loopState.frameCount
|
|
2257
|
-
};
|
|
2258
|
-
for (const job of root.sortedJobs) {
|
|
2259
|
-
if (!shouldRun(job, timestamp)) continue;
|
|
2260
|
-
try {
|
|
2261
|
-
job.callback(frameState, delta);
|
|
2262
|
-
} catch (error) {
|
|
2263
|
-
console.error(`[Scheduler] Error in job "${job.id}":`, error);
|
|
2264
|
-
this.triggerError(error instanceof Error ? error : new Error(String(error)));
|
|
2338
|
+
}
|
|
2339
|
+
/**
|
|
2340
|
+
* Execute all jobs for a single root in sorted order.
|
|
2341
|
+
* Rebuilds sorted job list if needed, then dispatches each job.
|
|
2342
|
+
* Errors are caught and propagated via triggerError.
|
|
2343
|
+
* @param {RootEntry} root - The root entry to tick
|
|
2344
|
+
* @param {number} timestamp - RAF timestamp in milliseconds
|
|
2345
|
+
* @param {number} delta - Time since last frame in seconds
|
|
2346
|
+
* @returns {void}
|
|
2347
|
+
* @private
|
|
2348
|
+
*/
|
|
2349
|
+
tickRoot(root, timestamp, delta) {
|
|
2350
|
+
if (root.needsRebuild) {
|
|
2351
|
+
root.sortedJobs = rebuildSortedJobs(root.jobs, this.phaseGraph);
|
|
2352
|
+
root.needsRebuild = false;
|
|
2353
|
+
}
|
|
2354
|
+
const providedState = root.getState?.() ?? {};
|
|
2355
|
+
const frameState = {
|
|
2356
|
+
...providedState,
|
|
2357
|
+
time: timestamp,
|
|
2358
|
+
delta,
|
|
2359
|
+
elapsed: this.loopState.elapsedTime / 1e3,
|
|
2360
|
+
// Convert ms to seconds
|
|
2361
|
+
frame: this.loopState.frameCount
|
|
2362
|
+
};
|
|
2363
|
+
for (const job of root.sortedJobs) {
|
|
2364
|
+
if (!shouldRun(job, timestamp)) continue;
|
|
2365
|
+
try {
|
|
2366
|
+
job.callback(frameState, delta);
|
|
2367
|
+
} catch (error) {
|
|
2368
|
+
console.error(`[Scheduler] Error in job "${job.id}":`, error);
|
|
2369
|
+
this.triggerError(error instanceof Error ? error : new Error(String(error)));
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
//* Debug & Inspection Methods ================================
|
|
2374
|
+
/**
|
|
2375
|
+
* Get the total number of registered jobs across all roots.
|
|
2376
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2377
|
+
* @returns {number} Total job count
|
|
2378
|
+
*/
|
|
2379
|
+
getJobCount() {
|
|
2380
|
+
let count = 0;
|
|
2381
|
+
for (const root of this.roots.values()) {
|
|
2382
|
+
count += root.jobs.size;
|
|
2383
|
+
}
|
|
2384
|
+
return count + this.globalBeforeJobs.size + this.globalAfterJobs.size;
|
|
2385
|
+
}
|
|
2386
|
+
/**
|
|
2387
|
+
* Get all registered job IDs across all roots.
|
|
2388
|
+
* Includes both per-root jobs and global before/after jobs.
|
|
2389
|
+
* @returns {string[]} Array of all job IDs
|
|
2390
|
+
*/
|
|
2391
|
+
getJobIds() {
|
|
2392
|
+
const ids = [];
|
|
2393
|
+
for (const root of this.roots.values()) {
|
|
2394
|
+
ids.push(...root.jobs.keys());
|
|
2395
|
+
}
|
|
2396
|
+
ids.push(...this.globalBeforeJobs.keys());
|
|
2397
|
+
ids.push(...this.globalAfterJobs.keys());
|
|
2398
|
+
return ids;
|
|
2399
|
+
}
|
|
2400
|
+
/**
|
|
2401
|
+
* Get the number of registered roots (Canvas instances).
|
|
2402
|
+
* @returns {number} Number of registered roots
|
|
2403
|
+
*/
|
|
2404
|
+
getRootCount() {
|
|
2405
|
+
return this.roots.size;
|
|
2406
|
+
}
|
|
2407
|
+
/**
|
|
2408
|
+
* Check if any user (non-system) jobs are registered in a specific phase.
|
|
2409
|
+
* Used by the default render job to know if a user has taken over rendering.
|
|
2410
|
+
*
|
|
2411
|
+
* @param phase The phase to check
|
|
2412
|
+
* @param rootId Optional root ID to check (checks all roots if not provided)
|
|
2413
|
+
* @returns true if any user jobs exist in the phase
|
|
2414
|
+
*/
|
|
2415
|
+
hasUserJobsInPhase(phase, rootId) {
|
|
2416
|
+
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2417
|
+
return rootsToCheck.some((root) => {
|
|
2418
|
+
if (!root) return false;
|
|
2419
|
+
for (const job of root.jobs.values()) {
|
|
2420
|
+
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2421
|
+
}
|
|
2422
|
+
return false;
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
//* Utility Methods ================================
|
|
2426
|
+
/**
|
|
2427
|
+
* Generate a unique root ID for automatic root registration.
|
|
2428
|
+
* @returns {string} A unique root ID in the format 'root_N'
|
|
2429
|
+
*/
|
|
2430
|
+
generateRootId() {
|
|
2431
|
+
return `root_${this.nextRootIndex++}`;
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Generate a unique job ID.
|
|
2435
|
+
* @returns {string} A unique job ID in the format 'job_N'
|
|
2436
|
+
* @private
|
|
2437
|
+
*/
|
|
2438
|
+
generateJobId() {
|
|
2439
|
+
return `job_${this.nextJobIndex}`;
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* Normalize before/after constraints to a Set.
|
|
2443
|
+
* Handles undefined, single string, or array inputs.
|
|
2444
|
+
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2445
|
+
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2446
|
+
* @private
|
|
2447
|
+
*/
|
|
2448
|
+
normalizeConstraints(value) {
|
|
2449
|
+
if (!value) return /* @__PURE__ */ new Set();
|
|
2450
|
+
if (Array.isArray(value)) return new Set(value);
|
|
2451
|
+
return /* @__PURE__ */ new Set([value]);
|
|
2452
|
+
}
|
|
2453
|
+
};
|
|
2454
|
+
//* Static State & Methods (Singleton Usage) ================================
|
|
2455
|
+
//* Cross-Bundle Singleton Key ==============================
|
|
2456
|
+
// Use Symbol.for() to ensure scheduler is shared across bundle boundaries
|
|
2457
|
+
// This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
|
|
2458
|
+
__publicField(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
|
|
2459
|
+
let Scheduler = _Scheduler;
|
|
2460
|
+
const getScheduler = () => Scheduler.get();
|
|
2461
|
+
if (hmrData) {
|
|
2462
|
+
hmrData.accept?.();
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
const R3F_CONTEXT = Symbol.for("@react-three/fiber.context");
|
|
2466
|
+
const context = globalThis[R3F_CONTEXT] ?? (globalThis[R3F_CONTEXT] = React.createContext(null));
|
|
2467
|
+
const createStore = (invalidate, advance) => {
|
|
2468
|
+
const rootStore = createWithEqualityFn((set, get) => {
|
|
2469
|
+
const position = new Vector3();
|
|
2470
|
+
const defaultTarget = new Vector3();
|
|
2471
|
+
const tempTarget = new Vector3();
|
|
2472
|
+
function getCurrentViewport(camera = get().camera, target = defaultTarget, size = get().size) {
|
|
2473
|
+
const { width, height, top, left } = size;
|
|
2474
|
+
const aspect = width / height;
|
|
2475
|
+
if (target.isVector3) tempTarget.copy(target);
|
|
2476
|
+
else tempTarget.set(...target);
|
|
2477
|
+
const distance = camera.getWorldPosition(position).distanceTo(tempTarget);
|
|
2478
|
+
if (isOrthographicCamera(camera)) {
|
|
2479
|
+
return { width: width / camera.zoom, height: height / camera.zoom, top, left, factor: 1, distance, aspect };
|
|
2480
|
+
} else {
|
|
2481
|
+
const fov = camera.fov * Math.PI / 180;
|
|
2482
|
+
const h = 2 * Math.tan(fov / 2) * distance;
|
|
2483
|
+
const w = h * (width / height);
|
|
2484
|
+
return { width: w, height: h, top, left, factor: width / w, distance, aspect };
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
let performanceTimeout = void 0;
|
|
2488
|
+
const setPerformanceCurrent = (current) => set((state2) => ({ performance: { ...state2.performance, current } }));
|
|
2489
|
+
const pointer = new Vector2();
|
|
2490
|
+
const rootState = {
|
|
2491
|
+
set,
|
|
2492
|
+
get,
|
|
2493
|
+
// Mock objects that have to be configured
|
|
2494
|
+
// primaryStore is set after store creation (self-reference for primary, primary's store for secondary)
|
|
2495
|
+
primaryStore: null,
|
|
2496
|
+
gl: null,
|
|
2497
|
+
renderer: null,
|
|
2498
|
+
camera: null,
|
|
2499
|
+
frustum: new Frustum(),
|
|
2500
|
+
autoUpdateFrustum: true,
|
|
2501
|
+
raycaster: null,
|
|
2502
|
+
events: { priority: 1, enabled: true, connected: false },
|
|
2503
|
+
scene: null,
|
|
2504
|
+
rootScene: null,
|
|
2505
|
+
xr: null,
|
|
2506
|
+
inspector: null,
|
|
2507
|
+
invalidate: (frames = 1, stackFrames = false) => invalidate(get(), frames, stackFrames),
|
|
2508
|
+
advance: (timestamp, runGlobalEffects) => advance(timestamp, runGlobalEffects, get()),
|
|
2509
|
+
textureColorSpace: SRGBColorSpace,
|
|
2510
|
+
isLegacy: false,
|
|
2511
|
+
webGPUSupported: false,
|
|
2512
|
+
isNative: false,
|
|
2513
|
+
controls: null,
|
|
2514
|
+
pointer,
|
|
2515
|
+
mouse: pointer,
|
|
2516
|
+
frameloop: "always",
|
|
2517
|
+
onPointerMissed: void 0,
|
|
2518
|
+
onDragOverMissed: void 0,
|
|
2519
|
+
onDropMissed: void 0,
|
|
2520
|
+
performance: {
|
|
2521
|
+
current: 1,
|
|
2522
|
+
min: 0.5,
|
|
2523
|
+
max: 1,
|
|
2524
|
+
debounce: 200,
|
|
2525
|
+
regress: () => {
|
|
2526
|
+
const state2 = get();
|
|
2527
|
+
if (performanceTimeout) clearTimeout(performanceTimeout);
|
|
2528
|
+
if (state2.performance.current !== state2.performance.min) setPerformanceCurrent(state2.performance.min);
|
|
2529
|
+
performanceTimeout = setTimeout(
|
|
2530
|
+
() => setPerformanceCurrent(get().performance.max),
|
|
2531
|
+
state2.performance.debounce
|
|
2532
|
+
);
|
|
2533
|
+
}
|
|
2534
|
+
},
|
|
2535
|
+
size: { width: 0, height: 0, top: 0, left: 0 },
|
|
2536
|
+
viewport: {
|
|
2537
|
+
initialDpr: 0,
|
|
2538
|
+
dpr: 0,
|
|
2539
|
+
width: 0,
|
|
2540
|
+
height: 0,
|
|
2541
|
+
top: 0,
|
|
2542
|
+
left: 0,
|
|
2543
|
+
aspect: 0,
|
|
2544
|
+
distance: 0,
|
|
2545
|
+
factor: 0,
|
|
2546
|
+
getCurrentViewport
|
|
2547
|
+
},
|
|
2548
|
+
setEvents: (events) => set((state2) => ({ ...state2, events: { ...state2.events, ...events } })),
|
|
2549
|
+
setSize: (width, height, top, left) => {
|
|
2550
|
+
const state2 = get();
|
|
2551
|
+
if (width === void 0) {
|
|
2552
|
+
set({ _sizeImperative: false });
|
|
2553
|
+
if (state2._sizeProps) {
|
|
2554
|
+
const { width: propW, height: propH } = state2._sizeProps;
|
|
2555
|
+
if (propW !== void 0 || propH !== void 0) {
|
|
2556
|
+
const currentSize = state2.size;
|
|
2557
|
+
const newSize = {
|
|
2558
|
+
width: propW ?? currentSize.width,
|
|
2559
|
+
height: propH ?? currentSize.height,
|
|
2560
|
+
top: currentSize.top,
|
|
2561
|
+
left: currentSize.left
|
|
2562
|
+
};
|
|
2563
|
+
set((s) => ({
|
|
2564
|
+
size: newSize,
|
|
2565
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
2566
|
+
}));
|
|
2567
|
+
getScheduler().invalidate();
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
const w = width;
|
|
2573
|
+
const h = height ?? width;
|
|
2574
|
+
const t = top ?? state2.size.top;
|
|
2575
|
+
const l = left ?? state2.size.left;
|
|
2576
|
+
const size = { width: w, height: h, top: t, left: l };
|
|
2577
|
+
set((s) => ({
|
|
2578
|
+
size,
|
|
2579
|
+
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
2580
|
+
_sizeImperative: true
|
|
2581
|
+
}));
|
|
2582
|
+
getScheduler().invalidate();
|
|
2583
|
+
},
|
|
2584
|
+
setDpr: (dpr) => set((state2) => {
|
|
2585
|
+
const resolved = calculateDpr(dpr);
|
|
2586
|
+
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
2587
|
+
}),
|
|
2588
|
+
setFrameloop: (frameloop = "always") => {
|
|
2589
|
+
set(() => ({ frameloop }));
|
|
2590
|
+
},
|
|
2591
|
+
setError: (error) => set(() => ({ error })),
|
|
2592
|
+
error: null,
|
|
2593
|
+
//* TSL State (managed via hooks: useUniforms, useNodes, useTextures, usePostProcessing) ==============================
|
|
2594
|
+
uniforms: {},
|
|
2595
|
+
nodes: {},
|
|
2596
|
+
textures: /* @__PURE__ */ new Map(),
|
|
2597
|
+
postProcessing: null,
|
|
2598
|
+
passes: {},
|
|
2599
|
+
_hmrVersion: 0,
|
|
2600
|
+
_sizeImperative: false,
|
|
2601
|
+
_sizeProps: null,
|
|
2602
|
+
previousRoot: void 0,
|
|
2603
|
+
internal: {
|
|
2604
|
+
// Events
|
|
2605
|
+
interaction: [],
|
|
2606
|
+
hovered: /* @__PURE__ */ new Map(),
|
|
2607
|
+
subscribers: [],
|
|
2608
|
+
initialClick: [0, 0],
|
|
2609
|
+
initialHits: [],
|
|
2610
|
+
capturedMap: /* @__PURE__ */ new Map(),
|
|
2611
|
+
lastEvent: React.createRef(),
|
|
2612
|
+
// Visibility tracking (onFramed, onOccluded, onVisible)
|
|
2613
|
+
visibilityRegistry: /* @__PURE__ */ new Map(),
|
|
2614
|
+
// Occlusion system (WebGPU only)
|
|
2615
|
+
occlusionEnabled: false,
|
|
2616
|
+
occlusionObserver: null,
|
|
2617
|
+
occlusionCache: /* @__PURE__ */ new Map(),
|
|
2618
|
+
helperGroup: null,
|
|
2619
|
+
// Updates
|
|
2620
|
+
active: false,
|
|
2621
|
+
frames: 0,
|
|
2622
|
+
priority: 0,
|
|
2623
|
+
subscribe: (ref, priority, store) => {
|
|
2624
|
+
const internal = get().internal;
|
|
2625
|
+
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
2626
|
+
internal.subscribers.push({ ref, priority, store });
|
|
2627
|
+
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
2628
|
+
return () => {
|
|
2629
|
+
const internal2 = get().internal;
|
|
2630
|
+
if (internal2?.subscribers) {
|
|
2631
|
+
internal2.priority = internal2.priority - (priority > 0 ? 1 : 0);
|
|
2632
|
+
internal2.subscribers = internal2.subscribers.filter((s) => s.ref !== ref);
|
|
2633
|
+
}
|
|
2634
|
+
};
|
|
2635
|
+
},
|
|
2636
|
+
// Renderer Storage (single source of truth)
|
|
2637
|
+
actualRenderer: null,
|
|
2638
|
+
// Scheduler for useFrameNext (initialized in renderer.tsx)
|
|
2639
|
+
scheduler: null
|
|
2640
|
+
}
|
|
2641
|
+
};
|
|
2642
|
+
return rootState;
|
|
2643
|
+
});
|
|
2644
|
+
const state = rootStore.getState();
|
|
2645
|
+
Object.defineProperty(state, "gl", {
|
|
2646
|
+
get() {
|
|
2647
|
+
const currentState = rootStore.getState();
|
|
2648
|
+
if (!currentState.isLegacy && currentState.internal.actualRenderer) {
|
|
2649
|
+
const stack = new Error().stack || "";
|
|
2650
|
+
const isInternalAccess = stack.includes("zustand") || stack.includes("setState") || stack.includes("Object.assign") || stack.includes("react-three-fiber/packages/fiber/src/core");
|
|
2651
|
+
if (!isInternalAccess) {
|
|
2652
|
+
const cleanedStack = stack.split("\n").slice(2).join("\n") || "Stack trace unavailable";
|
|
2653
|
+
notifyDepreciated({
|
|
2654
|
+
heading: "Accessing state.gl in WebGPU mode",
|
|
2655
|
+
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
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
return currentState.internal.actualRenderer;
|
|
2660
|
+
},
|
|
2661
|
+
set(value) {
|
|
2662
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2663
|
+
},
|
|
2664
|
+
enumerable: true,
|
|
2665
|
+
configurable: true
|
|
2666
|
+
});
|
|
2667
|
+
Object.defineProperty(state, "renderer", {
|
|
2668
|
+
get() {
|
|
2669
|
+
return rootStore.getState().internal.actualRenderer;
|
|
2670
|
+
},
|
|
2671
|
+
set(value) {
|
|
2672
|
+
rootStore.getState().internal.actualRenderer = value;
|
|
2673
|
+
},
|
|
2674
|
+
enumerable: true,
|
|
2675
|
+
configurable: true
|
|
2676
|
+
});
|
|
2677
|
+
let oldScene = state.scene;
|
|
2678
|
+
rootStore.subscribe(() => {
|
|
2679
|
+
const currentState = rootStore.getState();
|
|
2680
|
+
const { scene, rootScene, set } = currentState;
|
|
2681
|
+
if (scene !== oldScene) {
|
|
2682
|
+
oldScene = scene;
|
|
2683
|
+
if (scene?.isScene && scene !== rootScene) {
|
|
2684
|
+
set({ rootScene: scene });
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
});
|
|
2688
|
+
let oldSize = state.size;
|
|
2689
|
+
let oldDpr = state.viewport.dpr;
|
|
2690
|
+
let oldCamera = state.camera;
|
|
2691
|
+
rootStore.subscribe(() => {
|
|
2692
|
+
const { camera, size, viewport, set, internal } = rootStore.getState();
|
|
2693
|
+
const actualRenderer = internal.actualRenderer;
|
|
2694
|
+
const canvasTarget = internal.canvasTarget;
|
|
2695
|
+
if (size.width !== oldSize.width || size.height !== oldSize.height || viewport.dpr !== oldDpr) {
|
|
2696
|
+
oldSize = size;
|
|
2697
|
+
oldDpr = viewport.dpr;
|
|
2698
|
+
updateCamera(camera, size);
|
|
2699
|
+
if (canvasTarget) {
|
|
2700
|
+
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
2701
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && canvasTarget.domElement instanceof HTMLCanvasElement;
|
|
2702
|
+
canvasTarget.setSize(size.width, size.height, updateStyle);
|
|
2703
|
+
} else {
|
|
2704
|
+
if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
|
|
2705
|
+
const updateStyle = typeof HTMLCanvasElement !== "undefined" && actualRenderer.domElement instanceof HTMLCanvasElement;
|
|
2706
|
+
actualRenderer.setSize(size.width, size.height, updateStyle);
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
if (camera !== oldCamera) {
|
|
2710
|
+
oldCamera = camera;
|
|
2711
|
+
const { rootScene } = rootStore.getState();
|
|
2712
|
+
if (camera && rootScene && !camera.parent) {
|
|
2713
|
+
rootScene.add(camera);
|
|
2714
|
+
}
|
|
2715
|
+
set((state2) => ({ viewport: { ...state2.viewport, ...state2.viewport.getCurrentViewport(camera) } }));
|
|
2716
|
+
const currentState = rootStore.getState();
|
|
2717
|
+
if (currentState.autoUpdateFrustum && camera) {
|
|
2718
|
+
updateFrustum(camera, currentState.frustum);
|
|
2265
2719
|
}
|
|
2266
2720
|
}
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2721
|
+
});
|
|
2722
|
+
rootStore.subscribe((state2) => invalidate(state2));
|
|
2723
|
+
return rootStore;
|
|
2724
|
+
};
|
|
2725
|
+
|
|
2726
|
+
const memoizedLoaders = /* @__PURE__ */ new WeakMap();
|
|
2727
|
+
const isConstructor$1 = (value) => typeof value === "function" && value?.prototype?.constructor === value;
|
|
2728
|
+
function getLoader(Proto) {
|
|
2729
|
+
if (isConstructor$1(Proto)) {
|
|
2730
|
+
let loader = memoizedLoaders.get(Proto);
|
|
2731
|
+
if (!loader) {
|
|
2732
|
+
loader = new Proto();
|
|
2733
|
+
memoizedLoaders.set(Proto, loader);
|
|
2278
2734
|
}
|
|
2279
|
-
return
|
|
2735
|
+
return loader;
|
|
2280
2736
|
}
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2737
|
+
return Proto;
|
|
2738
|
+
}
|
|
2739
|
+
function loadingFn(extensions, onProgress) {
|
|
2740
|
+
return function(Proto, input) {
|
|
2741
|
+
const loader = getLoader(Proto);
|
|
2742
|
+
if (extensions) extensions(loader);
|
|
2743
|
+
if ("loadAsync" in loader && typeof loader.loadAsync === "function") {
|
|
2744
|
+
return loader.loadAsync(input, onProgress).then((data) => {
|
|
2745
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2746
|
+
return data;
|
|
2747
|
+
});
|
|
2290
2748
|
}
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
*/
|
|
2310
|
-
hasUserJobsInPhase(phase, rootId) {
|
|
2311
|
-
const rootsToCheck = rootId ? [this.roots.get(rootId)].filter(Boolean) : Array.from(this.roots.values());
|
|
2312
|
-
return rootsToCheck.some((root) => {
|
|
2313
|
-
if (!root) return false;
|
|
2314
|
-
for (const job of root.jobs.values()) {
|
|
2315
|
-
if (job.phase === phase && !job.system && job.enabled) return true;
|
|
2316
|
-
}
|
|
2317
|
-
return false;
|
|
2318
|
-
});
|
|
2319
|
-
}
|
|
2320
|
-
//* Utility Methods ================================
|
|
2321
|
-
/**
|
|
2322
|
-
* Generate a unique root ID for automatic root registration.
|
|
2323
|
-
* @returns {string} A unique root ID in the format 'root_N'
|
|
2324
|
-
*/
|
|
2325
|
-
generateRootId() {
|
|
2326
|
-
return `root_${this.nextRootIndex++}`;
|
|
2327
|
-
}
|
|
2328
|
-
/**
|
|
2329
|
-
* Generate a unique job ID.
|
|
2330
|
-
* @returns {string} A unique job ID in the format 'job_N'
|
|
2331
|
-
* @private
|
|
2332
|
-
*/
|
|
2333
|
-
generateJobId() {
|
|
2334
|
-
return `job_${this.nextJobIndex}`;
|
|
2335
|
-
}
|
|
2336
|
-
/**
|
|
2337
|
-
* Normalize before/after constraints to a Set.
|
|
2338
|
-
* Handles undefined, single string, or array inputs.
|
|
2339
|
-
* @param {string | string[] | undefined} value - The constraint value(s)
|
|
2340
|
-
* @returns {Set<string>} Normalized Set of constraint strings
|
|
2341
|
-
* @private
|
|
2342
|
-
*/
|
|
2343
|
-
normalizeConstraints(value) {
|
|
2344
|
-
if (!value) return /* @__PURE__ */ new Set();
|
|
2345
|
-
if (Array.isArray(value)) return new Set(value);
|
|
2346
|
-
return /* @__PURE__ */ new Set([value]);
|
|
2347
|
-
}
|
|
2348
|
-
};
|
|
2349
|
-
//* Static State & Methods (Singleton Usage) ================================
|
|
2350
|
-
//* Cross-Bundle Singleton Key ==============================
|
|
2351
|
-
// Use Symbol.for() to ensure scheduler is shared across bundle boundaries
|
|
2352
|
-
// This prevents issues when mixing imports from @react-three/fiber and @react-three/fiber/webgpu
|
|
2353
|
-
__publicField(_Scheduler, "INSTANCE_KEY", Symbol.for("@react-three/fiber.scheduler"));
|
|
2354
|
-
let Scheduler = _Scheduler;
|
|
2355
|
-
const getScheduler = () => Scheduler.get();
|
|
2356
|
-
if (hmrData) {
|
|
2357
|
-
hmrData.accept?.();
|
|
2749
|
+
return new Promise(
|
|
2750
|
+
(res, reject) => loader.load(
|
|
2751
|
+
input,
|
|
2752
|
+
(data) => {
|
|
2753
|
+
if (isObject3D(data?.scene)) Object.assign(data, buildGraph(data.scene));
|
|
2754
|
+
res(data);
|
|
2755
|
+
},
|
|
2756
|
+
onProgress,
|
|
2757
|
+
(error) => reject(new Error(`Could not load ${input}: ${error?.message}`))
|
|
2758
|
+
)
|
|
2759
|
+
);
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
function useLoader(loader, input, extensions, onProgress) {
|
|
2763
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2764
|
+
const fn = loadingFn(extensions, onProgress);
|
|
2765
|
+
const results = keys.map((key) => suspend(fn, [loader, key], { equal: is.equ }));
|
|
2766
|
+
return Array.isArray(input) ? results : results[0];
|
|
2358
2767
|
}
|
|
2768
|
+
useLoader.preload = function(loader, input, extensions, onProgress) {
|
|
2769
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2770
|
+
keys.forEach((key) => preload(loadingFn(extensions, onProgress), [loader, key]));
|
|
2771
|
+
};
|
|
2772
|
+
useLoader.clear = function(loader, input) {
|
|
2773
|
+
const keys = Array.isArray(input) ? input : [input];
|
|
2774
|
+
keys.forEach((key) => clear([loader, key]));
|
|
2775
|
+
};
|
|
2776
|
+
useLoader.loader = getLoader;
|
|
2359
2777
|
|
|
2360
2778
|
function useFrame(callback, priorityOrOptions) {
|
|
2361
2779
|
const store = React.useContext(context);
|
|
@@ -2536,6 +2954,9 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2536
2954
|
const textureCache = useThree((state) => state.textures);
|
|
2537
2955
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
2538
2956
|
const { onLoad, cache = false } = options;
|
|
2957
|
+
const onLoadRef = useRef(onLoad);
|
|
2958
|
+
onLoadRef.current = onLoad;
|
|
2959
|
+
const onLoadCalledForRef = useRef(null);
|
|
2539
2960
|
const urls = useMemo(() => getUrls(input), [input]);
|
|
2540
2961
|
const cachedResult = useMemo(() => {
|
|
2541
2962
|
if (!cache) return null;
|
|
@@ -2546,9 +2967,13 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
2546
2967
|
TextureLoader,
|
|
2547
2968
|
IsObject(input) ? Object.values(input) : input
|
|
2548
2969
|
);
|
|
2970
|
+
const inputKey = urls.join("\0");
|
|
2549
2971
|
useLayoutEffect(() => {
|
|
2550
|
-
if (
|
|
2551
|
-
|
|
2972
|
+
if (cachedResult) return;
|
|
2973
|
+
if (onLoadCalledForRef.current === inputKey) return;
|
|
2974
|
+
onLoadCalledForRef.current = inputKey;
|
|
2975
|
+
onLoadRef.current?.(loadedTextures);
|
|
2976
|
+
}, [cachedResult, loadedTextures, inputKey]);
|
|
2552
2977
|
useEffect(() => {
|
|
2553
2978
|
if (cachedResult) return;
|
|
2554
2979
|
if ("initTexture" in renderer) {
|
|
@@ -2715,16 +3140,33 @@ function useTextures() {
|
|
|
2715
3140
|
}, [store]);
|
|
2716
3141
|
}
|
|
2717
3142
|
|
|
2718
|
-
function useRenderTarget(
|
|
3143
|
+
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
2719
3144
|
const isLegacy = useThree((s) => s.isLegacy);
|
|
2720
3145
|
const size = useThree((s) => s.size);
|
|
3146
|
+
let width;
|
|
3147
|
+
let height;
|
|
3148
|
+
let opts;
|
|
3149
|
+
if (typeof widthOrOptions === "object") {
|
|
3150
|
+
opts = widthOrOptions;
|
|
3151
|
+
} else if (typeof widthOrOptions === "number") {
|
|
3152
|
+
width = widthOrOptions;
|
|
3153
|
+
if (typeof heightOrOptions === "object") {
|
|
3154
|
+
height = widthOrOptions;
|
|
3155
|
+
opts = heightOrOptions;
|
|
3156
|
+
} else if (typeof heightOrOptions === "number") {
|
|
3157
|
+
height = heightOrOptions;
|
|
3158
|
+
opts = options;
|
|
3159
|
+
} else {
|
|
3160
|
+
height = widthOrOptions;
|
|
3161
|
+
}
|
|
3162
|
+
}
|
|
2721
3163
|
return useMemo(() => {
|
|
2722
3164
|
const w = width ?? size.width;
|
|
2723
3165
|
const h = height ?? size.height;
|
|
2724
3166
|
{
|
|
2725
|
-
return isLegacy ? new WebGLRenderTarget(w, h,
|
|
3167
|
+
return isLegacy ? new WebGLRenderTarget(w, h, opts) : new RenderTarget(w, h, opts);
|
|
2726
3168
|
}
|
|
2727
|
-
}, [width, height, size.width, size.height,
|
|
3169
|
+
}, [width, height, size.width, size.height, opts, isLegacy]);
|
|
2728
3170
|
}
|
|
2729
3171
|
|
|
2730
3172
|
function useStore() {
|
|
@@ -2774,7 +3216,7 @@ function addTail(callback) {
|
|
|
2774
3216
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
2775
3217
|
getScheduler().invalidate(frames, stackFrames);
|
|
2776
3218
|
}
|
|
2777
|
-
function advance(timestamp
|
|
3219
|
+
function advance(timestamp) {
|
|
2778
3220
|
getScheduler().step(timestamp);
|
|
2779
3221
|
}
|
|
2780
3222
|
|
|
@@ -14228,6 +14670,7 @@ function swapInstances() {
|
|
|
14228
14670
|
instance.object = instance.props.object ?? new target(...instance.props.args ?? []);
|
|
14229
14671
|
instance.object.__r3f = instance;
|
|
14230
14672
|
setFiberRef(fiber, instance.object);
|
|
14673
|
+
delete instance.appliedOnce;
|
|
14231
14674
|
applyProps(instance.object, instance.props);
|
|
14232
14675
|
if (instance.props.attach) {
|
|
14233
14676
|
attach(parent, instance);
|
|
@@ -14301,8 +14744,22 @@ const reconciler = /* @__PURE__ */ createReconciler({
|
|
|
14301
14744
|
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
14302
14745
|
if (isTailSibling) swapInstances();
|
|
14303
14746
|
},
|
|
14304
|
-
finalizeInitialChildren: () =>
|
|
14305
|
-
|
|
14747
|
+
finalizeInitialChildren: (instance) => {
|
|
14748
|
+
for (const prop in instance.props) {
|
|
14749
|
+
if (isFromRef(instance.props[prop])) return true;
|
|
14750
|
+
}
|
|
14751
|
+
return false;
|
|
14752
|
+
},
|
|
14753
|
+
commitMount(instance) {
|
|
14754
|
+
const resolved = {};
|
|
14755
|
+
for (const prop in instance.props) {
|
|
14756
|
+
const value = instance.props[prop];
|
|
14757
|
+
if (isFromRef(value)) {
|
|
14758
|
+
const ref = value[FROM_REF];
|
|
14759
|
+
if (ref.current != null) resolved[prop] = ref.current;
|
|
14760
|
+
}
|
|
14761
|
+
}
|
|
14762
|
+
if (Object.keys(resolved).length) applyProps(instance.object, resolved);
|
|
14306
14763
|
},
|
|
14307
14764
|
getPublicInstance: (instance) => instance?.object,
|
|
14308
14765
|
prepareForCommit: () => null,
|
|
@@ -14523,6 +14980,9 @@ function createRoot(canvas) {
|
|
|
14523
14980
|
let resolve;
|
|
14524
14981
|
pending = new Promise((_resolve) => resolve = _resolve);
|
|
14525
14982
|
const {
|
|
14983
|
+
id: canvasId,
|
|
14984
|
+
primaryCanvas,
|
|
14985
|
+
scheduler: schedulerConfig,
|
|
14526
14986
|
gl: glConfig,
|
|
14527
14987
|
renderer: rendererConfig,
|
|
14528
14988
|
size: propsSize,
|
|
@@ -14530,10 +14990,7 @@ function createRoot(canvas) {
|
|
|
14530
14990
|
events,
|
|
14531
14991
|
onCreated: onCreatedCallback,
|
|
14532
14992
|
shadows = false,
|
|
14533
|
-
linear = false,
|
|
14534
|
-
flat = false,
|
|
14535
14993
|
textureColorSpace = SRGBColorSpace,
|
|
14536
|
-
legacy = false,
|
|
14537
14994
|
orthographic = false,
|
|
14538
14995
|
frameloop = "always",
|
|
14539
14996
|
dpr = [1, 2],
|
|
@@ -14545,7 +15002,8 @@ function createRoot(canvas) {
|
|
|
14545
15002
|
onDropMissed,
|
|
14546
15003
|
autoUpdateFrustum = true,
|
|
14547
15004
|
occlusion = false,
|
|
14548
|
-
_sizeProps
|
|
15005
|
+
_sizeProps,
|
|
15006
|
+
forceEven
|
|
14549
15007
|
} = props;
|
|
14550
15008
|
const state = store.getState();
|
|
14551
15009
|
const defaultGLProps = {
|
|
@@ -14555,7 +15013,8 @@ function createRoot(canvas) {
|
|
|
14555
15013
|
alpha: true
|
|
14556
15014
|
};
|
|
14557
15015
|
const defaultGPUProps = {
|
|
14558
|
-
canvas
|
|
15016
|
+
canvas,
|
|
15017
|
+
antialias: true
|
|
14559
15018
|
};
|
|
14560
15019
|
const wantsGL = (state.isLegacy || glConfig || !R3F_BUILD_WEBGPU || !rendererConfig);
|
|
14561
15020
|
if (glConfig && rendererConfig) {
|
|
@@ -14569,10 +15028,35 @@ function createRoot(canvas) {
|
|
|
14569
15028
|
});
|
|
14570
15029
|
}
|
|
14571
15030
|
let renderer = state.internal.actualRenderer;
|
|
15031
|
+
if (primaryCanvas && wantsGL) {
|
|
15032
|
+
throw new Error(
|
|
15033
|
+
"The `primaryCanvas` prop for multi-canvas rendering cannot be used with WebGL. Remove the `gl` prop or use WebGPU."
|
|
15034
|
+
);
|
|
15035
|
+
}
|
|
14572
15036
|
if (wantsGL && !state.internal.actualRenderer) {
|
|
14573
15037
|
renderer = await resolveRenderer(glConfig, defaultGLProps, WebGLRenderer);
|
|
14574
15038
|
state.internal.actualRenderer = renderer;
|
|
14575
|
-
state.set({ isLegacy: true, gl: renderer, renderer });
|
|
15039
|
+
state.set({ isLegacy: true, gl: renderer, renderer, primaryStore: store });
|
|
15040
|
+
} else if (!wantsGL && primaryCanvas && !state.internal.actualRenderer) {
|
|
15041
|
+
const primary = await waitForPrimary(primaryCanvas);
|
|
15042
|
+
renderer = primary.renderer;
|
|
15043
|
+
state.internal.actualRenderer = renderer;
|
|
15044
|
+
const canvasTarget = new CanvasTarget(canvas);
|
|
15045
|
+
primary.store.setState((prev) => ({
|
|
15046
|
+
internal: { ...prev.internal, isMultiCanvas: true }
|
|
15047
|
+
}));
|
|
15048
|
+
state.set((prev) => ({
|
|
15049
|
+
webGPUSupported: primary.store.getState().webGPUSupported,
|
|
15050
|
+
renderer,
|
|
15051
|
+
primaryStore: primary.store,
|
|
15052
|
+
internal: {
|
|
15053
|
+
...prev.internal,
|
|
15054
|
+
canvasTarget,
|
|
15055
|
+
isMultiCanvas: true,
|
|
15056
|
+
isSecondary: true,
|
|
15057
|
+
targetId: primaryCanvas
|
|
15058
|
+
}
|
|
15059
|
+
}));
|
|
14576
15060
|
} else if (!wantsGL && !state.internal.actualRenderer) {
|
|
14577
15061
|
renderer = await resolveRenderer(rendererConfig, defaultGPUProps, WebGPURenderer);
|
|
14578
15062
|
if (!renderer.hasInitialized?.()) {
|
|
@@ -14581,7 +15065,18 @@ function createRoot(canvas) {
|
|
|
14581
15065
|
const backend = renderer.backend;
|
|
14582
15066
|
const isWebGPUBackend = backend && "isWebGPUBackend" in backend;
|
|
14583
15067
|
state.internal.actualRenderer = renderer;
|
|
14584
|
-
state.set({ webGPUSupported: isWebGPUBackend, renderer });
|
|
15068
|
+
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
15069
|
+
if (canvasId && !state.internal.isSecondary) {
|
|
15070
|
+
const canvasTarget = new CanvasTarget(canvas);
|
|
15071
|
+
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
15072
|
+
state.set((prev) => ({
|
|
15073
|
+
internal: {
|
|
15074
|
+
...prev.internal,
|
|
15075
|
+
canvasTarget,
|
|
15076
|
+
unregisterPrimary
|
|
15077
|
+
}
|
|
15078
|
+
}));
|
|
15079
|
+
}
|
|
14585
15080
|
}
|
|
14586
15081
|
let raycaster = state.raycaster;
|
|
14587
15082
|
if (!raycaster) state.set({ raycaster: raycaster = new Raycaster() });
|
|
@@ -14590,6 +15085,7 @@ function createRoot(canvas) {
|
|
|
14590
15085
|
if (!is.equ(params, raycaster.params, shallowLoose)) {
|
|
14591
15086
|
applyProps(raycaster, { params: { ...raycaster.params, ...params } });
|
|
14592
15087
|
}
|
|
15088
|
+
let tempCamera = state.camera;
|
|
14593
15089
|
if (!state.camera || state.camera === lastCamera && !is.equ(lastCamera, cameraOptions, shallowLoose)) {
|
|
14594
15090
|
lastCamera = cameraOptions;
|
|
14595
15091
|
const isCamera = cameraOptions?.isCamera;
|
|
@@ -14609,6 +15105,7 @@ function createRoot(canvas) {
|
|
|
14609
15105
|
if (!state.camera && !cameraOptions?.rotation) camera.lookAt(0, 0, 0);
|
|
14610
15106
|
}
|
|
14611
15107
|
state.set({ camera });
|
|
15108
|
+
tempCamera = camera;
|
|
14612
15109
|
raycaster.camera = camera;
|
|
14613
15110
|
}
|
|
14614
15111
|
if (!state.scene) {
|
|
@@ -14626,7 +15123,7 @@ function createRoot(canvas) {
|
|
|
14626
15123
|
rootScene: scene,
|
|
14627
15124
|
internal: { ...prev.internal, container: scene }
|
|
14628
15125
|
}));
|
|
14629
|
-
const camera =
|
|
15126
|
+
const camera = tempCamera;
|
|
14630
15127
|
if (camera && !camera.parent) scene.add(camera);
|
|
14631
15128
|
}
|
|
14632
15129
|
if (events && !state.events.handlers) {
|
|
@@ -14643,6 +15140,9 @@ function createRoot(canvas) {
|
|
|
14643
15140
|
if (_sizeProps !== void 0) {
|
|
14644
15141
|
state.set({ _sizeProps });
|
|
14645
15142
|
}
|
|
15143
|
+
if (forceEven !== void 0 && state.internal.forceEven !== forceEven) {
|
|
15144
|
+
state.set((prev) => ({ internal: { ...prev.internal, forceEven } }));
|
|
15145
|
+
}
|
|
14646
15146
|
const size = computeInitialSize(canvas, propsSize);
|
|
14647
15147
|
if (!state._sizeImperative && !is.equ(size, state.size, shallowLoose)) {
|
|
14648
15148
|
const wasImperative = state._sizeImperative;
|
|
@@ -14672,7 +15172,7 @@ function createRoot(canvas) {
|
|
|
14672
15172
|
const handleXRFrame = (timestamp, frame) => {
|
|
14673
15173
|
const state2 = store.getState();
|
|
14674
15174
|
if (state2.frameloop === "never") return;
|
|
14675
|
-
advance(timestamp
|
|
15175
|
+
advance(timestamp);
|
|
14676
15176
|
};
|
|
14677
15177
|
const actualRenderer = state.internal.actualRenderer;
|
|
14678
15178
|
const handleSessionChange = () => {
|
|
@@ -14684,16 +15184,16 @@ function createRoot(canvas) {
|
|
|
14684
15184
|
};
|
|
14685
15185
|
const xr = {
|
|
14686
15186
|
connect() {
|
|
14687
|
-
const { gl, renderer: renderer2
|
|
14688
|
-
const
|
|
14689
|
-
|
|
14690
|
-
|
|
15187
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15188
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15189
|
+
xrManager.addEventListener("sessionstart", handleSessionChange);
|
|
15190
|
+
xrManager.addEventListener("sessionend", handleSessionChange);
|
|
14691
15191
|
},
|
|
14692
15192
|
disconnect() {
|
|
14693
|
-
const { gl, renderer: renderer2
|
|
14694
|
-
const
|
|
14695
|
-
|
|
14696
|
-
|
|
15193
|
+
const { gl, renderer: renderer2 } = store.getState();
|
|
15194
|
+
const xrManager = (renderer2 || gl).xr;
|
|
15195
|
+
xrManager.removeEventListener("sessionstart", handleSessionChange);
|
|
15196
|
+
xrManager.removeEventListener("sessionend", handleSessionChange);
|
|
14697
15197
|
}
|
|
14698
15198
|
};
|
|
14699
15199
|
if (typeof renderer.xr?.addEventListener === "function") xr.connect();
|
|
@@ -14721,34 +15221,9 @@ function createRoot(canvas) {
|
|
|
14721
15221
|
renderer.shadowMap.needsUpdate = true;
|
|
14722
15222
|
}
|
|
14723
15223
|
}
|
|
14724
|
-
{
|
|
14725
|
-
|
|
14726
|
-
|
|
14727
|
-
const flatChanged = flat !== lastConfiguredProps.flat;
|
|
14728
|
-
if (legacyChanged) {
|
|
14729
|
-
if (legacy) {
|
|
14730
|
-
notifyDepreciated({
|
|
14731
|
-
heading: "Legacy Color Management",
|
|
14732
|
-
body: "Legacy color management is deprecated and will be removed in a future version.",
|
|
14733
|
-
link: "https://docs.pmnd.rs/react-three-fiber/api/hooks#useframe"
|
|
14734
|
-
});
|
|
14735
|
-
}
|
|
14736
|
-
}
|
|
14737
|
-
if (legacyChanged) {
|
|
14738
|
-
ColorManagement.enabled = !legacy;
|
|
14739
|
-
lastConfiguredProps.legacy = legacy;
|
|
14740
|
-
}
|
|
14741
|
-
if (!configured || linearChanged) {
|
|
14742
|
-
renderer.outputColorSpace = linear ? LinearSRGBColorSpace : SRGBColorSpace;
|
|
14743
|
-
lastConfiguredProps.linear = linear;
|
|
14744
|
-
}
|
|
14745
|
-
if (!configured || flatChanged) {
|
|
14746
|
-
renderer.toneMapping = flat ? NoToneMapping : ACESFilmicToneMapping;
|
|
14747
|
-
lastConfiguredProps.flat = flat;
|
|
14748
|
-
}
|
|
14749
|
-
if (legacyChanged && state.legacy !== legacy) state.set(() => ({ legacy }));
|
|
14750
|
-
if (linearChanged && state.linear !== linear) state.set(() => ({ linear }));
|
|
14751
|
-
if (flatChanged && state.flat !== flat) state.set(() => ({ flat }));
|
|
15224
|
+
if (!configured) {
|
|
15225
|
+
renderer.outputColorSpace = SRGBColorSpace;
|
|
15226
|
+
renderer.toneMapping = ACESFilmicToneMapping;
|
|
14752
15227
|
}
|
|
14753
15228
|
if (textureColorSpace !== lastConfiguredProps.textureColorSpace) {
|
|
14754
15229
|
if (state.textureColorSpace !== textureColorSpace) state.set(() => ({ textureColorSpace }));
|
|
@@ -14766,11 +15241,26 @@ function createRoot(canvas) {
|
|
|
14766
15241
|
const scheduler = getScheduler();
|
|
14767
15242
|
const rootId = state.internal.rootId;
|
|
14768
15243
|
if (!rootId) {
|
|
14769
|
-
const newRootId = scheduler.generateRootId();
|
|
15244
|
+
const newRootId = canvasId || scheduler.generateRootId();
|
|
14770
15245
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14771
15246
|
getState: () => store.getState(),
|
|
14772
15247
|
onError: (err) => store.getState().setError(err)
|
|
14773
15248
|
});
|
|
15249
|
+
const unregisterCanvasTarget = scheduler.register(
|
|
15250
|
+
() => {
|
|
15251
|
+
const state2 = store.getState();
|
|
15252
|
+
if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
|
|
15253
|
+
const renderer2 = state2.internal.actualRenderer;
|
|
15254
|
+
renderer2.setCanvasTarget(state2.internal.canvasTarget);
|
|
15255
|
+
}
|
|
15256
|
+
},
|
|
15257
|
+
{
|
|
15258
|
+
id: `${newRootId}_canvasTarget`,
|
|
15259
|
+
rootId: newRootId,
|
|
15260
|
+
phase: "start",
|
|
15261
|
+
system: true
|
|
15262
|
+
}
|
|
15263
|
+
);
|
|
14774
15264
|
const unregisterFrustum = scheduler.register(
|
|
14775
15265
|
() => {
|
|
14776
15266
|
const state2 = store.getState();
|
|
@@ -14812,11 +15302,15 @@ function createRoot(canvas) {
|
|
|
14812
15302
|
}
|
|
14813
15303
|
},
|
|
14814
15304
|
{
|
|
14815
|
-
|
|
15305
|
+
// Use canvas ID directly as job ID if available, otherwise use generated rootId
|
|
15306
|
+
id: canvasId || `${newRootId}_render`,
|
|
14816
15307
|
rootId: newRootId,
|
|
14817
15308
|
phase: "render",
|
|
14818
|
-
system: true
|
|
15309
|
+
system: true,
|
|
14819
15310
|
// Internal flag: this is a system job, not user-controlled
|
|
15311
|
+
// Apply scheduler config for render ordering and rate limiting
|
|
15312
|
+
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
15313
|
+
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14820
15314
|
}
|
|
14821
15315
|
);
|
|
14822
15316
|
state.set((state2) => ({
|
|
@@ -14825,6 +15319,7 @@ function createRoot(canvas) {
|
|
|
14825
15319
|
rootId: newRootId,
|
|
14826
15320
|
unregisterRoot: () => {
|
|
14827
15321
|
unregisterRoot();
|
|
15322
|
+
unregisterCanvasTarget();
|
|
14828
15323
|
unregisterFrustum();
|
|
14829
15324
|
unregisterVisibility();
|
|
14830
15325
|
unregisterRender();
|
|
@@ -14883,15 +15378,24 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14883
15378
|
const renderer = state.internal.actualRenderer;
|
|
14884
15379
|
const unregisterRoot = state.internal.unregisterRoot;
|
|
14885
15380
|
if (unregisterRoot) unregisterRoot();
|
|
15381
|
+
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
15382
|
+
if (unregisterPrimary) unregisterPrimary();
|
|
15383
|
+
const canvasTarget = state.internal.canvasTarget;
|
|
15384
|
+
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14886
15385
|
state.events.disconnect?.();
|
|
14887
15386
|
cleanupHelperGroup(root.store);
|
|
14888
|
-
renderer
|
|
14889
|
-
|
|
14890
|
-
|
|
15387
|
+
if (state.isLegacy && renderer) {
|
|
15388
|
+
;
|
|
15389
|
+
renderer.renderLists?.dispose?.();
|
|
15390
|
+
renderer.forceContextLoss?.();
|
|
15391
|
+
}
|
|
15392
|
+
if (!state.internal.isSecondary) {
|
|
15393
|
+
if (renderer?.xr) state.xr.disconnect();
|
|
15394
|
+
}
|
|
14891
15395
|
dispose(state.scene);
|
|
14892
15396
|
_roots.delete(canvas);
|
|
14893
15397
|
if (callback) callback(canvas);
|
|
14894
|
-
} catch
|
|
15398
|
+
} catch {
|
|
14895
15399
|
}
|
|
14896
15400
|
}, 500);
|
|
14897
15401
|
}
|
|
@@ -14899,36 +15403,34 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14899
15403
|
}
|
|
14900
15404
|
}
|
|
14901
15405
|
function createPortal(children, container, state) {
|
|
14902
|
-
return /* @__PURE__ */ jsx(
|
|
15406
|
+
return /* @__PURE__ */ jsx(Portal, { children, container, state });
|
|
14903
15407
|
}
|
|
14904
|
-
function
|
|
15408
|
+
function Portal({ children, container, state }) {
|
|
14905
15409
|
const isRef = useCallback((obj) => obj && "current" in obj, []);
|
|
14906
|
-
const [resolvedContainer,
|
|
15410
|
+
const [resolvedContainer, _setResolvedContainer] = useState(() => {
|
|
14907
15411
|
if (isRef(container)) return container.current ?? null;
|
|
14908
15412
|
return container;
|
|
14909
15413
|
});
|
|
15414
|
+
const setResolvedContainer = useCallback(
|
|
15415
|
+
(newContainer) => {
|
|
15416
|
+
if (!newContainer || newContainer === resolvedContainer) return;
|
|
15417
|
+
_setResolvedContainer(isRef(newContainer) ? newContainer.current : newContainer);
|
|
15418
|
+
},
|
|
15419
|
+
[resolvedContainer, _setResolvedContainer, isRef]
|
|
15420
|
+
);
|
|
14910
15421
|
useMemo(() => {
|
|
14911
|
-
if (isRef(container)) {
|
|
14912
|
-
|
|
14913
|
-
|
|
14914
|
-
|
|
14915
|
-
const updated = container.current;
|
|
14916
|
-
if (updated && updated !== resolvedContainer) {
|
|
14917
|
-
setResolvedContainer(updated);
|
|
14918
|
-
}
|
|
14919
|
-
});
|
|
14920
|
-
} else if (current !== resolvedContainer) {
|
|
14921
|
-
setResolvedContainer(current);
|
|
14922
|
-
}
|
|
14923
|
-
} else if (container !== resolvedContainer) {
|
|
14924
|
-
setResolvedContainer(container);
|
|
15422
|
+
if (isRef(container) && !container.current) {
|
|
15423
|
+
return queueMicrotask(() => {
|
|
15424
|
+
setResolvedContainer(container.current);
|
|
15425
|
+
});
|
|
14925
15426
|
}
|
|
14926
|
-
|
|
15427
|
+
setResolvedContainer(container);
|
|
15428
|
+
}, [container, isRef, setResolvedContainer]);
|
|
14927
15429
|
if (!resolvedContainer) return /* @__PURE__ */ jsx(Fragment, {});
|
|
14928
15430
|
const portalKey = resolvedContainer.uuid ?? `portal-${resolvedContainer.id ?? "unknown"}`;
|
|
14929
|
-
return /* @__PURE__ */ jsx(
|
|
15431
|
+
return /* @__PURE__ */ jsx(PortalInner, { children, container: resolvedContainer, state }, portalKey);
|
|
14930
15432
|
}
|
|
14931
|
-
function
|
|
15433
|
+
function PortalInner({ state = {}, children, container }) {
|
|
14932
15434
|
const { events, size, injectScene = true, ...rest } = state;
|
|
14933
15435
|
const previousRoot = useStore();
|
|
14934
15436
|
const [raycaster] = useState(() => new Raycaster());
|
|
@@ -14949,11 +15451,12 @@ function Portal({ state = {}, children, container }) {
|
|
|
14949
15451
|
};
|
|
14950
15452
|
}, [portalScene, container, injectScene]);
|
|
14951
15453
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
15454
|
+
const resolvedSize = { ...rootState.size, ...injectState.size, ...size };
|
|
14952
15455
|
let viewport = void 0;
|
|
14953
|
-
if (injectState.camera && size) {
|
|
15456
|
+
if (injectState.camera && (size || injectState.size)) {
|
|
14954
15457
|
const camera = injectState.camera;
|
|
14955
|
-
viewport = rootState.viewport.getCurrentViewport(camera, new Vector3(),
|
|
14956
|
-
if (camera !== rootState.camera) updateCamera(camera,
|
|
15458
|
+
viewport = rootState.viewport.getCurrentViewport(camera, new Vector3(), resolvedSize);
|
|
15459
|
+
if (camera !== rootState.camera) updateCamera(camera, resolvedSize);
|
|
14957
15460
|
}
|
|
14958
15461
|
return {
|
|
14959
15462
|
// The intersect consists of the previous root state
|
|
@@ -14970,7 +15473,7 @@ function Portal({ state = {}, children, container }) {
|
|
|
14970
15473
|
previousRoot,
|
|
14971
15474
|
// Events, size and viewport can be overridden by the inject layer
|
|
14972
15475
|
events: { ...rootState.events, ...injectState.events, ...events },
|
|
14973
|
-
size:
|
|
15476
|
+
size: resolvedSize,
|
|
14974
15477
|
viewport: { ...rootState.viewport, ...viewport },
|
|
14975
15478
|
// Layers are allowed to override events
|
|
14976
15479
|
setEvents: (events2) => injectState.set((state2) => ({ ...state2, events: { ...state2.events, ...events2 } })),
|
|
@@ -15004,15 +15507,13 @@ function CanvasImpl({
|
|
|
15004
15507
|
fallback,
|
|
15005
15508
|
resize,
|
|
15006
15509
|
style,
|
|
15510
|
+
id,
|
|
15007
15511
|
gl,
|
|
15008
|
-
renderer,
|
|
15512
|
+
renderer: rendererProp,
|
|
15009
15513
|
events = createPointerEvents,
|
|
15010
15514
|
eventSource,
|
|
15011
15515
|
eventPrefix,
|
|
15012
15516
|
shadows,
|
|
15013
|
-
linear,
|
|
15014
|
-
flat,
|
|
15015
|
-
legacy,
|
|
15016
15517
|
orthographic,
|
|
15017
15518
|
frameloop,
|
|
15018
15519
|
dpr,
|
|
@@ -15027,10 +15528,43 @@ function CanvasImpl({
|
|
|
15027
15528
|
hmr,
|
|
15028
15529
|
width,
|
|
15029
15530
|
height,
|
|
15531
|
+
background,
|
|
15532
|
+
forceEven,
|
|
15030
15533
|
...props
|
|
15031
15534
|
}) {
|
|
15535
|
+
const { primaryCanvas, scheduler, ...rendererConfig } = typeof rendererProp === "object" && rendererProp !== null && !("render" in rendererProp) && ("primaryCanvas" in rendererProp || "scheduler" in rendererProp) ? rendererProp : { primaryCanvas: void 0, scheduler: void 0 };
|
|
15536
|
+
const renderer = Object.keys(rendererConfig).length > 0 ? rendererConfig : rendererProp;
|
|
15032
15537
|
React.useMemo(() => extend(THREE), []);
|
|
15033
15538
|
const Bridge = useBridge();
|
|
15539
|
+
const backgroundProps = React.useMemo(() => {
|
|
15540
|
+
if (!background) return null;
|
|
15541
|
+
if (typeof background === "object" && !background.isColor) {
|
|
15542
|
+
const { backgroundMap, envMap, files, preset, ...rest } = background;
|
|
15543
|
+
return {
|
|
15544
|
+
...rest,
|
|
15545
|
+
preset,
|
|
15546
|
+
files: envMap || files,
|
|
15547
|
+
backgroundFiles: backgroundMap,
|
|
15548
|
+
background: true
|
|
15549
|
+
};
|
|
15550
|
+
}
|
|
15551
|
+
if (typeof background === "number") {
|
|
15552
|
+
return { color: background, background: true };
|
|
15553
|
+
}
|
|
15554
|
+
if (typeof background === "string") {
|
|
15555
|
+
if (background in presetsObj) {
|
|
15556
|
+
return { preset: background, background: true };
|
|
15557
|
+
}
|
|
15558
|
+
if (/^(https?:\/\/|\/|\.\/|\.\.\/)|\\.(hdr|exr|jpg|jpeg|png|webp|gif)$/i.test(background)) {
|
|
15559
|
+
return { files: background, background: true };
|
|
15560
|
+
}
|
|
15561
|
+
return { color: background, background: true };
|
|
15562
|
+
}
|
|
15563
|
+
if (background.isColor) {
|
|
15564
|
+
return { color: background, background: true };
|
|
15565
|
+
}
|
|
15566
|
+
return null;
|
|
15567
|
+
}, [background]);
|
|
15034
15568
|
const hasInitialSizeRef = React.useRef(false);
|
|
15035
15569
|
const measureConfig = React.useMemo(() => {
|
|
15036
15570
|
if (!hasInitialSizeRef.current) {
|
|
@@ -15047,15 +15581,20 @@ function CanvasImpl({
|
|
|
15047
15581
|
};
|
|
15048
15582
|
}, [resize, hasInitialSizeRef.current]);
|
|
15049
15583
|
const [containerRef, containerRect] = useMeasure(measureConfig);
|
|
15050
|
-
const effectiveSize = React.useMemo(
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15584
|
+
const effectiveSize = React.useMemo(() => {
|
|
15585
|
+
let w = width ?? containerRect.width;
|
|
15586
|
+
let h = height ?? containerRect.height;
|
|
15587
|
+
if (forceEven) {
|
|
15588
|
+
w = Math.ceil(w / 2) * 2;
|
|
15589
|
+
h = Math.ceil(h / 2) * 2;
|
|
15590
|
+
}
|
|
15591
|
+
return {
|
|
15592
|
+
width: w,
|
|
15593
|
+
height: h,
|
|
15054
15594
|
top: containerRect.top,
|
|
15055
15595
|
left: containerRect.left
|
|
15056
|
-
}
|
|
15057
|
-
|
|
15058
|
-
);
|
|
15596
|
+
};
|
|
15597
|
+
}, [width, height, containerRect, forceEven]);
|
|
15059
15598
|
if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
|
|
15060
15599
|
hasInitialSizeRef.current = true;
|
|
15061
15600
|
}
|
|
@@ -15095,14 +15634,14 @@ function CanvasImpl({
|
|
|
15095
15634
|
async function run() {
|
|
15096
15635
|
if (!effectActiveRef.current || !root.current) return;
|
|
15097
15636
|
await root.current.configure({
|
|
15637
|
+
id,
|
|
15638
|
+
primaryCanvas,
|
|
15639
|
+
scheduler,
|
|
15098
15640
|
gl,
|
|
15099
15641
|
renderer,
|
|
15100
15642
|
scene,
|
|
15101
15643
|
events,
|
|
15102
15644
|
shadows,
|
|
15103
|
-
linear,
|
|
15104
|
-
flat,
|
|
15105
|
-
legacy,
|
|
15106
15645
|
orthographic,
|
|
15107
15646
|
frameloop,
|
|
15108
15647
|
dpr,
|
|
@@ -15112,6 +15651,7 @@ function CanvasImpl({
|
|
|
15112
15651
|
size: effectiveSize,
|
|
15113
15652
|
// Store size props for reset functionality
|
|
15114
15653
|
_sizeProps: width !== void 0 || height !== void 0 ? { width, height } : null,
|
|
15654
|
+
forceEven,
|
|
15115
15655
|
// Pass mutable reference to onPointerMissed so it's free to update
|
|
15116
15656
|
onPointerMissed: (...args) => handlePointerMissed.current?.(...args),
|
|
15117
15657
|
onDragOverMissed: (...args) => handleDragOverMissed.current?.(...args),
|
|
@@ -15135,7 +15675,10 @@ function CanvasImpl({
|
|
|
15135
15675
|
});
|
|
15136
15676
|
if (!effectActiveRef.current || !root.current) return;
|
|
15137
15677
|
root.current.render(
|
|
15138
|
-
/* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */
|
|
15678
|
+
/* @__PURE__ */ jsx(Bridge, { children: /* @__PURE__ */ jsx(ErrorBoundary, { set: setError, children: /* @__PURE__ */ jsxs(React.Suspense, { fallback: /* @__PURE__ */ jsx(Block, { set: setBlock }), children: [
|
|
15679
|
+
backgroundProps && /* @__PURE__ */ jsx(Environment, { ...backgroundProps }),
|
|
15680
|
+
children ?? null
|
|
15681
|
+
] }) }) })
|
|
15139
15682
|
);
|
|
15140
15683
|
}
|
|
15141
15684
|
run();
|
|
@@ -15162,14 +15705,16 @@ function CanvasImpl({
|
|
|
15162
15705
|
const canvas = canvasRef.current;
|
|
15163
15706
|
if (!canvas) return;
|
|
15164
15707
|
const handleHMR = () => {
|
|
15165
|
-
|
|
15166
|
-
|
|
15167
|
-
rootEntry
|
|
15168
|
-
|
|
15169
|
-
|
|
15170
|
-
|
|
15171
|
-
|
|
15172
|
-
|
|
15708
|
+
queueMicrotask(() => {
|
|
15709
|
+
const rootEntry = _roots.get(canvas);
|
|
15710
|
+
if (rootEntry?.store) {
|
|
15711
|
+
rootEntry.store.setState((state) => ({
|
|
15712
|
+
nodes: {},
|
|
15713
|
+
uniforms: {},
|
|
15714
|
+
_hmrVersion: state._hmrVersion + 1
|
|
15715
|
+
}));
|
|
15716
|
+
}
|
|
15717
|
+
});
|
|
15173
15718
|
};
|
|
15174
15719
|
if (typeof import.meta !== "undefined" && import.meta.hot) {
|
|
15175
15720
|
const hot = import.meta.hot;
|
|
@@ -15198,7 +15743,7 @@ function CanvasImpl({
|
|
|
15198
15743
|
...style
|
|
15199
15744
|
},
|
|
15200
15745
|
...props,
|
|
15201
|
-
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15746
|
+
children: /* @__PURE__ */ jsx("div", { ref: containerRef, className: "r3f-canvas-container", style: { width: "100%", height: "100%" }, children: /* @__PURE__ */ jsx("canvas", { ref: canvasRef, id, className: "r3f-canvas", style: { display: "block" }, children: fallback }) })
|
|
15202
15747
|
}
|
|
15203
15748
|
);
|
|
15204
15749
|
}
|
|
@@ -15208,4 +15753,4 @@ function Canvas(props) {
|
|
|
15208
15753
|
|
|
15209
15754
|
extend(THREE);
|
|
15210
15755
|
|
|
15211
|
-
export { Block, Canvas, ErrorBoundary, IsObject, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, 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, getInstanceProps, getRootState, getScheduler, getUuidPrefix, hasConstructor, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isObject3D, isOrthographicCamera, isRef, isRenderer, isTexture, isVectorLike, prepare, reconciler, removeInteractivity, resolve, unmountComponentAtNode, updateCamera, updateFrustum, useBridge, useFrame, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useMutableCallback, useRenderTarget, useStore, useTexture, useTextures, useThree };
|
|
15756
|
+
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Scheduler, 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, getScheduler, 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 };
|