Skip to content

vojtaholik/sketchpad

Repository files navigation

Sketchpad — generative art dashboard

Sketchpad

Generative art playground driven by Claude Code CLI

Compose · Tweak · Explore · Fork · Export

Next.js TypeScript SQLite Canvas Claude


What is Sketchpad?

A local-first generative art tool where you describe what you want and Claude writes the render code. No shader languages, no creative coding frameworks — just Canvas 2D and a conversation.

  "spiraling triangles that pulse outward"
                    │
                    ▼
        ┌───────────────────┐
        │   Claude Sonnet   │ ← writes renderCode as JS
        │   system prompt   │ ← knows Canvas 2D, noise, PRNG
        └─────────┬─────────┘
                  │
                  ▼
        ┌───────────────────┐
        │  AlgorithmSource  │ ← stored in SQLite
        │  { renderCode,    │
        │    defaultParams } │
        └─────────┬─────────┘
                  │
                  ▼
        ┌───────────────────┐
        │  new Function()   │ ← compiled once, cached
        │  → Canvas 2D      │
        └───────────────────┘

What you get:

  • Describe any visual idea in plain English → get a live, tweakable sketch
  • 10 built-in algorithms for instant starting points
  • Sliders for every parameter, real-time preview
  • Fork any sketch to branch into variations
  • Explore parameter space in a grid — see 9 or 16 variations at once
  • Full CLI for scripting and automation
  • Everything local. SQLite. Zero config.

Quick Start

git clone <repo-url> && cd sketchpad
npm install
npx prisma generate && npx prisma db push
npm run dev

Open localhost:3000. That's it.

AI Features

Sketchpad resolves Anthropic credentials automatically — if you have Claude Code installed, it reads your OAuth token from the system keychain. No API key needed.

Priority Method Setup
1 Claude Code CLI keychain Zero config — just have Claude Code installed
2 ANTHROPIC_API_KEY env Standard API key in .env
3 ANTHROPIC_BASE_URL env Proxy / alternative endpoint

Features

Compose with AI

Describe what you want. Claude writes a Canvas 2D render function, wires up parameters, picks a color palette. You get a live sketch you can tweak immediately.

npm run sketchpad -- compose "dense field of overlapping circles with watercolor transparency"

Or use the web UI — the compose bar is right at the top of the New Sketch page, with Haiku-generated prompt suggestions to get you started.

Refine with AI

Already have a composed sketch? Tell Claude what to change. It sees the current source and rewrites it.

npm run sketchpad -- refine <id> "add a radial gradient background and make circles smaller"

10 Built-in Algorithms

Algorithm Style Inspiration
flow-field Organic flowing lines Noise-driven vector fields
grid-subdivide Recursive rectangles Mondrian
circle-pack Packed circles Rejection sampling
particle-flow Luminous particle trails Drift simulation
hatched-blocks Hachure & cross-hatch fills Gorilla Sun's Block
quilt-tiles 8 tile pattern variants Generative quilts
watercolor-wash Layered transparent washes Tyler Hobbs
spiral-graph Hypotrochoid curves Spirograph
wave-grid Sine-modulated dot grid Moire patterns
voronoi-shatter Nearest-point cell fills Voronoi diagrams

11 Color Palettes

warm · cool · mono · neon · earth · sunset · ocean · forest · pastel · brutalist · random

Each palette is 6 colors. First color is background, rest are for shapes. The random palette generates a harmonious scheme from the sketch seed using HSL color theory.

Parameter Exploration

Navigate to any sketch's Explore view to see a grid of variations. Pick two numeric parameters for X and Y axes, and Sketchpad renders every combination. Click any cell to adopt those parameters.

  ┌─────┬─────┬─────┐
  │     │     │     │  ← noiseScale varies →
  ├─────┼─────┼─────┤
  │     │     │     │  ↑ lineCount varies
  ├─────┼─────┼─────┤
  │     │     │     │
  └─────┴─────┴─────┘
      3×3 or 4×4 grid

Forking & Lineage

Every sketch tracks its parent. Fork to branch into a new direction without losing the original. View the full lineage chain in the workspace breadcrumb.

npm run sketchpad -- fork <id> --name "sunset variation"
npm run sketchpad -- history <id>

CLI Reference

All commands output JSON. Pretty-printed on TTY, compact when piped.

npm run sketchpad -- <command> [options]
Command Description
new --algo <name> Create sketch from built-in algorithm
compose "prompt" AI-generate a custom algorithm
refine <id> "instruction" AI-refine a composed sketch
critique <id> AI critique with suggestions
list [--limit N] List recent sketches
show <id> Full sketch detail
tweak <id> key=value Update parameters
seed <id> --random Randomize seed
fork <id> Branch from existing sketch
explore <id> --vary p1,p2 Parameter space grid
history <id> Show fork lineage
algorithms List all algorithms + params
palettes List color palettes

Example Session

# Compose something from scratch
npm run sketchpad -- compose "crystalline void with floating shards"

# See what we got
npm run sketchpad -- show <id>

# Tweak parameters
npm run sketchpad -- tweak <id> shardCount=200 opacity=0.6

