Skip to content

Design lessons learned

What the Space Works build got wrong, how it was fixed, and the rule that came out of each fix. It is written for the people building the other Space Works apps (web, Android, iOS, sibling apps) so they can skip the mistakes we already paid for.

Most of the pain was colour in light and dark. A palette that looks right in one theme quietly fails in the other: teal that reads well on cream is nearly invisible on black, a pastel pill that is calm on cream glares on black, a hairline that frames a card on cream disappears on black. So most of this page is about colour. The rest covers type, motion, components and the process that keeps all of it from drifting.

How to read a lesson. Each one has a Problem (what went wrong), a Rule, the Values involved, how it is Enforced (a test, guard or file) and a Source (commit hash in the app repo SpaceWorks or in this design repo, or a decision number from the build’s decisions ledger). Where a rule is derived from the tokens rather than from a shipped fix, the lesson says so.

Words used here.

  • Token: a named colour (for example panel) instead of a hex value typed into a screen.
  • Contrast ratio: the WCAG number from 1 to 21 for how far apart two colours are. Text needs 4.5 or more; icons, borders and focus rings need 3 or more.
  • Ink: a colour meant for text and small marks (for example accent-ink). A fill is a colour meant for a filled background, with its own label colour (on-accent).
  • Soft: a quiet, opaque tinted background (for example success-soft).

All hex values come from tokens/tokens.json. Ratios were computed with the WCAG formula from those values.


One row per role. Ratios are measured against the background named in the last column. “n/a” means the colour is not meant to be read against that background. Mobile apps should use these exact values (convert to the platform colour type) and not re-derive them.

Role Light Dark Light ratio Dark ratio Measured against
Page background (bg) #FFF4E8 #000000 n/a n/a the page itself
Surface #F6ECE0 #0B0B0B 1.08 1.07 bg (a layer step, not text)
Panel (cards) #FFFFFF #141414 1.08 1.14 bg
Hover #EFE6DB #1C1C1C 1.14 1.23 bg
Line (hairline, decorative) #D5D0C6 #2C2C2C 1.42 1.50 bg (1.54 / 1.32 on panel)
Outline (control edge) #828A83 #787878 3.27 4.76 bg (3.55 / 4.17 on panel)
Text (ink) #142C2A #FFF4E8 13.60 19.36 bg (14.75 / 16.98 on panel)
Muted text #5B6863 #ACACAC 5.37 9.25 bg (5.83 / 8.12 on panel)
Accent fill (accent) #006E63 #006E63 5.68 3.41 bg (6.16 / 2.99 on panel); never carry meaning alone in dark
Label on accent (on-accent) #FFF4E8 #FFF4E8 5.68 5.68 the accent fill
Accent text and small marks (accent-ink) #006E63 #80B1A6 6.16 7.68 panel (5.68 / 8.76 on bg)
Focus ring #006E63 #DFFF8F (Citron) 5.68 18.84 bg (6.16 / 16.53 on panel)
Success fill / label #DFFF8F / #142C2A same 13.23 13.23 the fill
Success text on soft ink #536D49, soft #FBFFF2 ink #E9FCAA, soft #20221B 5.67 14.52 its own soft
Warn fill / label #FFD447 / #142C2A same 10.37 10.37 the fill
Warn text on soft ink #696834, soft #FFFAE9 ink #FFDE77, soft #222017 5.54 12.41 its own soft
Info fill / label #B5CDFF / #142C2A same 9.23 9.23 the fill
Info text on soft ink #51697B, soft #F6F9FF ink #CBD9F8, soft #1E1F22 5.45 11.63 its own soft
Danger (text and fill) #B91C1C #FCA5A5 6.47 9.71 panel (5.96 / 11.06 on bg)
Label on danger fill #FFF4E8 #142C2A 5.96 7.77 the danger fill
Danger card border (danger-line) #FCA5A5 #7C6261 1.90 3.31 panel (decorative)
Emphasis fill (Workshop Orange) #FF7447 #FF7447 2.47 7.84 bg; as a fill only, label #142C2A is 5.51 in both
Emphasis soft #FFEEE9 #221A17 13.11 15.76 text on it (ink)
Sidebar #DFFF8F (Citron) #0B0B0B 13.23 18.14 ink on the sidebar
Sidebar active item #006E63 #006E63 5.68 5.68 on-accent label on it
Scrim (dialog backdrop) #142C2A #000000 n/a n/a see lesson 17
Chart edge (SW-380) #142C2A #FFF4E8 14.75 16.98 panel (12.64 / 18.14 on surface, 13.60 / 19.36 on bg); the mark boundary
Chart fills 1-5 (SW-380) same bright brand colours same 1.11 to 6.16 2.99 to 16.53 panel; fills alone may miss 3:1, the edge carries it
Chart: danger #B91C1C #FCA5A5 6.47 9.71 panel; not a series colour
Loader: box under-face #354845 #66625D 9.70 3.04 panel (8.94 / 3.47 on bg)
Loader: spark #142C2A #FFF4E8 14.75 16.98 panel
Loader: seam #142C2A #000000 14.75 n/a panel; in dark the seam is the page colour on purpose (lesson 24)

Things this table shows at a glance:

  • Dark outline (4.76) is easier to see than light outline (3.27); dark line is barely there (1.5). That is deliberate (lessons 3 and 4).
  • Teal as a fill is 3.41 on black and 2.99 on the dark panel. That is below the 4.5 needed for text, which is why dark text and icons use accent-ink (lesson 5).
  • Orange as text on cream is 2.47, so orange is a fill with a dark label, never text (lesson 12).
  • Every status fill is the same hex in both themes; only the text-on-tint colours change (lessons 9 and 10).