# Argentos P5js

> Production pipeline for interactive and generative visual art using p5.js. Creates browser-based sketches, generative art, data visualizations, interactive experiences, 3D scenes, audio-reactive visuals, and motion graphics — exported as HTML, PNG, GIF, MP4, or SVG. Covers: 2D/3D rendering, noise and particle systems, flow fields, shaders (GLSL), pixel manipulation, kinetic typography, WebGL scenes, audio analysis, mouse/keyboard interaction, and headless high-res export. Use when users request: p5.js sketches, creative coding, generative art, interactive visualizations, canvas animations, browser-based visual art, data viz, shader effects, or any p5.js project.

- Skill: `argentaios/argentos-p5js` (Agent Skill, multi-file: 17 files)
- Install (CLI): `npx skillmds@latest add argentaios/argentos-p5js`
- Raw SKILL.md: https://api.skillmd.com/api/skills/argentaios/argentos-p5js/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: argentaios (https://skillmd.com/u/argentaios)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/argentaios/argentos-p5js

---


# p5.js Production Pipeline

## Creative Standard

This is visual art rendered in the browser. The canvas is the medium; the algorithm is the brush.

**Before writing a single line of code**, articulate the creative concept. What does this piece communicate? What makes the viewer stop scrolling? What separates this from a code tutorial example? The user's prompt is a starting point — interpret it with creative ambition.

**First-render excellence is non-negotiable.** The output must be visually striking on first load. If it looks like a p5.js tutorial exercise, a default configuration, or "AI-generated creative coding," it is wrong. Rethink before shipping.

**Go beyond the reference vocabulary.** The noise functions, particle systems, color palettes, and shader effects in the references are a starting vocabulary. For every project, combine, layer, and invent. The catalog is a palette of paints — you write the painting.

**Be proactively creative.** If the user asks for "a particle system," deliver a particle system with emergent flocking behavior, trailing ghost echoes, palette-shifted depth fog, and a background noise field that breathes. Include at least one visual detail the user didn't ask for but will appreciate.

**Dense, layered, considered.** Every frame should reward viewing. Never flat white backgrounds. Always compositional hierarchy. Always intentional color. Always micro-detail that only appears on close inspection.

**Cohesive aesthetic over feature count.** All elements must serve a unified visual language — shared color temperature, consistent stroke weight vocabulary, harmonious motion speeds. A sketch with ten unrelated effects is worse than one with three that belong together.

## Modes

| Mode                            | Input                 | Output                                            | Reference                                           |
| ------------------------------- | --------------------- | ------------------------------------------------- | --------------------------------------------------- |
| **Generative art**              | Seed / parameters     | Procedural visual composition (still or animated) | `references/visual-effects.md`                      |
| **Data visualization**          | Dataset / API         | Interactive charts, graphs, custom data displays  | `references/interaction.md`                         |
| **Interactive experience**      | None (user drives)    | Mouse/keyboard/touch-driven sketch                | `references/interaction.md`                         |
| **Animation / motion graphics** | Timeline / storyboard | Timed sequences, kinetic typography, transitions  | `references/animation.md`                           |
| **3D scene**                    | Concept description   | WebGL geometry, lighting, camera, materials       | `references/webgl-and-3d.md`                        |
| **Image processing**            | Image file(s)         | Pixel manipulation, filters, mosaic, pointillism  | `references/visual-effects.md` § Pixel Manipulation |
| **Audio-reactive**              | Audio file / mic      | Sound-driven generative visuals                   | `references/interaction.md` § Audio Input           |

## Stack

Single self-contained HTML file per project. No build step required.

