Modifiers
Modifiers are chainable operations that animate or style a shape. They return a new ShapeBuilder so you can keep chaining.
Timing Model
Most animated modifiers accept the same timing fields:
duration(ms, required)start(numberorTimeReflikescene+200orprev.end+150)delay(ms)repeatDelay(ms)loop(boolean)ease(linear,easeIn,easeOut,easeInOut, or{ type: 'cubicBezier', x1, y1, x2, y2 })keyframes(array of{ time, value }withtimein ms)
If keyframes is provided, the last keyframe time defines the duration unless you also set duration.
Color & Opacity
fill
fill
Solid fill or animated color transitions.
DSL
Circle(48)
.fill({ from: '#0ea5e9', to: '#22c55e', duration: 1200, loop: true, ease: 'easeInOut' })
gradient
gradient
Linear or radial gradients with stops.
DSL
Rect(180, 100)
.gradient({
type: 'linear',
from: { x: -90, y: -50 },
to: { x: 90, y: 50 },
stops: [
{ pos: 0, color: '#0ea5e9' },
{ pos: 1, color: '#22c55e' },
],
})
stroke
stroke
Outline with width, dash patterns, and color.
DSL
Path([
{ x: -80, y: -40 },
{ x: 80, y: 40 },
], false)
.fill('rgba(0,0,0,0)')
.stroke({ color: '#22d3ee', width: 6, dash: [8, 6] })
opacity
opacity
Fade in or out over time.
DSL
Rect(140, 80)
.fill('#0f172a')
.opacity({ from: 0, to: 1, duration: 600, loop: true })
shadow
shadow
Drop shadow with blur and offsets.
DSL
Rect(160, 90)
.fill('#ffffff')
.shadow({ color: 'rgba(0,0,0,0.2)', blur: 10, offsetX: 0, offsetY: 8 })
blendMode
blendMode
Controls canvas compositing.
DSL
Circle(60)
.fill('#22d3ee')
.blendMode('screen')
fillMode
fillMode
Tints images with fill colors.
DSL
Image('https://placehold.co/320x200/png', 160, 120)
.fill('#0ea5e9')
.fillMode('multiply')
Position & Motion
at
at
Sets an absolute position in local space.
DSL
Circle(20)
.fill('#22c55e')
.at({ x: -120, y: 40 })
move
move
Linear motion between two points.
DSL
Circle(30)
.fill('#0ea5e9')
.move({ x: [-120, 120], duration: 1200, loop: true, ease: 'easeInOut' })
curve
curve
Move along a quadratic curve.
DSL
Circle(18)
.fill('#f97316')
.curve({
from: { x: -120, y: 60 },
control: { x: 0, y: -120 },
to: { x: 120, y: 60 },
duration: 1400,
loop: true,
})
pathMotion
pathMotion
Follow a custom path.
DSL
Circle(14)
.fill('#38bdf8')
.pathMotion({
path: [
{ x: -120, y: -40 },
{ x: 0, y: 60 },
{ x: 120, y: -40 },
],
duration: 1200,
loop: true,
})
orientToPath
orientToPath
Rotate to align with the path tangent.
DSL
Triangle(60, 40, { direction: 'right' })
.fill('#0f172a')
.pathMotion({
path: [
{ x: -120, y: -40 },
{ x: 0, y: 60 },
{ x: 120, y: -40 },
],
duration: 1200,
loop: true,
})
.orientToPath({ offset: Math.PI / 2 })
velocity
velocity
Constant velocity motion.
DSL
Circle(10)
.fill('#a3e635')
.velocity({ x: 0.08, y: 0.02, duration: 2000, loop: true })
acceleration
acceleration
Constant acceleration.
DSL
Circle(10)
.fill('#f472b6')
.acceleration({ x: 0.0002, y: 0.0004, duration: 2000, loop: true })
spring
spring
Spring easing between two points.
DSL
Circle(28)
.fill('#facc15')
.spring({ x: [-80, 80], duration: 1200, loop: true, stiffness: 160, damping: 18, mass: 1 })
Transform
scale
scale
Uniform scaling.
DSL
Rect(120, 70)
.fill('#0ea5e9')
.scale({ from: 0.8, to: 1.1, duration: 900, loop: true, ease: 'easeInOut' })
scaleX / scaleY
scaleX / scaleY
Independent axis scaling.
DSL
Rect(120, 70)
.fill('#22c55e')
.scaleX({ from: 0.6, to: 1.2, duration: 900, loop: true, ease: 'easeInOut' })
.scaleY({ from: 1.2, to: 0.6, duration: 900, loop: true, ease: 'easeInOut' })
rotate
rotate
Rotate around the anchor.
DSL
Rect(100, 100)
.fill('#0f172a')
.rotate({ from: 0, to: Math.PI * 2, duration: 2000, loop: true, ease: 'linear' })
skewX / skewY
skewX / skewY
Skew along an axis.
DSL
Rect(120, 70)
.fill('#38bdf8')
.skewX({ from: -0.3, to: 0.3, duration: 1000, loop: true, ease: 'easeInOut' })
flip
flip
Cosine-based flip on axis.
DSL
Rect(120, 70)
.fill('#f97316')
.flip({ from: 0, to: Math.PI, duration: 1200, loop: true, axis: 'y' })
anchor
anchor
Change transform pivot.
DSL
Rect(160, 100)
.fill('#111827')
.anchor('topLeft')
.rotate({ from: 0, to: Math.PI / 8, duration: 800, loop: true })
Shape-Specific
distort
distort
Warp path corners with bilinear corner offsets. Works with Rect, Path, and Compound paths.
DSL
Rect(180, 110)
.fill('#0f172a')
.distort({
tl: { x: -20, y: 0 },
tr: { x: -44, y: 16 },
br: { x: -8, y: 0 },
bl: { x: 6, y: -8 },
})
trim
trim
Trim a path by percentage.
DSL
Circle(60)
.fill('rgba(0,0,0,0)')
.stroke({ color: '#22d3ee', width: 6 })
.trim({ from: 0, to: 0.75, duration: 1200, loop: true })
morph
morph
Morph between compatible shapes.
DSL
Rect(120, 80)
.fill('#a855f7')
.morph({ width: 120, height: 80 }, { width: 200, height: 60 }, 1200, { loop: true })
clip
clip
Clip a shape using another shape.
DSL
Circle(60)
.fill('#22c55e')
.clip(Rect(120, 80).rotate({ from: 0, to: Math.PI / 8, duration: 1200, loop: true }))
textPath
textPath
Render text along a smooth Bezier path.
DSL
Text('Disclose', { fontSize: 30, fontWeight: 600, letterSpacing: 1 })
.fill('#0ea5e9')
.textPath({
path: BezierPath([
{ cmd: 'moveTo', x: -140, y: 10 },
{ cmd: 'quadTo', cpx: -70, cpy: -40, x: 0, y: 0 },
{ cmd: 'quadTo', cpx: 70, cpy: 40, x: 140, y: 10 },
]),
align: 'center',
})
Ordering & Time
zIndex
zIndex
Higher zIndex draws on top.
DSL
Scene(() => [
Circle(60).fill('#0f172a').zIndex(1),
Circle(40).fill('#38bdf8').zIndex(2),
])
timeScale
timeScale
Speed up or slow down a shape's time.
DSL
Circle(20)
.fill('#22d3ee')
.timeScale(2)
.move({ x: [-60, 60], duration: 600, loop: true })
Chained Examples
Chained Modifiers
Style, motion, and timing combined.
DSL
Rect(180, 100)
.fill('#0f172a')
.stroke({ color: '#ffffff', width: 2 })
.shadow({ color: 'rgba(0,0,0,0.35)', blur: 12, offsetY: 10 })
.rotate({ from: -0.08, to: 0.08, duration: 1200, loop: true, ease: 'easeInOut' })
.scale({ from: 0.96, to: 1.02, duration: 1200, loop: true, ease: 'easeInOut' })
.opacity({ from: 0.7, to: 1, duration: 1200, loop: true })
Chained Motion
Multiple motion modifiers stacked together.
DSL
Circle(28)
.fill('#22c55e')
.move({ x: [-140, 140], duration: 1800, loop: true, ease: 'easeInOut' })
.scale({ from: 0.8, to: 1.1, duration: 900, loop: true, ease: 'easeInOut' })
.opacity({ from: 0.5, to: 1, duration: 900, loop: true, ease: 'easeInOut' })