@react-three/fiber 10.0.0-alpha.3 → 10.0.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  import * as webgpu from 'three/webgpu';
2
2
  import { CubeRenderTarget, RenderTarget, Frustum, Matrix4, Group, BoxGeometry, MeshBasicNodeMaterial, Mesh, Node, NodeUpdateType, Layers, ShaderMaterial, Uniform, SRGBColorSpace, RGBAFormat, UnsignedByteType, Vector3, Vector2, TextureLoader, Texture as Texture$1, CubeReflectionMapping, EquirectangularReflectionMapping, CubeTextureLoader, CanvasTarget, Raycaster, OrthographicCamera, PerspectiveCamera, Scene, PCFShadowMap, VSMShadowMap, BasicShadowMap, ACESFilmicToneMapping, WebGPURenderer, HalfFloatType, Color } from 'three/webgpu';
3
3
  import { WebGLCubeRenderTarget, WebGLRenderTarget, WebGLRenderer } from 'three';
4
- import { Inspector } from 'three/addons/inspector/Inspector.js';
5
4
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
6
5
  import * as React from 'react';
7
6
  import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
@@ -13,6 +12,7 @@ export { Scheduler, getScheduler } from '@pmndrs/scheduler';
13
12
  import Tb, { unstable_getCurrentPriorityLevel, unstable_IdlePriority, unstable_LowPriority, unstable_NormalPriority, unstable_UserBlockingPriority, unstable_ImmediatePriority, unstable_scheduleCallback } from 'scheduler';
14
13
  import { GroundedSkybox } from 'three/examples/jsm/objects/GroundedSkybox.js';
15
14
  import { HDRLoader } from 'three/examples/jsm/loaders/HDRLoader.js';
15
+ import { HDRCubeTextureLoader } from 'three/examples/jsm/loaders/HDRCubeTextureLoader.js';
16
16
  import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js';
17
17
  import { UltraHDRLoader } from 'three/examples/jsm/loaders/UltraHDRLoader.js';
18
18
  import { GainMapLoader } from '@monogrid/gainmap-js';
@@ -32,18 +32,22 @@ function _mergeNamespaces(n, m) {
32
32
 
33
33
  const R3F_BUILD_LEGACY = true;
34
34
  const R3F_BUILD_WEBGPU = true;
35
+ async function loadInspector() {
36
+ const { Inspector } = await import('three/addons/inspector/Inspector.js');
37
+ return Inspector;
38
+ }
35
39
 
36
40
  const THREE = /*#__PURE__*/_mergeNamespaces({
37
41
  __proto__: null,
38
42
  CubeRenderTarget: CubeRenderTarget,
39
43
  CubeRenderTargetCompat: CubeRenderTarget,
40
- Inspector: Inspector,
41
44
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
42
45
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
43
46
  RenderTargetCompat: RenderTarget,
44
47
  WebGLCubeRenderTarget: WebGLCubeRenderTarget,
45
48
  WebGLRenderTarget: WebGLRenderTarget,
46
- WebGLRenderer: WebGLRenderer
49
+ WebGLRenderer: WebGLRenderer,
50
+ loadInspector: loadInspector
47
51
  }, [webgpu]);
48
52
 
49
53
  const primaryRegistry = /* @__PURE__ */ new Map();
@@ -506,8 +510,10 @@ function hasVisibilityHandlers(handlers) {
506
510
  }
507
511
 
508
512
  const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
509
- function fromRef(ref) {
510
- return { [FROM_REF]: ref };
513
+ function fromRef(ref, transform) {
514
+ const marker = { [FROM_REF]: ref };
515
+ if (transform) marker.transform = transform;
516
+ return marker;
511
517
  }
512
518
  function isFromRef(value) {
513
519
  return value !== null && typeof value === "object" && FROM_REF in value;
@@ -608,11 +614,9 @@ function diffProps(instance, newProps) {
608
614
  for (const prop in instance.props) {
609
615
  if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
610
616
  const { root, key } = resolve(instance.object, prop);
611
- if (root.constructor && root.constructor.length === 0) {
617
+ if (typeof root?.constructor === "function") {
612
618
  const ctor = getMemoizedPrototype(root);
613
619
  if (!is.und(ctor)) changedProps[prop] = ctor[key];
614
- } else {
615
- changedProps[prop] = 0;
616
620
  }
617
621
  }
618
622
  return changedProps;
@@ -902,7 +906,7 @@ const createStore = (invalidate, advance) => {
902
906
  size: newSize,
903
907
  viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
904
908
  }));
905
- getScheduler().invalidate();
909
+ get().invalidate();
906
910
  }
907
911
  }
908
912
  return;
@@ -917,15 +921,16 @@ const createStore = (invalidate, advance) => {
917
921
  viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
918
922
  _sizeImperative: true
919
923
  }));
