Tokens

Defined once in TypeScript. The JSON, the CSS custom properties, and the StyleX vars are generated.

Ink to paper. There is no accent.

TokenLightDark
paper#FAF8F2#0E0C0A
ink#1A1A1A#E8E8E8
gray#6B6B6B#949494
dividerrgba(0,0,0,0.08)rgba(255,255,255,0.10)
dividerSubtlergba(0,0,0,0.06)rgba(255,255,255,0.07)
gridLinergba(0,0,0,0.04)rgba(255,255,255,0.05)
tableAltrgba(0,0,0,0.02)rgba(255,255,255,0.03)
controlBorderrgba(0,0,0,0.42)rgba(255,255,255,0.38)

Two grid inks in one family: divider is the stronger step for cell cages and rules; gridLine is the quieter step for the 204 verticals. controlBorder is the one boundary that must reach 3:1, so form controls read on paper and on black. Each scheme also sets color-scheme. The custom property names and the override recipe are in Theming.

StyleSizeWeightTrackingLeading
displayXl52px600-0.035em1.05
display38px600-0.03em1.15
title22px600-0.02em1.3
subhead17px500-0.01em1.5
body15px500-0.01em1.6
label13px600-0.01em1.3

Inter, 500 for body and 600 for headings and labels. Sizes ship in rem with no root font-size pin. The measure is 3 columns, 592px, about 66 characters. Never all caps; labels and eyebrows are sentence case. Reading type multiplies by --text-scale (steps 0.9, 1, 1.1, 1.25, 1.4); chrome stays put.

204px modules: a 184px column and a 20px gutter. Inner pages draw the quiet --grid-line verticals, including the left gutter. Home and About use a stronger --divider cell cage, with --grid-line only on the left and right of the box. Content boxes span whole modules; edges step from grid line to grid line on resize. Up to 6 modules, 1244px.

BreakpointWidthChanges
mobileGrid480pxTwo columns on 25px gutters; --pad 25px
mobileLayout640pxPhone control scale, stacked layouts
rail1024pxDocs rail and the one-module inset
wide1440pxThe airy first module returns on the catalogue
cap1700pxLayout stops growing

One token: --radius-sm (4px), the standalone button radius. Toggles share it. Cards are chrome-square (no frame, 0). Callouts are hairline, radius 0. Nested inners follow Steve Ruiz. Chrome stays 0. Chrome stays 0. Nested corners stay concentric: Steve Ruiz innerRadius, clamped at 0. The rule lives in the kit; it is not a catalogue card.

import { innerRadius, concentricInner, concentricOuter } from "@noorddev/vlak";

innerRadius(28, 16);      // 12
concentricInner(28, 16);  // 12
concentricOuter(12, 16);  // 28

// CSS: --rs-out and --rs-gap; --rs-in is the closed form of the fit.

Desktop: 40px controls, 14px type, 12px labels, 40px hits. At or under 640px: 44px controls, 16px type, 15px labels, 44pt hits. The desktop is the poster; the phone is the hand.

A state the user caused may ease, snap with a short curve, or confirm. Entry is not a show. Color and opacity name the change; nothing bounces. Snap 0.12s, ease 0.2s, confirm 0.16s. Curve cubic-bezier(0.3, 0, 0.2, 1). Under prefers-reduced-motion: looping demos and unsolicited entry disabled under prefers-reduced-motion.

16 viewBox, 1px currentColor, drawn at 12 or 16. 1px currentColor hairline, butt/miter, no rx, no fill; draw at 12 or 16.

import { vlakTokens } from "@noorddev/vlak";

vlakTokens.color.light.paper;         // "#FAF8F2"
vlakTokens.color.light.controlBorder; // "rgba(0,0,0,0.42)"
vlakTokens.grid.module;               // 204

// as JSON
import tokens from "@noorddev/vlak/tokens";

// in StyleX
import { vlak } from "@noorddev/vlak-react/tokens.stylex";

// in the terminal
// npx @noorddev/vlak-cli tokens