A creative coding playground for generative art, visual experiments, and algorithmic beauty. Built with Next.js, TypeScript, and the HTML Canvas API.
- Framework: Next.js 16 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS 4
- Font: Geist Mono
- Canvas: HTML5 Canvas with a custom React hook
npm install
npm run devOpen http://localhost:3000 to see the gallery.
-
Create a new directory under
app/experiments/:app/experiments/my-experiment/page.tsx -
Use the shared
ExperimentLayoutwrapper anduseCanvashook:"use client"; import { useRef } from "react"; import ExperimentLayout from "@/components/ExperimentLayout"; import { useCanvas } from "@/lib/canvas/setup"; export default function MyExperiment() { const canvasRef = useRef<HTMLCanvasElement>(null); useCanvas(canvasRef, ({ ctx, width, height, elapsed }) => { ctx.clearRect(0, 0, width, height); // Your drawing code here }); return ( <ExperimentLayout title="My Experiment"> <canvas ref={canvasRef} className="block w-full h-full" /> </ExperimentLayout> ); }
-
Add the experiment to the gallery by updating the
experimentsarray inapp/page.tsx:const experiments: Experiment[] = [ { slug: "my-experiment", title: "My Experiment", description: "A brief description of what this does.", date: "2025-01-15", }, ];
tech-art/
├── app/
│ ├── layout.tsx # Root layout — dark theme, Geist Mono
│ ├── page.tsx # Gallery index — lists all experiments
│ ├── globals.css # Base styles + Tailwind
│ └── experiments/ # Each experiment gets a directory here
│ └── [slug]/page.tsx
├── components/
│ └── ExperimentLayout.tsx # Shared wrapper for experiments
├── lib/
│ ├── canvas/
│ │ └── setup.ts # useCanvas hook — resize, DPR, animation loop
│ ├── math/
│ │ ├── vec2.ts # 2D vector operations
│ │ └── utils.ts # clamp, lerp, easing functions
│ └── colour/
│ └── palettes.ts # Curated colour palettes
└── public/ # Static assets
Handles canvas setup, DPR scaling, resize observation, and the animation loop. Your draw function receives:
ctx— the 2D rendering context (already DPR-scaled)width,height— logical dimensions in CSS pixelsframeCount— frames since mountdeltaTime— seconds since last frameelapsed— seconds since mount
Basic 2D vector math: add, sub, mul, div, length, normalize, dot, distance, lerp.
clamp, map (range remapping), lerp, and easing functions (easeInOut, easeInQuad, easeOutQuad, easeInOutCubic).
Curated palettes: Warm Sunset, Cool Ocean, Neon, Monochrome, Earth Tones, Retrowave, Forest. Each palette is an array of hex strings with helper functions randomColour and colourAt.
MIT