920
- getScheduler().invalidate();
924
+ get().invalidate();
921
925
  },
922
926
  setDpr: (dpr) => set((state2) => {
923
927
  const resolved = calculateDpr(dpr);
924
928
  return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
925
929
  }),
926
930
  setFrameloop: (frameloop = "always") => {
931
+ const rootId = get().internal.rootId;
932
+ if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
927
933
  set(() => ({ frameloop }));
928
- getScheduler().frameloop = frameloop;
929
934
  },
930
935
  setError: (error) => set(() => ({ error })),
931
936
  error: null,
@@ -1041,17 +1046,11 @@ const createStore = (invalidate, advance) => {
1041
1046
  oldSize = size;
1042
1047
  oldDpr = viewport.dpr;
1043
1048
  updateCamera(camera, size);
1044
- if (internal.isSecondary && canvasTarget) {
1045
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1046
- canvasTarget.setSize(size.width, size.height, false);
1047
- } else {
1048
- if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
1049
- actualRenderer.setSize(size.width, size.height, false);
1050
- if (canvasTarget) {
1051
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1052
- canvasTarget.setSize(size.width, size.height, false);
1053
- }
1054
- }
1049
+ const resizeTarget = canvasTarget ?? actualRenderer;
1050
+ if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
1051
+ resizeTarget.setSize(size.width, size.height, false);
1052
+ const activeTarget = actualRenderer.getCanvasTarget?.();
1053
+ if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
1055
1054
  }
