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.
Animation Loop
IntermediaterequestAnimationFrame-driven animation — bouncing balls with gravity, friction, trails, and radial gradient shading. MDN Reference
// Always cancel on destroy to prevent leaks
private rafId = 0;
ngAfterViewInit() {
const ctx = canvas.getContext('2d')!;
const step = () => {
// Semi-transparent clear = motion blur
ctx.fillStyle = 'rgba(255,255,255,0.18)';
ctx.fillRect(0, 0, W, H);
for (const b of balls) {
b.vy += gravity; // gravity
b.vx *= friction; // air resistance
b.vy *= friction;
b.x += b.vx;
b.y += b.vy;
// Bounce
if (b.x - b.r < 0) { b.x = b.r; b.vx = Math.abs(b.vx); }
if (b.x + b.r > W) { b.x = W - b.r; b.vx = -Math.abs(b.vx); }
if (b.y + b.r > H) {
b.y = H - b.r;
b.vy = -Math.abs(b.vy) * 0.85; // energy loss
}
// Radial gradient for 3D look
const grad = ctx.createRadialGradient(
b.x - b.r * 0.3, b.y - b.r * 0.3, 2,
b.x, b.y, b.r
);
grad.addColorStop(0, '#fff');
grad.addColorStop(1, b.color + '88');
ctx.beginPath();
ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2);
ctx.fillStyle = grad;
ctx.fill();
}
this.rafId = requestAnimationFrame(step);
};
this.rafId = requestAnimationFrame(step);
}
ngOnDestroy() {
cancelAnimationFrame(this.rafId); // essential!
}Key Concepts
requestAnimationFrame(callback)— callscallbackbefore the next repaint (~60 fps)cancelAnimationFrame(id)— stops the loop; always call inngOnDestroy- Semi-transparent clear (
rgba(255,255,255,0.18)) leaves ghost trails (motion blur) - Multiply velocity by
friction < 1each frame for realistic deceleration - Add constant
gravitytovyeach frame to simulate downward acceleration - Bounce by negating velocity component when hitting a wall