Dynamic props
Drive any numeric or position prop from time, the cursor, or another layer, without writing animation code.
A dynamic prop is an object you pass in place of a prop's value. Its type field names what drives the value: auto-animate, mouse-position, mouse, or map. Here the same radius prop is set statically, then animated:
<!-- Static value -->
<Circle :radius="0.5" />
<!-- Dynamic prop: radius moves between 0.2 and 0.6 on its own -->
<Circle :radius="{ type: 'auto-animate', mode: 'ping-pong', outputMin: 0.2, outputMax: 0.6 }" />
Animating a prop over time
The auto-animate type moves a numeric prop between two values, forever. Set the range with outputMin and outputMax, and the pace with speed:
The auto-animate fields:
| Field | Type | Default | Description |
|---|---|---|---|
mode | 'ping-pong' | 'loop' | required | ping-pong oscillates between min and max. loop advances from min to max, then wraps. |
outputMin | number | required | Value at the start of the range. |
outputMax | number | required | Value at the end of the range. |
speed | number | 1.0 | Cycles per second. Negative values reverse the loop direction. |
easing | string | 'sine' | Easing curve, ping-pong mode only: sine, linear, quad, expo, or bounce. |
Use it for pulsing shapes, breathing glow intensities, or looping gradient angles. For a continuous rotation, use loop mode from outputMin: 0 to outputMax: 360.
Following the cursor
The mouse-position type drives a position prop from the cursor. Use it on any prop that takes { x, y } coordinates, such as center, position, or offset:
smoothing makes the circle lag behind the cursor, and momentum lets it overshoot and spring back. The mouse-position fields:
| Field | Type | Default | Description |
|---|---|---|---|
x | 'mouse' | number | 'mouse' | 'mouse' tracks cursor X. A number pins X to that value (0–1). |
y | 'mouse' | number | 'mouse' | 'mouse' tracks cursor Y. A number pins Y to that value (0–1). |
invertX | boolean | false | Flips the X direction: moving the cursor right moves the position left. |
invertY | boolean | false | Flips the Y direction. |
smoothing | number | 0 | Lag (0–1). 0 follows instantly; higher values follow more slowly. |
momentum | number | 0 | Spring bounce (0–1). 0 has no overshoot; values near 1 are springy. |
reach | number | 1 | Scales how far the position travels from the origin point. 1 tracks the cursor 1:1, 2 travels twice as far, 0 stays at the origin point. |
originX | number | 0.5 | X coordinate of the origin point that reach scales from. |
originY | number | 0.5 | Y coordinate of the origin point. |
To track one axis only, set the other to a number. This circle follows the cursor horizontally and stays at the vertical center:
<Circle :radius="0.15" :center="{ type: 'mouse-position', y: 0.5 }" />
Mapping the cursor to a number
The mouse type drives a single numeric prop from the cursor's X or Y position. Here the circle grows as the cursor moves right:
The mouse fields:
| Field | Type | Default | Description |
|---|---|---|---|
axis | 'x' | 'y' | required | Which cursor axis drives the prop. |
outputMin | number | required | Value when the axis is at 0 (left or top). |
outputMax | number | required | Value when the axis is at 1 (right or bottom). |
curve | number | 0 | Power curve, -1 to +1. Negative values bias toward outputMin, positive toward outputMax. |
smoothing | number | 0 | Lag (0–1), as in mouse-position. |
momentum | number | 0 | Spring bounce (0–1), as in mouse-position. |
Use it to set a blur amount from the horizontal position, brightness from the vertical position, a hue shift, or a zoom intensity.
Driving a prop from another layer
The map type drives a numeric prop from what another layer draws. It reads one channel of that layer, either its alpha (opacity) or its luminance (brightness), and turns it into a value. Picture CSS mask-image, except the image sets a number instead of visibility.
Each pixel reads the source at its own position, so the driven prop can vary across the canvas. (DotGrid and Grid read it once per cell, so each dot gets one size.) Give the source component an id, then name that id as the source:
The demo hides the gradient with visible: false, and the dots still read it. The map fields:
| Field | Type | Default | Description |
|---|---|---|---|
source | string | required | The id of the component to read from. |
channel | string | required | Which channel to read: alpha, alphaInverted, luminance, or luminanceInverted. |
inputMin | number | required | Source values at or below this count as 0. |
inputMax | number | required | Source values at or above this count as 1. |
outputMin | number | required | Value when the input is 0. |
outputMax | number | required | Value when the input is 1. |
curve | number | 0 | Power curve applied after the input is normalized, -1 to +1. |
The first map driver renders its source layer to a texture, an offscreen image the driven prop samples from. The source layer renders into that texture every frame, so each map source adds one render pass.
Combining dynamic props
A component can have several dynamic props at once, one per prop. This lens flare follows the cursor while its intensity pulses:
Switching at runtime with the JS API
In the JavaScript API, shader.update() accepts dynamic props too, so a prop can switch between a static value and a dynamic one at any point:
// Start with a static value
const shader = await createShader(canvas, {
components: [
{ type: 'Circle', id: 'c', props: { radius: 0.4 } }
]
})
// Later: switch to animated
shader.update('c', {
radius: {
type: 'auto-animate',
mode: 'ping-pong',
outputMin: 0.2,
outputMax: 0.7
}
})
// Later: switch back to static
shader.update('c', { radius: 0.4 })
Next steps
- Props and reactivity: bind props to your framework's state.
- Transforms: position, size, and rotate a layer inside the canvas.
- Performance: what each layer and texture costs.