particle-system

This skill should be used when the user asks to "build a particle system", "make confetti/snow/smoke/sparks", "create a connected-dot/constellation network background", "add a flow-field or curl-noise particle effect", "render thousands of GPU particles with Three.js Points", or "animate emitters wi

By iart-ai · 497 installs

npx skills add iart-ai/webgl-animation-skills --skill particle-system

Source repository · Upstream listing

Particle System Drive many small elements with simple per particle rules to get emergent, organic motion. Use 2D canvas for hundreds, GPU Points for thousands. When to use Particle/constellation backgrounds and ambient motion. Celebratory bursts: confetti, sparks. Weather: snow, rain. Volumetric: smoke. Flow field / curl noise swirls and data driven point clouds. Connected dot networks (lines between nearby particles). Core loop: integrate per particle Each particle holds state and is advanced every frame: accumulate forces into acceleration, integrate velocity and position, age it, respawn when dead. Scale by dt for frame rate independence. Prefer semi implicit Euler (update velocity first, then position with the new velocity, as above) — it is stable for the spring/drag forces particles use. Use a fixed or clamped dt ( Math.min(dt, 1/30) ) so a stalled tab does not explode the simulation. Forces A force is a function returning an acceleration [fx, fy] . Compose a list. Repulsion is attract with negative strength. Springs toward a home position give "settle back" effects. Flow fields / curl noise (organic swirl) Sample a noise field to derive a velocity direction per particle. Use the noise value as an angle: True curl noise is divergence free (no sources/sinks → fluid like). Compute the curl of a potential by finite differences: Add time to the noise input ( noise2D(x scale, y scale + t) ) to make the field evolve. Emission: burst vs continuous Burst (confetti, sparks): spawn N particles at once at a point with randomized angle/speed within a cone, then let gravity + drag take over. No respawn — remove when dead. Continuous (snow, smoke): spawn a steady rate; respawn dead particles at the top/source. Randomize within a range for natural spread: angle = base + (Math.random() 0.5) spread; speed = min + Math.random() (max min) . Confetti reads as confetti because of rotation + flat rectangles + gravity + air drag , not round dots. Snow reads as snow from slow fall + gentle horizontal sine sway + size varied depth. Connected dot network without O(n²) Naively checking every pair is O(n²) and dies past ~300 particles. Use a uniform spatial grid : bin particles by cell, only compare against the 8 neighboring cells. This is O(n) for evenly distributed particles. Each pair is found twice; halve work by only checking forward neighbors if needed. GPU particles: Three.js Points + shader For thousands+, push all positions into a BufferGeometry and render as Points . Animate in the vertex shader for true GPU scale. AdditiveBlending + depthWrite: false gives the glowing particle look. discard on gl PointCoord distance makes square points round. For per particle data (life, seed), add custom attributes and read them in the shader. Deliver & verify (standalone HTML) Packaged helper ( scripts/ ): scripts/seek shot.sh anim.html 0 1.5 3 freezes the ?t=N harness and screenshots each moment; scripts/contact sheet.sh sheet.png frame .png tiles them for one glance review. See scripts/README.md . For a self contained particle effect (constellation background, confetti burst, flow field, GPU points) the deliverable is one HTML file that opens directly in a browser — canvas 2D inline, or Three.js from a CDN via an importmap for GPU Points , one render loop, no build step. A single file is the right tier; don't reach for a bundler when one file does the job. Output contract: One .html : for canvas, the simulation + 2D draw loop in one inline <script ; for GPU points, importmap pins three to a CDN with the Points setup inline. Drive the sim from one accumulated time (sum of clamped dt , or clock.getElapsedTime() / u time for GPU). No Date.now() scattered per particle. Seed the RNG — replace bare Math.random() with a seeded PRNG (e.g. mulberry32) so spawn positions, angles, and bursts reproduce frame for frame. Seek/freeze harness — advance to a fixed time, render ONE frame for screenshots. ?t=N re seeds, steps the sim deterministically to N seconds with a fixed timestep, renders once, and stops the loop. Verify loop — render → freeze → screenshot → check: open at three instants — start, mid, settle ( ?t=0 , ?t=<mid , ?t=<end ; for a burst, t≈0 spawn / t≈0.5 spread / t≈1.5 settle) — screenshot each, and check both fidelity (matches the brief) and artifacts : a blank canvas = parse/init error (check the console), particles escaping the frame (clamp/wrap missing), NaN positions (everything vanishes), all particles bunched at the origin (RNG not wired). For GPU points, WebGL needs a GPU context; Playwright/Chromium supplies one (swiftshader) headless. Before you finish: 1. Canvas renders particles — not blank, no console/WebGL errors, no CDN 404s. 2. ?t=N freezes a reproducible frame (seeded RNG + fixed timestep → same N → same pixels). 3. Screenshotted at start / mid / settle — matches the brief, no escaped/NaN/origin bunched particles. 4. Disposed and leak free if embedded in an SPA (cancel the rAF loop; for GPU, dispose geometry/material/renderer). 5. prefers reduced motion honored — fewer particles or a static field where motion is decorative. Quick reference Effect Recipe Confetti burst + gravity + drag + rotating rects Snow continuous top spawn + slow fall + sine sway Smoke continuous + upward + grow size + fade alpha Sparks short life burst + additive + fast fade Flow field noise angle → velocity, evolve with time Curl noise curl of noise potential (divergence free) Constellation spatial grid, link within radius, fade by distance 1000s+ Three.js Points + ShaderMaterial, animate in vertex shader Reference files references/particle recipes.md — Complete canvas confetti, snow, and smoke systems; mouse attraction/repulsion; full simplex flow field and curl noise field with a rendered streaming look; the spatial grid connected dot background end to end; and a GPU Points system with per particle life/seed attributes, additive glow, and respawn in the shader.