| Layer         | Tool                                                   | Purpose                                                |
| ------------- | ------------------------------------------------------ | ------------------------------------------------------ |
| Core          | p5.js 1.11.3 (CDN)                                     | Canvas rendering, math, transforms, event handling     |
| 3D            | p5.js WebGL mode                                       | 3D geometry, camera, lighting, GLSL shaders            |
| Audio         | p5.sound.js (CDN)                                      | FFT analysis, amplitude, mic input, oscillators        |
| Export        | Built-in `saveCanvas()` / `saveGif()` / `saveFrames()` | PNG, GIF, frame sequence output                        |
| Capture       | CCapture.js (optional)                                 | Deterministic framerate video capture (WebM, GIF)      |
| Headless      | Puppeteer + Node.js (optional)                         | Automated high-res rendering, MP4 via ffmpeg           |
| SVG           | p5.js-svg 1.6.0 (optional)                             | Vector output for print — requires p5.js 1.x           |
| Natural media | p5.brush (optional)                                    | Watercolor, charcoal, pen — requires p5.js 2.x + WEBGL |
| Texture       | p5.grain (optional)                                    | Film grain, texture overlays                           |
| Fonts         | Google Fonts / `loadFont()`                            | Custom typography via OTF/TTF/WOFF2                    |

### Version Note

**p5.js 1.x** (1.11.3) is the default — stable, well-documented, broadest library compatibility. Use this unless a project requires 2.x features.

**p5.js 2.x** (2.2+) adds: `async setup()` replacing `preload()`, OKLCH/OKLAB color modes, `splineVertex()`, shader `.modify()` API, variable fonts, `textToContours()`, pointer events. Required for p5.brush. See `references/core-api.md` § p5.js 2.0.

## Pipeline

Every project follows the same 6-stage path:

```
CONCEPT → DESIGN → CODE → PREVIEW → EXPORT → VERIFY
```

1. **CONCEPT** — Articulate the creative vision: mood, color world, motion vocabulary, what makes this unique
2. **DESIGN** — Choose mode, canvas size, interaction model, color system, export format. Map concept to technical decisions
3. **CODE** — Write single HTML file with inline p5.js. Structure: globals → `preload()` → `setup()` → `draw()` → helpers → classes → event handlers
4. **PREVIEW** — Open in browser, verify visual quality. Test at target resolution. Check performance
5. **EXPORT** — Capture output: `saveCanvas()` for PNG, `saveGif()` for GIF, `saveFrames()` + ffmpeg for MP4, Puppeteer for headless batch
6. **VERIFY** — Does the output match the concept? Is it visually striking at the intended display size? Would you frame it?

## Creative Direction

### Aesthetic Dimensions

| Dimension             | Options                                                                        | Reference                                           |
| --------------------- | ------------------------------------------------------------------------------ | --------------------------------------------------- |
| **Color system**      | HSB/HSL, RGB, named palettes, procedural harmony, gradient interpolation       | `references/color-systems.md`                       |
| **Noise vocabulary**  | Perlin noise, simplex, fractal (octaved), domain warping, curl noise           | `references/visual-effects.md` § Noise              |
| **Particle systems**  | Physics-based, flocking, trail-drawing, attractor-driven, flow-field following | `references/visual-effects.md` § Particles          |
| **Shape language**    | Geometric primitives, custom vertices, bezier curves, SVG paths                | `references/shapes-and-geometry.md`                 |
| **Motion style**      | Eased, spring-based, noise-driven, physics sim, lerped, stepped                | `references/animation.md`                           |
| **Typography**        | System fonts, loaded OTF, `textToPoints()` particle text, kinetic              | `references/typography.md`                          |
| **Shader effects**    | GLSL fragment/vertex, filter shaders, post-processing, feedback loops          | `references/webgl-and-3d.md` § Shaders              |
| **Composition**       | Grid, radial, golden ratio, rule of thirds, organic scatter, tiled             | `references/core-api.md` § Composition              |
| **Interaction model** | Mouse follow, click spawn, drag, keyboard state, scroll-driven, mic input      | `references/interaction.md`                         |
| **Blend modes**       | `BLEND`, `ADD`, `MULTIPLY`, `SCREEN`, `DIFFERENCE`, `EXCLUSION`, `OVERLAY`     | `references/color-systems.md` § Blend Modes         |
| **Layering**          | `createGraphics()` offscreen buffers, alpha compositing, masking               | `references/core-api.md` § Offscreen Buffers        |
| **Texture**           | Perlin surface, stippling, hatching, halftone, pixel sorting                   | `references/visual-effects.md` § Texture Generation |

