Labs
Where the rule stops being obedient.
11 experiments, studies and lab projects: shaders, physics, typography, a pixel village in VS Code. Built to understand something, kept because they still do. The finished work is on sammii.dev.
Charts
Information design about the things design engineers work with. Interactive, sourced, and a poster you can download. All charts.
01 · SVG, React, CSS Color 4
The family tree of colour spaces
25 colour spaces from Munsell and CIE XYZ to OKLCH and CSS Color 4 on a timeline in six lanes, the derivations drawn in, live ramps in each space, and the poster to download.
02 · First-principles colour maths
Why HSL lies
Twenty-four hues at one nominal lightness in HSL, CIELCH and OKLCH, with the measured luminance under every swatch. The skyline versus the flat line.
04 · Lineage tree, live specimens
The typography genome
Latin type as a family tree from Textura to variable fonts, five lanes, every node shown in a live stand-in font. Serif is one unbroken line from Jenson.
06 · CIE 1931 diagram, per-pixel canvas
The gamuts
Every colour you can see as the CIE horseshoe, with sRGB, Display P3, Adobe RGB and Rec. 2020 as triangles, and a check of what your own screen can show.
10 · 148 names, resolved by your browser
Every named CSS colour, in OKLCH
The named colours placed by what they look like: OKLCH hue round the wheel, chroma outward, lightness as dot size. darkgray is lighter than gray, and the wheel shows why the set is lopsided.
14 · WCAG 2 and APCA, first principles
Contrast, two ways that disagree
The same text and background scored by WCAG 2 and by APCA next to the rendered text, and the full grey ramp on white and on black to show where they part company. Orange on white fails one and is a fine heading in the other.
11 · Waterfall from round trips, six knobs
How a URL becomes a page
DNS, the handshakes, the first byte, the HTML, the CSS, the JavaScript and the paint as one waterfall computed from the round-trip time you pick. On a slow link the waiting dwarfs the work.
07 · Pipeline map, 55 properties
What a CSS property costs
Every common CSS property sorted by what changing it forces: layout, paint or composite. Pick one and the pipeline lights up. Two properties live in the cheap column.
08 · Live demos plus a stepper
The event loop, for interfaces
Why the loading label never shows, why the CSS animation survives a busy page and the JavaScript one freezes, measured with real work. Then the rules underneath, stepped through: 1, 4, 3, 2.
09 · Live measured demo plus curves
Big O, in the keystroke
A filtered list that stops keeping up with your typing, measured per keystroke against the 16 ms and 100 ms budgets, and the one line behind it. Then eight classes to scale, log or linear, with the time each takes at a billion operations a second.
12 · Live physics, recorded from the screen
Easing versus springs
A CSS transition and a spring moving the same card, both sampled from the screen every frame. Interrupt them mid-flight: the spring keeps its velocity, the transition starts a fresh curve. Stiffness, damping, mass, and the settle time a spring has instead of a duration.
13 · Live DOM, computed paint order
Why z-index: 9999 does nothing
A real dropdown on a real card. Toggle transform, opacity, filter or will-change on the card and the menu vanishes under the next section; the panel shows the stacking-context tree the browser built and the order it painted. Two fixes, one of them the start of the next war.
15 · Selectors Level 4 parser, live ranking
Specificity, three columns
Type any selector and see its specificity as three bars, with :is, :where, :not, :has and nth-child-of handled properly. The rules on one button ranked, and the seven cascade steps that get a say before specificity does.
17 · Seven eras of real CSS, live
Thirty years of CSS layout, the same page each way
One page built seven times: tables, floats, inline-block, flexbox, grid, container queries and subgrid, in the real CSS of each era and rendered by your browser. Drag the width and what each era could not do is visible, not described.
19 · Live counts, Intl.Segmenter
The four lengths of a string
Why "family".length lies: graphemes, code points, UTF-16 units and UTF-8 bytes counted live for anything you type, every grapheme with its code points, and what a 20-character limit written three ways does to a name, a flag and a family.
20 · Measured layout, decoded doubles
Floating point, at the pixel
The seam between tiles at a third of the width, the border that goes fuzzy at half a pixel, the basket that says 0.30000000000000004, and the 64 bits of any number you type. Measured with getBoundingClientRect and decoded with a DataView, live.
21 · Generated bundle, measured in-page
What a byte of JavaScript costs
A bundle of the size you choose is generated, gzipped, parsed, compiled and executed in your browser and timed, then laid next to its download on the network you pick and next to the same bytes as an image. The byte is not the cost; the thread is.
22 · Object graph, nine commands stepped
Your commit is not gone
reset --hard rewrote one 40-byte file and your afternoon appeared to vanish. Step nine commands through the object graph, with unreachable commits left drawn because none of these commands deletes anything, and watch a rebase write new objects while a merge keeps every id.
23 · Top layer, anchor positioning, live support
Getting the menu out of the card
The sequel to z-index 9999: the same dropdown three ways inside a scrolling, transformed card. Absolute and clipped, a popover in the top layer positioned by hand on every scroll, and a popover positioned in CSS with anchor-name, with support detected on your browser.
25 · RFC 9111 freshness, five presets
Why they are still seeing the old version
Five sets of caching headers run against the same six visits, with your deploy in the middle: which visits hit memory without asking, which send a conditional request, which get an empty 304, and which users are still looking at yesterday's build.
05 · Latency flow, four knobs
How a keypress becomes a pixel
Twelve hops between a finger and the glass, drawn to their share of the time. The code you write is two of them; the display is three.
16 · Planetary hours, stepped live
Seven, and why the week is in that order
Step the hours of the week and the seven-pointed star draws itself: 24 mod 7 = 3 is why the days go Sun, Moon, Mars, Mercury, Jupiter, Venus, Saturn. Then the sevens in columns, from Newton's spectrum to the seven spheres of my MA installation.
18 · 22 families measured live, canvas API
Why 16px is not 16px
font-size is a box and every family fills it differently. Twenty-two families loaded and measured in your browser: x-height, cap height, ascender, descender and line box as fractions of the em, the size each needs to match a reference, and font-size-adjust switched on live.
24 · Hand-placed names, measured metrics
The anatomy of a letter
Four specimens with their parts named, and their horizontal lines measured from the live font in your browser: x-height, cap height, ascender, descender, and the overshoot that makes a round letter look the same height as a flat one.
03 · Scroll timeline, 65 entries
Six centuries of communication and type
Gutenberg to ChatGPT on one spine, inventions on the left and typefaces on the right, so the two histories read against each other.
Experiments
One idea each, built to see it move.

