BONES Design System
BONES is the design system behind ianbone.com, and it is also a case study about itself. The tokens that style every page are the same tokens documented on this page, compiled through a build step and rendered live in front of you. Now that AI reads code about as fluently as people do, a system that stays legible right down in its source is a system that keeps scaling, and this page is the proof of that.
01/The pipeline
One TypeScript file holds every token. A build step compiles that file into a Tailwind theme, the whole site is styled from that theme, and this page reads the same file again to document itself. That’s four stages running off a single source of truth.
02/Color · 3 scales · 15 semantic · 2 themes
There are two tiers to it. Primitives are the raw tonal scales, so three hues running 50 to 900 with no particular job attached to them yet. The semantic layer is where each token gets a job (text, icon, background, border), and every one of those points back at a primitive and resolves to a different step depending on the theme. Components only ever touch the semantic layer, so flipping the theme repaints the whole system without me editing a single component.
Primitives · tonal scales
Aliases · legacy pigment names → scale
Semantic · text
| Token | Light | Dark | Role |
|---|---|---|---|
| fg | #12261f· pine.800 | #f6f4ee· paper.100 | Primary text. |
| fg-soft | #45564f· pine.400 | #b7c3bd· pine.100 | Secondary text, captions, meta. |
| fg-faint | #617168· pine.300 | #94a69f· pine.200 | De-emphasised labels and hints. |
| fg-accent | #1e3d36· pine.600 | #d0fe91· lime.300 | Brand-green emphasis — two-tone headlines, hover. |
| on-accent | #12261f· pine.800 | #12261f· pine.800 | Text that sits on an accent fill. |
Semantic · icon
| Token | Light | Dark | Role |
|---|---|---|---|
| icon | #12261f· pine.800 | #f6f4ee· paper.100 | Primary icons. |
| icon-soft | #45564f· pine.400 | #b7c3bd· pine.100 | Secondary icons. |
| icon-faint | #617168· pine.300 | #94a69f· pine.200 | De-emphasised icons. |
| icon-accent | #1e3d36· pine.600 | #d0fe91· lime.300 | Accent icons — markers, arrows. |
Semantic · background
| Token | Light | Dark | Role |
|---|---|---|---|
| surface | #f6f4ee· paper.100 | #142a25· pine.700 | Page background. |
| raised | #fbfaf5· paper.50 | #1e3d36· pine.600 | Cards, insets, anything lifted off the page. |
| accent | #d0fe91· lime.300 | #d0fe91· lime.300 | The single accent — links, markers, primary actions. |
| accent-strong | #b7ec74· lime.400 | #b7ec74· lime.400 | Accent hover / pressed state. |
Semantic · border
| Token | Light | Dark | Role |
|---|---|---|---|
| edge | #ddd8cb· paper.300 | #33514a· pine.500 | Hairline rules and component borders. |
| edge-strong | #c8c1af· paper.400 | #45564f· pine.400 | Emphasised borders — focus, active edges. |
03/Type · 3 roles · 7 steps
Type is grouped by role. Each role commits to one family, so monospace (JetBrains Mono) carries all the structure and sans (Archivo) carries the reading, and its steps hold size, weight, and line-height as tokens. Weight is kept even across the system for now, though the axis is a first-class token on every step, so it’s ready to tune whenever I want to. Every specimen renders at its literal token values.
Good bones
Good bones
Good bones
Good bones
Good bones
Good bones
Good bones
04/Sizing · 0.25rem base unit
One ruler sits underneath every measurement on the site. The size scale is the primitive, so 4px steps with nothing arbitrary thrown in. Spacing and radius are semantic references into that scale, each one named for the job it actually does.
Primitive · size scale
Semantic · spacing
Semantic · radius
05/Grid
- Columns
- Gutter
- Max width
- Margin
- Baseline
Press G to overlay it anywhere
12 columns · 1.5rem gutter
06/Primitives
Pages are built up from a small set of primitives rather than raw utilities, a bit like Lego blocks I can snap together. That’s what keeps the site consistent and the code easy to read, and it holds up whether it’s a person or a model doing the reading.
01/Label
Indexed mono eyebrow — opens every section
Title — mono section heading
Hairline
- MetaRow
07/Components · 4
A design system is more than just its tokens. These are the composable parts built on top of them, and each one ships with a machine-readable spec and gets rendered here in both themes straight from that same source. What you see in the preview is the actual component, and the table and the JSON next to it are its contract, so none of them can drift away from what the site really ships.
Button
ActionThe system's one interactive primitive. Square, monospace, uppercase. Renders as an anchor when `href` is set, a native button otherwise.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'solid' | 'accent' | 'outline' | 'ghost' | 'solid' | Visual weight. solid inverts to the foreground; accent fills with lime; outline is a hairline; ghost is text-only until hover. |
| size | 'sm' | 'md' | 'md' | Padding and type scale. |
| href | string | — | When provided, renders an <a> instead of a <button>. |
| disabled | boolean | false | Disables the native button. |
| children * | ReactNode | — | Button label. |
{ } Machine-readable spec→
{
"name": "Button",
"category": "Action",
"description": "The system's one interactive primitive. Square, monospace, uppercase. Renders as an anchor when `href` is set, a native button otherwise.",
"keywords": [
"button",
"cta",
"action",
"link",
"submit"
],
"props": [
{
"name": "variant",
"type": "'solid' | 'accent' | 'outline' | 'ghost'",
"description": "Visual weight. solid inverts to the foreground; accent fills with lime; outline is a hairline; ghost is text-only until hover.",
"default": "'solid'"
},
{
"name": "size",
"type": "'sm' | 'md'",
"description": "Padding and type scale.",
"default": "'md'"
},
{
"name": "href",
"type": "string",
"description": "When provided, renders an <a> instead of a <button>."
},
{
"name": "disabled",
"type": "boolean",
"description": "Disables the native button.",
"default": "false"
},
{
"name": "children",
"type": "ReactNode",
"description": "Button label.",
"required": true
}
],
"examples": [
{
"label": "Primary",
"code": "<Button>See the work</Button>"
},
{
"label": "Accent",
"code": "<Button variant=\"accent\">Get in touch</Button>"
},
{
"label": "Outline, small",
"code": "<Button variant=\"outline\" size=\"sm\">Résumé ↓</Button>"
},
{
"label": "As link",
"code": "<Button variant=\"ghost\" href=\"/work/\">All work →</Button>"
}
],
"accessibility": [
"Renders a native <button> or <a> — full keyboard and screen-reader support for free.",
"Visible focus ring uses the accent token with a surface-colored offset.",
"Disabled state sets the native disabled attribute, not just styling."
]
}Tag
DisplaySmall monospace chip for disciplines, statuses, and categories. The only component that uses the 2px corner radius; everything else is square.
| Prop | Type | Default | Description |
|---|---|---|---|
| children * | ReactNode | — | Tag label. |
| dot | boolean | false | Draw a small accent dot before the label. |
{ } Machine-readable spec→
{
"name": "Tag",
"category": "Display",
"description": "Small monospace chip for disciplines, statuses, and categories. The only component that uses the 2px corner radius; everything else is square.",
"keywords": [
"tag",
"chip",
"badge",
"label",
"pill"
],
"props": [
{
"name": "children",
"type": "ReactNode",
"description": "Tag label.",
"required": true
},
{
"name": "dot",
"type": "boolean",
"description": "Draw a small accent dot before the label.",
"default": "false"
}
],
"examples": [
{
"label": "Plain",
"code": "<Tag>Design systems</Tag>"
},
{
"label": "With status dot",
"code": "<Tag dot>Shipping</Tag>"
}
],
"accessibility": [
"Non-interactive by default — purely presentational, so it carries no ARIA role.",
"The accent dot is aria-hidden; meaning lives in the text label."
]
}Card
ContainerA lifted surface bounded by a hairline — the system's core container. Optional indexed eyebrow, label, and title; becomes a link when `href` is set.
01/Case study
Unmarked Apparel
01/Case study
Unmarked Apparel
| Prop | Type | Default | Description |
|---|---|---|---|
| index | string | — | Two-digit eyebrow, e.g. "01", rendered in the accent color. |
| label | string | — | Uppercase mono label above the title. |
| title | ReactNode | — | Mono heading. |
| children | ReactNode | — | Card body. |
| href | string | — | Turns the whole card into a link with a hover border. |
{ } Machine-readable spec→
{
"name": "Card",
"category": "Container",
"description": "A lifted surface bounded by a hairline — the system's core container. Optional indexed eyebrow, label, and title; becomes a link when `href` is set.",
"keywords": [
"card",
"surface",
"panel",
"container",
"tile"
],
"props": [
{
"name": "index",
"type": "string",
"description": "Two-digit eyebrow, e.g. \"01\", rendered in the accent color."
},
{
"name": "label",
"type": "string",
"description": "Uppercase mono label above the title."
},
{
"name": "title",
"type": "ReactNode",
"description": "Mono heading."
},
{
"name": "children",
"type": "ReactNode",
"description": "Card body."
},
{
"name": "href",
"type": "string",
"description": "Turns the whole card into a link with a hover border."
}
],
"examples": [
{
"label": "Titled",
"code": "<Card index=\"01\" label=\"Case study\" title=\"Unmarked Apparel\">Brand, storefront, and admin — solo.</Card>"
},
{
"label": "As link",
"code": "<Card href=\"/work/spabreaks/\" title=\"Spabreaks.com\" />"
}
],
"accessibility": [
"When `href` is set the entire card is a single anchor — one focus stop, one predictable target.",
"Hover and focus both shift the border to the foreground token for a clear affordance."
]
}Field
Data entryLabeled text input. Mono label above a square field, accent focus ring, optional hint. Generates and links an id from the label when none is given.
I reply within a day.
I reply within a day.
| Prop | Type | Default | Description |
|---|---|---|---|
| label * | string | — | Mono label, also the accessible name. |
| id | string | — | Field id; defaults to a slug of the label. |
| hint | string | — | Helper or error text below the field. |
| placeholder | string | — | Native placeholder, shown in the faint token. |
{ } Machine-readable spec→
{
"name": "Field",
"category": "Data entry",
"description": "Labeled text input. Mono label above a square field, accent focus ring, optional hint. Generates and links an id from the label when none is given.",
"keywords": [
"field",
"input",
"text",
"form",
"label"
],
"props": [
{
"name": "label",
"type": "string",
"description": "Mono label, also the accessible name.",
"required": true
},
{
"name": "id",
"type": "string",
"description": "Field id; defaults to a slug of the label."
},
{
"name": "hint",
"type": "string",
"description": "Helper or error text below the field."
},
{
"name": "placeholder",
"type": "string",
"description": "Native placeholder, shown in the faint token."
}
],
"examples": [
{
"label": "Basic",
"code": "<Field label=\"Email\" placeholder=\"you@studio.com\" />"
},
{
"label": "With hint",
"code": "<Field label=\"Project\" hint=\"One line is plenty.\" />"
}
],
"accessibility": [
"The <label> is linked to the input via htmlFor/id — clicking the label focuses the field.",
"An id is derived from the label when omitted, so the association never silently breaks.",
"Focus shows both a border shift and an accent ring."
]
}