### Per-Project Variation Rules

Never use default configurations. For every project:

- **Custom color palette** — never raw `fill(255, 0, 0)`. Always a designed palette with 3-7 colors
- **Custom stroke weight vocabulary** — thin accents (0.5), medium structure (1-2), bold emphasis (3-5)
- **Background treatment** — never plain `background(0)` or `background(255)`. Always textured, gradient, or layered
- **Motion variety** — different speeds for different elements. Primary at 1x, secondary at 0.3x, ambient at 0.1x
- **At least one invented element** — a custom particle behavior, a novel noise application, a unique interaction response

### Project-Specific Invention

For every project, invent at least one of:

- A custom color palette matching the mood (not a preset)
- A novel noise field combination (e.g., curl noise + domain warp + feedback)
- A unique particle behavior (custom forces, custom trails, custom spawning)
- An interaction mechanic the user didn't request but that elevates the piece
- A compositional technique that creates visual hierarchy

### Parameter Design Philosophy

Parameters should emerge from the algorithm, not from a generic menu. Ask: "What properties of _this_ system should be tunable?"

**Good parameters** expose the algorithm's character:

- **Quantities** — how many particles, branches, cells (controls density)
- **Scales** — noise frequency, element size, spacing (controls texture)
- **Rates** — speed, growth rate, decay (controls energy)
- **Thresholds** — when does behavior change? (controls drama)
- **Ratios** — proportions, balance between forces (controls harmony)

**Bad parameters** are generic controls unrelated to the algorithm:

- "color1", "color2", "size" — meaningless without context
- Toggle switches for unrelated effects
- Parameters that only change cosmetics, not behavior

Every parameter should change how the algorithm _thinks_, not just how it _looks_. A "turbulence" parameter that changes noise octaves is good. A "particle size" slider that only changes `ellipse()` radius is shallow.

## Workflow

### Step 1: Creative Vision

Before any code, articulate:

- **Mood / atmosphere**: What should the viewer feel? Contemplative? Energized? Unsettled? Playful?
- **Visual story**: What happens over time (or on interaction)? Build? Decay? Transform? Oscillate?
- **Color world**: Warm/cool? Monochrome? Complementary? What's the dominant hue? The accent?
- **Shape language**: Organic curves? Sharp geometry? Dots? Lines? Mixed?
- **Motion vocabulary**: Slow drift? Explosive burst? Breathing pulse? Mechanical precision?
- **What makes THIS different**: What is the one thing that makes this sketch unique?

Map the user's prompt to aesthetic choices. "Relaxing generative background" demands different everything from "glitch data visualization."

### Step 2: Technical Design

- **Mode** — which of the 7 modes from the table above
- **Canvas size** — landscape 1920x1080, portrait 1080x1920, square 1080x1080, or responsive `windowWidth/windowHeight`
- **Renderer** — `P2D` (default) or `WEBGL` (for 3D, shaders, advanced blend modes)
- **Frame rate** — 60fps (interactive), 30fps (ambient animation), or `noLoop()` (static generative)
- **Export target** — browser display, PNG still, GIF loop, MP4 video, SVG vector
- **Interaction model** — passive (no input), mouse-driven, keyboard-driven, audio-reactive, scroll-driven
- **Viewer UI** — for interactive generative art, start from `templates/viewer.html` which provides seed navigation, parameter sliders, and download. For simple sketches or video export, use bare HTML

### Step 3: Code the Sketch

For **interactive generative art** (seed exploration, parameter tuning): start from `templates/viewer.html`. Read the template first, keep the fixed sections (seed nav, actions), replace the algorithm and parameter controls. This gives the user seed prev/next/random/jump, parameter sliders with live update, and PNG download — all wired up.

For **animations, video export, or simple sketches**: use bare HTML:

