Version 1.0 · 19 tokens
A portfolio site
disguised as a
miniature operating system.
Everything below is the working vocabulary of KAPPA OS — the colours, faces, radii and rules the desktop is actually built from. The components are the live imports, not pictures of them, and every value resolves from the same custom property the OS reads, so this page cannot quietly fall out of step with it.
The bar for the codebase is that it behaves like a real OS rather than a page that looks like one. Where a decision was between simpler to build and how the real thing behaves, the real thing won — and that is what most of these notes are recording.
01
Principles
Five rules. Each one is here because it was broken first, and the break shipped.
Monochrome, flat, engineered
Nothing OS-inspired. Colour lives only in tiny functional accents and never in the chrome — the moment a surface takes a hue it stops reading as a machine.
Tokens only
Reach for text-ink-soft or bg-[color:var(--card)], never a hex. A hex is a value that cannot follow the theme, and it will be found in dark mode by a visitor rather than by you.
Depth is tone, not borders
A card is one tone step deeper than the surface it sits on. Where a line is genuinely needed it is --line, a hairline, and it is the exception.
No shadows as decoration
The only elevation in the system is .floating on window chrome, and it deepens on focus. A shadow that isn't saying which surface is in front is noise.
Everything is drawn
No images for chrome, no icon fonts — SVG paths and CSS. Sounds are synthesised at runtime; there are no audio files anywhere in the project.
02
Colour
Two scales and a hairline carry the entire interface. The accent is the only hue, it is the visitor’s to choose, and it appears only where the interface is answering them.
Ink
Text and strokes
--ink
—
Body text, glyph strokes, anything meant to be read first.
--ink-soft
—
Secondary copy and metadata — present, not competing.
--ink-faint
—
Labels at rest, placeholder text, a disabled control.
Surface
Depth, in tone steps
--canvas
—
The page itself. Everything else is measured against it.
--card
—
A window body — one tone step deeper than the canvas.
--card-deep
—
A card inside a window, and the pressed state of a button.
--pill
—
Raised controls: the dock, buttons, sort bars.
--canvas-dot
—
The graph-paper dot in the default wallpaper.
The scale, nested
canvas
card
card-deep
pill
Structure
--line
—
The hairline, and the only border in the system. Reach for a tone step first.
Accent
Functional only
--accent
—
Whichever of the four the visitor picked. Focus rings, switches, selection.
--accent-red
—
The default.
--accent-green
—
--accent-blue
—
--accent-amber
—
Live — this sets the accent for the whole OS
Device
Outside the theme
--terminal-green
—· fixed in both themes
Green-on-black widget text.
--vfd-amber
—· fixed in both themes
A lit segment on the Tunes display and the boot screen. One token, so the two can't drift.
--vfd-amber-dim
—· fixed in both themes
The same segment unlit — a VFD shows you the segments it isn't using.
--danger
—· fixed in both themes
The close circle on hover, and every destructive action that borrowed it — Finder's delete, Settings' danger zone.
--ok
—· fixed in both themes
The zoom square on hover, and the copy-not-move badge.
The chrome never takes an accent. A window title bar in the visitor’s blue is a themed application; the same bar in ink with a blue focus ring is a machine that answered them. The accent marks where the interface is responding — focus, a selection, a switch that is on — and nowhere else.
03
Typography
Four faces, each with one job. The body face is the monospace — this is a machine, and it reads like one.
Dot matrix
Doto · wordmark and clock only
KAPPA OS
09:41:07
Family
Doto
Two uses in the whole OS, and no third. It is the machine saying its own name — spend it anywhere else and it stops meaning that.
Label
Geist Mono · UI labels and metadata
Desktop · Projects · 14 items
Modified 12 Aug · 2.4 MB
Size
11px
Transform
uppercase
Tracking
0.14em
Uppercase at 11px sets too tight by default; the tracking is what makes it a label rather than a shout.
Display
Lustria · display copy
The single deliberate touch of warmth.
Family
Lustria
Stretch
95%
Tracking
-0.01em
A serif in an engineered system is a considered exception, and it is kept to display sizes — it never sets a paragraph of interface copy.
Body
Geist Mono · everything else
Body text is the mono face. It is doing the ordinary work: file names, notes, panel copy, this paragraph. Monospace for running text is usually a mistake, and it is the right one here — the whole conceit is that you are reading a machine.
Family
Geist Mono
Sizes
11 / 12 / 13px
Three sizes carry the interface. A fourth is nearly always a layout problem wearing a type solution.
04
Radius
Three radii and one drawn curve. A corner says what kind of object it is, so the set stays small enough to mean something.
Window
.floating
14px
Every floating surface: windows, panels, viewers, the shell.
Card
.card
4px
Content blocks inside a window. Small enough to read as a cut, not a lozenge.
Pill
.pill, .btn
9999px
Controls that are pressed: buttons, switches, the dock, dots.
App icon
SquircleIcon
squircle
A drawn path, not a radius. A rounded corner and this curve disagree by about a pixel at dock size, which was visible when half the icons used each.
05
Elevation
One shadow, three states. It exists to say which window you are talking to, and it is not used for anything else.
Focus states
.floating
The window you are in.
Open, not focused.
Unfocused and slightly see-through — which counts as translucency, so that setting turns it off.
Dark mode gets its own pair of shadows rather than the same ones at a higher opacity. A shadow is the absence of light, and on a near-black canvas there is very little to take away — the light-mode values simply disappear.
06
Motion
Quick and mechanical. No bounce, no spring, 60–240ms. If an animation draws attention to itself, it is wrong.
Every duration in the system
window-in
140ms · linear
A window opening: 6px of travel and a fade.
page-in
120ms · linear
A document arriving inside a window that is already open — half the travel, because it is the smaller event.
Button
120ms · linear
Background on hover, opacity on the solid variant.
Dock item
120ms · linear
The 3px lift under the cursor.
Switch
150ms · default
Track colour and knob travel together.
Elevation
240ms · ease
A window's shadow deepening as it takes focus. The slowest thing here, because it is the one nobody is waiting on.
Screensaver in
700ms · ease-out
The machine going quiet. The one deliberate exception — it is the only transition that isn't answering a gesture.
window-in, live
07
Components
These are the live imports from the OS, not reproductions. Three copies of the same markup is how the traffic lights drifted apart the first time.
Traffic lights
TrafficLights.tsx
Close is a circle, minimise a downward triangle, zoom a square. At rest the outlines sit in --ink-faint at 40%, so the cluster recedes into the titlebar; hover it and all three colour at once, because the hover group is the row rather than the mark. Unavailable lights render per inert: hidden, blank (the shape, uncoloured) or dim (own colour at 30%).
Window chrome
Window.tsx
14px radius, no border, a hairline under the title bar, and the focused shadow. Every floating surface in the OS is this same frame.
Switch
SettingsPanel.tsx
The off track is ink at 18%, not a grey — it has to stay visible on both the card and the canvas, and a fixed grey can only manage one of them.
Buttons
Pill radius throughout. The solid variant fades on hover rather than shifting colour, because it is already ink and there is nowhere darker to go.
App icons
SquircleIcon.tsx
Solid ink, thin line glyphs, and the squircle path rather than a border radius. The corner reaches 34% along each edge, and anything sitting concentrically around an icon derives its own radius from that instead of guessing.
Cards and pills
Card
4px, no border
Pill
Raised control
Neither carries a line. The card is a tone step down, the pill a tone step up — that difference is the whole elevation model outside window chrome.
08
Stacking
One z-order, and a fixed set of bands above it. Every floating surface takes its z from nextZ() and calls it again on focus, so clicking anything brings it to the front.
Reserved bands
Every floating surface
100+
Windows, Finder, viewers, panels — all from nextZ(), all re-stamped on focus.
Context menus and their scrim
6000 / 6001
The dock
7000
Above menus, which is why a menu anchors to the top of the dock pill rather than to the pointer.
Drag ghosts
9000
An icon mid-drag has left the stack it came from.
Modal dialogs
9500
The blue screen, cover games
9990
Pretending to have stopped covers everything…
The screensaver
9995
…resting covers that…
The boot screen
10000
…and only starting up outranks resting.
Never invent a separate band. A viewer that gave itself its own range is what made the SNAP window unable to rise above a photo — both were “on top”, of different things.
09
Sound
Feedback, never decoration. Seven cues cover the whole OS, all synthesised at runtime — there are no audio files in the project.
The vocabulary
Click to play
A window opens.
Something is put down.
A drop resolved.
A drop was refused.
A switch changed.
A light touch — clearing a field, a minor control.
The machine is available: the end of boot, and waking.
Reuse this vocabulary rather than adding to it. Seven sounds a visitor can learn is a language; twelve they can’t is furniture noise. Volume and mute are governed globally from Settings, so these respect whatever the OS is set to.
10
Exceptions
Two surfaces are allowed their own idiom, and a third would be a decision to argue for rather than to assume.
Tunes
Skeuomorphic
A late-80s deck rendered as a physical object rather than a document: brushed aluminium, an amber VFD, milled grooves, keys that travel a pixel under the finger. The unlit segments are drawn behind the lit ones — showing you the segments it isn’t using is most of what makes a VFD read as one.
kappash
Phosphor
kappash 1.0
> COLOR AMBER
>
A phosphor tube: green on black, scanlines, bloom, a block cursor sitting on the character it will overwrite. The visitor sets its finish from the shell itself, because how a device’s screen is set up answers to the person using it and not to the desktop theme.
Both keep their finish in both themes, because a real device doesn’t repaint itself when the desktop theme flips. Both stop at the content edge — the window around them is the ordinary OS chrome. Neither idiom leaks anywhere else.