View raw

particles#

Deterministic, stateless particle systems. Every particle's position, size, rotation, and color is a pure function of (element id, particle index, age) — which means seeking backward or jumping to a frame works without resimulating from the start. A Clipkit extension. Inherits common fields.

interface ParticlesElement extends BaseElement {
  type: 'particles';
  rate?: number;
  lifetime?: number;
  velocity?: number;
  spread?: number;
  direction?: number;
  gravity?: number;
  color?: string | string[];
  size?: number;
  size_variation?: number;
  particle_shape?: 'square' | 'circle';
  rotation_speed?: number;
  burst?: boolean;
  burst_count?: number;
  fade_at?: number;

  // Convergence mode
  target_points?: [number, number][];
  convergence_easing?: EasingFunction;
  scatter_radius?: number;
}

Two modes#

The element runs in one of two modes:

  • Ballistic (default) — particles emit from the element's (x, y), given a random initial velocity, and fall under gravity. Use for confetti, sparks, snow, dust.
  • Convergence — set target_points. Particles interpolate from random scattered start positions toward those points over their lifetime. Use for "particles assemble into a logo" effects.

Emission#

FieldTypeDefaultDescription
ratenumber60Particles per second (continuous mode).
burstbooleanfalseIf true, emit burst_count particles instantly at element start instead of continuously.
burst_countnumber80Number of particles in a burst.
lifetimenumber1.5Lifetime per particle, in seconds.
fade_atnumber0.7Fraction of lifetime at which particles start fading out. 1 = no fade.

Motion (ballistic mode)#

FieldTypeDefaultDescription
velocitynumber300Initial speed in px/s. Actual speed is velocity × (1 ± 0.3 × random).
spreadnumber360Spread cone in degrees. 0 = directional (everyone moves the same way); 360 = omnidirectional.
directionnumber-90Emission direction in degrees. = right; 90° = down; -90° = up.
gravitynumber600Vertical acceleration in px/s². Positive = downward.
rotation_speednumber360Rotation rate in deg/s. Sign is randomized per particle.

Motion (convergence mode)#

FieldTypeDefaultDescription
target_points[number, number][]Target positions in canvas pixel coordinates. Particles are assigned round-robin to these points by index. When set, motion fields above (velocity, gravity, etc.) are ignored.
convergence_easingEasingFunction'ease-out-quart'Easing applied to the convergence interpolation.
scatter_radiusnumbermax(canvas_width, canvas_height)Radius of the random scatter region around the emitter where particles start.

Appearance#

FieldTypeDefaultDescription
colorstring | string[]'#ffffff'Hex color, or an array for per-particle randomization (uniform).
sizenumber12Mean particle size in pixels.
size_variationnumber0.4Random size variation in [0, 1]. 0 = all uniform; 1 = sizes anywhere in [0, size].
particle_shape'square' | 'circle''square'Per-particle shape.

Example: confetti burst#

{
  "type": "particles",
  "id": "celebrate",
  "x": 960, "y": 540,
  "time": 3,
  "duration": 2,
  "burst": true,
  "burst_count": 200,
  "lifetime": 2,
  "velocity": 800,
  "spread": 180,
  "direction": -90,
  "gravity": 800,
  "rotation_speed": 540,
  "size": 14,
  "size_variation": 0.6,
  "color": ["#ef4444", "#facc15", "#22c55e", "#3b82f6", "#a855f7"]
}

Example: logo convergence#

Pair with SVGPathElement.getPointAtLength() ahead of time to pre-sample N points along your logo's outline, then:

{
  "type": "particles",
  "id": "assemble",
  "x": 960, "y": 540,
  "time": 0,
  "duration": 2,
  "burst": true,
  "burst_count": 120,
  "lifetime": 1.6,
  "fade_at": 1,
  "color": "#facc15",
  "size": 6,
  "size_variation": 0.2,
  "particle_shape": "circle",
  "convergence_easing": "ease-out-quart",
  "target_points": [
    [860, 480], [880, 480], [900, 480]
    /* ... 117 more, sampled from your logo path ... */
  ]
}

Notes#

  • Deterministic — particles use a seeded PRNG keyed off (element id, particle index). The same Source renders identically every time.
  • No collisions — there is no inter-particle physics. Each particle is independent.
  • No emitters-over-time — the element has one continuous emitter or one burst. For multiple bursts, use multiple particles elements.