@react-three/fiber 9.0.0-alpha.7 → 9.0.0-alpha.8
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/declarations/src/core/events.d.ts +1 -1
- package/dist/declarations/src/core/hooks.d.ts +1 -6
- package/dist/declarations/src/core/index.d.ts +1 -3
- package/dist/declarations/src/core/reconciler.d.ts +3 -2
- package/dist/declarations/src/core/renderer.d.ts +2 -6
- package/dist/declarations/src/core/store.d.ts +3 -21
- package/dist/declarations/src/core/utils.d.ts +8 -0
- package/dist/declarations/src/three-types.d.ts +8 -15
- package/dist/{loop-2e09d861.cjs.prod.js → loop-5012a96a.cjs.prod.js} +158 -337
- package/dist/{loop-4ac96174.cjs.dev.js → loop-8dd3f5bb.cjs.dev.js} +158 -337
- package/dist/{loop-2db547cd.esm.js → loop-ed5edcdb.esm.js} +159 -334
- package/dist/react-three-fiber.cjs.dev.js +1 -6
- package/dist/react-three-fiber.cjs.prod.js +1 -6
- package/dist/react-three-fiber.esm.js +2 -3
- package/native/dist/react-three-fiber-native.cjs.dev.js +1 -7
- package/native/dist/react-three-fiber-native.cjs.prod.js +1 -7
- package/native/dist/react-three-fiber-native.esm.js +2 -4
- package/package.json +3 -3
- package/dist/declarations/src/core/stages.d.ts +0 -64
|
@@ -38,6 +38,9 @@ var threeTypes = /*#__PURE__*/Object.freeze({
|
|
|
38
38
|
__proto__: null
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
// TODO: upstream to DefinitelyTyped for React 19
|
|
42
|
+
// https://github.com/facebook/react/issues/28956
|
|
43
|
+
|
|
41
44
|
const createReconciler = Reconciler__default["default"];
|
|
42
45
|
|
|
43
46
|
// TODO: handle constructor overloads
|
|
@@ -46,25 +49,17 @@ const createReconciler = Reconciler__default["default"];
|
|
|
46
49
|
|
|
47
50
|
const catalogue = {};
|
|
48
51
|
let i = 0;
|
|
49
|
-
const
|
|
50
|
-
|
|
52
|
+
const isConstructor$1 = object => typeof object === 'function';
|
|
53
|
+
function extend(objects) {
|
|
54
|
+
if (isConstructor$1(objects)) {
|
|
51
55
|
const Component = `${i++}`;
|
|
52
56
|
catalogue[Component] = objects;
|
|
53
|
-
|
|
54
|
-
// Returns a component whose name will be inferred in devtools
|
|
55
|
-
// @ts-expect-error
|
|
56
|
-
return /*#__PURE__*/React__namespace.forwardRef({
|
|
57
|
-
[objects.name]: (props, ref) => /*#__PURE__*/jsxRuntime.jsx(Component, {
|
|
58
|
-
...props,
|
|
59
|
-
ref: ref
|
|
60
|
-
})
|
|
61
|
-
}[objects.name]);
|
|
57
|
+
return Component;
|
|
62
58
|
} else {
|
|
63
|
-
|
|
59
|
+
Object.assign(catalogue, objects);
|
|
64
60
|
}
|
|
65
|
-
}
|
|
66
|
-
function
|
|
67
|
-
var _props$object;
|
|
61
|
+
}
|
|
62
|
+
function validateInstance(type, props) {
|
|
68
63
|
// Get target from catalogue
|
|
69
64
|
const name = `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
70
65
|
const target = catalogue[name];
|
|
@@ -77,13 +72,14 @@ function createInstance(type, props, root, flushPrimitive = true) {
|
|
|
77
72
|
|
|
78
73
|
// Throw if an object or literal was passed for args
|
|
79
74
|
if (props.args !== undefined && !Array.isArray(props.args)) throw new Error('R3F: The args prop must be an array!');
|
|
75
|
+
}
|
|
76
|
+
function createInstance(type, props, root) {
|
|
77
|
+
var _props$object;
|
|
78
|
+
validateInstance(type, props);
|
|
80
79
|
|
|
81
80
|
// Regenerate the R3F instance for primitives to simulate a new object
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
// Create instance
|
|
85
|
-
const instance = prepare(props.object, root, type, props);
|
|
86
|
-
return instance;
|
|
81
|
+
if (type === 'primitive' && (_props$object = props.object) != null && _props$object.__r3f) delete props.object.__r3f;
|
|
82
|
+
return prepare(props.object, root, type, props);
|
|
87
83
|
}
|
|
88
84
|
function hideInstance(instance) {
|
|
89
85
|
if (!instance.isHidden) {
|
|
@@ -180,15 +176,29 @@ function insertBefore(parent, child, beforeChild) {
|
|
|
180
176
|
// Attach tree once complete
|
|
181
177
|
handleContainerEffects(parent, child, beforeChild);
|
|
182
178
|
}
|
|
183
|
-
function
|
|
179
|
+
function disposeOnIdle(object) {
|
|
180
|
+
if (typeof object.dispose === 'function') {
|
|
181
|
+
const handleDispose = () => {
|
|
182
|
+
try {
|
|
183
|
+
object.dispose();
|
|
184
|
+
} catch {
|
|
185
|
+
// no-op
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// In a testing environment, cleanup immediately
|
|
190
|
+
if (typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined') handleDispose();
|
|
191
|
+
// Otherwise, using a real GPU so schedule cleanup to prevent stalls
|
|
192
|
+
else scheduler.unstable_scheduleCallback(scheduler.unstable_IdlePriority, handleDispose);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function removeChild(parent, child, dispose) {
|
|
184
196
|
if (!child) return;
|
|
185
197
|
|
|
186
198
|
// Unlink instances
|
|
187
199
|
child.parent = null;
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
191
|
-
}
|
|
200
|
+
const childIndex = parent.children.indexOf(child);
|
|
201
|
+
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
192
202
|
|
|
193
203
|
// Eagerly tear down tree
|
|
194
204
|
if (child.props.attach) {
|
|
@@ -202,10 +212,11 @@ function removeChild(parent, child, dispose, recursive) {
|
|
|
202
212
|
const shouldDispose = child.props.dispose !== null && dispose !== false;
|
|
203
213
|
|
|
204
214
|
// Recursively remove instance children
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
child
|
|
215
|
+
for (let i = child.children.length - 1; i >= 0; i--) {
|
|
216
|
+
const node = child.children[i];
|
|
217
|
+
removeChild(child, node, shouldDispose);
|
|
208
218
|
}
|
|
219
|
+
child.children.length = 0;
|
|
209
220
|
|
|
210
221
|
// Unlink instance object
|
|
211
222
|
delete child.object.__r3f;
|
|
@@ -217,96 +228,108 @@ function removeChild(parent, child, dispose, recursive) {
|
|
|
217
228
|
// - cannot be a <primitive object={...} />
|
|
218
229
|
// - cannot be a THREE.Scene, because three has broken its own API
|
|
219
230
|
if (shouldDispose && child.type !== 'primitive' && child.object.type !== 'Scene') {
|
|
220
|
-
|
|
221
|
-
const dispose = child.object.dispose.bind(child.object);
|
|
222
|
-
const handleDispose = () => {
|
|
223
|
-
try {
|
|
224
|
-
dispose();
|
|
225
|
-
} catch (e) {
|
|
226
|
-
// no-op
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// In a testing environment, cleanup immediately
|
|
231
|
-
if (typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined') handleDispose();
|
|
232
|
-
// Otherwise, using a real GPU so schedule cleanup to prevent stalls
|
|
233
|
-
else scheduler.unstable_scheduleCallback(scheduler.unstable_IdlePriority, handleDispose);
|
|
234
|
-
}
|
|
231
|
+
disposeOnIdle(child.object);
|
|
235
232
|
}
|
|
236
233
|
|
|
237
234
|
// Tree was updated, request a frame for top-level instance
|
|
238
235
|
if (dispose === undefined) invalidateInstance(child);
|
|
239
236
|
}
|
|
240
|
-
function
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
237
|
+
function setFiberRef(fiber, publicInstance) {
|
|
238
|
+
for (const _fiber of [fiber, fiber.alternate]) {
|
|
239
|
+
if (_fiber !== null) {
|
|
240
|
+
if (typeof _fiber.ref === 'function') {
|
|
241
|
+
_fiber.refCleanup == null ? void 0 : _fiber.refCleanup();
|
|
242
|
+
const cleanup = _fiber.ref(publicInstance);
|
|
243
|
+
if (typeof cleanup === 'function') _fiber.refCleanup = cleanup;
|
|
244
|
+
} else if (_fiber.ref) {
|
|
245
|
+
_fiber.ref.current = publicInstance;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
244
248
|
}
|
|
245
249
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
//
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
250
|
+
const reconstructed = [];
|
|
251
|
+
function swapInstances() {
|
|
252
|
+
// Detach instance
|
|
253
|
+
for (const [instance] of reconstructed) {
|
|
254
|
+
const parent = instance.parent;
|
|
255
|
+
if (parent) {
|
|
256
|
+
if (instance.props.attach) {
|
|
257
|
+
detach(parent, instance);
|
|
258
|
+
} else if (isObject3D(instance.object) && isObject3D(parent.object)) {
|
|
259
|
+
parent.object.remove(instance.object);
|
|
260
|
+
}
|
|
261
|
+
for (const child of instance.children) {
|
|
262
|
+
if (child.props.attach) {
|
|
263
|
+
detach(instance, child);
|
|
264
|
+
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
265
|
+
instance.object.remove(child.object);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
260
269
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (parent) {
|
|
271
|
-
// Manually handle replace https://github.com/pmndrs/react-three-fiber/pull/2680
|
|
272
|
-
|
|
273
|
-
newInstance.autoRemovedBeforeAppend = !!newInstance.parent;
|
|
274
|
-
if (!oldInstance.autoRemovedBeforeAppend) removeChild(parent, oldInstance);
|
|
275
|
-
appendChild(parent, newInstance);
|
|
276
|
-
|
|
277
|
-
// if (!oldInstance.autoRemovedBeforeAppend) {
|
|
278
|
-
// insertBefore(parent, newInstance, oldInstance)
|
|
279
|
-
// removeChild(parent, oldInstance)
|
|
280
|
-
// } else {
|
|
281
|
-
// appendChild(parent, newInstance)
|
|
282
|
-
// }
|
|
270
|
+
// If the old instance is hidden, we need to unhide it.
|
|
271
|
+
// React assumes it can discard instances since they're pure for DOM.
|
|
272
|
+
// This isn't true for us since our lifetimes are impure and longliving.
|
|
273
|
+
// So, we manually check if an instance was hidden and unhide it.
|
|
274
|
+
if (instance.isHidden) unhideInstance(instance);
|
|
275
|
+
|
|
276
|
+
// Dispose of old object if able
|
|
277
|
+
if (instance.object.__r3f) delete instance.object.__r3f;
|
|
278
|
+
if (instance.type !== 'primitive') disposeOnIdle(instance.object);
|
|
283
279
|
}
|
|
284
280
|
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
281
|
+
// Update instance
|
|
282
|
+
for (const [instance, props, fiber] of reconstructed) {
|
|
283
|
+
instance.props = props;
|
|
284
|
+
const parent = instance.parent;
|
|
285
|
+
if (parent) {
|
|
286
|
+
var _instance$props$objec, _instance$props$args;
|
|
287
|
+
// Get target from catalogue
|
|
288
|
+
const name = `${instance.type[0].toUpperCase()}${instance.type.slice(1)}`;
|
|
289
|
+
const target = catalogue[name];
|
|
290
|
+
|
|
291
|
+
// Create object
|
|
292
|
+
instance.object = (_instance$props$objec = instance.props.object) != null ? _instance$props$objec : new target(...((_instance$props$args = instance.props.args) != null ? _instance$props$args : []));
|
|
293
|
+
instance.object.__r3f = instance;
|
|
294
|
+
setFiberRef(fiber, instance.object);
|
|
295
|
+
|
|
296
|
+
// Set initial props
|
|
297
|
+
applyProps(instance.object, instance.props);
|
|
298
|
+
if (instance.props.attach) {
|
|
299
|
+
attach(parent, instance);
|
|
300
|
+
} else if (isObject3D(instance.object) && isObject3D(parent.object)) {
|
|
301
|
+
parent.object.add(instance.object);
|
|
302
|
+
}
|
|
303
|
+
for (const child of instance.children) {
|
|
304
|
+
if (child.props.attach) {
|
|
305
|
+
attach(instance, child);
|
|
306
|
+
} else if (isObject3D(child.object) && isObject3D(instance.object)) {
|
|
307
|
+
instance.object.add(child.object);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
291
310
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
311
|
+
// Tree was updated, request a frame
|
|
312
|
+
invalidateInstance(instance);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
reconstructed.length = 0;
|
|
295
316
|
}
|
|
296
317
|
|
|
297
318
|
// Don't handle text instances, warn on undefined behavior
|
|
298
319
|
const handleTextInstance = () => console.warn('R3F: Text is not allowed in JSX! This could be stray whitespace or characters.');
|
|
299
320
|
const NO_CONTEXT = {};
|
|
300
321
|
let currentUpdatePriority = constants.NoEventPriority;
|
|
322
|
+
|
|
323
|
+
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js
|
|
324
|
+
const NoFlags = 0;
|
|
325
|
+
const Update = 4;
|
|
301
326
|
const reconciler = createReconciler({
|
|
302
327
|
isPrimaryRenderer: false,
|
|
303
328
|
warnsIfNotActing: false,
|
|
304
329
|
supportsMutation: true,
|
|
305
330
|
supportsPersistence: false,
|
|
306
331
|
supportsHydration: false,
|
|
307
|
-
createInstance
|
|
308
|
-
return createInstance(type, props, root);
|
|
309
|
-
},
|
|
332
|
+
createInstance,
|
|
310
333
|
removeChild,
|
|
311
334
|
appendChild,
|
|
312
335
|
appendInitialChild: appendChild,
|
|
@@ -330,12 +353,11 @@ const reconciler = createReconciler({
|
|
|
330
353
|
getChildHostContext: () => NO_CONTEXT,
|
|
331
354
|
commitUpdate(instance, type, oldProps, newProps, fiber) {
|
|
332
355
|
var _newProps$args, _oldProps$args, _newProps$args2;
|
|
356
|
+
validateInstance(type, newProps);
|
|
333
357
|
let reconstruct = false;
|
|
334
358
|
|
|
335
359
|
// Reconstruct primitives if object prop changes
|
|
336
360
|
if (instance.type === 'primitive' && oldProps.object !== newProps.object) reconstruct = true;
|
|
337
|
-
// Reconstruct instance if args was changed to an invalid value
|
|
338
|
-
else if (newProps.args !== undefined && !Array.isArray(newProps.args)) reconstruct = true;
|
|
339
361
|
// Reconstruct instance if args were added or removed
|
|
340
362
|
else if (((_newProps$args = newProps.args) == null ? void 0 : _newProps$args.length) !== ((_oldProps$args = oldProps.args) == null ? void 0 : _oldProps$args.length)) reconstruct = true;
|
|
341
363
|
// Reconstruct instance if args were changed
|
|
@@ -345,14 +367,22 @@ const reconciler = createReconciler({
|
|
|
345
367
|
})) reconstruct = true;
|
|
346
368
|
|
|
347
369
|
// Reconstruct when args or <primitive object={...} have changes
|
|
348
|
-
if (reconstruct)
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
370
|
+
if (reconstruct) {
|
|
371
|
+
reconstructed.push([instance, {
|
|
372
|
+
...newProps
|
|
373
|
+
}, fiber]);
|
|
374
|
+
} else {
|
|
375
|
+
// Create a diff-set, flag if there are any changes
|
|
376
|
+
const changedProps = diffProps(instance, newProps);
|
|
377
|
+
if (Object.keys(changedProps).length) {
|
|
378
|
+
Object.assign(instance.props, changedProps);
|
|
379
|
+
applyProps(instance.object, changedProps);
|
|
380
|
+
}
|
|
355
381
|
}
|
|
382
|
+
|
|
383
|
+
// Flush reconstructed siblings when we hit the last updated child in a sequence
|
|
384
|
+
const isTailSibling = fiber.sibling === null || (fiber.flags & Update) === NoFlags;
|
|
385
|
+
if (isTailSibling) swapInstances();
|
|
356
386
|
},
|
|
357
387
|
finalizeInitialChildren: () => false,
|
|
358
388
|
commitMount() {},
|
|
@@ -697,7 +727,7 @@ function detach(parent, child) {
|
|
|
697
727
|
}
|
|
698
728
|
const RESERVED_PROPS = [...REACT_INTERNAL_PROPS,
|
|
699
729
|
// Instance props
|
|
700
|
-
'args', 'dispose', 'attach', 'object',
|
|
730
|
+
'args', 'dispose', 'attach', 'object', 'onUpdate',
|
|
701
731
|
// Behavior flags
|
|
702
732
|
'dispose'];
|
|
703
733
|
const MEMOIZED_PROTOTYPES = new Map();
|
|
@@ -871,6 +901,8 @@ function applyProps(object, props) {
|
|
|
871
901
|
}
|
|
872
902
|
function invalidateInstance(instance) {
|
|
873
903
|
var _instance$root;
|
|
904
|
+
if (!instance.parent) return;
|
|
905
|
+
instance.props.onUpdate == null ? void 0 : instance.props.onUpdate(instance.object);
|
|
874
906
|
const state = (_instance$root = instance.root) == null ? void 0 : _instance$root.getState == null ? void 0 : _instance$root.getState();
|
|
875
907
|
if (state && state.internal.frames === 0) state.invalidate();
|
|
876
908
|
}
|
|
@@ -1433,13 +1465,9 @@ const createStore = (invalidate, advance) => {
|
|
|
1433
1465
|
}
|
|
1434
1466
|
};
|
|
1435
1467
|
}),
|
|
1436
|
-
setFrameloop: frameloop => {
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
const mode = typeof frameloop === 'string' ? frameloop : (frameloop == null ? void 0 : frameloop.mode) === 'auto' ? 'always' : (_frameloop$mode = frameloop == null ? void 0 : frameloop.mode) != null ? _frameloop$mode : state.frameloop;
|
|
1440
|
-
const render = typeof frameloop === 'string' ? state.internal.render : (_frameloop$render = frameloop == null ? void 0 : frameloop.render) != null ? _frameloop$render : state.internal.render;
|
|
1441
|
-
const maxDelta = typeof frameloop === 'string' ? state.internal.maxDelta : (_frameloop$maxDelta = frameloop == null ? void 0 : frameloop.maxDelta) != null ? _frameloop$maxDelta : state.internal.maxDelta;
|
|
1442
|
-
const clock = state.clock;
|
|
1468
|
+
setFrameloop: (frameloop = 'always') => {
|
|
1469
|
+
const clock = get().clock;
|
|
1470
|
+
|
|
1443
1471
|
// if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
1444
1472
|
clock.stop();
|
|
1445
1473
|
clock.elapsedTime = 0;
|
|
@@ -1448,12 +1476,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1448
1476
|
clock.elapsedTime = 0;
|
|
1449
1477
|
}
|
|
1450
1478
|
set(() => ({
|
|
1451
|
-
frameloop
|
|
1452
|
-
internal: {
|
|
1453
|
-
...state.internal,
|
|
1454
|
-
render,
|
|
1455
|
-
maxDelta
|
|
1456
|
-
}
|
|
1479
|
+
frameloop
|
|
1457
1480
|
}));
|
|
1458
1481
|
},
|
|
1459
1482
|
previousRoot: undefined,
|
|
@@ -1469,25 +1492,14 @@ const createStore = (invalidate, advance) => {
|
|
|
1469
1492
|
// Updates
|
|
1470
1493
|
active: false,
|
|
1471
1494
|
frames: 0,
|
|
1472
|
-
stages: [],
|
|
1473
|
-
render: 'auto',
|
|
1474
|
-
maxDelta: 1 / 10,
|
|
1475
1495
|
priority: 0,
|
|
1476
1496
|
subscribe: (ref, priority, store) => {
|
|
1477
|
-
const
|
|
1478
|
-
const internal = state.internal;
|
|
1497
|
+
const internal = get().internal;
|
|
1479
1498
|
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1480
1499
|
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1481
1500
|
// As long as this flag is positive there can be no internal rendering at all
|
|
1482
1501
|
// because there could be multiple render subscriptions
|
|
1483
1502
|
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1484
|
-
// We use the render flag and deprecate priority
|
|
1485
|
-
if (internal.priority && state.internal.render === 'auto') set(() => ({
|
|
1486
|
-
internal: {
|
|
1487
|
-
...state.internal,
|
|
1488
|
-
render: 'manual'
|
|
1489
|
-
}
|
|
1490
|
-
}));
|
|
1491
1503
|
internal.subscribers.push({
|
|
1492
1504
|
ref,
|
|
1493
1505
|
priority,
|
|
@@ -1497,18 +1509,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1497
1509
|
// highest priority renders last (on top of the other frames)
|
|
1498
1510
|
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1499
1511
|
return () => {
|
|
1500
|
-
const
|
|
1501
|
-
const internal = state.internal;
|
|
1512
|
+
const internal = get().internal;
|
|
1502
1513
|
if (internal != null && internal.subscribers) {
|
|
1503
1514
|
// Decrease manual flag if this subscription had a priority
|
|
1504
1515
|
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1505
|
-
// We use the render flag and deprecate priority
|
|
1506
|
-
if (!internal.priority && state.internal.render === 'manual') set(() => ({
|
|
1507
|
-
internal: {
|
|
1508
|
-
...state.internal,
|
|
1509
|
-
render: 'auto'
|
|
1510
|
-
}
|
|
1511
|
-
}));
|
|
1512
1516
|
// Remove subscriber from list
|
|
1513
1517
|
internal.subscribers = internal.subscribers.filter(s => s.ref !== ref);
|
|
1514
1518
|
}
|
|
@@ -1562,139 +1566,6 @@ const createStore = (invalidate, advance) => {
|
|
|
1562
1566
|
return rootStore;
|
|
1563
1567
|
};
|
|
1564
1568
|
|
|
1565
|
-
// TODO: Remove deprecated fields in `Subscription`
|
|
1566
|
-
|
|
1567
|
-
/**
|
|
1568
|
-
* Class representing a stage that updates every frame.
|
|
1569
|
-
* Stages are used to build a lifecycle of effects for an app's frameloop.
|
|
1570
|
-
*/
|
|
1571
|
-
class Stage {
|
|
1572
|
-
constructor() {
|
|
1573
|
-
this.subscribers = [];
|
|
1574
|
-
this._frameTime = 0;
|
|
1575
|
-
}
|
|
1576
|
-
|
|
1577
|
-
/**
|
|
1578
|
-
* Executes all callback subscriptions on the stage.
|
|
1579
|
-
* @param delta - Delta time between frame calls.
|
|
1580
|
-
* @param [frame] - The XR frame if it exists.
|
|
1581
|
-
*/
|
|
1582
|
-
frame(delta, frame) {
|
|
1583
|
-
const subs = this.subscribers;
|
|
1584
|
-
const initialTime = performance.now();
|
|
1585
|
-
for (let i = 0; i < subs.length; i++) {
|
|
1586
|
-
subs[i].ref.current(subs[i].store.getState(), delta, frame);
|
|
1587
|
-
}
|
|
1588
|
-
this._frameTime = performance.now() - initialTime;
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
/**
|
|
1592
|
-
* Adds a callback subscriber to the stage.
|
|
1593
|
-
* @param ref - The mutable callback reference.
|
|
1594
|
-
* @param store - The store to be used with the callback execution.
|
|
1595
|
-
* @returns A function to remove the subscription.
|
|
1596
|
-
*/
|
|
1597
|
-
add(ref, store) {
|
|
1598
|
-
this.subscribers.push({
|
|
1599
|
-
ref,
|
|
1600
|
-
store
|
|
1601
|
-
});
|
|
1602
|
-
return () => {
|
|
1603
|
-
this.subscribers = this.subscribers.filter(sub => {
|
|
1604
|
-
return sub.ref !== ref;
|
|
1605
|
-
});
|
|
1606
|
-
};
|
|
1607
|
-
}
|
|
1608
|
-
get frameTime() {
|
|
1609
|
-
return this._frameTime;
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
|
|
1613
|
-
// Using Unity's fixedStep default.
|
|
1614
|
-
const FPS_50 = 1 / 50;
|
|
1615
|
-
|
|
1616
|
-
/**
|
|
1617
|
-
* Class representing a stage that updates every frame at a fixed rate.
|
|
1618
|
-
* @param name - Name of the stage.
|
|
1619
|
-
* @param [fixedStep] - Fixed step rate.
|
|
1620
|
-
* @param [maxSubsteps] - Maximum number of substeps.
|
|
1621
|
-
*/
|
|
1622
|
-
class FixedStage extends Stage {
|
|
1623
|
-
constructor(fixedStep, maxSubSteps) {
|
|
1624
|
-
super();
|
|
1625
|
-
this._fixedStep = fixedStep != null ? fixedStep : FPS_50;
|
|
1626
|
-
this._maxSubsteps = maxSubSteps != null ? maxSubSteps : 6;
|
|
1627
|
-
this._accumulator = 0;
|
|
1628
|
-
this._alpha = 0;
|
|
1629
|
-
this._fixedFrameTime = 0;
|
|
1630
|
-
this._substepTimes = [];
|
|
1631
|
-
}
|
|
1632
|
-
|
|
1633
|
-
/**
|
|
1634
|
-
* Executes all callback subscriptions on the stage.
|
|
1635
|
-
* @param delta - Delta time between frame calls.
|
|
1636
|
-
* @param [frame] - The XR frame if it exists.
|
|
1637
|
-
*/
|
|
1638
|
-
frame(delta, frame) {
|
|
1639
|
-
const initialTime = performance.now();
|
|
1640
|
-
let substeps = 0;
|
|
1641
|
-
this._substepTimes = [];
|
|
1642
|
-
this._accumulator += delta;
|
|
1643
|
-
while (this._accumulator >= this._fixedStep && substeps < this._maxSubsteps) {
|
|
1644
|
-
this._accumulator -= this._fixedStep;
|
|
1645
|
-
substeps++;
|
|
1646
|
-
super.frame(this._fixedStep, frame);
|
|
1647
|
-
this._substepTimes.push(super.frameTime);
|
|
1648
|
-
}
|
|
1649
|
-
this._fixedFrameTime = performance.now() - initialTime;
|
|
1650
|
-
|
|
1651
|
-
// The accumulator will only be larger than the fixed step if we had to
|
|
1652
|
-
// bail early due to hitting the max substep limit or execution time lagging.
|
|
1653
|
-
// In that case, we want to shave off the excess so we don't fall behind next frame.
|
|
1654
|
-
this._accumulator = this._accumulator % this._fixedStep;
|
|
1655
|
-
this._alpha = this._accumulator / this._fixedStep;
|
|
1656
|
-
}
|
|
1657
|
-
get frameTime() {
|
|
1658
|
-
return this._fixedFrameTime;
|
|
1659
|
-
}
|
|
1660
|
-
get substepTimes() {
|
|
1661
|
-
return this._substepTimes;
|
|
1662
|
-
}
|
|
1663
|
-
get fixedStep() {
|
|
1664
|
-
return this._fixedStep;
|
|
1665
|
-
}
|
|
1666
|
-
set fixedStep(fixedStep) {
|
|
1667
|
-
this._fixedStep = fixedStep;
|
|
1668
|
-
}
|
|
1669
|
-
get maxSubsteps() {
|
|
1670
|
-
return this._maxSubsteps;
|
|
1671
|
-
}
|
|
1672
|
-
set maxSubsteps(maxSubsteps) {
|
|
1673
|
-
this._maxSubsteps = maxSubsteps;
|
|
1674
|
-
}
|
|
1675
|
-
get accumulator() {
|
|
1676
|
-
return this._accumulator;
|
|
1677
|
-
}
|
|
1678
|
-
get alpha() {
|
|
1679
|
-
return this._alpha;
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
const Early = /*#__PURE__*/new Stage();
|
|
1683
|
-
const Fixed = /*#__PURE__*/new FixedStage();
|
|
1684
|
-
const Update = /*#__PURE__*/new Stage();
|
|
1685
|
-
const Late = /*#__PURE__*/new Stage();
|
|
1686
|
-
const Render = /*#__PURE__*/new Stage();
|
|
1687
|
-
const After = /*#__PURE__*/new Stage();
|
|
1688
|
-
const Stages = {
|
|
1689
|
-
Early,
|
|
1690
|
-
Fixed,
|
|
1691
|
-
Update,
|
|
1692
|
-
Late,
|
|
1693
|
-
Render,
|
|
1694
|
-
After
|
|
1695
|
-
};
|
|
1696
|
-
const Lifecycle = [Early, Fixed, Update, Late, Render, After];
|
|
1697
|
-
|
|
1698
1569
|
/**
|
|
1699
1570
|
* Exposes an object's {@link Instance}.
|
|
1700
1571
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#useinstancehandle
|
|
@@ -1740,21 +1611,6 @@ function useFrame(callback, renderPriority = 0) {
|
|
|
1740
1611
|
return null;
|
|
1741
1612
|
}
|
|
1742
1613
|
|
|
1743
|
-
/**
|
|
1744
|
-
* Executes a callback in a given update stage.
|
|
1745
|
-
* Uses the stage instance to identify which stage to target in the lifecycle.
|
|
1746
|
-
*/
|
|
1747
|
-
function useUpdate(callback, stage = Stages.Update) {
|
|
1748
|
-
const store = useStore();
|
|
1749
|
-
const stages = store.getState().internal.stages;
|
|
1750
|
-
// Memoize ref
|
|
1751
|
-
const ref = useMutableCallback(callback);
|
|
1752
|
-
// Throw an error if a stage does not exist in the lifecycle
|
|
1753
|
-
if (!stages.includes(stage)) throw new Error(`An invoked stage does not exist in the lifecycle.`);
|
|
1754
|
-
// Subscribe on mount, unsubscribe on unmount
|
|
1755
|
-
useIsomorphicLayoutEffect(() => stage.add(ref, store), [stage]);
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
1614
|
/**
|
|
1759
1615
|
* Returns a node graph of an object with named nodes & materials.
|
|
1760
1616
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
@@ -1838,42 +1694,6 @@ const createRendererInstance = (gl, canvas) => {
|
|
|
1838
1694
|
...gl
|
|
1839
1695
|
});
|
|
1840
1696
|
};
|
|
1841
|
-
const createStages = (stages, store) => {
|
|
1842
|
-
const state = store.getState();
|
|
1843
|
-
let subscribers;
|
|
1844
|
-
let subscription;
|
|
1845
|
-
const _stages = stages != null ? stages : Lifecycle;
|
|
1846
|
-
if (!_stages.includes(Stages.Update)) throw 'The Stages.Update stage is required for R3F.';
|
|
1847
|
-
if (!_stages.includes(Stages.Render)) throw 'The Stages.Render stage is required for R3F.';
|
|
1848
|
-
state.set(({
|
|
1849
|
-
internal
|
|
1850
|
-
}) => ({
|
|
1851
|
-
internal: {
|
|
1852
|
-
...internal,
|
|
1853
|
-
stages: _stages
|
|
1854
|
-
}
|
|
1855
|
-
}));
|
|
1856
|
-
|
|
1857
|
-
// Add useFrame loop to update stage
|
|
1858
|
-
const frameCallback = {
|
|
1859
|
-
current(state, delta, frame) {
|
|
1860
|
-
subscribers = state.internal.subscribers;
|
|
1861
|
-
for (let i = 0; i < subscribers.length; i++) {
|
|
1862
|
-
subscription = subscribers[i];
|
|
1863
|
-
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
};
|
|
1867
|
-
Stages.Update.add(frameCallback, store);
|
|
1868
|
-
|
|
1869
|
-
// Add render callback to render stage
|
|
1870
|
-
const renderCallback = {
|
|
1871
|
-
current(state) {
|
|
1872
|
-
if (state.internal.render === 'auto' && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
1873
|
-
}
|
|
1874
|
-
};
|
|
1875
|
-
Stages.Render.add(renderCallback, store);
|
|
1876
|
-
};
|
|
1877
1697
|
function computeInitialSize(canvas, size) {
|
|
1878
1698
|
if (!size && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1879
1699
|
const {
|
|
@@ -1971,8 +1791,7 @@ function createRoot(canvas) {
|
|
|
1971
1791
|
performance,
|
|
1972
1792
|
raycaster: raycastOptions,
|
|
1973
1793
|
camera: cameraOptions,
|
|
1974
|
-
onPointerMissed
|
|
1975
|
-
stages
|
|
1794
|
+
onPointerMissed
|
|
1976
1795
|
} = props;
|
|
1977
1796
|
let state = store.getState();
|
|
1978
1797
|
|
|
@@ -2164,9 +1983,6 @@ function createRoot(canvas) {
|
|
|
2164
1983
|
}
|
|
2165
1984
|
}));
|
|
2166
1985
|
|
|
2167
|
-
// Create update stages. Only do this once on init
|
|
2168
|
-
if (state.internal.stages.length === 0) createStages(stages, store);
|
|
2169
|
-
|
|
2170
1986
|
// Set locals
|
|
2171
1987
|
onCreated = onCreatedCallback;
|
|
2172
1988
|
configured = true;
|
|
@@ -2390,21 +2206,30 @@ function flushGlobalEffects(type, timestamp) {
|
|
|
2390
2206
|
return run(globalTailEffects, timestamp);
|
|
2391
2207
|
}
|
|
2392
2208
|
}
|
|
2209
|
+
let subscribers;
|
|
2210
|
+
let subscription;
|
|
2393
2211
|
function update(timestamp, state, frame) {
|
|
2394
2212
|
// Run local effects
|
|
2395
2213
|
let delta = state.clock.getDelta();
|
|
2214
|
+
|
|
2396
2215
|
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
2397
2216
|
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
2398
2217
|
delta = timestamp - state.clock.elapsedTime;
|
|
2399
2218
|
state.clock.oldTime = state.clock.elapsedTime;
|
|
2400
2219
|
state.clock.elapsedTime = timestamp;
|
|
2401
|
-
} else {
|
|
2402
|
-
delta = Math.max(Math.min(delta, state.internal.maxDelta), 0);
|
|
2403
2220
|
}
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2221
|
+
|
|
2222
|
+
// Call subscribers (useFrame)
|
|
2223
|
+
subscribers = state.internal.subscribers;
|
|
2224
|
+
for (let i = 0; i < subscribers.length; i++) {
|
|
2225
|
+
subscription = subscribers[i];
|
|
2226
|
+
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
2407
2227
|
}
|
|
2228
|
+
|
|
2229
|
+
// Render content
|
|
2230
|
+
if (!state.internal.priority && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
2231
|
+
|
|
2232
|
+
// Decrease frame count
|
|
2408
2233
|
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
2409
2234
|
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
2410
2235
|
}
|
|
@@ -2489,9 +2314,6 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
|
2489
2314
|
|
|
2490
2315
|
exports.Block = Block;
|
|
2491
2316
|
exports.ErrorBoundary = ErrorBoundary;
|
|
2492
|
-
exports.FixedStage = FixedStage;
|
|
2493
|
-
exports.Stage = Stage;
|
|
2494
|
-
exports.Stages = Stages;
|
|
2495
2317
|
exports._roots = _roots;
|
|
2496
2318
|
exports.act = act;
|
|
2497
2319
|
exports.addAfterEffect = addAfterEffect;
|
|
@@ -2523,4 +2345,3 @@ exports.useLoader = useLoader;
|
|
|
2523
2345
|
exports.useMutableCallback = useMutableCallback;
|
|
2524
2346
|
exports.useStore = useStore;
|
|
2525
2347
|
exports.useThree = useThree;
|
|
2526
|
-
exports.useUpdate = useUpdate;
|