Projects

Experiments

Unfinished on purpose. Each one exists to work out a single technique in isolation, which is usually where the interesting problems turn up first. They run in the browser, here on the page.

Thread drawing, pick a color and draw on the shirt Canvas · Path2D

One canvas, no DOM elements. The shirt is a Path2D, so isPointInPath decides whether a stroke lands on the garment and clip keeps the thread inside the silhouette. The drawable area is the shape itself, not a rectangle standing in for it. Points are only recorded past a minimum distance, so a slow drag doesn't pile up hundreds of coordinates in one spot, and the whole layout, swatches included, is recomputed from the canvas size on resize.

Face cloud. 478 landmarks, tracked live and drawn as points of light. Source Three.js · MediaPipe · WebGL

One buffer holds both states. With no face it's a slow ring, and when tracking starts each point is handed a new target and interpolates toward it, so the idle animation becomes a face instead of being replaced by one. Detection and rendering are separate loops, so the render keeps interpolating at full frame rate while the detector only runs on new video frames. The camera stays off until you press the button, and if it's refused, WebGL is missing, or reduced motion is on, it falls back to the idle cloud rather than breaking.

Experience

Design and front-end work, and the four years of developer advocacy in the middle of it. Where the evidence survives, it's here.