@react-three/fiber 9.0.0-alpha.6 → 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/CHANGELOG.md +6 -0
- 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 +6 -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 +9 -1
- package/dist/declarations/src/three-types.d.ts +8 -15
- package/dist/{loop-6e8a6208.cjs.prod.js → loop-5012a96a.cjs.prod.js} +177 -348
- package/dist/{loop-c991cb05.cjs.dev.js → loop-8dd3f5bb.cjs.dev.js} +177 -348
- package/dist/{loop-ef070875.esm.js → loop-ed5edcdb.esm.js} +178 -345
- 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,27 +38,28 @@ 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
|
+
|
|
44
|
+
const createReconciler = Reconciler__default["default"];
|
|
45
|
+
|
|
46
|
+
// TODO: handle constructor overloads
|
|
47
|
+
// https://github.com/pmndrs/react-three-fiber/pull/2931
|
|
48
|
+
// https://github.com/microsoft/TypeScript/issues/37079
|
|
49
|
+
|
|
41
50
|
const catalogue = {};
|
|
42
51
|
let i = 0;
|
|
43
|
-
const
|
|
44
|
-
|
|
52
|
+
const isConstructor$1 = object => typeof object === 'function';
|
|
53
|
+
function extend(objects) {
|
|
54
|
+
if (isConstructor$1(objects)) {
|
|
45
55
|
const Component = `${i++}`;
|
|
46
56
|
catalogue[Component] = objects;
|
|
47
|
-
|
|
48
|
-
// Returns a component whose name will be inferred in devtools
|
|
49
|
-
// @ts-expect-error
|
|
50
|
-
return /*#__PURE__*/React__namespace.forwardRef({
|
|
51
|
-
[objects.name]: (props, ref) => /*#__PURE__*/jsxRuntime.jsx(Component, {
|
|
52
|
-
...props,
|
|
53
|
-
ref: ref
|
|
54
|
-
})
|
|
55
|
-
}[objects.name]);
|
|
57
|
+
return Component;
|
|
56
58
|
} else {
|
|
57
|
-
|
|
59
|
+
Object.assign(catalogue, objects);
|
|
58
60
|
}
|
|
59
|
-
}
|
|
60
|
-
function
|
|
61
|
-
var _props$object;
|
|
61
|
+
}
|
|
62
|
+
function validateInstance(type, props) {
|
|
62
63
|
// Get target from catalogue
|
|
63
64
|
const name = `${type[0].toUpperCase()}${type.slice(1)}`;
|
|
64
65
|
const target = catalogue[name];
|
|
@@ -71,13 +72,14 @@ function createInstance(type, props, root, flushPrimitive = true) {
|
|
|
71
72
|
|
|
72
73
|
// Throw if an object or literal was passed for args
|
|
73
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);
|
|
74
79
|
|
|
75
80
|
// Regenerate the R3F instance for primitives to simulate a new object
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
// Create instance
|
|
79
|
-
const instance = prepare(props.object, root, type, props);
|
|
80
|
-
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);
|
|
81
83
|
}
|
|
82
84
|
function hideInstance(instance) {
|
|
83
85
|
if (!instance.isHidden) {
|
|
@@ -174,15 +176,29 @@ function insertBefore(parent, child, beforeChild) {
|
|
|
174
176
|
// Attach tree once complete
|
|
175
177
|
handleContainerEffects(parent, child, beforeChild);
|
|
176
178
|
}
|
|
177
|
-
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) {
|
|
178
196
|
if (!child) return;
|
|
179
197
|
|
|
180
198
|
// Unlink instances
|
|
181
199
|
child.parent = null;
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
185
|
-
}
|
|
200
|
+
const childIndex = parent.children.indexOf(child);
|
|
201
|
+
if (childIndex !== -1) parent.children.splice(childIndex, 1);
|
|
186
202
|
|
|
187
203
|
// Eagerly tear down tree
|
|
188
204
|
if (child.props.attach) {
|
|
@@ -196,10 +212,11 @@ function removeChild(parent, child, dispose, recursive) {
|
|
|
196
212
|
const shouldDispose = child.props.dispose !== null && dispose !== false;
|
|
197
213
|
|
|
198
214
|
// Recursively remove instance children
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
child
|
|
215
|
+
for (let i = child.children.length - 1; i >= 0; i--) {
|
|
216
|
+
const node = child.children[i];
|
|
217
|
+
removeChild(child, node, shouldDispose);
|
|
202
218
|
}
|
|
219
|
+
child.children.length = 0;
|
|
203
220
|
|
|
204
221
|
// Unlink instance object
|
|
205
222
|
delete child.object.__r3f;
|
|
@@ -211,96 +228,108 @@ function removeChild(parent, child, dispose, recursive) {
|
|
|
211
228
|
// - cannot be a <primitive object={...} />
|
|
212
229
|
// - cannot be a THREE.Scene, because three has broken its own API
|
|
213
230
|
if (shouldDispose && child.type !== 'primitive' && child.object.type !== 'Scene') {
|
|
214
|
-
|
|
215
|
-
const dispose = child.object.dispose.bind(child.object);
|
|
216
|
-
const handleDispose = () => {
|
|
217
|
-
try {
|
|
218
|
-
dispose();
|
|
219
|
-
} catch (e) {
|
|
220
|
-
// no-op
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// In a testing environment, cleanup immediately
|
|
225
|
-
if (typeof IS_REACT_ACT_ENVIRONMENT !== 'undefined') handleDispose();
|
|
226
|
-
// Otherwise, using a real GPU so schedule cleanup to prevent stalls
|
|
227
|
-
else scheduler.unstable_scheduleCallback(scheduler.unstable_IdlePriority, handleDispose);
|
|
228
|
-
}
|
|
231
|
+
disposeOnIdle(child.object);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
234
|
// Tree was updated, request a frame for top-level instance
|
|
232
235
|
if (dispose === undefined) invalidateInstance(child);
|
|
233
236
|
}
|
|
234
|
-
function
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
+
}
|
|
238
248
|
}
|
|
239
249
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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
|
+
}
|
|
254
269
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
if (parent) {
|
|
265
|
-
// Manually handle replace https://github.com/pmndrs/react-three-fiber/pull/2680
|
|
266
|
-
|
|
267
|
-
newInstance.autoRemovedBeforeAppend = !!newInstance.parent;
|
|
268
|
-
if (!oldInstance.autoRemovedBeforeAppend) removeChild(parent, oldInstance);
|
|
269
|
-
appendChild(parent, newInstance);
|
|
270
|
-
|
|
271
|
-
// if (!oldInstance.autoRemovedBeforeAppend) {
|
|
272
|
-
// insertBefore(parent, newInstance, oldInstance)
|
|
273
|
-
// removeChild(parent, oldInstance)
|
|
274
|
-
// } else {
|
|
275
|
-
// appendChild(parent, newInstance)
|
|
276
|
-
// }
|
|
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);
|
|
277
279
|
}
|
|
278
280
|
|
|
279
|
-
//
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
}
|
|
285
310
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
311
|
+
// Tree was updated, request a frame
|
|
312
|
+
invalidateInstance(instance);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
reconstructed.length = 0;
|
|
289
316
|
}
|
|
290
317
|
|
|
291
318
|
// Don't handle text instances, warn on undefined behavior
|
|
292
319
|
const handleTextInstance = () => console.warn('R3F: Text is not allowed in JSX! This could be stray whitespace or characters.');
|
|
293
320
|
const NO_CONTEXT = {};
|
|
294
321
|
let currentUpdatePriority = constants.NoEventPriority;
|
|
295
|
-
|
|
322
|
+
|
|
323
|
+
// https://github.com/facebook/react/blob/main/packages/react-reconciler/src/ReactFiberFlags.js
|
|
324
|
+
const NoFlags = 0;
|
|
325
|
+
const Update = 4;
|
|
326
|
+
const reconciler = createReconciler({
|
|
296
327
|
isPrimaryRenderer: false,
|
|
297
328
|
warnsIfNotActing: false,
|
|
298
329
|
supportsMutation: true,
|
|
299
330
|
supportsPersistence: false,
|
|
300
331
|
supportsHydration: false,
|
|
301
|
-
createInstance
|
|
302
|
-
return createInstance(type, props, root);
|
|
303
|
-
},
|
|
332
|
+
createInstance,
|
|
304
333
|
removeChild,
|
|
305
334
|
appendChild,
|
|
306
335
|
appendInitialChild: appendChild,
|
|
@@ -322,15 +351,13 @@ const reconciler = Reconciler__default["default"]({
|
|
|
322
351
|
},
|
|
323
352
|
getRootHostContext: () => NO_CONTEXT,
|
|
324
353
|
getChildHostContext: () => NO_CONTEXT,
|
|
325
|
-
// @ts-expect-error prepareUpdate and updatePayload removed with React 19
|
|
326
354
|
commitUpdate(instance, type, oldProps, newProps, fiber) {
|
|
327
355
|
var _newProps$args, _oldProps$args, _newProps$args2;
|
|
356
|
+
validateInstance(type, newProps);
|
|
328
357
|
let reconstruct = false;
|
|
329
358
|
|
|
330
359
|
// Reconstruct primitives if object prop changes
|
|
331
360
|
if (instance.type === 'primitive' && oldProps.object !== newProps.object) reconstruct = true;
|
|
332
|
-
// Reconstruct instance if args was changed to an invalid value
|
|
333
|
-
else if (newProps.args !== undefined && !Array.isArray(newProps.args)) reconstruct = true;
|
|
334
361
|
// Reconstruct instance if args were added or removed
|
|
335
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;
|
|
336
363
|
// Reconstruct instance if args were changed
|
|
@@ -340,14 +367,22 @@ const reconciler = Reconciler__default["default"]({
|
|
|
340
367
|
})) reconstruct = true;
|
|
341
368
|
|
|
342
369
|
// Reconstruct when args or <primitive object={...} have changes
|
|
343
|
-
if (reconstruct)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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
|
+
}
|
|
350
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();
|
|
351
386
|
},
|
|
352
387
|
finalizeInitialChildren: () => false,
|
|
353
388
|
commitMount() {},
|
|
@@ -369,8 +404,8 @@ const reconciler = Reconciler__default["default"]({
|
|
|
369
404
|
beforeActiveInstanceBlur() {},
|
|
370
405
|
afterActiveInstanceBlur() {},
|
|
371
406
|
detachDeletedInstance() {},
|
|
372
|
-
|
|
373
|
-
|
|
407
|
+
prepareScopeUpdate() {},
|
|
408
|
+
getInstanceFromScope: () => null,
|
|
374
409
|
shouldAttemptEagerTransition() {
|
|
375
410
|
return false;
|
|
376
411
|
},
|
|
@@ -414,7 +449,8 @@ const reconciler = Reconciler__default["default"]({
|
|
|
414
449
|
default:
|
|
415
450
|
return constants.DefaultEventPriority;
|
|
416
451
|
}
|
|
417
|
-
}
|
|
452
|
+
},
|
|
453
|
+
resetFormInstance() {}
|
|
418
454
|
});
|
|
419
455
|
|
|
420
456
|
var _window$document, _window$navigator;
|
|
@@ -691,7 +727,7 @@ function detach(parent, child) {
|
|
|
691
727
|
}
|
|
692
728
|
const RESERVED_PROPS = [...REACT_INTERNAL_PROPS,
|
|
693
729
|
// Instance props
|
|
694
|
-
'args', 'dispose', 'attach', 'object',
|
|
730
|
+
'args', 'dispose', 'attach', 'object', 'onUpdate',
|
|
695
731
|
// Behavior flags
|
|
696
732
|
'dispose'];
|
|
697
733
|
const MEMOIZED_PROTOTYPES = new Map();
|
|
@@ -865,6 +901,8 @@ function applyProps(object, props) {
|
|
|
865
901
|
}
|
|
866
902
|
function invalidateInstance(instance) {
|
|
867
903
|
var _instance$root;
|
|
904
|
+
if (!instance.parent) return;
|
|
905
|
+
instance.props.onUpdate == null ? void 0 : instance.props.onUpdate(instance.object);
|
|
868
906
|
const state = (_instance$root = instance.root) == null ? void 0 : _instance$root.getState == null ? void 0 : _instance$root.getState();
|
|
869
907
|
if (state && state.internal.frames === 0) state.invalidate();
|
|
870
908
|
}
|
|
@@ -1427,13 +1465,9 @@ const createStore = (invalidate, advance) => {
|
|
|
1427
1465
|
}
|
|
1428
1466
|
};
|
|
1429
1467
|
}),
|
|
1430
|
-
setFrameloop: frameloop => {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
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;
|
|
1434
|
-
const render = typeof frameloop === 'string' ? state.internal.render : (_frameloop$render = frameloop == null ? void 0 : frameloop.render) != null ? _frameloop$render : state.internal.render;
|
|
1435
|
-
const maxDelta = typeof frameloop === 'string' ? state.internal.maxDelta : (_frameloop$maxDelta = frameloop == null ? void 0 : frameloop.maxDelta) != null ? _frameloop$maxDelta : state.internal.maxDelta;
|
|
1436
|
-
const clock = state.clock;
|
|
1468
|
+
setFrameloop: (frameloop = 'always') => {
|
|
1469
|
+
const clock = get().clock;
|
|
1470
|
+
|
|
1437
1471
|
// if frameloop === "never" clock.elapsedTime is updated using advance(timestamp)
|
|
1438
1472
|
clock.stop();
|
|
1439
1473
|
clock.elapsedTime = 0;
|
|
@@ -1442,12 +1476,7 @@ const createStore = (invalidate, advance) => {
|
|
|
1442
1476
|
clock.elapsedTime = 0;
|
|
1443
1477
|
}
|
|
1444
1478
|
set(() => ({
|
|
1445
|
-
frameloop
|
|
1446
|
-
internal: {
|
|
1447
|
-
...state.internal,
|
|
1448
|
-
render,
|
|
1449
|
-
maxDelta
|
|
1450
|
-
}
|
|
1479
|
+
frameloop
|
|
1451
1480
|
}));
|
|
1452
1481
|
},
|
|
1453
1482
|
previousRoot: undefined,
|
|
@@ -1463,25 +1492,14 @@ const createStore = (invalidate, advance) => {
|
|
|
1463
1492
|
// Updates
|
|
1464
1493
|
active: false,
|
|
1465
1494
|
frames: 0,
|
|
1466
|
-
stages: [],
|
|
1467
|
-
render: 'auto',
|
|
1468
|
-
maxDelta: 1 / 10,
|
|
1469
1495
|
priority: 0,
|
|
1470
1496
|
subscribe: (ref, priority, store) => {
|
|
1471
|
-
const
|
|
1472
|
-
const internal = state.internal;
|
|
1497
|
+
const internal = get().internal;
|
|
1473
1498
|
// If this subscription was given a priority, it takes rendering into its own hands
|
|
1474
1499
|
// For that reason we switch off automatic rendering and increase the manual flag
|
|
1475
1500
|
// As long as this flag is positive there can be no internal rendering at all
|
|
1476
1501
|
// because there could be multiple render subscriptions
|
|
1477
1502
|
internal.priority = internal.priority + (priority > 0 ? 1 : 0);
|
|
1478
|
-
// We use the render flag and deprecate priority
|
|
1479
|
-
if (internal.priority && state.internal.render === 'auto') set(() => ({
|
|
1480
|
-
internal: {
|
|
1481
|
-
...state.internal,
|
|
1482
|
-
render: 'manual'
|
|
1483
|
-
}
|
|
1484
|
-
}));
|
|
1485
1503
|
internal.subscribers.push({
|
|
1486
1504
|
ref,
|
|
1487
1505
|
priority,
|
|
@@ -1491,18 +1509,10 @@ const createStore = (invalidate, advance) => {
|
|
|
1491
1509
|
// highest priority renders last (on top of the other frames)
|
|
1492
1510
|
internal.subscribers = internal.subscribers.sort((a, b) => a.priority - b.priority);
|
|
1493
1511
|
return () => {
|
|
1494
|
-
const
|
|
1495
|
-
const internal = state.internal;
|
|
1512
|
+
const internal = get().internal;
|
|
1496
1513
|
if (internal != null && internal.subscribers) {
|
|
1497
1514
|
// Decrease manual flag if this subscription had a priority
|
|
1498
1515
|
internal.priority = internal.priority - (priority > 0 ? 1 : 0);
|
|
1499
|
-
// We use the render flag and deprecate priority
|
|
1500
|
-
if (!internal.priority && state.internal.render === 'manual') set(() => ({
|
|
1501
|
-
internal: {
|
|
1502
|
-
...state.internal,
|
|
1503
|
-
render: 'auto'
|
|
1504
|
-
}
|
|
1505
|
-
}));
|
|
1506
1516
|
// Remove subscriber from list
|
|
1507
1517
|
internal.subscribers = internal.subscribers.filter(s => s.ref !== ref);
|
|
1508
1518
|
}
|
|
@@ -1556,139 +1566,6 @@ const createStore = (invalidate, advance) => {
|
|
|
1556
1566
|
return rootStore;
|
|
1557
1567
|
};
|
|
1558
1568
|
|
|
1559
|
-
// TODO: Remove deprecated fields in `Subscription`
|
|
1560
|
-
|
|
1561
|
-
/**
|
|
1562
|
-
* Class representing a stage that updates every frame.
|
|
1563
|
-
* Stages are used to build a lifecycle of effects for an app's frameloop.
|
|
1564
|
-
*/
|
|
1565
|
-
class Stage {
|
|
1566
|
-
constructor() {
|
|
1567
|
-
this.subscribers = [];
|
|
1568
|
-
this._frameTime = 0;
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
/**
|
|
1572
|
-
* Executes all callback subscriptions on the stage.
|
|
1573
|
-
* @param delta - Delta time between frame calls.
|
|
1574
|
-
* @param [frame] - The XR frame if it exists.
|
|
1575
|
-
*/
|
|
1576
|
-
frame(delta, frame) {
|
|
1577
|
-
const subs = this.subscribers;
|
|
1578
|
-
const initialTime = performance.now();
|
|
1579
|
-
for (let i = 0; i < subs.length; i++) {
|
|
1580
|
-
subs[i].ref.current(subs[i].store.getState(), delta, frame);
|
|
1581
|
-
}
|
|
1582
|
-
this._frameTime = performance.now() - initialTime;
|
|
1583
|
-
}
|
|
1584
|
-
|
|
1585
|
-
/**
|
|
1586
|
-
* Adds a callback subscriber to the stage.
|
|
1587
|
-
* @param ref - The mutable callback reference.
|
|
1588
|
-
* @param store - The store to be used with the callback execution.
|
|
1589
|
-
* @returns A function to remove the subscription.
|
|
1590
|
-
*/
|
|
1591
|
-
add(ref, store) {
|
|
1592
|
-
this.subscribers.push({
|
|
1593
|
-
ref,
|
|
1594
|
-
store
|
|
1595
|
-
});
|
|
1596
|
-
return () => {
|
|
1597
|
-
this.subscribers = this.subscribers.filter(sub => {
|
|
1598
|
-
return sub.ref !== ref;
|
|
1599
|
-
});
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
get frameTime() {
|
|
1603
|
-
return this._frameTime;
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
// Using Unity's fixedStep default.
|
|
1608
|
-
const FPS_50 = 1 / 50;
|
|
1609
|
-
|
|
1610
|
-
/**
|
|
1611
|
-
* Class representing a stage that updates every frame at a fixed rate.
|
|
1612
|
-
* @param name - Name of the stage.
|
|
1613
|
-
* @param [fixedStep] - Fixed step rate.
|
|
1614
|
-
* @param [maxSubsteps] - Maximum number of substeps.
|
|
1615
|
-
*/
|
|
1616
|
-
class FixedStage extends Stage {
|
|
1617
|
-
constructor(fixedStep, maxSubSteps) {
|
|
1618
|
-
super();
|
|
1619
|
-
this._fixedStep = fixedStep != null ? fixedStep : FPS_50;
|
|
1620
|
-
this._maxSubsteps = maxSubSteps != null ? maxSubSteps : 6;
|
|
1621
|
-
this._accumulator = 0;
|
|
1622
|
-
this._alpha = 0;
|
|
1623
|
-
this._fixedFrameTime = 0;
|
|
1624
|
-
this._substepTimes = [];
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
/**
|
|
1628
|
-
* Executes all callback subscriptions on the stage.
|
|
1629
|
-
* @param delta - Delta time between frame calls.
|
|
1630
|
-
* @param [frame] - The XR frame if it exists.
|
|
1631
|
-
*/
|
|
1632
|
-
frame(delta, frame) {
|
|
1633
|
-
const initialTime = performance.now();
|
|
1634
|
-
let substeps = 0;
|
|
1635
|
-
this._substepTimes = [];
|
|
1636
|
-
this._accumulator += delta;
|
|
1637
|
-
while (this._accumulator >= this._fixedStep && substeps < this._maxSubsteps) {
|
|
1638
|
-
this._accumulator -= this._fixedStep;
|
|
1639
|
-
substeps++;
|
|
1640
|
-
super.frame(this._fixedStep, frame);
|
|
1641
|
-
this._substepTimes.push(super.frameTime);
|
|
1642
|
-
}
|
|
1643
|
-
this._fixedFrameTime = performance.now() - initialTime;
|
|
1644
|
-
|
|
1645
|
-
// The accumulator will only be larger than the fixed step if we had to
|
|
1646
|
-
// bail early due to hitting the max substep limit or execution time lagging.
|
|
1647
|
-
// In that case, we want to shave off the excess so we don't fall behind next frame.
|
|
1648
|
-
this._accumulator = this._accumulator % this._fixedStep;
|
|
1649
|
-
this._alpha = this._accumulator / this._fixedStep;
|
|
1650
|
-
}
|
|
1651
|
-
get frameTime() {
|
|
1652
|
-
return this._fixedFrameTime;
|
|
1653
|
-
}
|
|
1654
|
-
get substepTimes() {
|
|
1655
|
-
return this._substepTimes;
|
|
1656
|
-
}
|
|
1657
|
-
get fixedStep() {
|
|
1658
|
-
return this._fixedStep;
|
|
1659
|
-
}
|
|
1660
|
-
set fixedStep(fixedStep) {
|
|
1661
|
-
this._fixedStep = fixedStep;
|
|
1662
|
-
}
|
|
1663
|
-
get maxSubsteps() {
|
|
1664
|
-
return this._maxSubsteps;
|
|
1665
|
-
}
|
|
1666
|
-
set maxSubsteps(maxSubsteps) {
|
|
1667
|
-
this._maxSubsteps = maxSubsteps;
|
|
1668
|
-
}
|
|
1669
|
-
get accumulator() {
|
|
1670
|
-
return this._accumulator;
|
|
1671
|
-
}
|
|
1672
|
-
get alpha() {
|
|
1673
|
-
return this._alpha;
|
|
1674
|
-
}
|
|
1675
|
-
}
|
|
1676
|
-
const Early = /*#__PURE__*/new Stage();
|
|
1677
|
-
const Fixed = /*#__PURE__*/new FixedStage();
|
|
1678
|
-
const Update = /*#__PURE__*/new Stage();
|
|
1679
|
-
const Late = /*#__PURE__*/new Stage();
|
|
1680
|
-
const Render = /*#__PURE__*/new Stage();
|
|
1681
|
-
const After = /*#__PURE__*/new Stage();
|
|
1682
|
-
const Stages = {
|
|
1683
|
-
Early,
|
|
1684
|
-
Fixed,
|
|
1685
|
-
Update,
|
|
1686
|
-
Late,
|
|
1687
|
-
Render,
|
|
1688
|
-
After
|
|
1689
|
-
};
|
|
1690
|
-
const Lifecycle = [Early, Fixed, Update, Late, Render, After];
|
|
1691
|
-
|
|
1692
1569
|
/**
|
|
1693
1570
|
* Exposes an object's {@link Instance}.
|
|
1694
1571
|
* @see https://docs.pmnd.rs/react-three-fiber/api/additional-exports#useinstancehandle
|
|
@@ -1734,21 +1611,6 @@ function useFrame(callback, renderPriority = 0) {
|
|
|
1734
1611
|
return null;
|
|
1735
1612
|
}
|
|
1736
1613
|
|
|
1737
|
-
/**
|
|
1738
|
-
* Executes a callback in a given update stage.
|
|
1739
|
-
* Uses the stage instance to identify which stage to target in the lifecycle.
|
|
1740
|
-
*/
|
|
1741
|
-
function useUpdate(callback, stage = Stages.Update) {
|
|
1742
|
-
const store = useStore();
|
|
1743
|
-
const stages = store.getState().internal.stages;
|
|
1744
|
-
// Memoize ref
|
|
1745
|
-
const ref = useMutableCallback(callback);
|
|
1746
|
-
// Throw an error if a stage does not exist in the lifecycle
|
|
1747
|
-
if (!stages.includes(stage)) throw new Error(`An invoked stage does not exist in the lifecycle.`);
|
|
1748
|
-
// Subscribe on mount, unsubscribe on unmount
|
|
1749
|
-
useIsomorphicLayoutEffect(() => stage.add(ref, store), [stage]);
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
1614
|
/**
|
|
1753
1615
|
* Returns a node graph of an object with named nodes & materials.
|
|
1754
1616
|
* @see https://docs.pmnd.rs/react-three-fiber/api/hooks#usegraph
|
|
@@ -1832,42 +1694,6 @@ const createRendererInstance = (gl, canvas) => {
|
|
|
1832
1694
|
...gl
|
|
1833
1695
|
});
|
|
1834
1696
|
};
|
|
1835
|
-
const createStages = (stages, store) => {
|
|
1836
|
-
const state = store.getState();
|
|
1837
|
-
let subscribers;
|
|
1838
|
-
let subscription;
|
|
1839
|
-
const _stages = stages != null ? stages : Lifecycle;
|
|
1840
|
-
if (!_stages.includes(Stages.Update)) throw 'The Stages.Update stage is required for R3F.';
|
|
1841
|
-
if (!_stages.includes(Stages.Render)) throw 'The Stages.Render stage is required for R3F.';
|
|
1842
|
-
state.set(({
|
|
1843
|
-
internal
|
|
1844
|
-
}) => ({
|
|
1845
|
-
internal: {
|
|
1846
|
-
...internal,
|
|
1847
|
-
stages: _stages
|
|
1848
|
-
}
|
|
1849
|
-
}));
|
|
1850
|
-
|
|
1851
|
-
// Add useFrame loop to update stage
|
|
1852
|
-
const frameCallback = {
|
|
1853
|
-
current(state, delta, frame) {
|
|
1854
|
-
subscribers = state.internal.subscribers;
|
|
1855
|
-
for (let i = 0; i < subscribers.length; i++) {
|
|
1856
|
-
subscription = subscribers[i];
|
|
1857
|
-
subscription.ref.current(subscription.store.getState(), delta, frame);
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
};
|
|
1861
|
-
Stages.Update.add(frameCallback, store);
|
|
1862
|
-
|
|
1863
|
-
// Add render callback to render stage
|
|
1864
|
-
const renderCallback = {
|
|
1865
|
-
current(state) {
|
|
1866
|
-
if (state.internal.render === 'auto' && state.gl.render) state.gl.render(state.scene, state.camera);
|
|
1867
|
-
}
|
|
1868
|
-
};
|
|
1869
|
-
Stages.Render.add(renderCallback, store);
|
|
1870
|
-
};
|
|
1871
1697
|
function computeInitialSize(canvas, size) {
|
|
1872
1698
|
if (!size && canvas instanceof HTMLCanvasElement && canvas.parentElement) {
|
|
1873
1699
|
const {
|
|
@@ -1965,8 +1791,7 @@ function createRoot(canvas) {
|
|
|
1965
1791
|
performance,
|
|
1966
1792
|
raycaster: raycastOptions,
|
|
1967
1793
|
camera: cameraOptions,
|
|
1968
|
-
onPointerMissed
|
|
1969
|
-
stages
|
|
1794
|
+
onPointerMissed
|
|
1970
1795
|
} = props;
|
|
1971
1796
|
let state = store.getState();
|
|
1972
1797
|
|
|
@@ -2008,9 +1833,11 @@ function createRoot(canvas) {
|
|
|
2008
1833
|
applyProps(camera, cameraOptions);
|
|
2009
1834
|
// Preserve user-defined frustum if possible
|
|
2010
1835
|
// https://github.com/pmndrs/react-three-fiber/issues/3160
|
|
2011
|
-
if (
|
|
2012
|
-
|
|
2013
|
-
|
|
1836
|
+
if (!camera.manual) {
|
|
1837
|
+
if ('aspect' in cameraOptions || 'left' in cameraOptions || 'right' in cameraOptions || 'bottom' in cameraOptions || 'top' in cameraOptions) {
|
|
1838
|
+
camera.manual = true;
|
|
1839
|
+
camera.updateProjectionMatrix();
|
|
1840
|
+
}
|
|
2014
1841
|
}
|
|
2015
1842
|
}
|
|
2016
1843
|
// Always look at center by default
|
|
@@ -2156,9 +1983,6 @@ function createRoot(canvas) {
|
|
|
2156
1983
|
}
|
|
2157
1984
|
}));
|
|
2158
1985
|
|
|
2159
|
-
// Create update stages. Only do this once on init
|
|
2160
|
-
if (state.internal.stages.length === 0) createStages(stages, store);
|
|
2161
|
-
|
|
2162
1986
|
// Set locals
|
|
2163
1987
|
onCreated = onCreatedCallback;
|
|
2164
1988
|
configured = true;
|
|
@@ -2265,7 +2089,7 @@ function Portal({
|
|
|
2265
2089
|
const [raycaster] = React__namespace.useState(() => new THREE__namespace.Raycaster());
|
|
2266
2090
|
const [pointer] = React__namespace.useState(() => new THREE__namespace.Vector2());
|
|
2267
2091
|
const inject = useMutableCallback((rootState, injectState) => {
|
|
2268
|
-
let viewport;
|
|
2092
|
+
let viewport = undefined;
|
|
2269
2093
|
if (injectState.camera && size) {
|
|
2270
2094
|
const camera = injectState.camera;
|
|
2271
2095
|
// Calculate the override viewport, if present
|
|
@@ -2276,8 +2100,7 @@ function Portal({
|
|
|
2276
2100
|
return {
|
|
2277
2101
|
// The intersect consists of the previous root state
|
|
2278
2102
|
...rootState,
|
|
2279
|
-
|
|
2280
|
-
set: injectState.set,
|
|
2103
|
+
...injectState,
|
|
2281
2104
|
// Portals have their own scene, which forms the root, a raycaster and a pointer
|
|
2282
2105
|
scene: container,
|
|
2283
2106
|
raycaster,
|
|
@@ -2310,6 +2133,7 @@ function Portal({
|
|
|
2310
2133
|
};
|
|
2311
2134
|
});
|
|
2312
2135
|
const usePortalStore = React__namespace.useMemo(() => {
|
|
2136
|
+
// Create a mirrored store, based on the previous root with a few overrides ...
|
|
2313
2137
|
const store = traditional.createWithEqualityFn((set, get) => ({
|
|
2314
2138
|
...rest,
|
|
2315
2139
|
set,
|
|
@@ -2382,21 +2206,30 @@ function flushGlobalEffects(type, timestamp) {
|
|
|
2382
2206
|
return run(globalTailEffects, timestamp);
|
|
2383
2207
|
}
|
|
2384
2208
|
}
|
|
2209
|
+
let subscribers;
|
|
2210
|
+
let subscription;
|
|
2385
2211
|
function update(timestamp, state, frame) {
|
|
2386
2212
|
// Run local effects
|
|
2387
2213
|
let delta = state.clock.getDelta();
|
|
2214
|
+
|
|
2388
2215
|
// In frameloop='never' mode, clock times are updated using the provided timestamp
|
|
2389
2216
|
if (state.frameloop === 'never' && typeof timestamp === 'number') {
|
|
2390
2217
|
delta = timestamp - state.clock.elapsedTime;
|
|
2391
2218
|
state.clock.oldTime = state.clock.elapsedTime;
|
|
2392
2219
|
state.clock.elapsedTime = timestamp;
|
|
2393
|
-
} else {
|
|
2394
|
-
delta = Math.max(Math.min(delta, state.internal.maxDelta), 0);
|
|
2395
2220
|
}
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
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);
|
|
2399
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
|
|
2400
2233
|
state.internal.frames = Math.max(0, state.internal.frames - 1);
|
|
2401
2234
|
return state.frameloop === 'always' ? 1 : state.internal.frames;
|
|
2402
2235
|
}
|
|
@@ -2481,9 +2314,6 @@ function advance(timestamp, runGlobalEffects = true, state, frame) {
|
|
|
2481
2314
|
|
|
2482
2315
|
exports.Block = Block;
|
|
2483
2316
|
exports.ErrorBoundary = ErrorBoundary;
|
|
2484
|
-
exports.FixedStage = FixedStage;
|
|
2485
|
-
exports.Stage = Stage;
|
|
2486
|
-
exports.Stages = Stages;
|
|
2487
2317
|
exports._roots = _roots;
|
|
2488
2318
|
exports.act = act;
|
|
2489
2319
|
exports.addAfterEffect = addAfterEffect;
|
|
@@ -2515,4 +2345,3 @@ exports.useLoader = useLoader;
|
|
|
2515
2345
|
exports.useMutableCallback = useMutableCallback;
|
|
2516
2346
|
exports.useStore = useStore;
|
|
2517
2347
|
exports.useThree = useThree;
|
|
2518
|
-
exports.useUpdate = useUpdate;
|