---
name: particle-swarm-sim
description: "Generate 20,000+ particle swarm simulators in two modes: sandbox (complete Three.js host runtime with gesture controls, security validation, code injection pipeline) and sim (behavior function bodies that position/color particles via a sandboxed API). The AI writes ONLY a function body — the host handles rendering, input, and security. Triggers on particle swarm, swarm simulator, particle behavior, swarm sandbox, gesture particles, 20K particles, particle function body, swarm sim, particle playground."
argument-hint: [--mode sandbox|sim] [concept or creative brief]
---

# Particle Swarm Simulator

Generate massive particle swarm simulations with a clean separation of concerns: a **host runtime** handles Three.js rendering, camera, input, gesture recognition, and security — the AI writes only a **behavior function body** that positions and colors 20,000+ particles per frame.

Not a narrative canvas. Not a phase engine. A sandbox where math becomes motion.

## Quick Start

```bash
# Generate a sandbox runtime with gesture controls
/particle-swarm-sim --mode sandbox dark theme, 30K particles, gesture OS enabled

# Generate a sim function body
/particle-swarm-sim --mode sim aurora borealis — curtains of light flowing along magnetic field lines

# Generate from preset
python3 scripts/swarm_generator.py --mode sim --preset galaxy-spiral --output galaxy.js
```

## The Separation of Concerns

```
HOST RUNTIME                          BEHAVIOR FUNCTION BODY
(sandbox-runtime.html)                (generated by AI)
                                      
Three.js scene                        target.set(x, y, z)
BufferGeometry (20K particles)   -->  color.setHSL(h, s, l)
Camera + input + gesture OS           addControl("speed", ...)
Security validator                    setInfo("title", ...)
Code injection pipeline               annotate("label", ...)
Dynamic controls UI                   
HUD + annotations                    
```

The host calls the function body 20,000 times per frame — once per particle. The function body mutates the provided `target` and `color` objects. Nothing else crosses the boundary.

## API Contract

### Read-Only Variables

| Variable | Type | Description |
|----------|------|-------------|
| `i` | Integer | Particle index (0 to count-1) |
| `count` | Integer | Total particle count |
| `time` | Float | Global simulation time in seconds |
| `THREE` | Object | Safe Three.js subset: `Vector3`, `Color`, `MathUtils` |

### Write-Only Variables

| Variable | Type | Mutation |
|----------|------|----------|
| `target` | THREE.Vector3 | `target.set(x, y, z)` — particle position |
| `color` | THREE.Color | `color.setHSL(h, s, l)` or `color.set(hex)` — particle color |

### Helper Functions

| Function | Signature | Notes |
|----------|-----------|-------|
| `addControl` | `(id, label, min, max, initial) => float` | Creates UI slider, returns current value |
| `setInfo` | `(title, description)` | Updates HUD. Guard: `if (i === 0)` |
| `annotate` | `(id, x, y, z, labelText)` | Floating 3D label. Guard: `if (i === 0)` |

For `setInfo` and `annotate`: call only when `i === 0`. Calling per-particle creates 20,000 DOM updates per frame. The `annotate` function takes numeric coordinates (not a Vector3) to avoid per-frame allocations.

Full specification: `references/api-contract.md`

## Mode: sandbox

Generate the complete host runtime HTML — the sandbox that executes behavior function bodies.

### Configuration

| Parameter | Default | Range | Effect |
|-----------|---------|-------|--------|
| `particleCount` | 20000 | 5000-50000 | Total particles in the swarm |
| `particleSize` | 0.06 | 0.01-0.5 | Point size (screen-space) |
| `backgroundColor` | `#050508` | hex | Scene background (never pure black) |
| `autoOrbitSpeed` | 0.1 | 0-1.0 | Camera auto-rotation rad/sec |
| `cameraRadius` | 30 | 5-100 | Default camera distance |
| `gestureEnabled` | true | bool | MediaPipe Hands activation |
| `injectionEnabled` | true | bool | Code editor textarea visible |

### Architecture

```
init() --> createScene() --> createParticles(count) --> setupCamera() --> setupInput()
                                                                           |
                                      setupGestureOS() --> setupInjection() --> setupHUD()
                                                                           |
animate() <-- requestAnimationFrame <-- executeSimFunction() --> updateBuffers()
    |
Per frame: for (i = 0; i < count; i++) { simFn(i, count, time, THREE, target, color, ...) }
    |
geometry.attributes.position.needsUpdate = true
geometry.attributes.color.needsUpdate = true
```

### Templates

