Skip to main content

Effects

Effects are post-process filters applied to any node via the effects prop. They are applied after the node is rendered, so they affect the entire node including its children.

MotionScript provides three built-in effects: blur, grayscale, and pixelate.

Using effects

Pass an effects prop to any node with either an array of effect objects or the FX builder:

import { Scene, Rect, FX } from '@motion-script/core';

export class MyScene extends Scene {
*build() {
// Using the FX builder (chainable)
this.add(<Rect width={300} height={300} fill="royalblue" effects={FX.blur(8)} />);

// Using a raw array
this.add(<Rect width={300} height={300} fill="royalblue" effects={[{ type: 'blur', radius: 8 }]} />);
}
}

Blur

Applies a Gaussian blur. radius is in pixels.

import { Scene, Rect, Image, FX, tween, lerpNumber, easeOut } from '@motion-script/core';

export class MyScene extends Scene {
*build() {
const bg = new Rect({
width: 800,
height: 450,
fill: { type: 'image', src: './photo.jpg', mode: 'fill' },
});
bg.set({ effects: FX.blur(20) });
this.add(bg);
}
}

Animating blur

Animate the radius inside a tween to create focus-in or defocus effects:

import { Scene, Rect, FX, tween, lerpNumber, easeOut } from '@motion-script/core';

export class MyScene extends Scene {
*build() {
const card = new Rect({ width: 400, height={300}, fill: '#1e293b' });
card.set({ effects: FX.blur(30) });
this.add(card);

// Focus in
yield* tween(1, (t) => {
card.set({ effects: FX.blur(lerpNumber(30, 0, easeOut(t))) });
});
}
}

Grayscale

Desaturates the node. amount ranges from 0 (full color) to 1 (fully grayscale).

<Rect
width={500} height={350}
fill={{ type: 'image', src: './photo.jpg', mode: 'fill' }}
effects={FX.grayscale(1)}
/>

Colorize animation

Animate from grayscale to full color:

yield* tween(1.5, (t) => {
photo.set({ effects: FX.grayscale(lerpNumber(1, 0, easeInOut(t))) });
});

Pixelate

Chunks the node into rectangular blocks. size is a value from 0 (no pixelation) to 1 (entire node collapsed to one block). The value is resolution-independent.

<Rect
width={300} height={300}
fill={{ type: 'image', src: './logo.png', mode: 'fit' }}
effects={FX.pixelate(0.4)}
/>

Pixel-reveal animation

import { Scene, Rect, FX, tween, lerpNumber, easeInOut } from '@motion-script/core';

export class MyScene extends Scene {
*build() {
const logo = new Rect({
width: 300,
height: 300,
fill: { type: 'image', src: './logo.png', mode: 'fit' },
});
logo.set({ effects: FX.pixelate(0.8) });
this.add(logo);

yield* tween(1.5, (t) => {
logo.set({ effects: FX.pixelate(lerpNumber(0.8, 0, easeInOut(t))) });
});
}
}

Chaining effects with FX

The FX builder lets you chain multiple effects fluently:

import { FX } from '@motion-script/core';

// Grayscale then blur
<Rect effects={FX.grayscale(0.8).blur(4)} />

// All three
<Rect effects={FX.pixelate(0.3).grayscale(0.5).blur(2)} />

Each FX method returns a new immutable chain, so chains are safe to reuse:

const base = FX.grayscale(1);
const blurry = base.blur(8); // 'base' is unchanged

Raw effect objects

You can also pass plain objects — useful when constructing effects programmatically:

effects={[
{ type: 'grayscale', amount: 0.8 },
{ type: 'blur', radius: 4 },
]}

Effect object types

TypeProps
{ type: 'blur', radius: number }radius — Gaussian blur radius in pixels
{ type: 'grayscale', amount: number }amount — 0 (color) to 1 (grayscale)
{ type: 'pixelate', horizontalBlocks: number, verticalBlocks: number }Block sizes 0–1 per axis