0023: Paper is the look, in light and dark

On this page

Status: accepted; its type is replaced by 0066, its port of the website's boards by 0068, and the website's motion by 0069

Context

Patch Bay gave Short Leash a dark, rack-gear look: graphite panels, amber and cyan lamps, Recursive throughout. The app only had its light variant when macOS was in light mode, and the website was dark only. Everything used one sans-serif voice, so screens had little hierarchy beyond size and weight. We wanted a calmer, more editorial look with a proper light theme, without losing what makes Short Leash recognizable.

Decision

  • Two themes from one set of tokens. Paper is warm paper (#f5f2ed) with graphite ink (#1b2330). Ink, the dark theme, is deep graphite (#11161e) with light grays. The --dk-* tokens in packages/design-tokens keep their names and take these values, and text passes 4.5:1 in both. Terminals and code blocks use a graphite set (--dk-code-*) in both themes.
  • Appearance follows the system by default.
    • In the app, Settings › Appearance offers Match system, Light and Dark. It's stored as appearance in [preferences] in config.toml. Every window applies it with data-theme on <html>, and the shell sets the native theme, so title bars and menus match.
    • On the website, the footer offers System, Light and Dark. The choice is kept in the browser as starlight-theme, the same setting the docs' theme menu uses, so one choice covers the landing page and the docs.
  • Type. Titles use Newsreader (SIL Open Font License), weight 400, self-hosted from Fontsource like Recursive. Every other word, body text included, uses Recursive with MONO at 1 and CASL at 0. Identifiers no longer need a different face to stand out: they're shown in ink with tabular figures.
  • Shapes. Buttons, filters and tabs are pills, with one primary (ink) pill per view. Fields have a 12 px radius, rows 16, menus 14, panels 20, dialogs 24 and website cards 32. Hairlines separate things. Only floating layers (menus, popovers, dialogs, toasts) and app windows shown on the website cast a shadow.
  • What stays.
    • The logo.
    • The lamp grammar: filled amber = running, hollow ring = stopped, cyan lamp and wire = shared, red lamp and message = failed.
    • The share wire.
    • Sentence case and the copy rules.
  • Motion. The app keeps its five moments: the share wire, the boot sequence, row expand, the switch throw and copy confirmation. The website adds its schematic's boot and wire, pane fades, <details> expanding and short scroll reveals. Everything honors prefers-reduced-motion.
  • Designs first. Every screen and page has a board on the "Short Leash — Paper UI" Design canvas. The website's landing, Terms and Privacy pages are still generated from their boards by apps/web/scripts/port-boards.py.

Consequences

  • The app and the website match the system's light or dark setting with no setup, and either can be fixed to one.
  • Every screen changed at once, so screenshots in older posts and issues no longer match. The docs' screenshots were retaken.
  • Newsreader adds one variable font file (about 130 KB for Latin, with optical sizes), cached like Recursive. It's only used for titles.
  • Mono body text is denser than proportional text. Long pages keep generous line height to stay readable.
  • The proxy's own pages (stopped, nothing served here) can't load Short Leash's fonts, so they use the system's serif and monospace with Paper's colors.