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

Effect kinds

Define an effect kind for SVG filters, with a stage that paints its effects.

An effect kind fixes what an effect of that kind supplies and what paints it. This page builds svgFilter for the SVG backend: an effect supplies filter primitives from its params, and a stage turns them into a <filter> around the actor.

The kind and its stage

import { function useId(): stringuseId, type 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
} from "react";
import {
function defineEffectKind<const TBackend extends string, const TName extends string, K extends EffectKindTypes, const TRaster extends EffectRaster = {
    readonly kind: "inline";
}, const TApplies extends EffectApplication = EffectApplication>(backend: BackendRef<TBackend>, spec: EffectKindDeclaration<K, TName, TRaster, TApplies>): EffectKind<TBackend, TName, K, TRaster, TApplies>
Define a kind of effect for a backend: what an author supplies for one shape of effect, and how it lowers to what a stage or host reads. The stage that paints it is the binding's, paired by the backend. `types` names the type slots (`spec`, `runtime`) in terms of `this["params"]`: export const pixiFilter = defineEffectKind(pixi, { name: "filter", types: effectKindTypes<PixiFilterTypes>(), * applies: "actor", lower: (spec) => (typeof spec.filter === "function" ? filterFromClass(spec.filter) : spec.filter), });
defineEffectKind
,
const effectKindTypes: <K extends EffectKindTypes>() => EffectKindTypesTag<K>
Names a kind's type slots (`spec`, `runtime`, in terms of `this["params"]`) for `defineEffectKind`.
effectKindTypes
,
const readEffectDefinition: (binding: EffectBinding | undefined) => AnyEffectDefinition | undefined
The definition a binding carries; `undefined` for a bare wire id (JSON that crossed IPC).
readEffectDefinition
,
const resolveEffectParams: (effect: Pick<ActiveEffect, "binding" | "params" | "effectType">) => Record<string, unknown>
The params render code reads for an `ActiveEffect`, however it was minted: every declared param the effect leaves out takes its declared default, and every typed one decodes (a colour string becomes a `Color`), the way `ctx.apply` and the factories treat them. Params nothing declares pass through. Returns `effect.params` itself when nothing changes. Stages and hosts call it before render code runs, so an editor that mints effects from `runtime.resolveEffectBinding(...)` gets the same values a scene does.
resolveEffectParams
,
type EffectKindTypes, type interface EffectStage<TNode = unknown>
How a backend paints effects around an actor's content, in the binding's node type (JSX for React). The element resolver decides geometry; the stage decides pixels. A backend pairs each stage with the kinds it paints (`createBackend(ref, { stages: [{ kinds, stage }] })`) and orders its stages from those kinds' `raster.kind`: offscreen stages wrap the content first (they need the subtree rendered before they run), inline stages wrap outside them.
EffectStage
,
} from "@motionactor/core"; import { const svg: BackendRef<"svg">svg } from "./svg"; /** One SVG filter primitive, as data. */ export type
type SvgPrimitive = {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
} | {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
} | {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
} | {
    readonly type: "feMerge";
    readonly inputs: readonly string[];
}
One SVG filter primitive, as data.
SvgPrimitive
=
| { readonly type: "feGaussianBlur"type: "feGaussianBlur"; readonly stdDeviation: numberstdDeviation: number; readonly result?: string | undefinedresult?: string; } | { readonly type: "feTurbulence"type: "feTurbulence"; readonly baseFrequency: numberbaseFrequency: number; readonly numOctaves: numbernumOctaves: number; readonly result: stringresult: string; } | { readonly type: "feDisplacementMap"type: "feDisplacementMap"; readonly in: stringin: string; readonly in2: stringin2: string; readonly scale: numberscale: number; } | { readonly type: "feMerge"type: "feMerge"; readonly inputs: readonly string[]inputs: readonly string[] }; /** The primitives of one filter, from an effect's params. */ export type type SvgPrimitives<P> = (params: P) => readonly SvgPrimitive[]
The primitives of one filter, from an effect's params.
SvgPrimitives
<function (type parameter) P in type SvgPrimitives<P>P> = (params: Pparams: function (type parameter) P in type SvgPrimitives<P>P) => readonly
type SvgPrimitive = {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
} | {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
} | {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
} | {
    readonly type: "feMerge";
    readonly inputs: readonly string[];
}
One SVG filter primitive, as data.
SvgPrimitive
[];
/** What an `svgFilter` effect supplies beside its params. */ export interface interface SvgFilterSpec<P>
What an `svgFilter` effect supplies beside its params.
SvgFilterSpec
<function (type parameter) P in SvgFilterSpec<P>P> {
readonly SvgFilterSpec<P>.primitives: SvgPrimitives<P>primitives: type SvgPrimitives<P> = (params: P) => readonly SvgPrimitive[]
The primitives of one filter, from an effect's params.
SvgPrimitives
<function (type parameter) P in SvgFilterSpec<P>P>;
} export interface SvgFilterTypes extends EffectKindTypes { readonly SvgFilterTypes.spec: SvgFilterSpec<this["params"]>spec: interface SvgFilterSpec<P>
What an `svgFilter` effect supplies beside its params.
SvgFilterSpec
<this["params"]>;
readonly SvgFilterTypes.runtime: SvgPrimitives<this["params"]>runtime: type SvgPrimitives<P> = (params: P) => readonly SvgPrimitive[]
The primitives of one filter, from an effect's params.
SvgPrimitives
<this["params"]>;
} const const element: (primitive: SvgPrimitive, key: number) => JSX.Elementelement = (primitive: SvgPrimitiveprimitive:
type SvgPrimitive = {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
} | {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
} | {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
} | {
    readonly type: "feMerge";
    readonly inputs: readonly string[];
}
One SVG filter primitive, as data.
SvgPrimitive
, key: numberkey: number) => {
switch (primitive: SvgPrimitiveprimitive.type: "feGaussianBlur" | "feTurbulence" | "feDisplacementMap" | "feMerge"type) { case "feGaussianBlur": return ( <React.JSX.IntrinsicElements.feGaussianBlur: React.SVGProps<SVGFEGaussianBlurElement>feGaussianBlur React.Attributes.key?: React.Key | null | undefinedkey={key: numberkey} React.SVGAttributes<SVGFEGaussianBlurElement>.stdDeviation?: string | number | undefinedstdDeviation={
primitive: {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
}
primitive
.stdDeviation: numberstdDeviation}
React.SVGAttributes<SVGFEGaussianBlurElement>.result?: string | undefinedresult={
primitive: {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
}
primitive
.result?: string | undefinedresult}
/> ); case "feTurbulence": return ( <React.JSX.IntrinsicElements.feTurbulence: React.SVGProps<SVGFETurbulenceElement>feTurbulence React.Attributes.key?: React.Key | null | undefinedkey={key: numberkey} React.SVGAttributes<SVGFETurbulenceElement>.baseFrequency?: string | number | undefinedbaseFrequency={
primitive: {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
}
primitive
.baseFrequency: numberbaseFrequency}
React.SVGAttributes<SVGFETurbulenceElement>.numOctaves?: string | number | undefinednumOctaves={
primitive: {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
}
primitive
.numOctaves: numbernumOctaves}
React.SVGAttributes<T>.result?: string | undefinedresult={
primitive: {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
}
primitive
.result: stringresult}
/> ); case "feDisplacementMap": return ( <React.JSX.IntrinsicElements.feDisplacementMap: React.SVGProps<SVGFEDisplacementMapElement>feDisplacementMap React.Attributes.key?: React.Key | null | undefinedkey={key: numberkey} React.SVGAttributes<SVGFEDisplacementMapElement>.in?: string | undefinedin={
primitive: {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
}
primitive
.in: stringin}
React.SVGAttributes<SVGFEDisplacementMapElement>.in2?: string | number | undefinedin2={
primitive: {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
}
primitive
.in2: stringin2}
React.SVGAttributes<SVGFEDisplacementMapElement>.scale?: string | number | undefinedscale={
primitive: {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
}
primitive
.scale: numberscale}
/> ); case "feMerge": return ( <React.JSX.IntrinsicElements.feMerge: React.SVGProps<SVGFEMergeElement>feMerge React.Attributes.key?: React.Key | null | undefinedkey={key: numberkey}> {
primitive: {
    readonly type: "feMerge";
    readonly inputs: readonly string[];
}
primitive
.inputs: readonly string[]inputs.ReadonlyArray<string>.map<JSX.Element>(callbackfn: (value: string, index: number, array: readonly string[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((input: stringinput, i: numberi) => (
<React.JSX.IntrinsicElements.feMergeNode: React.SVGProps<SVGFEMergeNodeElement>feMergeNode React.Attributes.key?: React.Key | null | undefinedkey={i: numberi} React.SVGAttributes<T>.in?: string | undefinedin={input: stringinput} /> ))} </React.JSX.IntrinsicElements.feMerge: React.SVGProps<SVGFEMergeElement>feMerge> ); } }; function
function Filtered(props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}): JSX.Element
Filtered
(
props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}
props
: {
primitives: readonly SvgPrimitive[]primitives: readonly
type SvgPrimitive = {
    readonly type: "feGaussianBlur";
    readonly stdDeviation: number;
    readonly result?: string;
} | {
    readonly type: "feTurbulence";
    readonly baseFrequency: number;
    readonly numOctaves: number;
    readonly result: string;
} | {
    readonly type: "feDisplacementMap";
    readonly in: string;
    readonly in2: string;
    readonly scale: number;
} | {
    readonly type: "feMerge";
    readonly inputs: readonly string[];
}
One SVG filter primitive, as data.
SvgPrimitive
[];
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 id: stringid = function useId(): stringuseId(); return ( <> <React.JSX.IntrinsicElements.filter: React.SVGProps<SVGFilterElement>filter React.SVGAttributes<SVGFilterElement>.id?: string | undefinedid={const id: stringid} React.SVGAttributes<SVGFilterElement>.x?: string | number | undefinedx="-50%" React.SVGAttributes<SVGFilterElement>.y?: string | number | undefinedy="-50%" React.SVGAttributes<SVGFilterElement>.width?: string | number | undefinedwidth="200%" React.SVGAttributes<SVGFilterElement>.height?: string | number | undefinedheight="200%"> {
props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}
props
.primitives: readonly SvgPrimitive[]primitives.ReadonlyArray<SvgPrimitive>.map<JSX.Element>(callbackfn: (value: SvgPrimitive, index: number, array: readonly SvgPrimitive[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(const element: (primitive: SvgPrimitive, key: number) => JSX.Elementelement)}
</React.JSX.IntrinsicElements.filter: React.SVGProps<SVGFilterElement>filter> <React.JSX.IntrinsicElements.g: React.SVGProps<SVGGElement>g React.SVGAttributes<SVGGElement>.filter?: string | undefinedfilter={`url(#${const id: stringid})`}>{
props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}
props
.children: ReactNodechildren}</React.JSX.IntrinsicElements.g: React.SVGProps<SVGGElement>g>
</> ); } /** Each effect gets its own filter, wrapped around the ones before it. */ export const const svgFilterStage: EffectStage<ReactNode>
Each effect gets its own filter, wrapped around the ones before it.
svgFilterStage
: interface EffectStage<TNode = unknown>
How a backend paints effects around an actor's content, in the binding's node type (JSX for React). The element resolver decides geometry; the stage decides pixels. A backend pairs each stage with the kinds it paints (`createBackend(ref, { stages: [{ kinds, stage }] })`) and orders its stages from those kinds' `raster.kind`: offscreen stages wrap the content first (they need the subtree rendered before they run), inline stages wrap outside them.
EffectStage
<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
> = {
EffectStage<React.ReactNode>.wrap: (context: EffectStageContext, node: ReactNode) => ReactNode
A property, not a method: its node input is checked contravariantly.
wrap
: ({ effects: readonly ActiveEffect[]
The actor's applied effects this stage owns, in application order.
effects
}, node: ReactNodenode) =>
effects: readonly ActiveEffect[]
The actor's applied effects this stage owns, in application order.
effects
.ReadonlyArray<ActiveEffect>.reduce<string | number | bigint | boolean | Iterable<ReactNode> | Promise<AwaitedReactNode> | JSX.Element | null | undefined>(callbackfn: (previousValue: string | number | bigint | boolean | Iterable<ReactNode> | Promise<AwaitedReactNode> | JSX.Element | null | undefined, currentValue: ActiveEffect, currentIndex: number, array: readonly ActiveEffect[]) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<AwaitedReactNode> | JSX.Element | null | undefined, initialValue: string | ... 7 more ... | undefined): string | ... 7 more ... | undefined (+2 overloads)
Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@paramcallbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array.@paraminitialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value.
reduce
((inner: ReactNodeinner, effect: ActiveEffecteffect) => {
const const definition: AnyEffectDefinition | undefineddefinition = function readEffectDefinition(binding: EffectBinding | undefined): AnyEffectDefinition | undefined
The definition a binding carries; `undefined` for a bare wire id (JSON that crossed IPC).
readEffectDefinition
(effect: ActiveEffecteffect.ActiveEffect.binding?: EffectBinding<string, string, unknown, EffectRaster> | undefined
The effect it applies, by wire id `{ backend, name }`; carries its definition when built in-process.
binding
);
const const primitives: SvgPrimitives<Record<string, unknown>> | undefinedprimitives = const definition: AnyEffectDefinition | undefineddefinition &&
const svgFilter: EffectKind<"svg", "filter", SvgFilterTypes, {
    readonly kind: "inline";
}, "actor">
svgFilter
.EffectKind<"svg", "filter", SvgFilterTypes, { readonly kind: "inline"; }, "actor">.runtimeOf(definition: AnyEffectDefinition): SvgPrimitives<Record<string, unknown>> | undefined
What this kind's stage or host runs for `definition`: its spec, lowered when it was defined. `undefined` for another kind's definition.
runtimeOf
(const definition: AnyEffectDefinitiondefinition);
if (!const primitives: SvgPrimitives<Record<string, unknown>> | undefinedprimitives) return inner: ReactNodeinner; return ( <
function Filtered(props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}): JSX.Element
Filtered
primitives: readonly SvgPrimitive[]primitives={const primitives: (params: Record<string, unknown>) => readonly SvgPrimitive[]primitives(function resolveEffectParams(effect: Pick<ActiveEffect, "binding" | "params" | "effectType">): Record<string, unknown>
The params render code reads for an `ActiveEffect`, however it was minted: every declared param the effect leaves out takes its declared default, and every typed one decodes (a colour string becomes a `Color`), the way `ctx.apply` and the factories treat them. Params nothing declares pass through. Returns `effect.params` itself when nothing changes. Stages and hosts call it before render code runs, so an editor that mints effects from `runtime.resolveEffectBinding(...)` gets the same values a scene does.
resolveEffectParams
(effect: ActiveEffecteffect))}>
{inner: ReactNodeinner} </
function Filtered(props: {
    primitives: readonly SvgPrimitive[];
    children: ReactNode;
}): JSX.Element
Filtered
>
); }, node: ReactNodenode), }; export const
const svgFilter: EffectKind<"svg", "filter", SvgFilterTypes, {
    readonly kind: "inline";
}, "actor">
svgFilter
=
defineEffectKind<"svg", "filter", SvgFilterTypes, {
    readonly kind: "inline";
}, "actor">(backend: BackendRef<"svg">, spec: EffectKindDeclaration<SvgFilterTypes, "filter", {
    readonly kind: "inline";
}, "actor">): EffectKind<"svg", "filter", SvgFilterTypes, {
    readonly kind: "inline";
}, "actor">
Define a kind of effect for a backend: what an author supplies for one shape of effect, and how it lowers to what a stage or host reads. The stage that paints it is the binding's, paired by the backend. `types` names the type slots (`spec`, `runtime`) in terms of `this["params"]`: export const pixiFilter = defineEffectKind(pixi, { name: "filter", types: effectKindTypes<PixiFilterTypes>(), * applies: "actor", lower: (spec) => (typeof spec.filter === "function" ? filterFromClass(spec.filter) : spec.filter), });
defineEffectKind
(const svg: BackendRef<"svg">svg, {
EffectKindDeclaration<SvgFilterTypes, "filter", { readonly kind: "inline"; }, "actor">.name: "filter"
Unique among the backend's kinds.
name
: "filter",
EffectKindDeclaration<SvgFilterTypes, "filter", { readonly kind: "inline"; }, "actor">.types: EffectKindTypesTag<SvgFilterTypes>
The kind's type slots: `effectKindTypes<PixiFilterTypes>()`.
types
: effectKindTypes<SvgFilterTypes>(): EffectKindTypesTag<SvgFilterTypes>
Names a kind's type slots (`spec`, `runtime`, in terms of `this["params"]`) for `defineEffectKind`.
effectKindTypes
<SvgFilterTypes>(),
EffectKindDeclaration<SvgFilterTypes, "filter", { readonly kind: "inline"; }, "actor">.applies: "actor"
What effects of the kind apply to unless they declare a `target`, kept literal (actor `fx` reads it).
applies
: "actor",
EffectKindDeclaration<SvgFilterTypes, "filter", { readonly kind: "inline"; }, "actor">.lower?: ((spec: SvgFilterSpec<Record<string, unknown>>) => SvgPrimitives<Record<string, unknown>>) | undefined
The kind's spec lowered to its runtime form, once at definition time. Absent, the spec is the runtime form: `K["spec"]` must then be `K["runtime"]`. `native` is the kind's bound here: one `lower` serves every effect's class.
lower
: (spec: SvgFilterSpec<Record<string, unknown>>spec) => spec: SvgFilterSpec<Record<string, unknown>>spec.SvgFilterSpec<Record<string, unknown>>.primitives: SvgPrimitives<Record<string, unknown>>primitives,
});

types names two slots in terms of the effect’s own params. spec is what defineEffect takes beside its name and params, and runtime is what the stage reads. lower turns one into the other once, when the effect is defined. Here the effect gives a primitives function and the stage calls it, so lower only unwraps it. The stage reads it back with svgFilter.runtimeOf(definition), typed by the kind, which is undefined for another kind’s effect.

A stage is one function, wrap(context, node). It gets the actor’s content and the effects it owns, and returns the content wrapped in their treatment. The DOM style stage wraps it in a styled element, and the Pixi filter stage in a container with filters. This one gives each effect its own <filter> and <g>, so two filters on one actor stack in the order they were applied. Filtered is a component so it can call useId, which keeps filter ids unique when the same scene renders twice on a page.

The kind names no stage. The backend pairs them, stages: [{ kinds: [svgFilter], stage: svgFilterStage }], so the same kind could paint through a Vue stage under another binding. Here both live in one React file for brevity; a backend shared across bindings keeps the kind in a framework-free module. The ref in svg.ts stays React-free, and a scene that applies SVG filters imports ./svg-filter.

A node a view binds to an actor has no wrapper to render. An inline stage that can paint on one anyway adds node to its pairing: given the same context, it returns the transform, filter, opacity and clipPath the node folds into its own style, or unsupported naming what it would need. The DOM style stage has one. A binding rejects an effect whose stage has none.

Effects

Every effect of the kind is a defineEffect call, typed from its params. The code beside the figure is its scene: blur is one primitive, halo merges a blurred copy under the dot, and wobble displaces the dot by a noise field. primitives returns SvgPrimitive[], so a misspelled primitive or a missing in2 fails the type check.

Each effect registers beside its definition, keyed "svg:<name>", so every actor reads dot.fx.blur(). filter.play drives progress from 0 to 1 as it does for a DOM effect, and filter.progress.tween(0) brings it back. See Effects.

Raster

A kind also declares a raster. Inline, the default, paints over the actor as it is drawn. Offscreen means the stage needs the actor’s pixels first, so offscreen stages wrap the content before inline ones do. An SVG filter is inline: the browser rasterizes the filtered group itself. Two kinds can share a stage if they agree on its raster; one kind pairs with one stage.

Effects that arrive by name

An effect a scene imports carries its definition, and readEffectDefinition returns it. An effect that crossed a process boundary as { backend: "svg", name: "halo" } has lost it. groupEffectsByStage rebinds it from the effect registry, where registerEffects([halo]) put it when its module was imported, and skips it when nothing registered that wire id. A host that reads effects itself, without a stage, rebinds the same way with registeredEffect(binding) from @motionactor/core/internal.

Was this page helpful?