| Template | Lines | Includes |
|----------|-------|----------|
| `assets/templates/sandbox-runtime.html` | ~900 | Full: gesture OS, code editor, security validator, HUD, annotations |
| `assets/templates/sandbox-minimal.html` | ~400 | Stripped: mouse/touch only, no code editor, no gesture — for embedding |

Full architecture: `references/sandbox-architecture.md`

## Mode: sim

Generate particle behavior function bodies from creative concepts. Output is a JS function body — no HTML, no Three.js setup. The body gets injected into a sandbox runtime.

### Concept-to-Form

| Concept Domain | Position Strategy | Color Strategy | Controls |
|----------------|-------------------|----------------|----------|
| Orbital / astronomical | Spherical coords + angular velocity | HSL hue from angle | orbit radius, speed |
| Biological / organic | Parametric curves + noise perturbation | Warm gradients from position | growth rate, density |
| Geometric / crystalline | Lattice positions + modular arithmetic | Discrete palette from `i % N` | symmetry order, scale |
| Fluid / flow | Curl noise or velocity field | Hue from velocity magnitude | viscosity, turbulence |
| Musical / rhythmic | Sin/cos with frequency ratios | HSL from beat phase | tempo, harmonics |

### Sim Presets

**Galaxy Spiral** — Logarithmic arms with density wave theory. `i % arms` grouping. HSL from arm index + distance falloff. Controls: arm count (2-8), spin rate, thickness. Reference: `assets/sims/galaxy-spiral.js`

**DNA Helix** — Double helix with base pair rungs. `i % 3` splits into strand A, strand B, rungs. Controls: helix radius, pitch, rung density. Reference: `assets/sims/dna-helix.js`

**Murmuration** — Boids-like flocking approximated via phase-shifted oscillators. No neighbor search, no arrays — purely mathematical. Controls: flock radius, speed, coherence. Reference: `assets/sims/flocking-murmuration.js`

**Torus Knot Flow** — Particles trace a (p,q) torus knot with index-based phase offset. HSL from progress along the knot. Controls: p, q, flow speed.

**Lorenz Attractor** — Time-stepped Lorenz system positions, particle index as time offset. Color from z-height. Controls: sigma, rho, beta.

**Reaction-Diffusion Shell** — Cone-shaped shell with Turing-like stripe patterns computed analytically. Controls: wavelength, cone aperture.

Full gallery with math breakdowns: `references/sim-gallery.md`

### Minimal Valid Sim

```javascript
const speed = addControl('speed', 'Speed', 0.1, 5.0, 1.0);
if (i === 0) setInfo('Expanding Sphere', 'Uniform distribution on sphere surface');

const phi = (i / count) * Math.PI * 2 * 10;
const theta = Math.acos(1 - 2 * (i / count));
const r = 10 + Math.sin(time * speed + i * 0.01) * 2;

target.set(
  r * Math.sin(theta) * Math.cos(phi),
  r * Math.sin(theta) * Math.sin(phi),
  r * Math.cos(theta)
);
color.setHSL(i / count, 0.8, 0.5 + 0.2 * Math.sin(time + i * 0.1));
```

## Performance Rules

This function runs 20,000 times per frame at 60fps = 1,200,000 calls per second.

| Rule | Why | Wrong | Right |
|------|-----|-------|-------|
| Zero allocations | 1.2M objects/sec overwhelms GC | `new THREE.Vector3(x,y,z)` | `target.set(x,y,z)` |
| Math over logic | Branch prediction fails at scale | `if (i < count/2) {...} else {...}` | `Math.sin(i / count * Math.PI)` |
| Mutate, never replace | Target/color are shared references | `target = new THREE.Vector3(...)` | `target.set(x, y, z)` |
| All values finite | NaN poisons the entire buffer | `1 / x` where x could be 0 | `1 / (x + 0.0001)` |
| Declare all variables | Strict mode violations | `x = 5;` | `const x = 5;` |
| No string operations | Concatenation creates GC pressure | `"particle_" + i` | Numeric IDs only |
| Constants outside loops | `addControl` creates DOM on first call | Call `addControl` inside conditionals | Call at function body top |

Full performance patterns: `references/performance-patterns.md`

## Security Sandbox

All behavior function bodies must pass validation before execution.

### Forbidden Patterns

| Pattern | Reason |
|---------|--------|
| `document`, `window` | DOM/global scope escape |
| `fetch`, `XMLHttpRequest`, `WebSocket` | Network access |
| `eval`, `Function(` | Code injection |
| `import(`, `require(` | Module loading |
| `__proto__`, `.prototype`, `globalThis` | Prototype pollution |
| `localStorage`, `sessionStorage`, `indexedDB` | Storage access |
| `setTimeout`, `setInterval` | Async execution outside frame loop |
| `alert()`, `confirm()`, `prompt()` | UI hijack |
| `navigator`, `location`, `self` | Browser API access |
| `crypto`, `process` | System access |