Single HTML file. Structure:

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Project Name</title>
    <script>
      p5.disableFriendlyErrors = true;
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.3/p5.min.js"></script>
    <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.3/addons/p5.sound.min.js"></script> -->
    <!-- <script src="https://unpkg.com/p5.js-svg@1.6.0"></script> -->
    <!-- SVG export -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/ccapture.js-npmfixed/build/CCapture.all.min.js"></script> -->
    <!-- video capture -->
    <style>
      html,
      body {
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
      canvas {
        display: block;
      }
    </style>
  </head>
  <body>
    <script>
      // === Configuration ===
      const CONFIG = {
        seed: 42,
        // ... project-specific params
      };

      // === Color Palette ===
      const PALETTE = {
        bg: "#0a0a0f",
        primary: "#e8d5b7",
        // ...
      };

      // === Global State ===
      let particles = [];

      // === Preload (fonts, images, data) ===
      function preload() {
        // font = loadFont('...');
      }

      // === Setup ===
      function setup() {
        createCanvas(1920, 1080);
        randomSeed(CONFIG.seed);
        noiseSeed(CONFIG.seed);
        colorMode(HSB, 360, 100, 100, 100);
        // Initialize state...
      }

      // === Draw Loop ===
      function draw() {
        // Render frame...
      }

      // === Helper Functions ===
      // ...

      // === Classes ===
      class Particle {
        // ...
      }

      // === Event Handlers ===
      function mousePressed() {
        /* ... */
      }
      function keyPressed() {
        /* ... */
      }
      function windowResized() {
        resizeCanvas(windowWidth, windowHeight);
      }
    </script>
  </body>
</html>
```

Key implementation patterns:

- **Seeded randomness**: Always `randomSeed()` + `noiseSeed()` for reproducibility
- **Color mode**: Use `colorMode(HSB, 360, 100, 100, 100)` for intuitive color control
- **State separation**: CONFIG for parameters, PALETTE for colors, globals for mutable state
- **Class-based entities**: Particles, agents, shapes as classes with `update()` + `display()` methods
- **Offscreen buffers**: `createGraphics()` for layered composition, trails, masks

### Step 4: Preview & Iterate

- Open HTML file directly in browser — no server needed for basic sketches
- For `loadImage()`/`loadFont()` from local files: use `scripts/serve.sh` or `python3 -m http.server`
- Chrome DevTools Performance tab to verify 60fps
- Test at target export resolution, not just the window size
- Adjust parameters until the visual matches the concept from Step 1

### Step 5: Export

| Format             | Method                                              | Command                                                                           |
| ------------------ | --------------------------------------------------- | --------------------------------------------------------------------------------- |
| **PNG**            | `saveCanvas('output', 'png')` in `keyPressed()`     | Press 's' to save                                                                 |
| **High-res PNG**   | Puppeteer headless capture                          | `node scripts/export-frames.js sketch.html --width 3840 --height 2160 --frames 1` |
| **GIF**            | `saveGif('output', 5)` — captures N seconds         | Press 'g' to save                                                                 |
| **Frame sequence** | `saveFrames('frame', 'png', 10, 30)` — 10s at 30fps | Then `ffmpeg -i frame-%04d.png -c:v libx264 output.mp4`                           |
| **MP4**            | Puppeteer frame capture + ffmpeg                    | `bash scripts/render.sh sketch.html output.mp4 --duration 30 --fps 30`            |
| **SVG**            | `createCanvas(w, h, SVG)` with p5.js-svg            | `save('output.svg')`                                                              |

### Step 6: Quality Verification

- **Does it match the vision?** Compare output to the creative concept. If it looks generic, go back to Step 1
- **Resolution check**: Is it sharp at the target display size? No aliasing artifacts?
- **Performance check**: Does it hold 60fps in browser? (30fps minimum for animations)
- **Color check**: Do the colors work together? Test on both light and dark monitors
- **Edge cases**: What happens at canvas edges? On resize? After running for 10 minutes?

## Critical Implementation Notes

### Performance — Disable FES First

The Friendly Error System (FES) adds up to 10x overhead. Disable it in every production sketch:

```javascript
p5.disableFriendlyErrors = true; // BEFORE setup()

function setup() {
  pixelDensity(1); // prevent 2x-4x overdraw on retina
  createCanvas(1920, 1080);
}
```

In hot loops (particles, pixel ops), use `Math.*` instead of p5 wrappers — measurably faster:

```javascript
// In draw() or update() hot paths:
let a = Math.sin(t); // not sin(t)
let r = Math.sqrt(dx * dx + dy * dy); // not dist() — or better: skip sqrt, compare magSq
let v = Math.random(); // not random() — when seed not needed
let m = Math.min(a, b); // not min(a, b)
```

Never `console.log()` inside `draw()`. Never manipulate DOM in `draw()`. See `references/troubleshooting.md` § Performance.

### Seeded Randomness — Always

Every generative sketch must be reproducible. Same seed, same output.

```javascript
function setup() {
  randomSeed(CONFIG.seed);
  noiseSeed(CONFIG.seed);
  // All random() and noise() calls now deterministic
}
```

Never use `Math.random()` for generative content — only for performance-critical non-visual code. Always `random()` for visual elements. If you need a random seed: `CONFIG.seed = floor(random(99999))`.

### Generative Art Platform Support (fxhash / Art Blocks)

For generative art platforms, replace p5's PRNG with the platform's deterministic random:

```javascript
// fxhash convention
const SEED = $fx.hash; // unique per mint
const rng = $fx.rand; // deterministic PRNG
$fx.features({ palette: "warm", complexity: "high" });

// In setup():
randomSeed(SEED); // for p5's noise()
noiseSeed(SEED);

// Replace random() with rng() for platform determinism
let x = rng() * width; // instead of random(width)
```

See `references/export-pipeline.md` § Platform Export.

### Color Mode — Use HSB

HSB (Hue, Saturation, Brightness) is dramatically easier to work with than RGB for generative art:

```javascript
colorMode(HSB, 360, 100, 100, 100);
// Now: fill(hue, sat, bri, alpha)
// Rotate hue: fill((baseHue + offset) % 360, 80, 90)
// Desaturate: fill(hue, sat * 0.3, bri)
// Darken: fill(hue, sat, bri * 0.5)
```

Never hardcode raw RGB values. Define a palette object, derive variations procedurally. See `references/color-systems.md`.

### Noise — Multi-Octave, Not Raw

Raw `noise(x, y)` looks like smooth blobs. Layer octaves for natural texture:

```javascript
function fbm(x, y, octaves = 4) {
  let val = 0,
    amp = 1,
    freq = 1,
    sum = 0;
  for (let i = 0; i < octaves; i++) {
    val += noise(x * freq, y * freq) * amp;
    sum += amp;
    amp *= 0.5;
    freq *= 2;
  }
  return val / sum;
}
```

For flowing organic forms, use **domain warping**: feed noise output back as noise input coordinates. See `references/visual-effects.md`.

### createGraphics() for Layers — Not Optional

Flat single-pass rendering looks flat. Use offscreen buffers for composition:

```javascript
let bgLayer, fgLayer, trailLayer;
function setup() {
  createCanvas(1920, 1080);
  bgLayer = createGraphics(width, height);
  fgLayer = createGraphics(width, height);
  trailLayer = createGraphics(width, height);
}
function draw() {
  renderBackground(bgLayer);
  renderTrails(trailLayer); // persistent, fading
  renderForeground(fgLayer); // cleared each frame
  image(bgLayer, 0, 0);
  image(trailLayer, 0, 0);
  image(fgLayer, 0, 0);
}
```

### Performance — Vectorize Where Possible

p5.js draw calls are expensive. For thousands of particles:

```javascript
// SLOW: individual shapes
for (let p of particles) {
  ellipse(p.x, p.y, p.size);
}

// FAST: single shape with beginShape()
beginShape(POINTS);
for (let p of particles) {
  vertex(p.x, p.y);
}
endShape();

// FASTEST: pixel buffer for massive counts
loadPixels();
for (let p of particles) {
  let idx = 4 * (floor(p.y) * width + floor(p.x));
  pixels[idx] = r;
  pixels[idx + 1] = g;
  pixels[idx + 2] = b;
  pixels[idx + 3] = 255;
}
updatePixels();
```

See `references/troubleshooting.md` § Performance.

### Instance Mode for Multiple Sketches

Global mode pollutes `window`. For production, use instance mode:

```javascript
const sketch = (p) => {
  p.setup = function () {
    p.createCanvas(800, 800);
  };
  p.draw = function () {
    p.background(0);
    p.ellipse(p.mouseX, p.mouseY, 50);
  };
};
new p5(sketch, "canvas-container");
```

Required when embedding multiple sketches on one page or integrating with frameworks.

### WebGL Mode Gotchas

- `createCanvas(w, h, WEBGL)` — origin is center, not top-left
- Y-axis is inverted (positive Y goes up in WEBGL, down in P2D)
- `translate(-width/2, -height/2)` to get P2D-like coordinates
- `push()`/`pop()` around every transform — matrix stack overflows silently
- `texture()` before `rect()`/`plane()` — not after
- Custom shaders: `createShader(vert, frag)` — test on multiple browsers

### Export — Key Bindings Convention

Every sketch should include these in `keyPressed()`:

```javascript
function keyPressed() {
  if (key === "s" || key === "S") saveCanvas("output", "png");
  if (key === "g" || key === "G") saveGif("output", 5);
  if (key === "r" || key === "R") {
    randomSeed(millis());
    noiseSeed(millis());
  }
  if (key === " ") CONFIG.paused = !CONFIG.paused;
}
```

### Headless Video Export — Use noLoop()

For headless rendering via Puppeteer, the sketch **must** use `noLoop()` in setup. Without it, p5's draw loop runs freely while screenshots are slow — the sketch races ahead and you get skipped/duplicate frames.

```javascript
function setup() {
  createCanvas(1920, 1080);
  pixelDensity(1);
  noLoop(); // capture script controls frame advance
  window._p5Ready = true; // signal readiness to capture script
}
```

The bundled `scripts/export-frames.js` detects `_p5Ready` and calls `redraw()` once per capture for exact 1:1 frame correspondence. See `references/export-pipeline.md` § Deterministic Capture.

For multi-scene videos, use the per-clip architecture: one HTML per scene, render independently, stitch with `ffmpeg -f concat`. See `references/export-pipeline.md` § Per-Clip Architecture.

### Agent Workflow

When building p5.js sketches:

1. **Write the HTML file** — single self-contained file, all code inline
2. **Open in browser** — `open sketch.html` (macOS) or `xdg-open sketch.html` (Linux)
3. **Local assets** (fonts, images) require a server: `python3 -m http.server 8080` in the project directory, then open `http://localhost:8080/sketch.html`
4. **Export PNG/GIF** — add `keyPressed()` shortcuts as shown above, tell the user which key to press
5. **Headless export** — `node scripts/export-frames.js sketch.html --frames 300` for automated frame capture (sketch must use `noLoop()` + `_p5Ready`)
6. **MP4 rendering** — `bash scripts/render.sh sketch.html output.mp4 --duration 30`
7. **Iterative refinement** — edit the HTML file, user refreshes browser to see changes
8. **Load references on demand** — use `skill_view(name="p5js", file_path="references/...")` to load specific reference files as needed during implementation

## Performance Targets

| Metric                        | Target                                            |
| ----------------------------- | ------------------------------------------------- |
| Frame rate (interactive)      | 60fps sustained                                   |
| Frame rate (animated export)  | 30fps minimum                                     |
| Particle count (P2D shapes)   | 5,000-10,000 at 60fps                             |
| Particle count (pixel buffer) | 50,000-100,000 at 60fps                           |
| Canvas resolution             | Up to 3840x2160 (export), 1920x1080 (interactive) |
| File size (HTML)              | < 100KB (excluding CDN libraries)                 |
| Load time                     | < 2s to first frame                               |

## References

| File                                | Contents                                                                                                                                                                                                     |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `references/core-api.md`            | Canvas setup, coordinate system, draw loop, `push()`/`pop()`, offscreen buffers, composition patterns, `pixelDensity()`, responsive design                                                                   |
| `references/shapes-and-geometry.md` | 2D primitives, `beginShape()`/`endShape()`, Bezier/Catmull-Rom curves, `vertex()` systems, custom shapes, `p5.Vector`, signed distance fields, SVG path conversion                                           |
| `references/visual-effects.md`      | Noise (Perlin, fractal, domain warp, curl), flow fields, particle systems (physics, flocking, trails), pixel manipulation, texture generation (stipple, hatch, halftone), feedback loops, reaction-diffusion |
| `references/animation.md`           | Frame-based animation, easing functions, `lerp()`/`map()`, spring physics, state machines, timeline sequencing, `millis()`-based timing, transition patterns                                                 |
| `references/typography.md`          | `text()`, `loadFont()`, `textToPoints()`, kinetic typography, text masks, font metrics, responsive text sizing                                                                                               |
| `references/color-systems.md`       | `colorMode()`, HSB/HSL/RGB, `lerpColor()`, `paletteLerp()`, procedural palettes, color harmony, `blendMode()`, gradient rendering, curated palette library                                                   |
| `references/webgl-and-3d.md`        | WEBGL renderer, 3D primitives, camera, lighting, materials, custom geometry, GLSL shaders (`createShader()`, `createFilterShader()`), framebuffers, post-processing                                          |
| `references/interaction.md`         | Mouse events, keyboard state, touch input, DOM elements, `createSlider()`/`createButton()`, audio input (p5.sound FFT/amplitude), scroll-driven animation, responsive events                                 |
| `references/export-pipeline.md`     | `saveCanvas()`, `saveGif()`, `saveFrames()`, deterministic headless capture, ffmpeg frame-to-video, CCapture.js, SVG export, per-clip architecture, platform export (fxhash), video gotchas                  |
| `references/troubleshooting.md`     | Performance profiling, per-pixel budgets, common mistakes, browser compatibility, WebGL debugging, font loading issues, pixel density traps, memory leaks, CORS                                              |
| `templates/viewer.html`             | Interactive viewer template: seed navigation (prev/next/random/jump), parameter sliders, download PNG, responsive canvas. Start from this for explorable generative art                                      |

---

## Creative Divergence (use only when user requests experimental/creative/unique output)

If the user asks for creative, experimental, surprising, or unconventional output, select the strategy that best fits and reason through its steps BEFORE generating code.

- **Conceptual Blending** — when the user names two things to combine or wants hybrid aesthetics
- **SCAMPER** — when the user wants a twist on a known generative art pattern
- **Distance Association** — when the user gives a single concept and wants exploration ("make something about time")

### Conceptual Blending

1. Name two distinct visual systems (e.g., particle physics + handwriting)
2. Map correspondences (particles = ink drops, forces = pen pressure, fields = letterforms)
3. Blend selectively — keep mappings that produce interesting emergent visuals
4. Code the blend as a unified system, not two systems side-by-side

### SCAMPER Transformation

Take a known generative pattern (flow field, particle system, L-system, cellular automata) and systematically transform it:

- **Substitute**: replace circles with text characters, lines with gradients
- **Combine**: merge two patterns (flow field + voronoi)
- **Adapt**: apply a 2D pattern to a 3D projection
- **Modify**: exaggerate scale, warp the coordinate space
- **Purpose**: use a physics sim for typography, a sorting algorithm for color
- **Eliminate**: remove the grid, remove color, remove symmetry
- **Reverse**: run the simulation backward, invert the parameter space

### Distance Association

1. Anchor on the user's concept (e.g., "loneliness")
2. Generate associations at three distances:
   - Close (obvious): empty room, single figure, silence
   - Medium (interesting): one fish in a school swimming the wrong way, a phone with no notifications, the gap between subway cars
   - Far (abstract): prime numbers, asymptotic curves, the color of 3am
3. Develop the medium-distance associations — they're specific enough to visualize but unexpected enough to be interesting

