@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/legacy.cjs CHANGED
@@ -10,6 +10,7 @@ const scheduler = require('@pmndrs/scheduler');
10
10
  const Tb = require('scheduler');
11
11
  const GroundedSkybox_js = require('three/examples/jsm/objects/GroundedSkybox.js');
12
12
  const HDRLoader_js = require('three/examples/jsm/loaders/HDRLoader.js');
13
+ const HDRCubeTextureLoader_js = require('three/examples/jsm/loaders/HDRCubeTextureLoader.js');
13
14
  const EXRLoader_js = require('three/examples/jsm/loaders/EXRLoader.js');
14
15
  const UltraHDRLoader_js = require('three/examples/jsm/loaders/UltraHDRLoader.js');
15
16
  const gainmapJs = require('@monogrid/gainmap-js');
@@ -50,16 +51,14 @@ const Tb__default = /*#__PURE__*/_interopDefaultCompat(Tb);
50
51
 
51
52
  const R3F_BUILD_LEGACY = true;
52
53
  const R3F_BUILD_WEBGPU = false;
53
- const Inspector = class Inspector2 {
54
- constructor() {
55
- throw new Error("Inspector is not available in legacy builds. Use @react-three/fiber/webgpu instead.");
56
- }
57
- };
58
- const WebGPURenderer = class WebGPURenderer2 {
54
+ async function loadInspector() {
55
+ throw new Error("Inspector is not available in legacy builds. Use @react-three/fiber/webgpu instead.");
56
+ }
57
+ class WebGPURenderer {
59
58
  constructor() {
60
59
  throw new Error("WebGPURenderer is not available in legacy builds. Use @react-three/fiber/webgpu instead.");
61
60
  }
62
- };
61
+ }
63
62
  const RenderTarget = null;
64
63
  const CubeRenderTarget = null;
65
64
 
@@ -67,12 +66,12 @@ const THREE = /*#__PURE__*/_mergeNamespaces({
67
66
  __proto__: null,
68
67
  CubeRenderTarget: CubeRenderTarget,
69
68
  CubeRenderTargetCompat: three.WebGLCubeRenderTarget,
70
- Inspector: Inspector,
71
69
  R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
72
70
  R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
73
71
  RenderTarget: RenderTarget,
74
72
  RenderTargetCompat: three.WebGLRenderTarget,
75
- WebGPURenderer: WebGPURenderer
73
+ WebGPURenderer: WebGPURenderer,
74
+ loadInspector: loadInspector
76
75
  }, [three__namespace]);
77
76
 
78
77
  const primaryRegistry = /* @__PURE__ */ new Map();
@@ -535,8 +534,10 @@ function hasVisibilityHandlers(handlers) {
535
534
  }
536
535
 
537
536
  const FROM_REF = Symbol.for("@react-three/fiber.fromRef");
538
- function fromRef(ref) {
539
- return { [FROM_REF]: ref };
537
+ function fromRef(ref, transform) {
538
+ const marker = { [FROM_REF]: ref };
539
+ if (transform) marker.transform = transform;
540
+ return marker;
540
541
  }
541
542
  function isFromRef(value) {
542
543
  return value !== null && typeof value === "object" && FROM_REF in value;
@@ -637,11 +638,9 @@ function diffProps(instance, newProps) {
637
638
  for (const prop in instance.props) {
638
639
  if (RESERVED_PROPS.includes(prop) || newProps.hasOwnProperty(prop)) continue;
639
640
  const { root, key } = resolve(instance.object, prop);
640
- if (root.constructor && root.constructor.length === 0) {
641
+ if (typeof root?.constructor === "function") {
641
642
  const ctor = getMemoizedPrototype(root);
642
643
  if (!is.und(ctor)) changedProps[prop] = ctor[key];
643
- } else {
644
- changedProps[prop] = 0;
645
644
  }
646
645
  }
647
646
  return changedProps;
@@ -931,7 +930,7 @@ const createStore = (invalidate, advance) => {
931
930
  size: newSize,
932
931
  viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
933
932
  }));
934
- scheduler.getScheduler().invalidate();
933
+ get().invalidate();
935
934
  }
936
935
  }
937
936
  return;
@@ -946,15 +945,16 @@ const createStore = (invalidate, advance) => {
946
945
  viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
947
946
  _sizeImperative: true
948
947
  }));
949
- scheduler.getScheduler().invalidate();
948
+ get().invalidate();
950
949
  },
951
950
  setDpr: (dpr) => set((state2) => {
952
951
  const resolved = calculateDpr(dpr);
953
952
  return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
954
953
  }),
955
954
  setFrameloop: (frameloop = "always") => {
955
+ const rootId = get().internal.rootId;
956
+ if (rootId) scheduler.getScheduler().setRootFrameloop(rootId, frameloop);
956
957
  set(() => ({ frameloop }));
957
- scheduler.getScheduler().frameloop = frameloop;
958
958
  },
959
959
  setError: (error) => set(() => ({ error })),
960
960
  error: null,
@@ -1070,17 +1070,11 @@ const createStore = (invalidate, advance) => {
1070
1070
  oldSize = size;
1071
1071
  oldDpr = viewport.dpr;
1072
1072
  updateCamera(camera, size);
1073
- if (internal.isSecondary && canvasTarget) {
1074
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1075
- canvasTarget.setSize(size.width, size.height, false);
1076
- } else {
1077
- if (viewport.dpr > 0) actualRenderer.setPixelRatio(viewport.dpr);
1078
- actualRenderer.setSize(size.width, size.height, false);
1079
- if (canvasTarget) {
1080
- if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
1081
- canvasTarget.setSize(size.width, size.height, false);
1082
- }
1083
- }
1073
+ const resizeTarget = canvasTarget ?? actualRenderer;
1074
+ if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
1075
+ resizeTarget.setSize(size.width, size.height, false);
1076
+ const activeTarget = actualRenderer.getCanvasTarget?.();
1077
+ if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
1084
1078
  }
1085
1079
  if (camera !== oldCamera) {
1086
1080
  oldCamera = camera;
@@ -1142,7 +1136,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
1142
1136
  const results = cacheKeys.map(
1143
1137
  (key, index) => suspendReact.suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
1144
1138
  );
1145
- return Array.isArray(input) ? results : results[0];
1139
+ const stableRef = React.useRef(null);
1140
+ const previous = stableRef.current;
1141
+ const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
1142
+ stableRef.current = stable;
1143
+ return Array.isArray(input) ? stable : stable[0];
1146
1144
  }
1147
1145
  useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
1148
1146
  const inputs = Array.isArray(input) ? input : [input];
@@ -1262,6 +1260,13 @@ function useFrame(callback, priorityOrOptions) {
1262
1260
  * Use for controlling the entire frame loop, adding phases, etc.
1263
1261
  */
1264
1262
  scheduler: scheduler2,
1263
+ /**
1264
+ * The root that currently owns this job. Resolve on access because ambient
1265
+ * jobs can be adopted by a Canvas after the controls object is created.
1266
+ */
1267
+ get rootId() {
1268
+ return scheduler.getScheduler().getJobRootId(id);
1269
+ },
1265
1270
  /**
1266
1271
  * Manually step this job only.
1267
1272
  * Bypasses FPS limiting - always runs.
@@ -1278,6 +1283,14 @@ function useFrame(callback, priorityOrOptions) {
1278
1283
  stepAll: (timestamp) => {
1279
1284
  scheduler.getScheduler().step(timestamp);
1280
1285
  },
1286
+ /**
1287
+ * Request frames for this job's owning root without waking sibling roots.
1288
+ */
1289
+ invalidate: (frames, stackFrames) => {
1290
+ const scheduler3 = scheduler.getScheduler();
1291
+ const rootId = scheduler3.getJobRootId(id);
1292
+ if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
1293
+ },
1281
1294
  /**
1282
1295
  * Pause this job (set enabled=false).
1283
1296
  * Job remains registered but won't run.
@@ -1307,6 +1320,11 @@ function getUrls(input) {
1307
1320
  if (Array.isArray(input)) return input;
1308
1321
  return Object.values(input);
1309
1322
  }
1323
+ function inputSignature(input) {
1324
+ if (typeof input === "string") return input;
1325
+ if (Array.isArray(input)) return input.join("\0");
1326
+ return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
1327
+ }
1310
1328
  function allUrlsCached(urls, textureCache) {
1311
1329
  return urls.every((url) => textureCache.has(url));
1312
1330
  }
@@ -1332,24 +1350,37 @@ function useTexture(input, optionsOrOnLoad) {
1332
1350
  const onLoadRef = React.useRef(onLoad);
1333
1351
  onLoadRef.current = onLoad;
1334
1352
  const onLoadCalledForRef = React.useRef(null);
1335
- const urls = React.useMemo(() => getUrls(input), [input]);
1353
+ const inputKey = React.useMemo(() => inputSignature(input), [input]);
1354
+ const stableInput = React.useMemo(() => input, [inputKey]);
1355
+ const urls = React.useMemo(() => getUrls(stableInput), [stableInput]);
1336
1356
  const cachedResult = React.useMemo(() => {
1337
1357
  if (!cache) return null;
1338
1358
  const textures = store.getState().textures;
1339
1359
  if (!allUrlsCached(urls, textures)) return null;
1340
- return buildFromCache(input, textures);
1341
- }, [cache, urls, input, store]);
1360
+ return buildFromCache(stableInput, textures);
1361
+ }, [cache, urls, stableInput, store]);
1342
1362
  const loadedTextures = useLoader(
1343
1363
  three.TextureLoader,
1344
- IsObject(input) ? Object.values(input) : input
1364
+ IsObject(stableInput) ? Object.values(stableInput) : stableInput
1345
1365
  );
1346
- const inputKey = urls.join("\0");
1366
+ const mappedTextures = React.useMemo(() => {
1367
+ if (cachedResult) return cachedResult;
1368
+ if (IsObject(stableInput)) {
1369
+ const keyed = {};
1370
+ const textureArray = loadedTextures;
1371
+ let i = 0;
1372
+ for (const key in stableInput) keyed[key] = textureArray[i++];
1373
+ return keyed;
1374
+ } else {
1375
+ return loadedTextures;
1376
+ }
1377
+ }, [stableInput, loadedTextures, cachedResult]);
1347
1378
  React.useLayoutEffect(() => {
1348
1379
  if (cachedResult) return;
1349
1380
  if (onLoadCalledForRef.current === inputKey) return;
1350
1381
  onLoadCalledForRef.current = inputKey;
1351
- onLoadRef.current?.(loadedTextures);
1352
- }, [cachedResult, loadedTextures, inputKey]);
1382
+ onLoadRef.current?.(mappedTextures);
1383
+ }, [cachedResult, mappedTextures, inputKey]);
1353
1384
  React.useEffect(() => {
1354
1385
  if (cachedResult) return;
1355
1386
  if ("initTexture" in renderer) {
@@ -1368,30 +1399,18 @@ function useTexture(input, optionsOrOnLoad) {
1368
1399
  });
1369
1400
  }
1370
1401
  }, [renderer, loadedTextures, cachedResult]);
1371
- const mappedTextures = React.useMemo(() => {
1372
- if (cachedResult) return cachedResult;
1373
- if (IsObject(input)) {
1374
- const keyed = {};
1375
- const textureArray = loadedTextures;
1376
- let i = 0;
1377
- for (const key in input) keyed[key] = textureArray[i++];
1378
- return keyed;
1379
- } else {
1380
- return loadedTextures;
1381
- }
1382
- }, [input, loadedTextures, cachedResult]);
1383
1402
  React.useEffect(() => {
1384
1403
  if (!cache) return;
1385
1404
  const urlTextureMap = [];
1386
- if (typeof input === "string") {
1387
- urlTextureMap.push([input, mappedTextures]);
1388
- } else if (Array.isArray(input)) {
1405
+ if (typeof stableInput === "string") {
1406
+ urlTextureMap.push([stableInput, mappedTextures]);
1407
+ } else if (Array.isArray(stableInput)) {
1389
1408
  const textureArray = mappedTextures;
1390
- input.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
1391
- } else if (IsObject(input)) {
1409
+ stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
1410
+ } else if (IsObject(stableInput)) {
1392
1411
  const textureRecord = mappedTextures;
1393
- for (const key in input) {
1394
- const url = input[key];
1412
+ for (const key in stableInput) {
1413
+ const url = stableInput[key];
1395
1414
  urlTextureMap.push([url, textureRecord[key]]);
1396
1415
  }
1397
1416
  }
@@ -1420,7 +1439,7 @@ function useTexture(input, optionsOrOnLoad) {
1420
1439
  }
1421
1440
  return { _textureRefs: refs };
1422
1441
  });
1423
- }, [cache, input, mappedTextures, store]);
1442
+ }, [cache, stableInput, mappedTextures, store]);
1424
1443
  return mappedTextures;
1425
1444
  }
1426
1445
  useTexture.preload = (url) => useLoader.preload(three.TextureLoader, url);
@@ -1581,7 +1600,7 @@ function useEnvironment({
1581
1600
  texture = texture.renderTarget?.texture;
1582
1601
  }
1583
1602
  texture.mapping = isCubemap ? three.CubeReflectionMapping : three.EquirectangularReflectionMapping;
1584
- texture.colorSpace = colorSpace ?? (isCubemap ? "srgb" : "srgb-linear");
1603
+ texture.colorSpace = colorSpace ?? (isCubemap && extension !== "hdr-cube" ? "srgb" : "srgb-linear");
1585
1604
  return texture;
1586
1605
  }
1587
1606
  const preloadDefaultOptions = {
@@ -1634,11 +1653,12 @@ function getExtension(files) {
1634
1653
  const isCubemap = isArray(files) && files.length === 6;
1635
1654
  const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith("json"));
1636
1655
  const firstEntry = isArray(files) ? files[0] : files;
1637
- 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();
1656
+ const firstExtension = firstEntry.split(".").pop()?.split("?")?.shift()?.toLowerCase();
1657
+ 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;
1638
1658
  return { extension, isCubemap, isGainmap };
1639
1659
  }
1640
1660
  function getLoader(extension) {
1641
- const loader = extension === "cube" ? three.CubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
1661
+ const loader = extension === "cube" ? three.CubeTextureLoader : extension === "hdr-cube" ? HDRCubeTextureLoader_js.HDRCubeTextureLoader : extension === "hdr" ? HDRLoader_js.HDRLoader : extension === "exr" ? EXRLoader_js.EXRLoader : extension === "jpg" || extension === "jpeg" ? UltraHDRLoader_js.UltraHDRLoader : extension === "webp" ? gainmapJs.GainMapLoader : null;
1642
1662
  return loader;
1643
1663
  }
1644
1664
 
@@ -1689,13 +1709,19 @@ function addTail(callback) {
1689
1709
  return scheduler.getScheduler().onIdle(callback);
1690
1710
  }
1691
1711
  function invalidate(state, frames = 1, stackFrames = false) {
1692
- scheduler.getScheduler().invalidate(frames, stackFrames);
1712
+ const rootId = state?.internal?.rootId;
1713
+ const scheduler$1 = scheduler.getScheduler();
1714
+ if (rootId) scheduler$1.invalidateRoot(rootId, frames, stackFrames);
1715
+ else scheduler$1.invalidate(frames, stackFrames);
1693
1716
  }
1694
- function advance(timestamp) {
1695
- scheduler.getScheduler().step(timestamp);
1717
+ function advance(timestamp, runGlobalEffects, state) {
1718
+ const rootId = state?.internal?.rootId;
1719
+ const scheduler$1 = scheduler.getScheduler();
1720
+ if (rootId) scheduler$1.stepRoot(rootId, timestamp);
1721
+ else scheduler$1.step(timestamp);
1696
1722
  }
1697
1723
 
1698
- const version = "10.0.0-alpha.3";
1724
+ const version = "10.0.0-alpha.5";
1699
1725
  const packageData = {
1700
1726
  version: version};
1701
1727
 
@@ -13554,7 +13580,10 @@ function extend(objects) {
13554
13580
  catalogue[Component] = objects;
13555
13581
  return Component;
13556
13582
  } else {
13557
- Object.assign(catalogue, objects);
13583
+ for (const name in objects) {
13584
+ const object = objects[name];
13585
+ if (isConstructor(object)) catalogue[name] = object;
13586
+ }
13558
13587
  }
13559
13588
  }
13560
13589
  function validateInstance(type, props) {
@@ -13902,7 +13931,7 @@ const reconciler = /* @__PURE__ */ createReconciler({
13902
13931
  getRootHostContext: () => NO_CONTEXT,
13903
13932
  getChildHostContext: () => NO_CONTEXT,
13904
13933
  commitUpdate(instance, type, oldProps, newProps, fiber) {
13905
- validateInstance(type, newProps);
13934
+ validateInstance(instance.type, newProps);
13906
13935
  let reconstruct = false;
13907
13936
  if (instance.type === "primitive" && oldProps.object !== newProps.object) reconstruct = true;
13908
13937
  else if (newProps.args?.length !== oldProps.args?.length) reconstruct = true;
@@ -13929,8 +13958,8 @@ const reconciler = /* @__PURE__ */ createReconciler({
13929
13958
  for (const prop in instance.props) {
13930
13959
  const value = instance.props[prop];
13931
13960
  if (isFromRef(value)) {
13932
- const ref = value[FROM_REF];
13933
- if (ref.current != null) resolved[prop] = ref.current;
13961
+ const { [FROM_REF]: ref, transform } = value;
13962
+ if (ref.current != null) resolved[prop] = transform ? transform(ref.current) : ref.current;
13934
13963
  }
13935
13964
  }
13936
13965
  if (Object.keys(resolved).length) applyProps(instance.object, resolved);
@@ -14307,7 +14336,7 @@ function createRoot(canvas) {
14307
14336
  const handleXRFrame = (timestamp, _frame) => {
14308
14337
  const state2 = store.getState();
14309
14338
  if (state2.frameloop === "never") return;
14310
- advance(timestamp);
14339
+ advance(timestamp, true, state2);
14311
14340
  };
14312
14341
  const actualRenderer = state.internal.actualRenderer;
14313
14342
  const handleSessionChange = () => {
@@ -14315,7 +14344,7 @@ function createRoot(canvas) {
14315
14344
  const renderer2 = state2.internal.actualRenderer;
14316
14345
  actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
14317
14346
  renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
14318
- if (!renderer2.xr.isPresenting) invalidate();
14347
+ if (!renderer2.xr.isPresenting) invalidate(state2);
14319
14348
  };
14320
14349
  const xr = {
14321
14350
  connect() {
@@ -14397,14 +14426,23 @@ function createRoot(canvas) {
14397
14426
  const newRootId = canvasId || scheduler$1.generateRootId();
14398
14427
  const unregisterRoot = scheduler$1.registerRoot(newRootId, {
14399
14428
  getState: () => store.getState(),
14400
- onError: (err) => store.getState().setError(err)
14429
+ onError: (err) => store.getState().setError(err),
14430
+ frameloop: store.getState().frameloop,
14431
+ before: schedulerConfig?.before,
14432
+ after: schedulerConfig?.after,
14433
+ order: schedulerConfig?.order
14401
14434
  });
14402
14435
  const unregisterCanvasTarget = scheduler$1.register(
14403
14436
  () => {
14404
14437
  const state2 = store.getState();
14405
- if (state2.internal.isMultiCanvas && state2.internal.canvasTarget) {
14438
+ const canvasTarget = state2.internal.canvasTarget;
14439
+ if (canvasTarget) {
14406
14440
  const renderer2 = state2.internal.actualRenderer;
14407
- renderer2.setCanvasTarget(state2.internal.canvasTarget);
14441
+ if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
14442
+ if (state2.internal.canvasTargetSizeDirty) {
14443
+ state2.internal.canvasTargetSizeDirty = false;
14444
+ renderer2.backend?.updateSize?.();
14445
+ }
14408
14446
  }
14409
14447
  },
14410
14448
  {
@@ -14473,8 +14511,7 @@ function createRoot(canvas) {
14473
14511
  phase: "render",
14474
14512
  system: true,
14475
14513
  // Internal flag: this is a system job, not user-controlled
14476
- // Apply scheduler config for render ordering and rate limiting
14477
- ...schedulerConfig?.after && { after: schedulerConfig.after },
14514
+ // FPS throttles only the default render job; Canvas ordering belongs to the root.
14478
14515
  ...schedulerConfig?.fps && { fps: schedulerConfig.fps }
14479
14516
  }
14480
14517
  );
@@ -14493,8 +14530,21 @@ function createRoot(canvas) {
14493
14530
  scheduler: scheduler$1
14494
14531
  }
14495
14532
  }));
14533
+ } else {
14534
+ const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
14535
+ if (constraintsChanged) {
14536
+ scheduler$1.setRootConstraints(rootId, {
14537
+ before: schedulerConfig?.before,
14538
+ after: schedulerConfig?.after
14539
+ });
14540
+ }
14541
+ if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
14542
+ scheduler$1.setRootOrder(rootId, schedulerConfig?.order ?? 0);
14543
+ }
14496
14544
  }
14497
- scheduler$1.frameloop = frameloop;
14545
+ lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
14546
+ lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
14547
+ lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
14498
14548
  onCreated = onCreatedCallback;
14499
14549
  configured = true;
14500
14550
  resolve();
@@ -14536,18 +14586,23 @@ function unmountComponentAtNode(canvas, callback) {
14536
14586
  const fiber = root?.fiber;
14537
14587
  if (fiber) {
14538
14588
  const state = root?.store.getState();
14539
- if (state) state.internal.active = false;
14589
+ if (state) {
14590
+ state.internal.active = false;
14591
+ const unregisterRoot = state.internal.unregisterRoot;
14592
+ if (unregisterRoot) {
14593
+ unregisterRoot();
14594
+ state.internal.unregisterRoot = void 0;
14595
+ }
14596
+ }
14540
14597
  reconciler.updateContainer(null, fiber, null, () => {
14541
14598
  if (state) {
14542
14599
  setTimeout(() => {
14543
14600
  try {
14544
14601
  const renderer = state.internal.actualRenderer;
14545
- const unregisterRoot = state.internal.unregisterRoot;
14546
- if (unregisterRoot) unregisterRoot();
14547
14602
  const unregisterPrimary = state.internal.unregisterPrimary;
14548
14603
  if (unregisterPrimary) unregisterPrimary();
14549
14604
  const canvasTarget = state.internal.canvasTarget;
14550
- if (canvasTarget?.dispose) canvasTarget.dispose();
14605
+ if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
14551
14606
  state.events.disconnect?.();
14552
14607
  cleanupHelperGroup(root.store);
14553
14608
  if (state.isLegacy && renderer) {
@@ -14688,16 +14743,11 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
14688
14743
  const oldbg = target.background;
14689
14744
  const oldenv = target.environment;
14690
14745
  const oldSceneProps = {
14691
- // @ts-ignore
14692
14746
  backgroundBlurriness: target.backgroundBlurriness,
14693
- // @ts-ignore
14694
14747
  backgroundIntensity: target.backgroundIntensity,
14695
- // @ts-ignore
14696
- backgroundRotation: target.backgroundRotation?.clone?.() ?? [0, 0, 0],
14697
- // @ts-ignore
14748
+ backgroundRotation: target.backgroundRotation.clone(),
14698
14749
  environmentIntensity: target.environmentIntensity,
14699
- // @ts-ignore
14700
- environmentRotation: target.environmentRotation?.clone?.() ?? [0, 0, 0]
14750
+ environmentRotation: target.environmentRotation.clone()
14701
14751
  };
14702
14752
  if (background !== "only") target.environment = texture;
14703
14753
  if (background) target.background = texture;
@@ -14991,9 +15041,9 @@ function CanvasImpl({
14991
15041
  React__namespace.useMemo(() => extend(THREE), []);
14992
15042
  const Bridge = useBridge();
14993
15043
  const backgroundProps = React__namespace.useMemo(() => parseBackground(background), [background]);
14994
- const hasInitialSizeRef = React__namespace.useRef(false);
15044
+ const [hasInitialSize, setHasInitialSize] = React__namespace.useState(false);
14995
15045
  const measureConfig = React__namespace.useMemo(() => {
14996
- if (!hasInitialSizeRef.current) {
15046
+ if (!hasInitialSize) {
14997
15047
  return {
14998
15048
  ...resize,
14999
15049
  scroll: resize?.scroll ?? true,
@@ -15005,7 +15055,7 @@ function CanvasImpl({
15005
15055
  debounce: { scroll: 50, resize: 0 },
15006
15056
  ...resize
15007
15057
  };
15008
- }, [resize, hasInitialSizeRef.current]);
15058
+ }, [hasInitialSize, resize]);
15009
15059
  const [containerRef, containerRect] = useMeasure__default(measureConfig);
15010
15060
  const effectiveSize = React__namespace.useMemo(() => {
15011
15061
  let w = width ?? containerRect.width;
@@ -15021,9 +15071,7 @@ function CanvasImpl({
15021
15071
  left: containerRect.left
15022
15072
  };
15023
15073
  }, [width, height, containerRect, forceEven]);
15024
- if (!hasInitialSizeRef.current && effectiveSize.width > 0 && effectiveSize.height > 0) {
15025
- hasInitialSizeRef.current = true;
15026
- }
15074
+ if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
15027
15075
  const canvasRef = React__namespace.useRef(null);
15028
15076
  const divRef = React__namespace.useRef(null);
15029
15077
  React__namespace.useImperativeHandle(ref, () => canvasRef.current);
@@ -15137,6 +15185,7 @@ function CanvasImpl({
15137
15185
  const canvas = canvasRef.current;
15138
15186
  if (canvas) {
15139
15187
  return () => {
15188
+ if (canvas.isConnected) return;
15140
15189
  unmountComponentAtNode(canvas);
15141
15190
  root.current = null;
15142
15191
  };