Principles

Star on GitHubFeedback

Principles

Five rules. When an item is in doubt, it asks these, in this order.

  1. Silence is structure. Space does the layout. A hairline appears only where space alone can't hold two things apart.
  2. Type is the only ornament. Weight, width, size, tracking and order carry every level of hierarchy. No icons, fills or shadows.
  3. Ours in roman, yours in italic. Interface text is the voice, upright. Anything the person chose, typed or set turns into the expression italic: a picked option, a typed value, a switch state, a slider value, a named item they own. Display uses --ot-expression-scale; text uses the same face in its reading grade, with more ink, a little air and a text-size optical cut where available. Musical and foreign terms are italic too (.ot-term), by book convention.
  4. One note of colour. One accent marks where you are: the current page, the chosen option, focus. At most one accent mark in view. Crimson is only for errors. The highlighter is only for reading marks.
  5. Nothing moves unless you do. Motion answers an action, then rests. Pointing sketches in pencil; choosing inks it in. The overture plays once per browser, on the home page's first visit, and can be skipped. A demonstration of a component waits for a Demonstrate press. The owner-approved exceptions (2026-10-01) are marquee, text-ribbon and word-relay autoplay: each is pausable and off under reduced motion.

The measure

Silence starts at the line. Drag its edge, or focus it and use the arrow keys: body text reads best between forty-five and seventy-five characters.

A line that runs too long loses the eye on its way back to the next one, and a line that runs too short breaks the sentence before it can breathe. Somewhere between them the reading goes quiet: you stop noticing the lines and only hear what they say. 0nlyType sets its body text there, at sixty-two characters, and leaves the rest of the page to space.

Conventions

  • Tokens are --ot-*. Component classes are ot-<name>.
  • States live on native attributes (:checked, :disabled, [aria-selected], [aria-invalid], [aria-current], [aria-pressed], [aria-busy]). Variants live on data-variant, and size on data-size.
  • [data-force~="hover"] and [data-force~="focus"] pin a state for documentation rows.
  • Every control is built on the right native element, so the React port can use native elements or Radix without changing the look.
  • Four switches on <html>, all optional:
    • data-mode="day | nocturne"
    • data-scheme="blueprint | statue | silence | riso" (no attribute means cotton)
    • data-key="ultramarine | viridian | ember | violet", which overrides the scheme's accent and is declared last so it always wins
    • data-pair="press | paris | salon" (no attribute means parma)
  • One creative move per component, and only one, drawn from the poster references (see "Where each move comes from"). Likewise one motion per component, named as an articulation (see "Motion").
  • [hidden] always wins over a component's display.
  • Copy: sentence case, active verbs. An action keeps its name through the flow (Upload, Uploading, Uploaded). Errors say what to fix and never apologise.