Foundations
Sixteen grays and two typefaces.
Sixteen grays are the palette. There are three stroke weights, thirteen drawn icons and one kind of change: a press. To try other typefaces, open the themer.
Levels
Sixteen grays, and no more
The palette is sixteen grays, from 0x00 to 0xFF in steps of 0x11, like ink ground with more or less water. Every color in Ink is one of them, and tools/check-stillness.mjs fails anything else. Each mode uses six, so every page keeps one quiet register.
#000000#111111#222222#333333#444444#555555#666666#777777#888888#999999#aaaaaa#bbbbbb#cccccc#dddddd#eeeeee#ffffffSemantic tokens
What each level is for
Components never name a level. They read these, so markup moves between modes untouched.
| Token | Paper | Night | Use |
|---|---|---|---|
--surface-canvas | #eeeeee | #111111 | The page. |
--surface-sunk | #dddddd | #222222 | A recessed area, a code block. |
--text-body | #111111 | #eeeeee | Everything read. Headings too. |
--text-secondary | #444444 | #bbbbbb | Captions and hints. Still 7:1. |
--mark-muted | #777777 | #777777 | Idle marks: leader dots. Never type. |
--rule | #999999 | #555555 | A decorative separator. |
--border-control | #111111 | #eeeeee | The edge of anything you touch. |
--selected-fill | #111111 | #eeeeee | Pressed and selected: the inversion. |
Text clears 7:1 on every ground, which is AAA, so it reads for tired eyes, low vision and any light. Control edges clear 4.5:1 and idle marks 3:1. tools/check-contrast.mjs measures every pair in both modes, at both ranges.
Range
Softened, or full
By default Ink keeps Ahimsa’s law: the ground stops at #eeeeee and the ink at #111111, so there is no glare and no smear. For the strongest contrast, add ink-full to <html> and the grounds open to pure paper and pure ink. Displays that report themselves as grayscale get the full range by themselves.
Paper · softened
Walden
#111111 on #eeeeee
Paper · full
Walden
#000000 on #ffffff
Night · softened
Walden
#eeeeee on #111111
Night · full
Walden
#ffffff on #000000
<html class="ink-paper"> <!-- softened: no glare, no smear -->
<html class="ink-paper ink-full"> <!-- full range: pure paper, pure ink -->Type
The book and the device
Lora · reading · --font-book
Simplicity, simplicity
Lora is a contemporary serif with brushed curves and moderate contrast, steady at reading sizes and warm without fuss. Ink sets it at weight 450 rather than 400, because sixteen-level anti-aliasing thins every stroke a little, and headings at 650.
Paragraphs are indented, not spaced, as in a book. Text is ragged right, hyphenated where the language allows, and runs the full width it is given unless --measure caps it.
Atkinson Hyperlegible Next · operating · --font-ui
Il1 O0 rn m
Buttons, labels, folios and settings. Its letters are drawn to stay distinct at small sizes and low contrast, so a glance is enough.
--size-titleWalden--size-h1Where I Lived--size-h2Solitude--size-h3 / leadThe Pond in Winter--size-bodyI went to the woods because I wished to live deliberately.--size-uiPage 3 of 12--size-captionSaved to your notes--size-labelContentsStrokes
Depth is a rule and a margin
There are no shadows. A surface is separated by a rule, a border or space. Three strokes, never thinner than one pixel.
--stroke 1px · rules and cards--stroke-control 2px · anything you touch--stroke-focus 3px · the focus ringIcons
Drawn on the pixel grid
Twenty-four units, a two-unit stroke on whole coordinates, round caps and joins, and no fills except the dots in contents. At 24px every line lands on a pixel, so it stays crisp. Each icon is symmetric unless the object is not, and each takes its ink from the text around it.
bookbookmarkcheckclosecontentslightmenumoonnextpenprevsearchtype<svg class="ink-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M6 3 H18 V21 L12 16 L6 21 Z"/>
</svg>Change
There is no motion
Press either button. It inverts at once and comes back when you let go. That is the whole vocabulary of change. It has no duration, so there is nothing to watch, only something that happened. There are no motion tokens, and nothing to reduce for reduced motion.