Detail 03 · Design system
The design system
Every token, typeface, pencil mark, spring, sound and component on this site, set out the way a Figma file would, but live: each one is the real thing, read from the code. 6 minutes, 13 demos.
01 · How to read it
A Figma file, but live
A design system usually lives in a Figma file: pages of colours, type and components, each a picture of what the code should do. This one lives in the code, so this page shows the code itself. Every swatch reads its colour from the page as it renders, every spring is imported from the file the site uses, every component is the one on the other pages, and every sound is made the moment you press it.
So it can’t drift. Change a token in globals.css and the swatch here changes with it. What this detail doesn’t do is give the reasons: the next two do, the pencil language for the look and how things move for the motion.
02 · Colour
Seven tokens, four more for what's drawn
Seven tokens make the page: its ground, a surface a shade under it, four greys for text and pencil, and ember. Ember is only for what matters: the active state, the thing being studied, a key note. Structure stays white pencil, at low opacity.
--color-background
The page: raven, a warm near-black
--color-surface
A shade under the page: frames, panels
--color-foreground
Text that matters: titles, the active row
--color-muted
Secondary text: labels, captions
--color-heading
Large display text
--color-ghost
Faint decorative text, outlines
--color-accent
Ember: only what matters
Four more colour what’s drawn on the page rather than the page itself: the case study’s book, its ink, the résumé’s sheet and the stage every demo plays on.
--color-paper
The case study's book: its pages
--color-ink
Text and drawings on that paper
--color-sheet
The résumé's sheet, and every demo of it
--color-stage
A demo's stage: the paper, 45% darker
Every pair below is measured as it renders: the text’s colour against the ground it sits on, as a contrast ratio. Body text needs 4.5:1, and each of these clears it, ember included.
foreground on background
Titles, links
muted on background
Labels, captions
accent on background
Ember notes
foreground on stage
A demo's text
ink on paper
The book's pages
muted on stage
A demo's labels
03 · Type
Four faces, one job each
EB Garamond for titles, Roboto for reading and the interface, Caveat for anything handwritten, and the signature’s face for the signature alone. Mono is only for code and readouts. The sizes below are read from the samples at this screen’s width, so on a phone the titles read smaller.
Page title
font-display ·
How I built this portfolio
Section title
font-display ·
Seven tokens and one rule
Summary
font-body ·
One line under the title, a little larger than reading.
Reading
font-body ·
Body copy, set for long reading in the column.
Note, kicker
font-hand ·
03 · The pencil language
Control label
font-body ·
Network
Code
font-mono ·
overflow-x: clip;
Signature
font-signature ·
Sujoy Kr. Haldar
04 · Pencil
Drawn, not bordered
Nothing on the site has a CSS border where a line can be drawn instead. Every mark is a few hand-made strokes, seeded by its own text so it comes out the same on every visit.
A ruled line
Two passes, ends a little past where it should stop: rules, dividers, the scroll ruler
A box
Four strokes that overshoot, traced twice: titles, the open detail
Hatching
Ember for what's chosen or read; white for a sketch's blocks
The film grain lies over this page too: at 15%, moving in whole-pixel jumps, and held still at 8% with animations off.
05 · Motion
Springs by job, curves for sequences
Anything that changes picks a spring by what it’s doing, never a new one written on the spot. Press a spring’s name to play it, or play them all and compare.
What’s timed rather than sprung, a sequence or a sketch or a page change, takes one of five named curves.
EASE.out
0.22, 1, 0.36, 1
Arriving or answering
EASE.flight
0.76, 0, 0.24, 1
A long flight across the page
EASE.move
0.65, 0, 0.35, 1
A shorter move on screen
EASE.sink
0.4, 0, 0.2, 1
The old page sinking away
EASE.deepen
0.5, 0, 0.75, 0
A blur that builds, then deepens
A press sinks by one of three depths, by what’s pressed. Press and hold each one.
PRESS.icon · 0.9
An icon on its own
PRESS.wide · 0.96
A label, a tab, a switch
PRESS.card · 0.98
A whole card
06 · Sound
Made as it plays
There are no sound files. Every sound is made in the browser as it plays, from a little noise or a tone, and only ever for something the visitor did. The settings island turns every one of them off.
Every pencil switch
Lower going off
The page transitions, the demo viewer, the share dialog
The case study's book
The piles under the book
Detail 05's drawing
Detail 12's drawing
Detail 17's drawing
Synthesized in the browser:no sound files.
07 · Components
The parts, live
These are the real components, not drawings of them: point at them, tab to them, press them.
Switch
Off, on, and disabled
Choice
One of a few
Slider
A value along a ruler
Buttons
A label; an icon, with its tooltip
Links
In running text: on this site, and on another
Read the pencil language, or TanStack Query.
Separated list
The mark never hangs at a wrap
Each control has the same five states, written in CSS so they look the same whatever the visitor’s animation setting.
Every state is CSS, marked interact: the same with animations on, off or calm. 150ms on EASE.out.
And the larger surfaces: a demo’s browser window, a code panel, an article’s card.
Browser window
A demo that's a page
A page in a window
Reload it, up in its bar.
Code
Its lines marked as they work
1.tags {2 overflow-x: clip;3}
08 · Modes
On, off and calm
The settings island has a switch for animations, and a device can ask for less motion. Every change on the site comes in three versions: animated, landing at once, or a calm fade. Demos keep playing in all three, because showing motion is what they’re for.
Animations on
Springs, blurs, morphs
Animations off
Every change lands at its end
Calm
A device asking for less motion: fades, no travel