Skip to content
MotionActor
Esc
↑↓navigate↵open⌘Jpreview
On this page

Holding a frame

Hold a frame while a texture, font or shader loads, and carry the frame context into another React reconciler.

Hosts and renderers draw synchronously, but some of what they draw arrives later: a texture, a font, a shader compile. useHold(label, when) from @motionactor/renderers/react holds the frame while when is true, and the host waits for it before showing or capturing the frame:

import { function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void
Accepts a function that contains imperative, possibly effectful code.
@parameffect Imperative function that can return a cleanup function@paramdeps If present, effect will only activate if the values in the list change.@version16.8.0@see{@link https://react.dev/reference/react/useEffect}
useEffect
, function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
} from "react";
import { function useHold(label: string, when: boolean): voiduseHold } from "@motionactor/renderers/react"; export function function useTexture(url: string): ImageBitmap | nulluseTexture(url: stringurl: string) { const [const bitmap: ImageBitmap | nullbitmap, const setBitmap: React.Dispatch<React.SetStateAction<ImageBitmap | null>>setBitmap] = useState<ImageBitmap | null>(initialState: ImageBitmap | (() => ImageBitmap | null) | null): [ImageBitmap | null, React.Dispatch<React.SetStateAction<ImageBitmap | null>>] (+1 overload)
Returns a stateful value, and a function to update it.
@version16.8.0@see{@link https://react.dev/reference/react/useState}
useState
<ImageBitmap | null>(null);
function useHold(label: string, when: boolean): voiduseHold(`texture ${url: stringurl}`, const bitmap: ImageBitmap | nullbitmap === null); function useEffect(effect: React.EffectCallback, deps?: React.DependencyList): void
Accepts a function that contains imperative, possibly effectful code.
@parameffect Imperative function that can return a cleanup function@paramdeps If present, effect will only activate if the values in the list change.@version16.8.0@see{@link https://react.dev/reference/react/useEffect}
useEffect
(() => {
let let live: booleanlive = true; void function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/fetch)
fetch
(url: stringurl)
.Promise<Response>.then<Blob, never>(onfulfilled?: ((value: Response) => Blob | PromiseLike<Blob>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<Blob>
Attaches callbacks for the resolution and/or rejection of the Promise.
@paramonfulfilled The callback to execute when the Promise is resolved.@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of which ever callback is executed.
then
((response: Responseresponse) => response: Responseresponse.Body.blob(): Promise<Blob>
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Request/blob)
blob
())
.Promise<Blob>.then<ImageBitmap, never>(onfulfilled?: ((value: Blob) => ImageBitmap | PromiseLike<ImageBitmap>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<ImageBitmap>
Attaches callbacks for the resolution and/or rejection of the Promise.
@paramonfulfilled The callback to execute when the Promise is resolved.@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of which ever callback is executed.
then
(function createImageBitmap(image: ImageBitmapSource, options?: ImageBitmapOptions): Promise<ImageBitmap> (+1 overload)
[MDN Reference](https://developer.mozilla.org/docs/Web/API/Window/createImageBitmap)
createImageBitmap
)
.Promise<ImageBitmap>.then<false | void, never>(onfulfilled?: ((value: ImageBitmap) => false | void | PromiseLike<false | void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<false | void>
Attaches callbacks for the resolution and/or rejection of the Promise.
@paramonfulfilled The callback to execute when the Promise is resolved.@paramonrejected The callback to execute when the Promise is rejected.@returnsA Promise for the completion of which ever callback is executed.
then
((next: ImageBitmapnext) => let live: booleanlive && const setBitmap: (value: React.SetStateAction<ImageBitmap | null>) => voidsetBitmap(next: ImageBitmapnext));
return () => { let live: booleanlive = false; }; }, [url: stringurl]); return const bitmap: ImageBitmap | nullbitmap; }

The label is what a capture timeout reports, so name the thing being waited for.

Another React tree

The frame source and the gate reach components through React context. A surface with its own React reconciler, such as a React Three Fiber or a Skia canvas, starts a new tree where that context is gone. Read both outside the canvas and bind them again inside it:

import {
  function FrameGateBinding({ gate, children }: FrameGateBindingProps): JSX.ElementFrameGateBinding,
  function FrameSourceBinding({ source, children }: FrameSourceBindingProps): JSX.ElementFrameSourceBinding,
  function useFrameGate(): FrameGateuseFrameGate,
  function useFrameSource(): FrameSourceuseFrameSource,
} from "@motionactor/renderers/react";

function 
function CanvasHost({ children }: {
    children: ReactNode;
}): JSX.Element
CanvasHost
({ children: ReactNodechildren }: { children: ReactNodechildren: type ReactNode = string | number | bigint | boolean | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<ReactNode> | React.ReactPortal | Promise<AwaitedReactNode> | null | undefined
Represents all of the things React can render. Where {@link ReactElement } only represents JSX, `ReactNode` represents everything that can be rendered.
@see{@link https://react-typescript-cheatsheet.netlify.app/docs/react-types/reactnode/ React TypeScript Cheatsheet}@example```tsx // Typing children type Props = { children: ReactNode } const Component = ({ children }: Props) => <div>{children}</div> <Component>hello</Component> ```@example```tsx // Typing a custom element type Props = { customElement: ReactNode } const Component = ({ customElement }: Props) => <div>{customElement}</div> <Component customElement={<div>hello</div>} /> ```
ReactNode
}) {
const const source: FrameSourcesource = function useFrameSource(): FrameSourceuseFrameSource(); const const gate: FrameGategate = function useFrameGate(): FrameGateuseFrameGate(); return ( <
function Canvas(props: {
    children: ReactNode;
}): ReactNode
Canvas
>
<function FrameSourceBinding({ source, children }: FrameSourceBindingProps): JSX.ElementFrameSourceBinding FrameSourceBindingProps.source: FrameSourcesource={const source: FrameSourcesource}> <function FrameGateBinding({ gate, children }: FrameGateBindingProps): JSX.ElementFrameGateBinding FrameGateBindingProps.gate: FrameGategate={const gate: FrameGategate}>{children: ReactNodechildren}</function FrameGateBinding({ gate, children }: FrameGateBindingProps): JSX.ElementFrameGateBinding> </function FrameSourceBinding({ source, children }: FrameSourceBindingProps): JSX.ElementFrameSourceBinding> </
function Canvas(props: {
    children: ReactNode;
}): ReactNode
Canvas
>
); }

The Three.js and Skia backends both do this.

Was this page helpful?