# Not quite right — refine with AI
npm run sketchpad -- refine <id> "make the shards more angular, add depth with size variation"

# Happy — fork for a color variant
npm run sketchpad -- fork <id> --name "crystalline void — warm"
npm run sketchpad -- tweak <new-id> palette=sunset

# Explore the parameter space
npm run sketchpad -- explore <id> --vary shardCount,opacity --grid 4

# Export from the web UI
open http://localhost:3000/sketch/<id>

How AI Composition Works

When you compose, Claude receives a system prompt that teaches it:

  • The render(ctx, params, seed, width, height) function signature
  • Available utilities: createSeededRandom(seed), createNoise2D(seed), getPalette(name, seed)
  • Canvas 2D API patterns for generative art
  • Compositional techniques (layering, noise fields, particle systems)
  • Strict JSON output format with renderCode as executable JS

The generated code is stored in AlgorithmSource, compiled once via new Function(), cached, and executed on every render with the engine utilities injected as parameters. Same seed always produces the same output.

┌──────────────────────────────────────────────────────┐
│                  Engine Utilities                     │
├──────────────┬──────────────┬────────────────────────┤
│ SeededRandom │  Noise2D     │  Palettes              │
│ .next()      │ simplex 2D   │ 11 palettes + random   │
│ .range()     │ returns      │ 6 colors each          │
│ .pick()      │ -1..1        │ HSL generation for     │
│ .shuffle()   │              │ random palettes         │
└──────────────┴──────────────┴────────────────────────┘
         ↓ injected into every render call
┌──────────────────────────────────────────────────────┐
│  renderCode(ctx, params, seed, w, h,                 │
│             createSeededRandom, createNoise2D,        │
│             getPalette)                               │
└──────────────────────────────────────────────────────┘

Architecture

app/
  page.tsx                 # Dashboard — sketch grid
  sketch/new/              # Algorithm picker + AI compose
  sketch/[id]/             # Workspace — canvas + params + refine
  sketch/[id]/explore/     # Parameter space grid
  api/
    sketches/              # CRUD + fork
    ai/                    # compose, refine, critique, describe, suggest
    sources/               # AlgorithmSource lookup

lib/
  engine/
    algorithms/            # 10 built-in render functions
    dynamic-algorithm.ts   # JSON → compiled Function (cached)
    renderer.ts            # renderAny / renderSketch dispatch
    registry.ts            # Built-in algorithm lookup
    palettes.ts            # 11 color palettes + random generation
    random.ts              # Seeded PRNG (mulberry32)
    noise.ts               # Simplex noise 2D
    types.ts               # AlgorithmDef, ParamDef, ParamValue
  ai/
    system-prompt.ts       # Claude system prompts for compose/refine
    compose-service.ts     # AI API calls + JSON parsing
  ai-client.ts             # Anthropic SDK wrapper
  claude-cli-auth.ts       # OAuth token from Claude Code keychain
  db.ts                    # Prisma client

cli/
  sketchpad.ts             # 13 commands, JSON output

prisma/
  schema.prisma            # Sketch, Tag, AlgorithmSource
  dev.db                   # SQLite (auto-created)

Database

SQLite via Prisma. Three models:

  • Sketch — name, algorithm, params (JSON), seed, parentId (fork lineage)
  • Tag — categorization (many-to-one with Sketch)
  • AlgorithmSource — stores AI-generated algorithm definitions (name, source JSON, version)

Rendering Pipeline

Built-in:   getAlgorithm(name) → algo.render(ctx, mergedParams, seed, w, h)
Composed:   cache.get(sourceJson) || (JSON.parse → new Function → cache) → algo.render(...)
Dispatch:   renderAny(canvas, name, params, seed, sourceJson?) handles both paths

Compiled algorithms are cached by source JSON — no recompilation on re-render or parameter changes.


Tech Stack

Layer Technology Role
Framework Next.js 16 (App Router) Server components, API routes
Language TypeScript 5.8 Type safety throughout
Database Prisma 7 + SQLite Local-first, zero setup
Rendering Canvas 2D Pure, no external graphics libs
Parameters Tweakpane 4 Real-time slider UI
AI Claude Sonnet 4 Algorithm generation + refinement
AI (fast) Claude Haiku 4.5 Prompt suggestions
Styling Tailwind CSS 4 Utility-first dark theme
Icons Lucide React Minimal icon set

Development

npm run dev              # Dev server with Turbopack
npm run build            # Production build
npm run sketchpad -- ... # CLI commands
npx prisma studio        # Browse database
npx prisma db push       # Apply schema changes

Adding a New Algorithm

  1. Create lib/engine/algorithms/your-algo.ts exporting an AlgorithmDef
  2. Register in lib/engine/registry.ts
  3. Done — it appears in the web UI picker and CLI

AlgorithmDef Interface

interface AlgorithmDef {
  name: string
  label: string
  description: string
  defaultParams: Record<string, ParamDef>
  render: (ctx, params, seed, width, height) => void
}

Built for playing with shapes, noise, and color.

About

A local-first generative art tool where you describe what you want and Claude writes the render code. No shader languages, no creative coding frameworks — just Canvas 2D and a conversation.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages