Code
Canvas
Basic Shapes
fillRect, strokeRect, arc, closePath and roundRect — the core drawing primitives.
Colors & Gradients
Linear, radial and conic gradients, drop shadows, and globalAlpha transparency.
Text Rendering
fillText, strokeText, font styles, textAlign, textBaseline, and measureText.
Transformations
translate, rotate, scale, setTransform and the save/restore state stack.
Bezier Paths
Quadratic and cubic Bézier curves, Path2D reuse, star polygons, and arcTo.
Animation Loop
requestAnimationFrame-driven bouncing balls with gravity, friction, and motion-blur trails.
Mouse Drawing
Interactive paint application — smooth draw/erase with brush colour and size controls.
Compositing Modes
All 16 globalCompositeOperation modes — from source-over to multiply and xor.
Pixel Manipulation
ImageData filters — grayscale, invert, sepia, brightness boost, and pixelate.
Particle System
Physics-based particles with buoyancy, turbulence, colour lifecycle, and additive blending.
Fractal Tree
Animated recursive fractal tree — dynamic branching angle with brown-to-green colour transition.
Conway's Game of Life
Cellular automaton on a toroidal grid — pause, resume, and randomise the population.
Flow Field
1,200 particles following a dynamic vector field built from layered sine/cosine noise.
Mandelbrot Set
Mandelbrot set with smooth colouring, auto-zooming into the Seahorse Valley.
Generative Art
Algorithmic tile grid — noise-driven hue and rotation with layered concentric ring overlays.
Generative Art
Advanced Algorithmic art — a noise-driven tile grid with rotating geometry and layered concentric rings, all animated in real time without any external library.
// 2-layer sine noise — no library required
const noise2 = (x: number, y: number, t: number) =>
Math.sin(x * 0.009 + t) *
Math.cos(y * 0.011 - t * 0.7) +
Math.sin(x * 0.021 - y * 0.013 + t * 1.3) * 0.5;
// Per-tile draw
const drawTile = (col: number, row: number) => {
const cx = (col + 0.5) * TW;
const cy = (row + 0.5) * TH;
const n = noise2(cx, cy, t); // −1.5 … 1.5
const hue = (n * 180 + t * 40) % 360;
// Background fill
ctx.fillStyle = `hsl(${hue}, 70%, ${45 + n*20}%)`;
ctx.fillRect(col * TW, row * TH, TW, TH);
// Rotated inner rect — weaving effect
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(n * Math.PI);
ctx.fillStyle = `hsla(${(hue+150)%360}, 70%, 63%, 0.65)`;
ctx.fillRect(-TW*0.28, -TH*0.28, TW*0.55, TH*0.55);
// Inner circle accent
ctx.beginPath();
ctx.arc(0, 0, Math.min(TW,TH)*0.2, 0, Math.PI*2);
ctx.fillStyle = `hsla(${(hue+60)%360}, 90%, 75%, 0.8)`;
ctx.fill();
ctx.restore();
};
// Concentric ring overlay
const drawRings = () => {
for (let i = 18; i > 0; i--) {
const r = (i / 18) * maxR;
const hue = ((i/18)*360 + t*30) % 360;
ctx.beginPath();
ctx.arc(W/2, H/2, r, 0, Math.PI*2);
ctx.strokeStyle = `hsla(${hue}, 80%, 60%, 0.35)`;
ctx.lineWidth = TH * 0.6;
ctx.stroke();
}
};
// Animation loop
const step = () => {
for (let row = 0; row < ROWS; row++)
for (let col = 0; col < COLS; col++)
drawTile(col, row);
drawRings();
t += 0.008;
this.rafId = requestAnimationFrame(step);
};
this.rafId = requestAnimationFrame(step);Key Concepts
- Layered sine/cosine at different frequencies approximates smooth 2D noise with no dependencies
- Noise value drives hue, rotation angle, and lightness simultaneously — one number shapes colour and form
ctx.save()/ctx.rotate()/ctx.restore()rotate each tile independently without affecting neighbours- Complementary hue offset (
+150,+60) creates contrast within each tile while the palette stays coherent - Concentric rings drawn with a wide
lineWidthact as a blended overlay — the radial gradient emerges from stroke alpha accumulation - Generative art principle: simple rules applied uniformly, varied by a slowly-changing parameter, produce complex and pleasing patterns