### Validation Pipeline

1. **Regex scan** — Reject if any forbidden pattern matches
2. **Syntax check** — Parse as function body
3. **Dry-run** (runtime only) — Execute with mock values for 3 frames, check for throws and non-finite output

The Python validator (`scripts/validate_sim.py`) handles steps 1-2. Step 3 happens client-side in the sandbox runtime.

Full specification: `references/security-sandbox.md`

## Gesture OS

Hand gesture camera controls via MediaPipe Hands. Optional — mouse/touch always works.

| Gesture | Detection | Action | Sensitivity |
|---------|-----------|--------|-------------|
| One finger drag | Index extended, others closed | Camera rotation (theta/phi) | 0.005 rad/px |
| Open palm swipe | All fingers extended, horizontal | Zoom in/out | 0.02 per px delta |
| Peace sign swipe | Index + middle extended | Simulation speed | 0.01x per px delta |
| Fist | All fingers closed | Pause/resume toggle | Single event |

Configuration:
- `maxNumHands: 1`
- `modelComplexity: 0` (fast mode)
- Detection runs every 3rd frame to reduce CPU load
- Dead zones prevent jitter near gesture boundaries

Full implementation: `references/gesture-os.md`

## Generator

```bash
# Full sandbox with gesture controls
python3 scripts/swarm_generator.py --mode sandbox --particles 30000 --gesture --output sandbox.html

# Minimal sandbox for embedding
python3 scripts/swarm_generator.py --mode sandbox --minimal --output embed.html

# Sim from preset
python3 scripts/swarm_generator.py --mode sim --preset galaxy-spiral --output galaxy.js

# Sim preset list
python3 scripts/swarm_generator.py --mode sim --list
```

| Flag | Mode | Default | Description |
|------|------|---------|-------------|
| `--mode` | both | required | `sandbox` or `sim` |
| `--particles` | sandbox | 20000 | Particle count |
| `--size` | sandbox | 0.06 | Point size |
| `--bg` | sandbox | `#050508` | Background color |
| `--gesture` | sandbox | off | Enable MediaPipe Hands |
| `--minimal` | sandbox | off | Use stripped-down template |
| `--preset` | sim | none | Load from `assets/sims/{name}.js` |
| `--list` | sim | n/a | List available presets |
| `--output` | both | stdout | Output file path |

## Post-Generation QA

```bash
# Validate sandbox runtime
python3 scripts/validate_sandbox.py output.html

# Validate sim function body
python3 scripts/validate_sim.py output.js
```

## Anti-Patterns

- Never allocate objects inside the function body — mutate `target` and `color` only
- Never use `new THREE.Vector3()` — use `target.set(x, y, z)`
- Never access DOM — the sandbox blocks it
- Never use `var` — `const`/`let` only
- Never use `if/else` chains for particle grouping — use modular arithmetic and trig
- Never leave division unguarded — always add epsilon (`+ 0.0001`)
- Never skip `setInfo` — every sim needs a title and description
- Never use duplicate `addControl` IDs — each must be unique
- Never call `setInfo`/`annotate` without `i === 0` guard
- Never pass a Vector3 to `annotate` — use numeric `(id, x, y, z, label)` to avoid allocations
- Never use framework code in the sandbox — vanilla JS + HTML only
- Never use `THREE.OrbitControls` — implement spherical camera directly
- Never use pure black (`#000000`) — use `#050508`
- Never skip security validation before code injection

## References

| Working on... | Load |
|---|---|
| API contract: variable types, mutation rules, helper lifecycle | `references/api-contract.md` |
| Sandbox architecture: scene graph, injection pipeline, frame loop | `references/sandbox-architecture.md` |
| Gesture OS: MediaPipe setup, gesture classification, action mapping | `references/gesture-os.md` |
| Security: forbidden patterns, dry-run protocol, validation pipeline | `references/security-sandbox.md` |
| Performance: zero-alloc patterns, math idioms, NaN guards | `references/performance-patterns.md` |
| Sim gallery: 10+ annotated behavior patterns with math breakdowns | `references/sim-gallery.md` |
| Galaxy spiral reference sim | `assets/sims/galaxy-spiral.js` |
| DNA helix reference sim | `assets/sims/dna-helix.js` |
| Flocking murmuration reference sim | `assets/sims/flocking-murmuration.js` |
| Full sandbox runtime template | `assets/templates/sandbox-runtime.html` |
| Minimal sandbox for embedding | `assets/templates/sandbox-minimal.html` |
