Skip to content

Commit c4ffe0d

Browse files
committed
Documentation added. Standard renamed to StandardStages to be more explicit
1 parent 4a1a61a commit c4ffe0d

File tree

6 files changed

+79
-19
lines changed

6 files changed

+79
-19
lines changed

example/src/demos/Update.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
Canvas,
44
FixedStage,
55
Stage,
6-
Standard,
6+
StandardStages as Standard,
77
useFrame,
88
useThree,
99
useUpdate,

packages/fiber/src/core/hooks.tsx

+9-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { StateSelector, EqualityChecker } from 'zustand'
44
import { suspend, preload, clear } from 'suspend-react'
55
import { context, RootState, RenderCallback } from './store'
66
import { buildGraph, ObjectMap, is, useMutableCallback, useIsomorphicLayoutEffect } from './utils'
7-
import { UpdateCallback } from './stages'
7+
import { Stages, UpdateCallback } from './stages'
88

99
export interface Loader<T> extends THREE.Loader {
1010
load(
@@ -52,11 +52,18 @@ export function useFrame(callback: RenderCallback, renderPriority: number = 0):
5252
return null
5353
}
5454

55-
export function useUpdate(callback: UpdateCallback, stage: string = 'update') {
55+
/**
56+
* Executes a callback in a given update stage.
57+
* The default stages can be accessed through the Stages enum.
58+
*/
59+
export function useUpdate(callback: UpdateCallback, stage: string = Stages.Update) {
5660
const store = useStore()
5761
const stagesMap = store.getState().internal.stagesMap
62+
// Memoize ref
5863
const ref = useMutableCallback(callback)
64+
// Throw an error if a stage does not exist
5965
if (!stagesMap[stage]) throw `A '${stage}' stage does not exist.`
66+
// Subscribe on mount, unsubscribe on unmount
6067
useIsomorphicLayoutEffect(() => stagesMap[stage].add(ref, store), [stage])
6168
}
6269

packages/fiber/src/core/index.tsx

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
setDeep,
3333
} from './utils'
3434
import { useStore } from './hooks'
35-
import { Stage, Standard, StandardStages } from './stages'
35+
import { Stage, StandardLifecycle, StandardStages } from './stages'
3636

3737
const roots = new Map<Element, Root>()
3838
const { invalidate, advance } = createLoop(roots)
@@ -125,10 +125,10 @@ const createStages = (stages: Stage[] | undefined, store: UseBoundStore<RootStat
125125
let subscribers: Subscription[]
126126
let subscription: Subscription
127127

128-
stages = stages ?? StandardStages
128+
stages = stages ?? StandardLifecycle
129129

130-
if (!stages.includes(Standard.Update)) throw 'The Standard.Update stage is required for R3F.'
131-
if (!stages.includes(Standard.Render)) throw 'The Standard.Render stage is required for R3F.'
130+
if (!stages.includes(StandardStages.Update)) throw 'The StandardStages.Update stage is required for R3F.'
131+
if (!stages.includes(StandardStages.Render)) throw 'The StandardStages.Render stage is required for R3F.'
132132

133133
state.set(({ internal }) => ({ internal: { ...internal, stages: stages! } }))
134134
for (const stage of stages) {

packages/fiber/src/core/stages.ts

+54-10
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@ export type UpdateCallbackRef = MutableRefObject<UpdateCallback>
1010
type Store = UseBoundStore<RootState, StoreApi<RootState>>
1111
export type UpdateSubscription = { ref: UpdateCallbackRef; store: Store }
1212

13-
export type FixedStageOptions = { fixedStep?: number; maxSubSteps?: number }
14-
13+
export type FixedStageOptions = { fixedStep?: number; maxSubsteps?: number }
14+
export type FixedStageProps = { fixedStep: number; maxSubsteps: number; accumulator: number; alpha: number }
15+
16+
/**
17+
* Class representing a stage that updates every frame.
18+
* Stages are used to build a lifecycle of effects for an app's frameloop.
19+
* @param {string} name - Name of the stage.
20+
*/
1521
export class Stage {
1622
name: string
1723
subscribers: UpdateSubscription[]
@@ -21,6 +27,11 @@ export class Stage {
2127
this.subscribers = []
2228
}
2329

30+
/**
31+
* Executes all callback subscriptions on the stage.
32+
* @param {number} delta - Delta time between frame calls.
33+
* @param {THREE.XRFrame | undefined} [frame] - The XR frame if it exists.
34+
*/
2435
frame(delta: number, frame?: THREE.XRFrame | undefined) {
2536
const subs = this.subscribers
2637

@@ -29,6 +40,12 @@ export class Stage {
2940
}
3041
}
3142

43+
/**
44+
* Adds a callback subscriber to the stage.
45+
* @param {UpdateCallbackRef} ref - The mutable callback reference.
46+
* @param {Store} store - The store to be used with the callback execution.
47+
* @returns {() => void} A function to remove the subscription.
48+
*/
3249
add(ref: UpdateCallbackRef, store: Store) {
3350
this.subscribers.push({ ref, store })
3451

@@ -40,9 +57,17 @@ export class Stage {
4057
}
4158
}
4259

43-
// Using Unity's default here.
60+
// Using Unity's fixedStep default.
4461
const FPS_50 = 1 / 50
4562

63+
/**
64+
* Class representing a stage that updates every frame at a fixed rate.
65+
* @param {string} name - Name of the stage.
66+
* @param {FixedStageOptions} [options] - Options for the fixed stage.
67+
* @param {number} [options.fixedStep] - Fixed step rate.
68+
* @param {number} [options.maxSubsteps] - Maximum number of substeps.
69+
* @extends Stage
70+
*/
4671
export class FixedStage extends Stage {
4772
private fixedStep: number
4873
private maxSubsteps: number
@@ -58,6 +83,11 @@ export class FixedStage extends Stage {
5883
this.alpha = 0
5984
}
6085

86+
/**
87+
* Executes all callback subscriptions on the stage.
88+
* @param {number} delta - Delta time between frame calls.
89+
* @param {THREE.XRFrame | undefined} [frame] - The XR frame if it exists.
90+
*/
6191
frame(delta: number, frame?: THREE.XRFrame | undefined) {
6292
const initialTime = performance.now()
6393
let substeps = 0
@@ -77,19 +107,33 @@ export class FixedStage extends Stage {
77107
}
78108

79109
// The accumulator will only be larger than the fixed step if we had to
80-
// bail early due to hitting the max substep limit. In that case, we want to
81-
// shave off the excess so we don't fall behind next frame.
110+
// bail early due to hitting the max substep limit or execution time lagging.
111+
// In that case, we want to shave off the excess so we don't fall behind next frame.
82112
this.accumulator = this.accumulator % this.fixedStep
83113
this.alpha = this.accumulator / this.fixedStep
84114
}
85115

116+
/**
117+
* Set the fixed stage properties.
118+
* @param {FixedStageOptions} options - Options for the fixed stage.
119+
* @param {number} [options.fixedStep] - Fixed step rate.
120+
* @param {number} [options.maxSubsteps] - Maximum number of substeps.
121+
*/
86122
set(options: FixedStageOptions) {
87-
const { fixedStep, maxSubSteps } = options
123+
const { fixedStep, maxSubsteps } = options
88124
if (fixedStep) this.fixedStep = fixedStep
89-
if (maxSubSteps) this.maxSubsteps = maxSubSteps
125+
if (maxSubsteps) this.maxSubsteps = maxSubsteps
90126
}
91127

92-
get() {
128+
/**
129+
* Get the fixed stage properties.
130+
* @returns {FixedStageProps} props The fixed stage properties.
131+
* @returns {number} props.fixedStep The fixed step rate.
132+
* @returns {number} props.maxSubsteps The maximum number of substeps.
133+
* @returns {number} props.accumulator The time left over in the accumulator.
134+
* @returns {number} props.alpha The ratio of remaining time and step size. Useful for interpolation.
135+
*/
136+
get(): FixedStageProps {
93137
return {
94138
fixedStep: this.fixedStep,
95139
maxSubsteps: this.maxSubsteps,
@@ -106,8 +150,8 @@ const Late = new Stage('late')
106150
const Render = new Stage('render')
107151
const After = new Stage('after')
108152

109-
export const Standard = { Early, Fixed, Update, Late, Render, After }
110-
export const StandardStages = [Early, Fixed, Update, Late, Render, After]
153+
export const StandardStages = { Early, Fixed, Update, Late, Render, After }
154+
export const StandardLifecycle = [Early, Fixed, Update, Late, Render, After]
111155

112156
export enum Stages {
113157
Early = 'early',

packages/fiber/src/core/store.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,20 @@ const createStore = (
303303

304304
// Updates
305305
active: false,
306-
priority: 0,
307306
frames: 0,
307+
/**
308+
* The ordered stages defining the lifecycle.
309+
*/
308310
stages: [],
311+
/**
312+
* The stages map, where the key is the stage name and the value is the stage.
313+
*/
309314
stagesMap: {},
315+
/**
316+
* The max delta time between two frames.
317+
*/
310318
maxDelta: 1 / 10,
319+
priority: 0,
311320
subscribe: (
312321
ref: React.MutableRefObject<RenderCallback>,
313322
priority: number,

packages/fiber/src/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ export type { ObjectMap, Camera } from './core/utils'
1717
export * from './web/Canvas'
1818
export { createPointerEvents as events } from './web/events'
1919
export * from './core'
20-
export { Stage, FixedStage, Standard, Stages } from './core/stages'
20+
export { Stage, FixedStage, StandardStages, Stages } from './core/stages'

0 commit comments

Comments
 (0)