1056
1055
  if (camera !== oldCamera) {
1057
1056
  oldCamera = camera;
@@ -1113,7 +1112,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
1113
1112
  const results = cacheKeys.map(
1114
1113
  (key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
1115
1114
  );
1116
- return Array.isArray(input) ? results : results[0];
1115
+ const stableRef = useRef(null);
1116
+ const previous = stableRef.current;
1117
+ const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
1118
+ stableRef.current = stable;
1119
+ return Array.isArray(input) ? stable : stable[0];
1117
1120
  }
1118
1121
  useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
1119
1122
  const inputs = Array.isArray(input) ? input : [input];
@@ -1233,6 +1236,13 @@ function useFrame(callback, priorityOrOptions) {
1233
1236
  * Use for controlling the entire frame loop, adding phases, etc.
1234
1237
  */
1235
1238
  scheduler: scheduler2,
1239
+ /**
1240
+ * The root that currently owns this job. Resolve on access because ambient
1241
+ * jobs can be adopted by a Canvas after the controls object is created.
1242
+ */
1243
+ get rootId() {
1244
+ return getScheduler().getJobRootId(id);
1245
+ },
1236
1246
  /**
1237
1247
  * Manually step this job only.
1238
1248
  * Bypasses FPS limiting - always runs.
@@ -1249,6 +1259,14 @@ function useFrame(callback, priorityOrOptions) {
1249
1259
  stepAll: (timestamp) => {
1250
1260
  getScheduler().step(timestamp);
1251
1261
  },
1262
+ /**
1263
+ * Request frames for this job's owning root without waking sibling roots.
1264
+ */
1265
+ invalidate: (frames, stackFrames) => {
1266
+ const scheduler3 = getScheduler();
1267
+ const rootId = scheduler3.getJobRootId(id);
1268
+ if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
1269
+ },
1252
1270
  /**
1253
1271
  * Pause this job (set enabled=false).
1254
1272
  * Job remains registered but won't run.
@@ -1278,6 +1296,11 @@ function getUrls(input) {
1278
1296
  if (Array.isArray(input)) return input;
1279
1297
  return Object.values(input);
1280
1298
  }
1299
+ function inputSignature(input) {
1300
+ if (typeof input === "string") return input;
1301
+ if (Array.isArray(input)) return input.join("\0");
1302
+ return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
1303
+ }
1281
1304
  function allUrlsCached(urls, textureCache) {
1282
1305
  return urls.every((url) => textureCache.has(url));
1283
1306
  }
@@ -1303,24 +1326,37 @@ function useTexture(input, optionsOrOnLoad) {
1303
1326
  const onLoadRef = useRef(onLoad);
1304
1327
  onLoadRef.current = onLoad;
1305
1328
  const onLoadCalledForRef = useRef(null);
1306
- const urls = useMemo(() => getUrls(input), [input]);
1329
+ const inputKey = useMemo(() => inputSignature(input), [input]);
1330
+ const stableInput = useMemo(() => input, [inputKey]);
1331
+ const urls = useMemo(() => getUrls(stableInput), [stableInput]);
1307
1332
  const cachedResult = useMemo(() => {
1308
1333
  if (!cache) return null;
1309
1334
  const textures = store.getState().textures;
1310
1335
  if (!allUrlsCached(urls, textures)) return null;
1311
- return buildFromCache(input, textures);
1312
- }, [cache, urls, input, store]);
1336
+ return buildFromCache(stableInput, textures);
1337
+ }, [cache, urls, stableInput, store]);
1313
1338
  const loadedTextures = useLoader(
1314
1339
  TextureLoader,
1315
- IsObject(input) ? Object.values(input) : input
1340
+ IsObject(stableInput) ? Object.values(stableInput) : stableInput
1316
1341
  );
1317
- const inputKey = urls.join("\0");
1342
+ const mappedTextures = useMemo(() => {
1343
+ if (cachedResult) return cachedResult;
1344
+ if (IsObject(stableInput)) {
1345
+ const keyed = {};
1346
+ const textureArray = loadedTextures;
1347
+ let i = 0;
1348
+ for (const key in stableInput) keyed[key] = textureArray[i++];
1349
+ return keyed;
1350
+ } else {
1351
+ return loadedTextures;
1352
+ }
1353
+ }, [stableInput, loadedTextures, cachedResult]);
1318
1354
  useLayoutEffect(() => {
1319
1355
  if (cachedResult) return;
1320
1356
  if (onLoadCalledForRef.current === inputKey) return;
1321
1357
  onLoadCalledForRef.current = inputKey;
1322
- onLoadRef.current?.(loadedTextures);
1323
- }, [cachedResult, loadedTextures, inputKey]);
1358
+ onLoadRef.current?.(mappedTextures);
1359
+ }, [cachedResult, mappedTextures, inputKey]);
1324
1360
  useEffect(() => {
1325
1361
  if (cachedResult) return;
1326
1362
  if ("initTexture" in renderer) {
@@ -1339,30 +1375,18 @@ function useTexture(input, optionsOrOnLoad) {
1339
1375
  });
1340
1376
  }
1341
1377
  }, [renderer, loadedTextures, cachedResult]);
1342
- const mappedTextures = useMemo(() => {
1343
- if (cachedResult) return cachedResult;
1344
- if (IsObject(input)) {
1345
- const keyed = {};
1346
- const textureArray = loadedTextures;
1347
- let i = 0;
1348
- for (const key in input) keyed[key] = textureArray[i++];
1349
- return keyed;
1350
- } else {
1351
- return loadedTextures;
1352
- }
1353
- }, [input, loadedTextures, cachedResult]);
1354
1378
  useEffect(() => {
1355
1379
  if (!cache) return;
1356
1380
  const urlTextureMap = [];
1357
- if (typeof input === "string") {
1358
- urlTextureMap.push([input, mappedTextures]);
1359
- } else if (Array.isArray(input)) {
1381
+ if (typeof stableInput === "string") {
1382
+ urlTextureMap.push([stableInput, mappedTextures]);
1383
+ } else if (Array.isArray(stableInput)) {
1360
1384
  const textureArray = mappedTextures;
1361
- input.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
1362
- } else if (IsObject(input)) {
1385
+ stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
1386
+ } else if (IsObject(stableInput)) {
1363
1387
  const textureRecord = mappedTextures;
1364
- for (const key in input) {
1365
- const url = input[key];
1388
+ for (const key in stableInput) {
1389
+ const url = stableInput[key];
1366
1390
  urlTextureMap.push([url, textureRecord[key]]);
1367
1391
  }
1368
1392
  }
@@ -1391,7 +1415,7 @@ function useTexture(input, optionsOrOnLoad) {
1391
1415
  }
1392
1416
  return { _textureRefs: refs };
1393
1417
  });
1394
- }, [cache, input, mappedTextures, store]);
1418
+ }, [cache, stableInput, mappedTextures, store]);
1395
1419
  return mappedTextures;
1396
1420
  }
1397
1421
  useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
@@ -1554,7 +1578,7 @@ function useEnvironment({
1554
1578
  texture = texture.renderTarget?.texture;
1555
1579
  }
1556
1580
  texture.mapping = isCubemap ? CubeReflectionMapping : EquirectangularReflectionMapping;
1557
- texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
1581
+ texture.colorSpace = colorSpace ?? (isCubemap && extension !== "hdr-cube" ? "srgb" : "srgb-linear");
1558
1582
  return texture;
1559
1583
  }
1560
1584
  const preloadDefaultOptions = {
@@ -1607,11 +1631,12 @@ function getExtension(files) {
1607
1631
  const isCubemap = isArray(files) && files.length === 6;
1608
1632
  const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
1609
1633
  const firstEntry = isArray(files) ? files[0] : files;
1610
- 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();
1634
+ const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
1635
+ const extension = isCubemap ? firstExtension === "hdr" ? "hdr-cube" : "cube" : isGainmap ? "webp" : firstEntry.startsWith("data:application/exr") ? "exr" : firstEntry.startsWith("data:application/hdr") ? "hdr" : firstEntry.startsWith("data:image/jpeg") ? "jpg" : firstExtension;
1611
1636
  return { extension, isCubemap, isGainmap };
1612
1637
  }
1613
1638
  function getLoader(extension) {
1614
- const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
1639
+ const loader = extension === "cube" ? CubeTextureLoader : extension === "hdr-cube" ? HDRCubeTextureLoader : extension === "hdr" ? HDRLoader : extension === "exr" ? EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader : extension === "webp" ? GainMapLoader : null;
1615
1640
  return loader;
1616
1641
  }
1617
1642
 
@@ -1662,13 +1687,19 @@ function addTail(callback) {
1662
1687
  return getScheduler().onIdle(callback);
1663
1688
  }
1664
1689
  function invalidate(state, frames = 1, stackFrames = false) {
1665
- getScheduler().invalidate(frames, stackFrames);
1690
+ const rootId = state?.internal?.rootId;
1691
+ const scheduler = getScheduler();
1692
+ if (rootId) scheduler.invalidateRoot(rootId, frames, stackFrames);
1693
+ else scheduler.invalidate(frames, stackFrames);
1666
1694
  }
1667
- function advance(timestamp) {
1668
- getScheduler().step(timestamp);
1695
+ function advance(timestamp, runGlobalEffects, state) {
1696
+ const rootId = state?.internal?.rootId;
1697
+ const scheduler = getScheduler();
1698
+ if (rootId) scheduler.stepRoot(rootId, timestamp);
1699
+ else scheduler.step(timestamp);
1669
1700
  }
1670
1701
 
1671
- const version = "10.0.0-alpha.3";
1702
+ const version = "10.0.0-alpha.5";
1672
1703
  const packageData = {
1673
1704
  version: version};
1674
1705
 
@@ -13527,7 +13558,10 @@ function extend(objects) {
13527
13558
  catalogue[Component] = objects;
13528
13559
  return Component;
13529
13560
  } else {
13530
- Object.assign(catalogue, objects);
13561
+ for (const name in objects) {
13562
+ const object = objects[name];
13563
+ if (isConstructor(object)) catalogue[name] = object;
13564
+ }
13531
13565
  }
13532
13566
  }
13533
13567
  function validateInstance(type, props) {
@@ -13875,7 +13909,7 @@ const reconciler = /* @__PURE__ */ createReconciler({
13875
13909
  getRootHostContext: () => NO_CONTEXT,
13876
13910
  getChildHostContext: () => NO_CONTEXT,
13877
13911
  commitUpdate(instance, type, oldProps, newProps, fiber) {
13878
- validateInstance(type, newProps);
13912
+ validateInstance(instance.type, newProps);
13879
13913
  let reconstruct = false;
13880
13914
  if (instance.type === "primitive" && oldProps.object !== newProps.object) reconstruct = true;
13881
13915
  else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
@@ -13902,8 +13936,8 @@ const reconciler = /* @__PURE__ */ createReconciler({
13902
13936
  for (const prop in instance.props) {
13903
13937
  const value = instance.props[prop];
13904
13938
  if (isFromRef(value)) {
13905
- const ref = value[FROM_REF];
13906
- if (ref.current != null) resolved[prop] = ref.current;
13939
+ const { [FROM_REF]: ref, transform } = value;
13940
+ if (ref.current != null) resolved[prop] = transform ? transform(ref.current) : ref.current;
13907
13941
  }
13908
13942
  }
13909
13943
  if (Object.keys(resolved).length) applyProps(instance.object, resolved);
@@ -14202,9 +14236,8 @@ function createRoot(canvas) {
14202
14236
  if (!renderer.hasInitialized?.()) {
14203
14237
  const size2 = computeInitialSize(canvas, propsSize);
14204
14238
  if (size2.width > 0 && size2.height > 0) {
14205
- const pixelRatio = calculateDpr(dpr);
14206
- canvas.width = size2.width * pixelRatio;
14207
- canvas.height = size2.height * pixelRatio;
14239
+ renderer.setPixelRatio(calculateDpr(dpr));
14240
+ renderer.setSize(size2.width, size2.height, false);
14208
14241
  }
14209
14242
  await renderer.init();
14210
14243
  }
@@ -14213,7 +14246,7 @@ function createRoot(canvas) {
14213
14246
  state.internal.actualRenderer = renderer;
14214
14247
  state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
14215
14248
  if (canvasId && !state.internal.isSecondary) {
14216
- const canvasTarget = new CanvasTarget(canvas);
14249
+ const canvasTarget = renderer.getCanvasTarget?.();
14217
14250
  const unregisterPrimary = registerPrimary(canvasId, renderer, store);
14218
14251
  state.set((prev) => ({
14219
14252
  internal: {
@@ -14327,7 +14360,7 @@ function createRoot(canvas) {
14327
14360
  const handleXRFrame = (timestamp, _frame) => {
14328
14361
  const state2 = store.getState();
14329
14362
  if (state2.frameloop === "never") return;
14330
- advance(timestamp);
14363
+ advance(timestamp, true, state2);
14331
14364
  };
14332
14365
  const actualRenderer = state.internal.actualRenderer;
14333
14366
  const handleSessionChange = () => {
@@ -14335,7 +14368,7 @@ function createRoot(canvas) {
14335
14368
  const renderer2 = state2.internal.actualRenderer;
14336
14369
  actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
14337
14370
  renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
14338
- if (!renderer2.xr.isPresenting) invalidate();
14371
+ if (!renderer2.xr.isPresenting) invalidate(state2);
14339
14372
  };
14340
14373
  const xr = {
14341
14374
  connect() {
@@ -14417,14 +14450,23 @@ function createRoot(canvas) {
14417
14450
  const newRootId = canvasId || scheduler.generateRootId();
14418
14451
  const unregisterRoot = scheduler.registerRoot(newRootId, {
14419
14452
  getState: () => store.getState(),
14420
- onError: (err) => store.getState().setError(err)
14453
+ onError: (err) => store.getState().setError(err),
14454
+ frameloop: store.getState().frameloop,
14455
+ before: schedulerConfig?.before,
14456
+ after: schedulerConfig?.after,
14457
+ order: schedulerConfig?.order
14421
14458
  });
14422
14459
  const unregisterCanvasTarget = scheduler.register(
14423
14460
  () => {
14424
14461
  const state2 = store.getState();
14425
- if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
14462
+ const canvasTarget = state2.internal.canvasTarget;
14463
+ if (canvasTarget) {
14426
14464
  const renderer2 = state2.internal.actualRenderer;
14427
- renderer2.setCanvasTarget(state2.internal.canvasTarget);
14465
+ if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
14466
+ if (state2.internal.canvasTargetSizeDirty) {
14467
+ state2.internal.canvasTargetSizeDirty = false;
14468
+ renderer2.backend?.updateSize?.();
14469
+ }
14428
14470
  }
14429
14471
  },
14430
14472
  {
@@ -14493,8 +14535,7 @@ function createRoot(canvas) {
14493
14535
  phase: "render",
14494
14536
  system: true,
14495
14537
  // Internal flag: this is a system job, not user-controlled
14496
- // Apply scheduler config for render ordering and rate limiting
14497
- ...schedulerConfig?.after && { after: schedulerConfig.after },
14538
+ // FPS throttles only the default render job; Canvas ordering belongs to the root.
14498
14539
  ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
14499
14540
  }
14500
14541
  );
@@ -14513,8 +14554,21 @@ function createRoot(canvas) {
14513
14554
  scheduler
14514
14555
  }
14515
14556
  }));
14557
+ } else {
14558
+ const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
14559
+ if (constraintsChanged) {
14560
+ scheduler.setRootConstraints(rootId, {
14561
+ before: schedulerConfig?.before,
14562
+ after: schedulerConfig?.after
14563
+ });
14564
+ }
14565
+ if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
14566
+ scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
14567
+ }
14516
14568
  }
14517
- scheduler.frameloop = frameloop;
14569
+ lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
14570
+ lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
14571
+ lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
14518
14572
  onCreated = onCreatedCallback;
14519
14573
  configured = true;
14520
14574
  resolve();
@@ -14556,18 +14610,23 @@ function unmountComponentAtNode(canvas, callback) {
14556
14610
  const fiber = root?.fiber;
14557
14611
  if (fiber) {
14558
14612
  const state = root?.store.getState();
14559
- if (state) state.internal.active = false;
14613
+ if (state) {
14614
+ state.internal.active = false;
14615
+ const unregisterRoot = state.internal.unregisterRoot;
14616
+ if (unregisterRoot) {
14617
+ unregisterRoot();
14618
+ state.internal.unregisterRoot = void 0;
14619
+ }
14620
+ }
14560
14621
  reconciler.updateContainer(null, fiber, null, () => {
14561
14622
  if (state) {
14562
14623
  setTimeout(() => {
14563
14624
  try {
14564
14625
  const renderer = state.internal.actualRenderer;
14565
- const unregisterRoot = state.internal.unregisterRoot;
14566
- if (unregisterRoot) unregisterRoot();
14567
14626
  const unregisterPrimary = state.internal.unregisterPrimary;
14568
14627
  if (unregisterPrimary) unregisterPrimary();
14569
14628
  const canvasTarget = state.internal.canvasTarget;
14570
- if (canvasTarget?.dispose) canvasTarget.dispose();
14629
+ if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
14571
14630
  state.events.disconnect?.();
14572
14631
  cleanupHelperGroup(root.store);
14573
14632
  if (state.isLegacy && renderer) {
@@ -14708,16 +14767,11 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
14708
14767
  const oldbg = target.background;
14709
14768
  const oldenv = target.environment;
14710
14769
  const oldSceneProps = {
14711
- // @ts-ignore
14712
14770
  backgroundBlurriness: target.backgroundBlurriness,
14713
- // @ts-ignore
14714
14771
  backgroundIntensity: target.backgroundIntensity,
14715
- // @ts-ignore
14716
- backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
14717
- // @ts-ignore
14772
+ backgroundRotation: target.backgroundRotation.clone(),
14718
14773
  environmentIntensity: target.environmentIntensity,
14719
- // @ts-ignore
14720
- environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
14774
+ environmentRotation: target.environmentRotation.clone()
14721
14775
  };
14722
14776
  if (background !== "only") target.environment = texture;
14723
14777
  if (background) target.background = texture;
@@ -15011,9 +15065,9 @@ function CanvasImpl({
15011
15065
  React.useMemo(() => extend(THREE), []);
15012
15066
  const Bridge = useBridge();
15013
15067
  const backgroundProps = React.useMemo(() => parseBackground(background), [background]);
15014
- const hasInitialSizeRef = React.useRef(false);
15068
+ const [hasInitialSize, setHasInitialSize] = React.useState(false);
15015
15069
  const measureConfig = React.useMemo(() => {
15016
- if (!hasInitialSizeRef.current) {
15070
+ if (!hasInitialSize) {
15017
15071
  return {
15018
15072
  ...resize,
15019
15073
  scroll: resize?.scroll ?? true,
@@ -15025,7 +15079,7 @@ function CanvasImpl({
15025
15079
  debounce: { scroll: 50, resize: 0 },
15026
15080
  ...resize
15027
15081
  };
15028
- }, [resize, hasInitialSizeRef.current]);
15082
+ }, [hasInitialSize, resize]);
15029
15083
  const [containerRef, containerRect] = useMeasure(measureConfig);
15030
15084
  const effectiveSize = React.useMemo(() => {
15031
15085
  let w = width ?? containerRect.width;
@@ -15041,9 +15095,7 @@ function CanvasImpl({
15041
15095
  left: containerRect.left
15042
15096
  };
15043
15097
  }, [width, height, containerRect, forceEven]);
15044
- if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
15045
- hasInitialSizeRef.current = true;
15046
- }
15098
+ if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
15047
15099
  const canvasRef = React.useRef(null);
15048
15100
  const divRef = React.useRef(null);
15049
15101
  React.useImperativeHandle(ref, () => canvasRef.current);
@@ -15157,6 +15209,7 @@ function CanvasImpl({
15157
15209
  const canvas = canvasRef.current;
15158
15210
  if (canvas) {
15159
15211
  return () => {
15212
+ if (canvas.isConnected) return;
15160
15213
  unmountComponentAtNode(canvas);
15161
15214
  root.current = null;
15162
15215
  };