Party
Build a visible result first, then tune it. Treat a Party scene as four layers:
- Spawn geometry and initial velocity.
- One or two primary force modules.
- Render treatment such as trails, lines, or color.
- Slow animation of a few meaningful parameters.
Start with a working scene
Use semantic enums and create particles before calling play():
import {
Behavior,
Boundary,
Engine,
Particles,
ParticlesColorType,
Spawner,
Trails,
} from "@cazala/party";
const canvas = document.querySelector<HTMLCanvasElement>("canvas")!;
const width = window.innerWidth;
const height = window.innerHeight;
const forces = [
new Boundary({ mode: "warp" }),
new Behavior({
wander: 18,
cohesion: 1.4,
alignment: 4,
separation: 35,
viewRadius: 80,
}),
];
const render = [
new Trails({ trailDecay: 8, trailDiffuse: 1 }),
new Particles({ colorType: ParticlesColorType.Hue, hue: 0.62 }),
];
const particles = new Spawner().initParticles({
count: 4_000,
shape: "donut",
center: { x: 0, y: 0 },
radius: Math.min(width, height) * 0.38,
innerRadius: Math.min(width, height) * 0.12,
size: 2.5,
mass: 1,
velocity: { speed: 120, direction: "clockwise" },
colors: ["#ffffff"],
});
const engine = new Engine({
canvas,
forces,
render,
runtime: "auto",
cellSize: 40,
maxNeighbors: 128,
});
await engine.initialize();
engine.setSize(width, height);
engine.setParticles(particles);
engine.addOscillator({
moduleName: "particles",
inputName: "hue",
min: 0,
max: 1,
speedHz: 0.01,
});
engine.play();
Copy the full Vite starter when building a new app. It includes responsive sizing, pointer interaction, cleanup, and five selectable scenes. Read its tested scene source when adapting a recipe.
Choose modules by visual intent
| Intent |
Start with |
| Falling, bouncing particles |
Environment + Boundary; add Collisions if particles must hit each other |
| Orbital motion |
Tangential Spawner velocity + inward Environment |
| Swarms and flocking |
Behavior; add Trails for readable motion |
| Slime-mold filaments |
Sensors + Trails + a warp Boundary |
| Liquid or viscous blobs |
Fluids + Boundary; add gravity or pointer Interaction |
| Pointer fields |
Interaction for attract/repel or Grab for one particle |
| Ropes and structures |
Joints + Lines |
| Text/image dissolves |
Text/image Spawner + outward velocity + Trails or Behavior |
Use the smallest combination that expresses the idea. Adding every module usually makes the motion harder to control.
Work creatively
- Define the desired silhouette and motion in one sentence.
- Select the matching composition above.
- Start with 2,000–5,000 particles so CPU fallback remains useful.
- Tune spawn speed and the primary force before adding effects.
- Add trails or color only after the motion reads clearly.
- Oscillate one to three inputs slowly; avoid animating everything.
- Inspect the scene near startup and after several seconds. Fix blank, explosive, static, or visually noisy states before increasing particle count.
Read creative-workflow.md for parameter intuition and iteration guidance. Read recipes.md for five compositions derived from Party playground demos.
Preserve runtime performance
- Use
runtime: "auto" unless the user requires a specific runtime.
- Treat
getParticles() as an expensive full WebGPU-to-CPU readback. Never call it in an animation, pointer-move, or drag loop.
- Use
await engine.getParticlesInRadius(...) for bounded local queries.
- Prefer
setParticle(...) and setParticleMass(...) for local mutations.
- Keep
cellSize near the largest active neighborhood radius, and cap maxNeighbors deliberately.
- Scale particle count after the composition works. Large playground demos are WebGPU showcase budgets, not safe defaults.
Load the right detail
- Read api.md for particle shape, lifecycle, modules, spawning, interaction, and queries.
- Read creative-workflow.md before inventing or substantially tuning a visual scene.
- Read recipes.md when adapting a known effect or playground demo.
- Read troubleshooting.md when output is blank, unstable, slow, or visually weak.
- Read the repository
docs/module-author-guide.md only when authoring a new force or render module from a full Party checkout.
Validate the result
- Compile the implementation; do not rely on plausible-looking option names.
- Confirm particles are spawned after initialization and the canvas has a non-zero size.
- Exercise CPU fallback with a reduced count when practical.
- Verify pointer coordinates are converted from screen space to Party world space.
- Remove listeners and call
await engine.destroy() during teardown.
- Visually inspect the running scene. A successful creative task must be coherent and interesting, not merely error-free.
1---2name: party3description: Build creative particle effects, generative art, interactive physics scenes, and production integrations with @cazala/party across WebGPU and CPU. Use when creating or tuning simulations, composing modules, spawning shape/text/image particles, translating Party playground demos into code, optimizing performance, or authoring custom modules.4---56# Party78Build a visible result first, then tune it. Treat a Party scene as four layers:9101. Spawn geometry and initial velocity.112. One or two primary force modules.123. Render treatment such as trails, lines, or color.134. Slow animation of a few meaningful parameters.1415## Start with a working scene1617Use semantic enums and create particles before calling `play()`:1819```ts20import {21 Behavior,22 Boundary,23 Engine,24 Particles,25 ParticlesColorType,26 Spawner,27 Trails,28} from "@cazala/party";2930const canvas = document.querySelector<HTMLCanvasElement>("canvas")!;31const width = window.innerWidth;32const height = window.innerHeight;3334const forces = [35 new Boundary({ mode: "warp" }),36 new Behavior({37 wander: 18,38 cohesion: 1.4,39 alignment: 4,40 separation: 35,41 viewRadius: 80,42 }),43];44const render = [45 new Trails({ trailDecay: 8, trailDiffuse: 1 }),46 new Particles({ colorType: ParticlesColorType.Hue, hue: 0.62 }),47];48const particles = new Spawner().initParticles({49 count: 4_000,50 shape: "donut",51 center: { x: 0, y: 0 },52 radius: Math.min(width, height) * 0.38,53 innerRadius: Math.min(width, height) * 0.12,54 size: 2.5,55 mass: 1,56 velocity: { speed: 120, direction: "clockwise" },57 colors: ["#ffffff"],58});5960const engine = new Engine({61 canvas,62 forces,63 render,64 runtime: "auto",65 cellSize: 40,66 maxNeighbors: 128,67});6869await engine.initialize();70engine.setSize(width, height);71engine.setParticles(particles);72engine.addOscillator({73 moduleName: "particles",74 inputName: "hue",75 min: 0,76 max: 1,77 speedHz: 0.01,78});79engine.play();80```8182Copy [the full Vite starter](assets/starter/) when building a new app. It includes responsive sizing, pointer interaction, cleanup, and five selectable scenes. Read its [tested scene source](assets/starter/src/scenes.ts) when adapting a recipe.8384## Choose modules by visual intent8586| Intent | Start with |87| --- | --- |88| Falling, bouncing particles | `Environment` + `Boundary`; add `Collisions` if particles must hit each other |89| Orbital motion | Tangential Spawner velocity + inward `Environment` |90| Swarms and flocking | `Behavior`; add `Trails` for readable motion |91| Slime-mold filaments | `Sensors` + `Trails` + a warp `Boundary` |92| Liquid or viscous blobs | `Fluids` + `Boundary`; add gravity or pointer `Interaction` |93| Pointer fields | `Interaction` for attract/repel or `Grab` for one particle |94| Ropes and structures | `Joints` + `Lines` |95| Text/image dissolves | Text/image `Spawner` + outward velocity + `Trails` or `Behavior` |9697Use the smallest combination that expresses the idea. Adding every module usually makes the motion harder to control.9899## Work creatively1001011. Define the desired silhouette and motion in one sentence.1022. Select the matching composition above.1033. Start with 2,000–5,000 particles so CPU fallback remains useful.1044. Tune spawn speed and the primary force before adding effects.1055. Add trails or color only after the motion reads clearly.1066. Oscillate one to three inputs slowly; avoid animating everything.1077. Inspect the scene near startup and after several seconds. Fix blank, explosive, static, or visually noisy states before increasing particle count.108109Read [creative-workflow.md](references/creative-workflow.md) for parameter intuition and iteration guidance. Read [recipes.md](references/recipes.md) for five compositions derived from Party playground demos.110111## Preserve runtime performance112113- Use `runtime: "auto"` unless the user requires a specific runtime.114- Treat `getParticles()` as an expensive full WebGPU-to-CPU readback. Never call it in an animation, pointer-move, or drag loop.115- Use `await engine.getParticlesInRadius(...)` for bounded local queries.116- Prefer `setParticle(...)` and `setParticleMass(...)` for local mutations.117- Keep `cellSize` near the largest active neighborhood radius, and cap `maxNeighbors` deliberately.118- Scale particle count after the composition works. Large playground demos are WebGPU showcase budgets, not safe defaults.119120## Load the right detail121122- Read [api.md](references/api.md) for particle shape, lifecycle, modules, spawning, interaction, and queries.123- Read [creative-workflow.md](references/creative-workflow.md) before inventing or substantially tuning a visual scene.124- Read [recipes.md](references/recipes.md) when adapting a known effect or playground demo.125- Read [troubleshooting.md](references/troubleshooting.md) when output is blank, unstable, slow, or visually weak.126- Read the repository `docs/module-author-guide.md` only when authoring a new force or render module from a full Party checkout.127128## Validate the result129130- Compile the implementation; do not rely on plausible-looking option names.131- Confirm particles are spawned after initialization and the canvas has a non-zero size.132- Exercise CPU fallback with a reduced count when practical.133- Verify pointer coordinates are converted from screen space to Party world space.134- Remove listeners and call `await engine.destroy()` during teardown.135- Visually inspect the running scene. A successful creative task must be coherent and interesting, not merely error-free.