Skip to content

Store

Angular Three store utilizes ngrx/signals, specifically SignalState, as the implementation details.

NgtCanvas component from each platform provides the default store which has the type of SignalState<NgtState>. Store can be layered, or linked, by component like NgtPortal or components that make use of NgtPortal.

export interface NgtState {
/** id **/
id: string;
/** The instance of the renderer */
gl: THREE.WebGLRenderer;
/** Default camera */
camera: NgtCamera;
/** Default scene */
scene: THREE.Scene;
/** Default raycaster */
raycaster: THREE.Raycaster;
/** Default clock */
clock: THREE.Clock;
/** Event layer interface, contains the event handler and the node they're connected to */
events: NgtEventManager<any>;
/** XR interface */
xr: NgtXRManager;
/** Currently used controls */
controls: THREE.EventDispatcher | null;
/** Normalized event coordinates */
pointer: THREE.Vector2;
/* Whether to enable r139's ColorManagement */
legacy: boolean;
/** Shortcut to gl.outputColorSpace = LinearSRGBColorSpace */
linear: boolean;
/** Shortcut to gl.toneMapping = NoTonemapping */
flat: boolean;
/** Render loop flags */
frameloop: NgtFrameloop;
/** Adaptive performance interface */
performance: NgtPerformance;
/** Reactive pixel-size of the canvas */
size: NgtSize;
/** Reactive size of the viewport in threejs units */
viewport: NgtViewport & {
getCurrentViewport: (
camera: NgtCamera,
target?: THREE.Vector3 | Parameters<THREE.Vector3['set']>,
size?: NgtSize,
) => Omit<NgtViewport, 'dpr' | 'initialDpr'>;
};
/** Flags the canvas for render, but doesn't render in itself */
invalidate: (frames?: number) => void;
/** Advance (render) one step */
advance: (timestamp: number, runGlobalEffects?: boolean) => void;
/** Shortcut to setting the event layer */
setEvents: (events: Partial<NgtEventManager<any>>) => void;
/**
* Shortcut to manual sizing
*/
setSize: (width: number, height: number, top?: number, left?: number) => void;
/** Shortcut to manual setting the pixel ratio */
setDpr: (dpr: NgtDpr) => void;
/** Shortcut to frameloop flags */
setFrameloop: (frameloop?: NgtFrameloop) => void;
/** When the canvas was clicked but nothing was hit */
/** PointerMissed Observable */
pointerMissed$: Observable<MouseEvent>;
/** If this state model is layered (via createPortal) then this contains the previous layer */
previousRoot: SignalState<NgtState> | null;
/** Internals */
internal: NgtInternalState;
}

injectStore()

To gain access to the store of the current context, either the root/default one or a layered one, you can call injectStore(). injectStore() accepts InjectOptions so you can control how DI works for injectStore().

export class MyCmp {
constructor() {
const store = injectStore(); // SignalState<NgtState>
}
}

Accessing reactive state

By implementing SignalState, Store is deeply reactive (via Proxy).

You can access any piece of the state by using dot-separated path.

export class MyCmp {
constructor() {
const store = injectStore();
store.gl(); // Signal<THREE.WebGLRenderer>
store.size(); // Signal<NgtSize>
store.size.width(); // Signal<number>
}
}

Accessing snapshot state

In situations like inside of injectBeforeRender body where whether tracking/reading a Signal does not matter, you can access the snapshot state instead via store.snapshot

export class MyCmp {
constructor() {
const store = injectStore();
injectBeforeRender(() => {
// because beforeRender body runs on every frame, it does not matter whether we read signal value or not
store.snapshot.camera; // NgtCamera
store.snapshot.invalidate(); // call invalidate()
})
}
}