Balloon Bonanza
React, TypeScript, Matter.js, Vite
A physics playground of 100 balloons that float, bounce, and can be grabbed and flung across the screen. Matter.js has no buoyancy, so the float is faked from tuned gravity, density, and air friction; each balloon is a two-body compound with a wobbling knot. Holds 60fps across 200+ bodies and 300+ constraints.






Tailwind Colour Creator
React, TypeScript, Vite, Tailwind CSS
Colour palette generator that produces Tailwind-accurate 11-step scales from any base colour. Derives lightness, saturation, and hue curves from official Tailwind palettes, with click-to-copy swatches and CSS variable or config output.
Superseded by Gamut.
Studies
Longer looks at a single question.
Lab projects
Bigger builds that never needed to be products.

Beyond Light VR
Three.js, WebXR, GLSL, Vite
WebXR reconstruction of my MA dissertation installation. A journey through the visible light spectrum from infrared to ultraviolet: quotes screen-printed on acetate walls remain invisible until the final UV phase, where they blaze to life with a custom GLSL UV-reactive shader before the room dissolves into white.

Celestial map
D3.js, HTML5 Canvas, Vite
Interactive star globe rendered on Canvas using D3 orthographic projection. Realistic star colours from B-V colour index, magnitude-scaled sizes with glow effects, constellation lines and labels, Milky Way band, drag-to-rotate with idle spin, and a time slider that shifts the sky in right ascension.

Isle
TypeScript, Canvas API, VS Code Extension API, Astronomy Engine
VS Code extension that visualises active Claude Code agent sessions as pixel-art characters in an Animal Crossing-style village. Agents sit at desks in an office, wander outdoors, and display real-time status. Dynamic time-of-day, seasonal changes, a pond, trees, and flowers.
