Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/hetari/creative-coding/llms.txt

Use this file to discover all available pages before exploring further.

Creative Coding is organized around a deliberate three-layer architecture that keeps creative implementation, experiment registration, and URL routing completely separate from one another. This separation means you can reorder, rename, recategorize, or add a sketch by touching a single file — and the dashboard, URLs, and previews all update automatically without any boilerplate. The decision is formally captured in docs/adr/0001-decouple-sketches-and-dynamic-routing.md.

Annotated Directory Tree

creative-coding/
├── src/
│   ├── config/
│   │   └── sketches.ts         # Central SKETCHES registry — add new sketches here
│   ├── composables/
│   │   ├── usePixiApp.ts        # PixiJS lifecycle composable
│   │   ├── useP5.ts             # p5.js lifecycle composable
│   │   ├── useGsap.ts           # GSAP + ScrollTrigger composable
│   │   ├── useAsciiRasterizer.ts# ASCII art image composable
│   │   └── useIsPreview.ts      # Iframe detection composable
│   ├── components/
│   │   ├── StatsPanel.vue       # FPS/MS/MB overlay
│   │   ├── LilGui.vue           # Parameter controller overlay
│   │   ├── ResourcesList.vue    # Reference links overlay
│   │   └── LazyIframePreview.vue# Lazy-loaded iframe preview card
│   ├── pages/
│   │   ├── index.vue            # Root dashboard
│   │   └── [...all].vue         # Catch-all router seam
│   ├── sketches/
│   │   ├── shader/learn/        # GLSL shader sketch
│   │   ├── images/swiper/       # PixiJS image swiper
│   │   └── gsap/
│   │       ├── footer/ascii-hand/   # ASCII hand footer
│   │       └── loading/reveal-loader/
│   ├── layouts/
│   │   └── default.vue          # Base layout wrapper
│   ├── utils/
│   │   ├── dashboard.ts         # buildDashboardItems()
│   │   ├── slug.ts              # slugToLabel(), stripSortPrefix()
│   │   └── earth.ts             # createEarthMesh() Three.js helper
│   └── lib/
│       ├── spline.ts            # CatmullRomCurve3 tunnel path
│       └── stars.ts             # Three.js star-field geometry helper
├── public/
│   └── images/                  # Static image assets
├── docs/
│   └── adr/                     # Architecture Decision Records
├── vite.config.ts
└── package.json

The Three Layers

Layer 1 — Sketch Implementations (src/sketches/)

Every creative coding experiment lives in its own domain folder under src/sketches/. A typical sketch folder contains an index.vue component that uses one of the lifecycle composables (usePixiApp, useP5, useGsap) to mount its canvas. More complex sketches also include GLSL shader sources (.vert / .frag), texture assets, and sketch-specific math helpers — all colocated together so the entire implementation is self-contained. This directory is never touched by the router. Vite imports sketch components lazily via dynamic () => import(...) expressions declared in the central registry, so the file tree here can grow freely without affecting URL generation or dashboard layout.
Colocation is a first-class concern. Put your shader files, helper utilities, and image assets in the same folder as your index.vue. There is no need to reach outside your sketch folder for sketch-specific assets.

Layer 2 — Central Registry (src/config/sketches.ts)

The SKETCHES array is the single source of truth for every experiment in the playground. Each SketchMeta entry defines:
export interface SketchMeta {
  id: string                              // Unique kebab-case identifier
  title: string                           // Display name on the dashboard
  category: string                        // Slash-separated category path
  path: string                            // URL path (no trailing slash)
  order: number                           // Sort key (lower = first)
  previewMode: 'image' | 'iframe'         // Dashboard card preview style
  resources?: string[]                    // Optional reference URLs
  component: () => Promise<{ default: Component }> // Lazy dynamic import
}
This is the only file you edit to add, remove, rename, or reorder a sketch. The dashboard, routing, and category grouping all derive from this array at runtime. There are no route config files, no manual imports, and no icon mappings to maintain elsewhere.
The registry also exports two helper functions used by the catch-all router: getSketchByPath(path) resolves a leaf sketch by its URL path, and isCategoryPath(path) determines whether a path matches a category prefix so the router knows to render the category dashboard instead.

Layer 3 — Routing Shell (src/pages/)

src/pages/ intentionally contains exactly two files and is never modified when adding sketches:
  • index.vue — Renders the root dashboard. Reads the SKETCHES registry to build a grouped grid of sketch cards, each showing either a lazy iframe preview or a static image preview.
  • [...all].vue — A catch-all route seam powered by vue-router/auto-routes. It watches route.path, consults the registry, and dynamically resolves one of three outcomes:
    1. Leaf sketch — Lazy-loads and mounts the sketch component found by getSketchByPath.
    2. Category dashboard — Renders IndexPage filtered to the matching category when isCategoryPath returns true.
    3. 404 fallback — Shows a styled “Page Not Found” screen with a link back to the dashboard.
This design means the routing shell is a permanent, stable piece of infrastructure. It does not grow as the project grows — only src/config/sketches.ts does.

Adding a New Sketch

The full step-by-step walkthrough for creating a sketch, registering it, and choosing a preview mode is covered in the Adding a Sketch guide. In summary, the two-step process is always:
  1. Create src/sketches/<category>/<name>/index.vue with your canvas implementation.
  2. Append one SketchMeta entry to the SKETCHES array in src/config/sketches.ts.
No other files need to change.

ADR: Decoupled Architecture

The three-layer separation was a deliberate architectural decision recorded in docs/adr/0001-decouple-sketches-and-dynamic-routing.md. The problem it solved: In the original design, src/pages/ carried two conflicting responsibilities — file-based route generation and creative implementation. This caused three compounding issues:
  • Numeric folder prefixes leaked into URLs. Folders like 000-learn/ were required for sorting, but unplugin-vue-router baked the prefix directly into the URL path (/shader/000-learn).
  • Dummy index.vue files proliferated. Every category directory (gsap/, gsap/footer/, shader/) required an empty index.vue solely to render a category card on the dashboard.
  • Shader binaries mixed with route definitions. GLSL .frag/.vert files and canvas rasterizers lived directly inside the route tree, making src/pages/ a confusing hybrid of infrastructure and implementation.
The outcome: By moving implementations to src/sketches/, centralizing metadata in src/config/sketches.ts, and reducing src/pages/ to a static two-file dynamic shell, the playground achieved clean URLs (e.g. /shader/learn), zero page boilerplate, isolated shaders, and a single well-known edit location for all sketch changes.
Do not add .vue files to src/pages/ for new sketches or categories. Doing so reintroduces the problems the ADR was written to solve: route-tree pollution, URL prefix leakage, and mixed responsibilities. Always work through src/sketches/ and src/config/sketches.ts.

Build docs developers (and LLMs) love