@react-three/fiber 10.0.0-canary.8f5b4d3 → 10.0.0-canary.979dc2d
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.cjs +120 -62
- package/dist/index.d.cts +180 -26
- package/dist/index.d.mts +180 -26
- package/dist/index.d.ts +180 -26
- package/dist/index.mjs +120 -62
- package/dist/legacy.cjs +116 -62
- package/dist/legacy.d.cts +179 -29
- package/dist/legacy.d.mts +179 -29
- package/dist/legacy.d.ts +179 -29
- package/dist/legacy.mjs +116 -62
- package/dist/webgpu/index.cjs +183 -99
- package/dist/webgpu/index.d.cts +204 -90
- package/dist/webgpu/index.d.mts +204 -90
- package/dist/webgpu/index.d.ts +204 -90
- package/dist/webgpu/index.mjs +183 -99
- package/package.json +4 -4
- package/readme.md +1 -1
- package/react-reconciler/constants.d.ts +0 -7
- package/react-reconciler/constants.js +0 -1
- package/react-reconciler/index.d.ts +0 -1044
- package/react-reconciler/index.js +0 -208
package/dist/webgpu/index.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
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, Vector4, RenderPipeline } from 'three/webgpu';
|
|
3
|
-
import { Inspector } from 'three/addons/inspector/Inspector.js';
|
|
4
3
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
4
|
import * as React from 'react';
|
|
6
5
|
import React__default, { useRef, useMemo, useLayoutEffect, useEffect, useContext, useImperativeHandle, useCallback, useState } from 'react';
|
|
@@ -34,6 +33,10 @@ function _mergeNamespaces(n, m) {
|
|
|
34
33
|
|
|
35
34
|
const R3F_BUILD_LEGACY = false;
|
|
36
35
|
const R3F_BUILD_WEBGPU = true;
|
|
36
|
+
async function loadInspector() {
|
|
37
|
+
const { Inspector } = await import('three/addons/inspector/Inspector.js');
|
|
38
|
+
return Inspector;
|
|
39
|
+
}
|
|
37
40
|
const WebGLRenderer = class WebGLRenderer2 {
|
|
38
41
|
constructor() {
|
|
39
42
|
throw new Error(
|
|
@@ -47,13 +50,13 @@ const WebGLCubeRenderTarget = null;
|
|
|
47
50
|
const THREE = /*#__PURE__*/_mergeNamespaces({
|
|
48
51
|
__proto__: null,
|
|
49
52
|
CubeRenderTargetCompat: CubeRenderTarget,
|
|
50
|
-
Inspector: Inspector,
|
|
51
53
|
R3F_BUILD_LEGACY: R3F_BUILD_LEGACY,
|
|
52
54
|
R3F_BUILD_WEBGPU: R3F_BUILD_WEBGPU,
|
|
53
55
|
RenderTargetCompat: RenderTarget,
|
|
54
56
|
WebGLCubeRenderTarget: WebGLCubeRenderTarget,
|
|
55
57
|
WebGLRenderTarget: WebGLRenderTarget,
|
|
56
|
-
WebGLRenderer: WebGLRenderer
|
|
58
|
+
WebGLRenderer: WebGLRenderer,
|
|
59
|
+
loadInspector: loadInspector
|
|
57
60
|
}, [webgpu]);
|
|
58
61
|
|
|
59
62
|
const primaryRegistry = /* @__PURE__ */ new Map();
|
|
@@ -912,7 +915,7 @@ const createStore = (invalidate, advance) => {
|
|
|
912
915
|
size: newSize,
|
|
913
916
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, newSize) }
|
|
914
917
|
}));
|
|
915
|
-
|
|
918
|
+
get().invalidate();
|
|
916
919
|
}
|
|
917
920
|
}
|
|
918
921
|
return;
|
|
@@ -927,15 +930,16 @@ const createStore = (invalidate, advance) => {
|
|
|
927
930
|
viewport: { ...s.viewport, ...getCurrentViewport(state2.camera, defaultTarget, size) },
|
|
928
931
|
_sizeImperative: true
|
|
929
932
|
}));
|
|
930
|
-
|
|
933
|
+
get().invalidate();
|
|
931
934
|
},
|
|
932
935
|
setDpr: (dpr) => set((state2) => {
|
|
933
936
|
const resolved = calculateDpr(dpr);
|
|
934
937
|
return { viewport: { ...state2.viewport, dpr: resolved, initialDpr: state2.viewport.initialDpr || resolved } };
|
|
935
938
|
}),
|
|
936
939
|
setFrameloop: (frameloop = "always") => {
|
|
940
|
+
const rootId = get().internal.rootId;
|
|
941
|
+
if (rootId) getScheduler().setRootFrameloop(rootId, frameloop);
|
|
937
942
|
set(() => ({ frameloop }));
|
|
938
|
-
getScheduler().frameloop = frameloop;
|
|
939
943
|
},
|
|
940
944
|
setError: (error) => set(() => ({ error })),
|
|
941
945
|
error: null,
|
|
@@ -1051,17 +1055,11 @@ const createStore = (invalidate, advance) => {
|
|
|
1051
1055
|
oldSize = size;
|
|
1052
1056
|
oldDpr = viewport.dpr;
|
|
1053
1057
|
updateCamera(camera, size);
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
actualRenderer.setSize(size.width, size.height, false);
|
|
1060
|
-
if (canvasTarget) {
|
|
1061
|
-
if (viewport.dpr > 0) canvasTarget.setPixelRatio(viewport.dpr);
|
|
1062
|
-
canvasTarget.setSize(size.width, size.height, false);
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1058
|
+
const resizeTarget = canvasTarget ?? actualRenderer;
|
|
1059
|
+
if (viewport.dpr > 0) resizeTarget.setPixelRatio(viewport.dpr);
|
|
1060
|
+
resizeTarget.setSize(size.width, size.height, false);
|
|
1061
|
+
const activeTarget = actualRenderer.getCanvasTarget?.();
|
|
1062
|
+
if (!canvasTarget || activeTarget !== canvasTarget) internal.canvasTargetSizeDirty = true;
|
|
1065
1063
|
}
|
|
1066
1064
|
if (camera !== oldCamera) {
|
|
1067
1065
|
oldCamera = camera;
|
|
@@ -1123,7 +1121,11 @@ function useLoader(loader, input, extensions, onProgress, cacheKey) {
|
|
|
1123
1121
|
const results = cacheKeys.map(
|
|
1124
1122
|
(key, index) => suspend(() => fn(loader, inputs[index]), [loader, key], { equal: is.equ })
|
|
1125
1123
|
);
|
|
1126
|
-
|
|
1124
|
+
const stableRef = useRef(null);
|
|
1125
|
+
const previous = stableRef.current;
|
|
1126
|
+
const stable = previous !== null && previous.length === results.length && previous.every((value, i) => value === results[i]) ? previous : results;
|
|
1127
|
+
stableRef.current = stable;
|
|
1128
|
+
return Array.isArray(input) ? stable : stable[0];
|
|
1127
1129
|
}
|
|
1128
1130
|
useLoader.preload = function(loader, input, extensions, onProgress, cacheKey) {
|
|
1129
1131
|
const inputs = Array.isArray(input) ? input : [input];
|
|
@@ -1138,7 +1140,7 @@ useLoader.clear = function(loader, input, cacheKey) {
|
|
|
1138
1140
|
};
|
|
1139
1141
|
useLoader.loader = getLoader$1;
|
|
1140
1142
|
|
|
1141
|
-
function useFrame(callback, priorityOrOptions) {
|
|
1143
|
+
function useFrame$1(callback, priorityOrOptions) {
|
|
1142
1144
|
const store = React.useContext(context);
|
|
1143
1145
|
const isInsideCanvas = store !== null;
|
|
1144
1146
|
const scheduler = getScheduler();
|
|
@@ -1243,6 +1245,13 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1243
1245
|
* Use for controlling the entire frame loop, adding phases, etc.
|
|
1244
1246
|
*/
|
|
1245
1247
|
scheduler: scheduler2,
|
|
1248
|
+
/**
|
|
1249
|
+
* The root that currently owns this job. Resolve on access because ambient
|
|
1250
|
+
* jobs can be adopted by a Canvas after the controls object is created.
|
|
1251
|
+
*/
|
|
1252
|
+
get rootId() {
|
|
1253
|
+
return getScheduler().getJobRootId(id);
|
|
1254
|
+
},
|
|
1246
1255
|
/**
|
|
1247
1256
|
* Manually step this job only.
|
|
1248
1257
|
* Bypasses FPS limiting - always runs.
|
|
@@ -1259,6 +1268,14 @@ function useFrame(callback, priorityOrOptions) {
|
|
|
1259
1268
|
stepAll: (timestamp) => {
|
|
1260
1269
|
getScheduler().step(timestamp);
|
|
1261
1270
|
},
|
|
1271
|
+
/**
|
|
1272
|
+
* Request frames for this job's owning root without waking sibling roots.
|
|
1273
|
+
*/
|
|
1274
|
+
invalidate: (frames, stackFrames) => {
|
|
1275
|
+
const scheduler3 = getScheduler();
|
|
1276
|
+
const rootId = scheduler3.getJobRootId(id);
|
|
1277
|
+
if (rootId) scheduler3.invalidateRoot(rootId, frames, stackFrames);
|
|
1278
|
+
},
|
|
1262
1279
|
/**
|
|
1263
1280
|
* Pause this job (set enabled=false).
|
|
1264
1281
|
* Job remains registered but won't run.
|
|
@@ -1288,6 +1305,11 @@ function getUrls(input) {
|
|
|
1288
1305
|
if (Array.isArray(input)) return input;
|
|
1289
1306
|
return Object.values(input);
|
|
1290
1307
|
}
|
|
1308
|
+
function inputSignature(input) {
|
|
1309
|
+
if (typeof input === "string") return input;
|
|
1310
|
+
if (Array.isArray(input)) return input.join("\0");
|
|
1311
|
+
return Object.keys(input).sort().map((key) => `${key}\0${input[key]}`).join("");
|
|
1312
|
+
}
|
|
1291
1313
|
function allUrlsCached(urls, textureCache) {
|
|
1292
1314
|
return urls.every((url) => textureCache.has(url));
|
|
1293
1315
|
}
|
|
@@ -1306,25 +1328,26 @@ function buildFromCache(input, textureCache) {
|
|
|
1306
1328
|
}
|
|
1307
1329
|
}
|
|
1308
1330
|
function useTexture(input, optionsOrOnLoad) {
|
|
1309
|
-
const renderer = useThree((state) => state.internal.actualRenderer);
|
|
1331
|
+
const renderer = useThree$1((state) => state.internal.actualRenderer);
|
|
1310
1332
|
const store = useStore();
|
|
1311
1333
|
const options = typeof optionsOrOnLoad === "function" ? { onLoad: optionsOrOnLoad } : optionsOrOnLoad ?? {};
|
|
1312
1334
|
const { onLoad, cache = true } = options;
|
|
1313
1335
|
const onLoadRef = useRef(onLoad);
|
|
1314
1336
|
onLoadRef.current = onLoad;
|
|
1315
1337
|
const onLoadCalledForRef = useRef(null);
|
|
1316
|
-
const
|
|
1338
|
+
const inputKey = useMemo(() => inputSignature(input), [input]);
|
|
1339
|
+
const stableInput = useMemo(() => input, [inputKey]);
|
|
1340
|
+
const urls = useMemo(() => getUrls(stableInput), [stableInput]);
|
|
1317
1341
|
const cachedResult = useMemo(() => {
|
|
1318
1342
|
if (!cache) return null;
|
|
1319
1343
|
const textures = store.getState().textures;
|
|
1320
1344
|
if (!allUrlsCached(urls, textures)) return null;
|
|
1321
|
-
return buildFromCache(
|
|
1322
|
-
}, [cache, urls,
|
|
1345
|
+
return buildFromCache(stableInput, textures);
|
|
1346
|
+
}, [cache, urls, stableInput, store]);
|
|
1323
1347
|
const loadedTextures = useLoader(
|
|
1324
1348
|
TextureLoader,
|
|
1325
|
-
IsObject(
|
|
1349
|
+
IsObject(stableInput) ? Object.values(stableInput) : stableInput
|
|
1326
1350
|
);
|
|
1327
|
-
const inputKey = urls.join("\0");
|
|
1328
1351
|
useLayoutEffect(() => {
|
|
1329
1352
|
if (cachedResult) return;
|
|
1330
1353
|
if (onLoadCalledForRef.current === inputKey) return;
|
|
@@ -1351,28 +1374,28 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1351
1374
|
}, [renderer, loadedTextures, cachedResult]);
|
|
1352
1375
|
const mappedTextures = useMemo(() => {
|
|
1353
1376
|
if (cachedResult) return cachedResult;
|
|
1354
|
-
if (IsObject(
|
|
1377
|
+
if (IsObject(stableInput)) {
|
|
1355
1378
|
const keyed = {};
|
|
1356
1379
|
const textureArray = loadedTextures;
|
|
1357
1380
|
let i = 0;
|
|
1358
|
-
for (const key in
|
|
1381
|
+
for (const key in stableInput) keyed[key] = textureArray[i++];
|
|
1359
1382
|
return keyed;
|
|
1360
1383
|
} else {
|
|
1361
1384
|
return loadedTextures;
|
|
1362
1385
|
}
|
|
1363
|
-
}, [
|
|
1386
|
+
}, [stableInput, loadedTextures, cachedResult]);
|
|
1364
1387
|
useEffect(() => {
|
|
1365
1388
|
if (!cache) return;
|
|
1366
1389
|
const urlTextureMap = [];
|
|
1367
|
-
if (typeof
|
|
1368
|
-
urlTextureMap.push([
|
|
1369
|
-
} else if (Array.isArray(
|
|
1390
|
+
if (typeof stableInput === "string") {
|
|
1391
|
+
urlTextureMap.push([stableInput, mappedTextures]);
|
|
1392
|
+
} else if (Array.isArray(stableInput)) {
|
|
1370
1393
|
const textureArray = mappedTextures;
|
|
1371
|
-
|
|
1372
|
-
} else if (IsObject(
|
|
1394
|
+
stableInput.forEach((url, i) => urlTextureMap.push([url, textureArray[i]]));
|
|
1395
|
+
} else if (IsObject(stableInput)) {
|
|
1373
1396
|
const textureRecord = mappedTextures;
|
|
1374
|
-
for (const key in
|
|
1375
|
-
const url =
|
|
1397
|
+
for (const key in stableInput) {
|
|
1398
|
+
const url = stableInput[key];
|
|
1376
1399
|
urlTextureMap.push([url, textureRecord[key]]);
|
|
1377
1400
|
}
|
|
1378
1401
|
}
|
|
@@ -1401,7 +1424,7 @@ function useTexture(input, optionsOrOnLoad) {
|
|
|
1401
1424
|
}
|
|
1402
1425
|
return { _textureRefs: refs };
|
|
1403
1426
|
});
|
|
1404
|
-
}, [cache,
|
|
1427
|
+
}, [cache, stableInput, mappedTextures, store]);
|
|
1405
1428
|
return mappedTextures;
|
|
1406
1429
|
}
|
|
1407
1430
|
useTexture.preload = (url) => useLoader.preload(TextureLoader, url);
|
|
@@ -1472,13 +1495,13 @@ function useTextures(selector) {
|
|
|
1472
1495
|
};
|
|
1473
1496
|
}, [store]);
|
|
1474
1497
|
const subscribe = selector ? () => selector(registry) : (state) => state.textures;
|
|
1475
|
-
const selected = useThree(subscribe);
|
|
1498
|
+
const selected = useThree$1(subscribe);
|
|
1476
1499
|
return selector ? selected : registry;
|
|
1477
1500
|
}
|
|
1478
1501
|
|
|
1479
1502
|
function useRenderTarget(widthOrOptions, heightOrOptions, options) {
|
|
1480
|
-
const isLegacy = useThree((s) => s.isLegacy);
|
|
1481
|
-
const size = useThree((s) => s.size);
|
|
1503
|
+
const isLegacy = useThree$1((s) => s.isLegacy);
|
|
1504
|
+
const size = useThree$1((s) => s.size);
|
|
1482
1505
|
let width;
|
|
1483
1506
|
let height;
|
|
1484
1507
|
let opts;
|
|
@@ -1535,7 +1558,7 @@ function useEnvironment({
|
|
|
1535
1558
|
const { extension, isCubemap } = getExtension(files);
|
|
1536
1559
|
const loader = getLoader(extension);
|
|
1537
1560
|
if (!loader) throw new Error("useEnvironment: Unrecognized file extension: " + files);
|
|
1538
|
-
const renderer = useThree((state) => state.renderer);
|
|
1561
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
1539
1562
|
useLayoutEffect(() => {
|
|
1540
1563
|
if (extension !== "webp" && extension !== "jpg" && extension !== "jpeg") return;
|
|
1541
1564
|
function clearGainmapTexture() {
|
|
@@ -1628,7 +1651,7 @@ function useStore() {
|
|
|
1628
1651
|
if (!store) throw new Error("R3F: Hooks can only be used within the Canvas component!");
|
|
1629
1652
|
return store;
|
|
1630
1653
|
}
|
|
1631
|
-
function useThree(selector = (state) => state, equalityFn) {
|
|
1654
|
+
function useThree$1(selector = (state) => state, equalityFn) {
|
|
1632
1655
|
return useStore()(selector, equalityFn);
|
|
1633
1656
|
}
|
|
1634
1657
|
function useInstanceHandle(ref) {
|
|
@@ -1670,13 +1693,19 @@ function addTail(callback) {
|
|
|
1670
1693
|
return getScheduler().onIdle(callback);
|
|
1671
1694
|
}
|
|
1672
1695
|
function invalidate(state, frames = 1, stackFrames = false) {
|
|
1673
|
-
|
|
1696
|
+
const rootId = state?.internal?.rootId;
|
|
1697
|
+
const scheduler = getScheduler();
|
|
1698
|
+
if (rootId) scheduler.invalidateRoot(rootId, frames, stackFrames);
|
|
1699
|
+
else scheduler.invalidate(frames, stackFrames);
|
|
1674
1700
|
}
|
|
1675
|
-
function advance(timestamp) {
|
|
1676
|
-
|
|
1701
|
+
function advance(timestamp, runGlobalEffects, state) {
|
|
1702
|
+
const rootId = state?.internal?.rootId;
|
|
1703
|
+
const scheduler = getScheduler();
|
|
1704
|
+
if (rootId) scheduler.stepRoot(rootId, timestamp);
|
|
1705
|
+
else scheduler.step(timestamp);
|
|
1677
1706
|
}
|
|
1678
1707
|
|
|
1679
|
-
const version = "10.0.0-alpha.
|
|
1708
|
+
const version = "10.0.0-alpha.4";
|
|
1680
1709
|
const packageData = {
|
|
1681
1710
|
version: version};
|
|
1682
1711
|
|
|
@@ -12959,7 +12988,10 @@ function releaseInternalPointerCapture(internal, obj, pointerId) {
|
|
|
12959
12988
|
const captureData = pointerState.captured.get(obj);
|
|
12960
12989
|
if (captureData) {
|
|
12961
12990
|
pointerState.captured.delete(obj);
|
|
12962
|
-
|
|
12991
|
+
try {
|
|
12992
|
+
captureData.target.releasePointerCapture?.(pointerId);
|
|
12993
|
+
} catch {
|
|
12994
|
+
}
|
|
12963
12995
|
}
|
|
12964
12996
|
}
|
|
12965
12997
|
function swapInteractivity(store, object, newObject) {
|
|
@@ -13053,7 +13085,9 @@ function createEvents(store) {
|
|
|
13053
13085
|
state2.events.compute?.(event, state2, state2.previousRoot?.getState());
|
|
13054
13086
|
if (state2.raycaster.camera === void 0) state2.raycaster.camera = null;
|
|
13055
13087
|
}
|
|
13056
|
-
|
|
13088
|
+
if (!state2.raycaster.camera) return [];
|
|
13089
|
+
obj.updateWorldMatrix(true, true);
|
|
13090
|
+
return state2.raycaster.intersectObject(obj, true);
|
|
13057
13091
|
}
|
|
13058
13092
|
let hits = eventsObjects.flatMap(handleRaycast).sort((a, b) => {
|
|
13059
13093
|
const aInteractivePriority = a.object.userData?.interactivePriority;
|
|
@@ -14187,9 +14221,8 @@ function createRoot(canvas) {
|
|
|
14187
14221
|
if (!renderer.hasInitialized?.()) {
|
|
14188
14222
|
const size2 = computeInitialSize(canvas, propsSize);
|
|
14189
14223
|
if (size2.width > 0 && size2.height > 0) {
|
|
14190
|
-
|
|
14191
|
-
|
|
14192
|
-
canvas.height = size2.height * pixelRatio;
|
|
14224
|
+
renderer.setPixelRatio(calculateDpr(dpr));
|
|
14225
|
+
renderer.setSize(size2.width, size2.height, false);
|
|
14193
14226
|
}
|
|
14194
14227
|
await renderer.init();
|
|
14195
14228
|
}
|
|
@@ -14198,7 +14231,7 @@ function createRoot(canvas) {
|
|
|
14198
14231
|
state.internal.actualRenderer = renderer;
|
|
14199
14232
|
state.set({ webGPUSupported: isWebGPUBackend, renderer, primaryStore: store });
|
|
14200
14233
|
if (canvasId && !state.internal.isSecondary) {
|
|
14201
|
-
const canvasTarget =
|
|
14234
|
+
const canvasTarget = renderer.getCanvasTarget?.();
|
|
14202
14235
|
const unregisterPrimary = registerPrimary(canvasId, renderer, store);
|
|
14203
14236
|
state.set((prev) => ({
|
|
14204
14237
|
internal: {
|
|
@@ -14312,7 +14345,7 @@ function createRoot(canvas) {
|
|
|
14312
14345
|
const handleXRFrame = (timestamp, _frame) => {
|
|
14313
14346
|
const state2 = store.getState();
|
|
14314
14347
|
if (state2.frameloop === "never") return;
|
|
14315
|
-
advance(timestamp);
|
|
14348
|
+
advance(timestamp, true, state2);
|
|
14316
14349
|
};
|
|
14317
14350
|
const actualRenderer = state.internal.actualRenderer;
|
|
14318
14351
|
const handleSessionChange = () => {
|
|
@@ -14320,7 +14353,7 @@ function createRoot(canvas) {
|
|
|
14320
14353
|
const renderer2 = state2.internal.actualRenderer;
|
|
14321
14354
|
actualRenderer.xr.enabled = actualRenderer.xr.isPresenting;
|
|
14322
14355
|
renderer2.xr.setAnimationLoop(renderer2.xr.isPresenting ? handleXRFrame : null);
|
|
14323
|
-
if (!renderer2.xr.isPresenting) invalidate();
|
|
14356
|
+
if (!renderer2.xr.isPresenting) invalidate(state2);
|
|
14324
14357
|
};
|
|
14325
14358
|
const xr = {
|
|
14326
14359
|
connect() {
|
|
@@ -14402,14 +14435,23 @@ function createRoot(canvas) {
|
|
|
14402
14435
|
const newRootId = canvasId || scheduler.generateRootId();
|
|
14403
14436
|
const unregisterRoot = scheduler.registerRoot(newRootId, {
|
|
14404
14437
|
getState: () => store.getState(),
|
|
14405
|
-
onError: (err) => store.getState().setError(err)
|
|
14438
|
+
onError: (err) => store.getState().setError(err),
|
|
14439
|
+
frameloop: store.getState().frameloop,
|
|
14440
|
+
before: schedulerConfig?.before,
|
|
14441
|
+
after: schedulerConfig?.after,
|
|
14442
|
+
order: schedulerConfig?.order
|
|
14406
14443
|
});
|
|
14407
14444
|
const unregisterCanvasTarget = scheduler.register(
|
|
14408
14445
|
() => {
|
|
14409
14446
|
const state2 = store.getState();
|
|
14410
|
-
|
|
14447
|
+
const canvasTarget = state2.internal.canvasTarget;
|
|
14448
|
+
if (canvasTarget) {
|
|
14411
14449
|
const renderer2 = state2.internal.actualRenderer;
|
|
14412
|
-
renderer2.setCanvasTarget(
|
|
14450
|
+
if (renderer2.getCanvasTarget() !== canvasTarget) renderer2.setCanvasTarget(canvasTarget);
|
|
14451
|
+
if (state2.internal.canvasTargetSizeDirty) {
|
|
14452
|
+
state2.internal.canvasTargetSizeDirty = false;
|
|
14453
|
+
renderer2.backend?.updateSize?.();
|
|
14454
|
+
}
|
|
14413
14455
|
}
|
|
14414
14456
|
},
|
|
14415
14457
|
{
|
|
@@ -14478,8 +14520,7 @@ function createRoot(canvas) {
|
|
|
14478
14520
|
phase: "render",
|
|
14479
14521
|
system: true,
|
|
14480
14522
|
// Internal flag: this is a system job, not user-controlled
|
|
14481
|
-
//
|
|
14482
|
-
...schedulerConfig?.after && { after: schedulerConfig.after },
|
|
14523
|
+
// FPS throttles only the default render job; Canvas ordering belongs to the root.
|
|
14483
14524
|
...schedulerConfig?.fps && { fps: schedulerConfig.fps }
|
|
14484
14525
|
}
|
|
14485
14526
|
);
|
|
@@ -14498,8 +14539,21 @@ function createRoot(canvas) {
|
|
|
14498
14539
|
scheduler
|
|
14499
14540
|
}
|
|
14500
14541
|
}));
|
|
14542
|
+
} else {
|
|
14543
|
+
const constraintsChanged = !is.equ(schedulerConfig?.before, lastConfiguredProps.schedulerBefore, shallowLoose) || !is.equ(schedulerConfig?.after, lastConfiguredProps.schedulerAfter, shallowLoose);
|
|
14544
|
+
if (constraintsChanged) {
|
|
14545
|
+
scheduler.setRootConstraints(rootId, {
|
|
14546
|
+
before: schedulerConfig?.before,
|
|
14547
|
+
after: schedulerConfig?.after
|
|
14548
|
+
});
|
|
14549
|
+
}
|
|
14550
|
+
if (schedulerConfig?.order !== lastConfiguredProps.schedulerOrder) {
|
|
14551
|
+
scheduler.setRootOrder(rootId, schedulerConfig?.order ?? 0);
|
|
14552
|
+
}
|
|
14501
14553
|
}
|
|
14502
|
-
|
|
14554
|
+
lastConfiguredProps.schedulerBefore = schedulerConfig?.before;
|
|
14555
|
+
lastConfiguredProps.schedulerAfter = schedulerConfig?.after;
|
|
14556
|
+
lastConfiguredProps.schedulerOrder = schedulerConfig?.order;
|
|
14503
14557
|
onCreated = onCreatedCallback;
|
|
14504
14558
|
configured = true;
|
|
14505
14559
|
resolve();
|
|
@@ -14541,18 +14595,23 @@ function unmountComponentAtNode(canvas, callback) {
|
|
|
14541
14595
|
const fiber = root?.fiber;
|
|
14542
14596
|
if (fiber) {
|
|
14543
14597
|
const state = root?.store.getState();
|
|
14544
|
-
if (state)
|
|
14598
|
+
if (state) {
|
|
14599
|
+
state.internal.active = false;
|
|
14600
|
+
const unregisterRoot = state.internal.unregisterRoot;
|
|
14601
|
+
if (unregisterRoot) {
|
|
14602
|
+
unregisterRoot();
|
|
14603
|
+
state.internal.unregisterRoot = void 0;
|
|
14604
|
+
}
|
|
14605
|
+
}
|
|
14545
14606
|
reconciler.updateContainer(null, fiber, null, () => {
|
|
14546
14607
|
if (state) {
|
|
14547
14608
|
setTimeout(() => {
|
|
14548
14609
|
try {
|
|
14549
14610
|
const renderer = state.internal.actualRenderer;
|
|
14550
|
-
const unregisterRoot = state.internal.unregisterRoot;
|
|
14551
|
-
if (unregisterRoot) unregisterRoot();
|
|
14552
14611
|
const unregisterPrimary = state.internal.unregisterPrimary;
|
|
14553
14612
|
if (unregisterPrimary) unregisterPrimary();
|
|
14554
14613
|
const canvasTarget = state.internal.canvasTarget;
|
|
14555
|
-
if (canvasTarget?.dispose) canvasTarget.dispose();
|
|
14614
|
+
if (state.internal.isSecondary && canvasTarget?.dispose) canvasTarget.dispose();
|
|
14556
14615
|
state.events.disconnect?.();
|
|
14557
14616
|
cleanupHelperGroup(root.store);
|
|
14558
14617
|
if (state.isLegacy && renderer) {
|
|
@@ -14714,7 +14773,7 @@ function setEnvProps(background, scene, defaultScene, texture, sceneProps = {})
|
|
|
14714
14773
|
};
|
|
14715
14774
|
}
|
|
14716
14775
|
function EnvironmentMap({ scene, background = false, map, ...config }) {
|
|
14717
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14776
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14718
14777
|
React.useLayoutEffect(() => {
|
|
14719
14778
|
if (map) return setEnvProps(background, scene, defaultScene, map, config);
|
|
14720
14779
|
});
|
|
@@ -14732,7 +14791,7 @@ function EnvironmentCube({
|
|
|
14732
14791
|
...rest
|
|
14733
14792
|
}) {
|
|
14734
14793
|
const texture = useEnvironment(rest);
|
|
14735
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14794
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14736
14795
|
React.useLayoutEffect(() => {
|
|
14737
14796
|
return setEnvProps(background, scene, defaultScene, texture, {
|
|
14738
14797
|
backgroundBlurriness: blur ?? backgroundBlurriness,
|
|
@@ -14769,9 +14828,9 @@ function EnvironmentPortal({
|
|
|
14769
14828
|
preset = void 0,
|
|
14770
14829
|
extensions
|
|
14771
14830
|
}) {
|
|
14772
|
-
const renderer = useThree((state) => state.renderer);
|
|
14773
|
-
const isLegacy = useThree((state) => state.isLegacy);
|
|
14774
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14831
|
+
const renderer = useThree$1((state) => state.renderer);
|
|
14832
|
+
const isLegacy = useThree$1((state) => state.isLegacy);
|
|
14833
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14775
14834
|
const camera = React.useRef(null);
|
|
14776
14835
|
const [virtualScene] = React.useState(() => new Scene());
|
|
14777
14836
|
const fbo = React.useMemo(() => {
|
|
@@ -14815,7 +14874,7 @@ function EnvironmentPortal({
|
|
|
14815
14874
|
environmentRotation
|
|
14816
14875
|
]);
|
|
14817
14876
|
let count = 1;
|
|
14818
|
-
useFrame(() => {
|
|
14877
|
+
useFrame$1(() => {
|
|
14819
14878
|
if (frames === Infinity || count < frames) {
|
|
14820
14879
|
const autoClear = renderer.autoClear;
|
|
14821
14880
|
renderer.autoClear = true;
|
|
@@ -14855,7 +14914,7 @@ function EnvironmentGround(props) {
|
|
|
14855
14914
|
] });
|
|
14856
14915
|
}
|
|
14857
14916
|
function EnvironmentColor({ color, scene }) {
|
|
14858
|
-
const defaultScene = useThree((state) => state.scene);
|
|
14917
|
+
const defaultScene = useThree$1((state) => state.scene);
|
|
14859
14918
|
React.useLayoutEffect(() => {
|
|
14860
14919
|
if (color === void 0) return;
|
|
14861
14920
|
const target = resolveScene(scene || defaultScene);
|
|
@@ -15093,9 +15152,9 @@ function CanvasImpl({
|
|
|
15093
15152
|
React.useMemo(() => extend(THREE), []);
|
|
15094
15153
|
const Bridge = useBridge();
|
|
15095
15154
|
const backgroundProps = React.useMemo(() => parseBackground(background), [background]);
|
|
15096
|
-
const
|
|
15155
|
+
const [hasInitialSize, setHasInitialSize] = React.useState(false);
|
|
15097
15156
|
const measureConfig = React.useMemo(() => {
|
|
15098
|
-
if (!
|
|
15157
|
+
if (!hasInitialSize) {
|
|
15099
15158
|
return {
|
|
15100
15159
|
...resize,
|
|
15101
15160
|
scroll: resize?.scroll ?? true,
|
|
@@ -15107,7 +15166,7 @@ function CanvasImpl({
|
|
|
15107
15166
|
debounce: { scroll: 50, resize: 0 },
|
|
15108
15167
|
...resize
|
|
15109
15168
|
};
|
|
15110
|
-
}, [
|
|
15169
|
+
}, [hasInitialSize, resize]);
|
|
15111
15170
|
const [containerRef, containerRect] = useMeasure(measureConfig);
|
|
15112
15171
|
const effectiveSize = React.useMemo(() => {
|
|
15113
15172
|
let w = width ?? containerRect.width;
|
|
@@ -15123,9 +15182,7 @@ function CanvasImpl({
|
|
|
15123
15182
|
left: containerRect.left
|
|
15124
15183
|
};
|
|
15125
15184
|
}, [width, height, containerRect, forceEven]);
|
|
15126
|
-
if (!
|
|
15127
|
-
hasInitialSizeRef.current = true;
|
|
15128
|
-
}
|
|
15185
|
+
if (!hasInitialSize && effectiveSize.width > 0 && effectiveSize.height > 0) setHasInitialSize(true);
|
|
15129
15186
|
const canvasRef = React.useRef(null);
|
|
15130
15187
|
const divRef = React.useRef(null);
|
|
15131
15188
|
React.useImperativeHandle(ref, () => canvasRef.current);
|
|
@@ -15239,6 +15296,7 @@ function CanvasImpl({
|
|
|
15239
15296
|
const canvas = canvasRef.current;
|
|
15240
15297
|
if (canvas) {
|
|
15241
15298
|
return () => {
|
|
15299
|
+
if (canvas.isConnected) return;
|
|
15242
15300
|
unmountComponentAtNode(canvas);
|
|
15243
15301
|
root.current = null;
|
|
15244
15302
|
};
|
|
@@ -15449,6 +15507,11 @@ function createTextureOperations(set) {
|
|
|
15449
15507
|
removeMultiple: (keys) => removeTextures(set, keys)
|
|
15450
15508
|
};
|
|
15451
15509
|
}
|
|
15510
|
+
function scopedNodeName(scope, name) {
|
|
15511
|
+
const raw = scope ? `${scope}_${name}` : name;
|
|
15512
|
+
const safe = raw.replace(/[^A-Za-z0-9_]/g, "_");
|
|
15513
|
+
return /^[A-Za-z_]/.test(safe) ? safe : `_${safe}`;
|
|
15514
|
+
}
|
|
15452
15515
|
function extractTSLValue(value) {
|
|
15453
15516
|
if (value === null || value === void 0) return value;
|
|
15454
15517
|
if (typeof value !== "object") return value;
|
|
@@ -15647,8 +15710,7 @@ function createUniform(inName, node, scope) {
|
|
|
15647
15710
|
const inValue = vectorize(node);
|
|
15648
15711
|
const newUniform = uniform(inValue);
|
|
15649
15712
|
if (typeof newUniform.setName === "function") {
|
|
15650
|
-
|
|
15651
|
-
newUniform.setName(name);
|
|
15713
|
+
newUniform.setName(scopedNodeName(scope, inName));
|
|
15652
15714
|
}
|
|
15653
15715
|
return newUniform;
|
|
15654
15716
|
}
|
|
@@ -15747,7 +15809,7 @@ function useNodes(creatorOrScope, scope) {
|
|
|
15747
15809
|
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15748
15810
|
},
|
|
15749
15811
|
prepare: (name, node) => {
|
|
15750
|
-
node.setName?.(scope
|
|
15812
|
+
node.setName?.(scopedNodeName(scope, name));
|
|
15751
15813
|
return node;
|
|
15752
15814
|
}
|
|
15753
15815
|
});
|
|
@@ -15856,7 +15918,7 @@ function useBuffers(creatorOrScope, scope) {
|
|
|
15856
15918
|
},
|
|
15857
15919
|
prepare: (name, buffer) => {
|
|
15858
15920
|
if ("setName" in buffer && typeof buffer.setName === "function") {
|
|
15859
|
-
buffer.setName(scope
|
|
15921
|
+
buffer.setName(scopedNodeName(scope, name));
|
|
15860
15922
|
}
|
|
15861
15923
|
return buffer;
|
|
15862
15924
|
}
|
|
@@ -15927,7 +15989,7 @@ function useGPUStorage(creatorOrScope, scope) {
|
|
|
15927
15989
|
return creatorOrScope(createLazyCreatorState(store.getState(), store));
|
|
15928
15990
|
},
|
|
15929
15991
|
prepare: (name, storage) => {
|
|
15930
|
-
const label = scope
|
|
15992
|
+
const label = scopedNodeName(scope, name);
|
|
15931
15993
|
if ("setName" in storage && typeof storage.setName === "function") {
|
|
15932
15994
|
storage.setName(label);
|
|
15933
15995
|
}
|
|
@@ -15958,9 +16020,10 @@ function rebuildAllStorage(store, scope) {
|
|
|
15958
16020
|
|
|
15959
16021
|
function useRenderPipeline(mainCB, setupCB) {
|
|
15960
16022
|
const store = useStore();
|
|
15961
|
-
const { scene, camera, renderer, isLegacy } = useThree();
|
|
16023
|
+
const { scene, camera, renderer, isLegacy } = useThree$1();
|
|
15962
16024
|
const callbacksRanRef = useRef(false);
|
|
15963
16025
|
const scenePassCacheRef = useRef(null);
|
|
16026
|
+
const forceScenePassRebuildRef = useRef(false);
|
|
15964
16027
|
const mainCBRef = useRef(mainCB);
|
|
15965
16028
|
const setupCBRef = useRef(setupCB);
|
|
15966
16029
|
mainCBRef.current = mainCB;
|
|
@@ -15968,7 +16031,7 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
15968
16031
|
const [rebuildVersion, setRebuildVersion] = useState(0);
|
|
15969
16032
|
useEffect(() => {
|
|
15970
16033
|
callbacksRanRef.current = false;
|
|
15971
|
-
|
|
16034
|
+
forceScenePassRebuildRef.current = true;
|
|
15972
16035
|
}, []);
|
|
15973
16036
|
const clearPasses = useCallback(() => {
|
|
15974
16037
|
store.setState({ passes: {} });
|
|
@@ -15978,12 +16041,14 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
15978
16041
|
renderPipeline: null,
|
|
15979
16042
|
passes: {}
|
|
15980
16043
|
});
|
|
16044
|
+
scenePassCacheRef.current?.scenePass.dispose();
|
|
15981
16045
|
callbacksRanRef.current = false;
|
|
15982
16046
|
scenePassCacheRef.current = null;
|
|
16047
|
+
forceScenePassRebuildRef.current = false;
|
|
15983
16048
|
}, [store]);
|
|
15984
16049
|
const rebuild = useCallback(() => {
|
|
15985
16050
|
callbacksRanRef.current = false;
|
|
15986
|
-
|
|
16051
|
+
forceScenePassRebuildRef.current = true;
|
|
15987
16052
|
setRebuildVersion((v) => v + 1);
|
|
15988
16053
|
}, []);
|
|
15989
16054
|
useLayoutEffect(() => {
|
|
@@ -15991,6 +16056,9 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
15991
16056
|
throw new Error("useRenderPipeline is only available with WebGPU renderer. Set renderer prop on Canvas.");
|
|
15992
16057
|
}
|
|
15993
16058
|
if (!renderer || !scene || !camera) return;
|
|
16059
|
+
if (!("isWebGPURenderer" in renderer)) {
|
|
16060
|
+
throw new Error("useRenderPipeline: renderer is not a WebGPURenderer but isLegacy is false.");
|
|
16061
|
+
}
|
|
15994
16062
|
const state = store.getState();
|
|
15995
16063
|
const set = store.setState;
|
|
15996
16064
|
try {
|
|
@@ -16001,21 +16069,33 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16001
16069
|
pipeline = new RenderPipeline(renderer);
|
|
16002
16070
|
justCreatedPipeline = true;
|
|
16003
16071
|
}
|
|
16004
|
-
const cacheValid = scenePassCacheRef.current && scenePassCacheRef.current.sceneUuid === scene.uuid && scenePassCacheRef.current.cameraUuid === camera.uuid;
|
|
16072
|
+
const cacheValid = !forceScenePassRebuildRef.current && scenePassCacheRef.current && scenePassCacheRef.current.sceneUuid === scene.uuid && scenePassCacheRef.current.cameraUuid === camera.uuid;
|
|
16073
|
+
let outgoingScenePass = null;
|
|
16005
16074
|
let scenePass;
|
|
16006
16075
|
if (cacheValid) {
|
|
16007
16076
|
scenePass = scenePassCacheRef.current.scenePass;
|
|
16008
16077
|
} else {
|
|
16078
|
+
outgoingScenePass = scenePassCacheRef.current?.scenePass ?? null;
|
|
16009
16079
|
scenePass = pass(scene, camera);
|
|
16010
16080
|
scenePassCacheRef.current = { sceneUuid: scene.uuid, cameraUuid: camera.uuid, scenePass };
|
|
16081
|
+
forceScenePassRebuildRef.current = false;
|
|
16011
16082
|
}
|
|
16012
16083
|
currentPasses.scenePass = scenePass;
|
|
16013
|
-
|
|
16084
|
+
let outputNodeChanged = false;
|
|
16085
|
+
if (!pipeline.outputNode || justCreatedPipeline || pipeline.outputNode === outgoingScenePass) {
|
|
16086
|
+
pipeline.outputNode = scenePass;
|
|
16087
|
+
outputNodeChanged = true;
|
|
16088
|
+
}
|
|
16014
16089
|
set({ renderPipeline: pipeline, passes: currentPasses });
|
|
16015
16090
|
const shouldRunCallbacks = justCreatedPipeline || !callbacksRanRef.current || !cacheValid;
|
|
16016
16091
|
if (shouldRunCallbacks) {
|
|
16017
16092
|
if (setupCBRef.current) {
|
|
16018
|
-
const freshState = store.getState()
|
|
16093
|
+
const freshState = Object.assign({}, store.getState(), {
|
|
16094
|
+
renderPipeline: pipeline,
|
|
16095
|
+
passes: { ...currentPasses, scenePass },
|
|
16096
|
+
renderer,
|
|
16097
|
+
isLegacy: false
|
|
16098
|
+
});
|
|
16019
16099
|
const setupResult = setupCBRef.current(freshState);
|
|
16020
16100
|
if (setupResult && typeof setupResult === "object") {
|
|
16021
16101
|
currentPasses = { ...currentPasses, ...setupResult };
|
|
@@ -16023,32 +16103,36 @@ function useRenderPipeline(mainCB, setupCB) {
|
|
|
16023
16103
|
}
|
|
16024
16104
|
}
|
|
16025
16105
|
if (mainCBRef.current) {
|
|
16026
|
-
const freshState = store.getState()
|
|
16106
|
+
const freshState = Object.assign({}, store.getState(), {
|
|
16107
|
+
renderPipeline: pipeline,
|
|
16108
|
+
passes: { ...currentPasses, scenePass },
|
|
16109
|
+
renderer,
|
|
16110
|
+
isLegacy: false
|
|
16111
|
+
});
|
|
16027
16112
|
const mainResult = mainCBRef.current(freshState);
|
|
16028
16113
|
if (mainResult && typeof mainResult === "object") {
|
|
16029
16114
|
currentPasses = { ...currentPasses, ...mainResult };
|
|
16030
16115
|
set({ passes: currentPasses });
|
|
16031
16116
|
}
|
|
16032
16117
|
}
|
|
16118
|
+
outputNodeChanged = true;
|
|
16033
16119
|
callbacksRanRef.current = true;
|
|
16034
16120
|
}
|
|
16121
|
+
if (outputNodeChanged) pipeline.needsUpdate = true;
|
|
16122
|
+
if (outgoingScenePass && outgoingScenePass !== scenePass) outgoingScenePass.dispose();
|
|
16035
16123
|
} catch (error) {
|
|
16036
16124
|
console.warn("[useRenderPipeline] Setup failed; the render pipeline was not configured:", error);
|
|
16037
16125
|
}
|
|
16038
16126
|
}, [store, renderer, scene, camera, isLegacy, rebuildVersion]);
|
|
16039
|
-
const passes = useThree((s) => s.passes);
|
|
16040
|
-
const renderPipeline = useThree((s) => s.renderPipeline);
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
|
|
16044
|
-
clearPasses,
|
|
16045
|
-
reset,
|
|
16046
|
-
rebuild,
|
|
16047
|
-
// isReady indicates if RenderPipeline is configured and ready for rendering
|
|
16048
|
-
isReady: renderPipeline !== null
|
|
16049
|
-
};
|
|
16127
|
+
const passes = useThree$1((s) => s.passes);
|
|
16128
|
+
const renderPipeline = useThree$1((s) => s.renderPipeline);
|
|
16129
|
+
const actions = { passes, clearPasses, reset, rebuild };
|
|
16130
|
+
if (renderPipeline) return { ...actions, isReady: true, renderPipeline };
|
|
16131
|
+
return { ...actions, isReady: false, renderPipeline: null };
|
|
16050
16132
|
}
|
|
16051
16133
|
|
|
16052
16134
|
extend(THREE);
|
|
16135
|
+
const useThree = useThree$1;
|
|
16136
|
+
const useFrame = useFrame$1;
|
|
16053
16137
|
|
|
16054
16138
|
export { Block, Canvas, Environment, EnvironmentCube, EnvironmentMap, EnvironmentPortal, ErrorBoundary, FROM_REF, IsObject, ONCE, Portal, R3F_BUILD_LEGACY, R3F_BUILD_WEBGPU, REACT_INTERNAL_PROPS, RESERVED_PROPS, Texture, _roots, addAfterEffect, addEffect, addTail, advance, applyProps, attach, buildGraph, calculateDpr, clearNodeScope, clearRootNodes, clearRootUniforms, clearScope, context, createEvents, createPointerEvents, createPortal, createRoot, createScopedStore, createStore, createTextureOperations, detach, diffProps, dispose, createPointerEvents as events, extend, findInitialRoot, flushSync, fromRef, getInstanceProps, getPrimary, getPrimaryIds, getRootState, getUuidPrefix, hasConstructor, hasPrimary, invalidate, invalidateInstance, is, isColorRepresentation, isCopyable, isFromRef, isObject3D, isOnce, isOrthographicCamera, isRef$1 as isRef, isRenderer, isTexture, isVectorLike, once, prepare, presetsObj, rebuildAllBuffers, rebuildAllNodes, rebuildAllStorage, rebuildAllUniforms, reconciler, registerPrimary, removeInteractivity, removeNodes, removeUniforms, resolve, swapInteractivity, unmountComponentAtNode, unregisterPrimary, updateCamera, updateFrustum, useBridge, useBuffers, useEnvironment, useFrame, useGPUStorage, useGraph, useInstanceHandle, useIsomorphicLayoutEffect, useLoader, useLocalNodes, useMutableCallback, useNodes, useRenderPipeline, useRenderTarget, useStore, useTexture, useTextures, useThree, useUniform, useUniforms, waitForPrimary };
|