@hegemonart/get-design-done 1.27.7 → 1.28.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/CHANGELOG.md +142 -0
  4. package/SKILL.md +1 -1
  5. package/agents/design-verifier.md +17 -0
  6. package/hooks/gdd-decision-injector.js +149 -3
  7. package/package.json +1 -1
  8. package/reference/accessibility.md +4 -0
  9. package/reference/adr-format.md +96 -0
  10. package/reference/apply-reflections-procedure.md +68 -0
  11. package/reference/architecture-vocabulary.md +102 -0
  12. package/reference/audit-scoring.md +14 -0
  13. package/reference/cache-policy.md +126 -0
  14. package/reference/color-theory.md +279 -0
  15. package/reference/compare-rubric.md +171 -0
  16. package/reference/composition.md +349 -0
  17. package/reference/connections-onboarding.md +417 -0
  18. package/reference/context-md-format.md +106 -0
  19. package/reference/contrast-advanced.md +205 -0
  20. package/reference/darkmode-audit-procedure.md +258 -0
  21. package/reference/debug-feedback-loops.md +119 -0
  22. package/reference/design-procedure.md +304 -0
  23. package/reference/design-system-guidance.md +2 -0
  24. package/reference/discover-procedure.md +204 -0
  25. package/reference/explore-procedure.md +267 -0
  26. package/reference/form-patterns.md +2 -0
  27. package/reference/health-mcp-detection.md +44 -0
  28. package/reference/health-skill-length-report.md +69 -0
  29. package/reference/heuristics.md +84 -0
  30. package/reference/i18n.md +554 -0
  31. package/reference/iconography.md +2 -0
  32. package/reference/milestone-completeness-rubric.md +87 -0
  33. package/reference/motion-interpolate.md +1 -0
  34. package/reference/palette-catalog.md +2 -0
  35. package/reference/peer-cli-protocol.md +161 -0
  36. package/reference/plan-procedure.md +278 -0
  37. package/reference/proportion-systems.md +267 -0
  38. package/reference/registry.json +204 -1
  39. package/reference/registry.schema.json +1 -1
  40. package/reference/router-rules.md +84 -0
  41. package/reference/rtl-cjk-cultural.md +2 -0
  42. package/reference/scan-procedure.md +731 -0
  43. package/reference/shared-preamble.md +78 -6
  44. package/reference/skill-authoring-contract.md +128 -0
  45. package/reference/start-procedure.md +115 -0
  46. package/reference/style-doc-procedure.md +150 -0
  47. package/reference/style-vocabulary.md +2 -0
  48. package/reference/threat-modeling.md +101 -0
  49. package/reference/typography.md +4 -0
  50. package/reference/verify-procedure.md +512 -0
  51. package/reference/visual-hierarchy-layout.md +4 -0
  52. package/scripts/validate-skill-length.cjs +283 -0
  53. package/skills/add-backlog/SKILL.md +1 -0
  54. package/skills/analyze-dependencies/SKILL.md +33 -122
  55. package/skills/apply-reflections/SKILL.md +1 -40
  56. package/skills/audit/SKILL.md +3 -1
  57. package/skills/bandit-status/SKILL.md +31 -66
  58. package/skills/benchmark/SKILL.md +15 -55
  59. package/skills/brief/SKILL.md +12 -1
  60. package/skills/cache-manager/SKILL.md +3 -57
  61. package/skills/check-update/SKILL.md +38 -75
  62. package/skills/compare/SKILL.md +29 -269
  63. package/skills/complete-cycle/SKILL.md +1 -1
  64. package/skills/connections/SKILL.md +21 -427
  65. package/skills/continue/SKILL.md +1 -0
  66. package/skills/darkmode/SKILL.md +32 -287
  67. package/skills/debug/SKILL.md +11 -8
  68. package/skills/design/SKILL.md +27 -245
  69. package/skills/discover/SKILL.md +26 -133
  70. package/skills/discuss/SKILL.md +18 -2
  71. package/skills/explore/SKILL.md +42 -176
  72. package/skills/fast/SKILL.md +1 -0
  73. package/skills/figma-write/SKILL.md +2 -2
  74. package/skills/health/SKILL.md +11 -33
  75. package/skills/help/SKILL.md +1 -0
  76. package/skills/list-assumptions/SKILL.md +1 -0
  77. package/skills/map/SKILL.md +8 -31
  78. package/skills/new-cycle/SKILL.md +3 -1
  79. package/skills/next/SKILL.md +1 -0
  80. package/skills/note/SKILL.md +1 -0
  81. package/skills/optimize/SKILL.md +21 -44
  82. package/skills/pause/SKILL.md +1 -0
  83. package/skills/peer-cli-add/SKILL.md +26 -108
  84. package/skills/peer-cli-customize/SKILL.md +22 -42
  85. package/skills/peers/SKILL.md +33 -57
  86. package/skills/plan/SKILL.md +33 -220
  87. package/skills/plant-seed/SKILL.md +1 -0
  88. package/skills/pr-branch/SKILL.md +1 -0
  89. package/skills/progress/SKILL.md +1 -7
  90. package/skills/quality-gate/SKILL.md +34 -166
  91. package/skills/quick/SKILL.md +1 -0
  92. package/skills/reapply-patches/SKILL.md +1 -0
  93. package/skills/recall/SKILL.md +1 -0
  94. package/skills/resume/SKILL.md +1 -0
  95. package/skills/review-backlog/SKILL.md +1 -0
  96. package/skills/router/SKILL.md +3 -59
  97. package/skills/scan/SKILL.md +36 -675
  98. package/skills/settings/SKILL.md +1 -0
  99. package/skills/ship/SKILL.md +1 -0
  100. package/skills/sketch/SKILL.md +1 -1
  101. package/skills/sketch-wrap-up/SKILL.md +13 -54
  102. package/skills/spike/SKILL.md +1 -1
  103. package/skills/spike-wrap-up/SKILL.md +12 -46
  104. package/skills/start/SKILL.md +13 -112
  105. package/skills/stats/SKILL.md +1 -0
  106. package/skills/style/SKILL.md +18 -140
  107. package/skills/synthesize/SKILL.md +1 -0
  108. package/skills/timeline/SKILL.md +1 -0
  109. package/skills/todo/SKILL.md +1 -0
  110. package/skills/turn-closeout/SKILL.md +36 -56
  111. package/skills/undo/SKILL.md +1 -0
  112. package/skills/update/SKILL.md +1 -0
  113. package/skills/verify/SKILL.md +42 -457
  114. package/skills/warm-cache/SKILL.md +3 -35
  115. package/skills/zoom-out/SKILL.md +26 -0
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: architecture-vocabulary
3
+ type: principles
4
+ version: 1.0.0
5
+ phase: 28.5
6
+ tags: [architecture, ousterhout, module, interface, depth, seam, adapter, leverage, locality]
7
+ last_updated: 2026-05-18
8
+ ---
9
+
10
+ Source: mattpocock/skills (MIT) via Ousterhout, *A Philosophy of Software Design* — adapted with permission. See `../NOTICE` for the full attribution block.
11
+
12
+ # Architecture Vocabulary
13
+
14
+ A shared vocabulary for architectural reasoning across GDD skills. Same words mean the same things across `zoom-out`, `debug`, `analyze-dependencies`, `map`, `quality-gate`, and the planning skills — so agents and humans do not re-litigate "what did you mean by *module*" every conversation. Drawn from John Ousterhout's *A Philosophy of Software Design* via mattpocock's `improve-codebase-architecture/LANGUAGE.md`. GDD design-engineering analogs are surfaced where applicable — a UI component is a module, a design-token API is an interface, a token theme is an adapter.
15
+
16
+ This file is the canonical reference; skills cite it instead of re-defining terms inline.
17
+
18
+ ## Module
19
+
20
+ A unit of code that hides implementation behind an interface. The module's value to its caller is everything inside that the caller no longer has to think about.
21
+
22
+ - A React component is a module — props are the interface, internal state and effects are the implementation.
23
+ - A skill is a module — frontmatter + workflow are the interface, the SKILL.md body is the implementation.
24
+ - See `./design-system-guidance.md` for the design-system-level analog: a component is a module; the token contract is its interface.
25
+
26
+ ## Interface
27
+
28
+ What a module exposes to callers — function signatures, props, return types, error contracts, side-effect promises. The interface is what callers depend on; everything else they must NOT depend on. Small, stable interfaces are the goal.
29
+
30
+ - `function fetchUser(id: string): Promise<User>` is the interface. How `fetchUser` calls the database is implementation.
31
+ - A React component's `props` plus its rendered DOM contract is the interface; useState, useEffect, internal helpers are not.
32
+ - See `./component-authoring.md` (6-principle quality standard, esp. "Minimal API" and "Composability") for the component-library-level analog.
33
+
34
+ ## Implementation
35
+
36
+ What the module hides — the code that does the work. Callers must not depend on it. Implementation is free to change as long as the interface holds.
37
+
38
+ - Switching `fetchUser` from REST to GraphQL without changing the call site = implementation change without interface change. Healthy.
39
+ - Renaming a private helper inside a React component does not break callers. Healthy.
40
+ - Exposing a class's "private" field that callers started reading turns implementation into de-facto interface. Unhealthy — fix by either formalizing the field as interface or stopping the leak.
41
+
42
+ ## Depth
43
+
44
+ A module is **deep** when the interface is simple and the implementation hides genuine complexity. A module is **shallow** when the interface is as complex as the implementation — the wrapper adds no leverage and just shuffles the caller's mental load sideways.
45
+
46
+ - `Array.sort()` is deep — one method name hides ~50 lines of comparison-sort logic plus stable-ordering guarantees.
47
+ - `class Wrapper { getX() { return this.x; } }` is shallow — the wrapper adds no leverage; the caller has to know about `Wrapper` AND `x`.
48
+ - Asymmetry in the caller's favor is the goal. Shallow modules cost the caller mental complexity without paying it back.
49
+ - See `./component-authoring.md` "Minimal API" — a 1-prop `<Image src=... />` that handles preload, lazy load, srcset, blur placeholder, error fallback is the depth principle applied to component design.
50
+
51
+ ## Seam
52
+
53
+ The boundary where two abstractions meet — where one module's interface is consumed by another. Seams are where you can replace one side without touching the other.
54
+
55
+ - **Hypothetical seam.** Only one implementation exists behind the boundary. Nothing yet validates the abstraction is meaningful — the seam is a possibility statement.
56
+ - **Real seam.** Two or more implementations exist; the boundary has been proved load-bearing by actual substitution. The seam is evidence.
57
+ - "One adapter = hypothetical seam; two adapters = real seam." See `## Principles` below.
58
+ - A `fetchUser` function backed only by Postgres is hypothetical; once a test double + a Postgres impl coexist, the seam is real.
59
+
60
+ ## Adapter
61
+
62
+ A module that transforms one interface into another to enable substitution behind a seam. Adapters create seams; the count of distinct adapters approximates the seam's realism.
63
+
64
+ - A Redux-to-Zustand adapter exposes Redux's `store.dispatch` while wrapping a Zustand store underneath — callers keep their Redux API; the implementation moved.
65
+ - A design-token theme is an adapter: it transforms one token contract (`--color-bg`) into specific concrete values (`oklch(98% 0 0)` in light theme, `oklch(15% 0 0)` in dark).
66
+ - An `acp-client` plus an `asp-client` are two adapters over the same "peer-CLI" seam — the second one proves the seam is meaningful (Phase 27).
67
+
68
+ ## Leverage
69
+
70
+ The ratio of work-the-system-does to interface-the-caller-touches. High leverage = high depth = the caller buys a lot of work for a little API. Architectural choices that maximize leverage reduce future cost across all callers.
71
+
72
+ - `<Image />` with a `src` prop that handles preload, lazy load, srcset generation, blur placeholder, error fallback — high leverage from a 1-prop API. Every caller benefits.
73
+ - A 5-prop `<Button variant size leftIcon rightIcon onClick />` that only renders a styled `<button>` — low leverage; the caller is still doing most of the configuration work.
74
+ - Leverage compounds. A high-leverage primitive used by 20 components multiplies the original investment 20×.
75
+
76
+ ## Locality
77
+
78
+ Related changes happen in the same place; unrelated changes do not ripple. Spatial cohesion of the change footprint. Locality is what makes a codebase "easy to modify" — you can find the thing and change just the thing.
79
+
80
+ - Healthy: adding a new chart type touches `chart-types/<new-type>.ts` only.
81
+ - Broken: adding a new chart type touches `chart-types.ts` AND `chart-renderer.ts` AND `chart-config.ts` AND `chart-styles.css` AND `chart-icons.svg`. The system is forcing the author to remember 5 files for a 1-concept change.
82
+ - Test it with the **deletion test** (see `## Principles`) — if removing the feature requires touching the same N files, locality is asymmetric and the abstraction is leaking.
83
+
84
+ ## Principles
85
+
86
+ Three load-bearing rules that operationalize the vocabulary above. Each one is a question you can ask during review.
87
+
88
+ - **Deletion test.** Can you delete the implementation and the interface still tells callers what they could do? If yes, the interface is well-defined and the module is properly encapsulated. If no, the interface is leaking implementation — callers are reaching past the abstraction. Apply this when reviewing a new module: imagine deleting the body; can a reader still describe the surface from the signature alone?
89
+ - **Interface is the test surface.** Tests target the interface; implementation churn does not churn tests. If a refactor that preserves behavior breaks tests, the test was implementation-coupled — fix the test, not the refactor. This is also the diagnostic for whether you have a real interface at all: if you cannot test through it, the interface is too narrow or the implementation is leaking.
90
+ - **One adapter = hypothetical seam; two adapters = real seam.** One substitution is a possibility statement; two substitutions are evidence the boundary is meaningful. Do not over-design seams without ≥2 implementations — the second one teaches you what the seam actually needs. This is YAGNI for boundaries: ship the first impl, extract the seam when the second one arrives.
91
+
92
+ ## How this applies to skill authoring
93
+
94
+ Skills are modules. The frontmatter (`name`, `description`, `tags`) plus the workflow signature is the interface; the SKILL.md body is the implementation. A deep skill has a small, predictable interface (clear when to invoke, clear output shape) hiding genuine workflow value. A shallow skill is one whose body adds little beyond what the frontmatter already implies — those skills should be either deepened or deleted. The skill-authoring contract's 100-line cap is the depth principle applied to skills: if the implementation cannot fit in 100 lines, either the workflow is too broad (split it) or supporting domain content should move to `reference/*.md` (extract-then-link, D-10). See `./skill-authoring-contract.md` for the full spec.
95
+
96
+ ## Cross-references
97
+
98
+ - Design-system-level analog — component-as-module, design-token-as-interface: see `./design-system-guidance.md`.
99
+ - Component-library-level analog — the 6-principle quality standard (Minimal API, Composability, ...): see `./component-authoring.md`.
100
+ - Skill-authoring application — extract-then-link, 100-line cap, refs-one-level-deep: see `./skill-authoring-contract.md`.
101
+ - `CONTEXT.md` glossary format (project-scoped ubiquitous language alongside this vocabulary): see `./context-md-format.md`.
102
+ - ADR format (heavier project-scoped decisions about architectural seams): see `./adr-format.md`.
@@ -234,3 +234,17 @@ Check for (see `reference/checklists.md` Micro-Polish Check gate):
234
234
  - No `transition: all` (BAN-12)
235
235
  - No `will-change: all` (BAN-13)
236
236
  - `prefers-reduced-motion` respected
237
+
238
+ ---
239
+
240
+ ## Lens-Tags (Orthogonal)
241
+
242
+ Tags auditors attach to findings under existing pillars to record cross-cutting dimensions without changing the pillar structure or weights. Same orthogonal pattern as Phase 19.6 `emotion_levels` and `authoring_principles`. Adding a lens-tag does NOT change pillar weights, scoring math, or audit output format — it is a label on an existing finding.
243
+
244
+ ### `composition_alignment`
245
+
246
+ Attach to findings under the Visual Hierarchy pillar that relate to compositional fundamentals (rule of thirds, golden ratio, root rectangles, focal-point construction, visual-weight calculus, optical-vs-mathematical centering, eye-flow patterns). See [`./composition.md`](./composition.md) for the rubric. Does NOT change the pillar weight or score; it is an orthogonal tag on the existing finding.
247
+
248
+ ### `i18n_readiness`
249
+
250
+ Attach to findings under the Accessibility pillar (for WCAG 3.1.1 / 3.1.2 violations) or under the Anti-Pattern Compliance pillar (for hardcoded-string / overflow-at-+40% defects). Emitted by the `agents/design-verifier.md` §i18n probes section (Phase 28-06). See [`./i18n.md`](./i18n.md) §WCAG i18n + §Verifier Integration Spec. Does NOT change pillar weights or scores.
@@ -0,0 +1,126 @@
1
+ ---
2
+ name: cache-policy
3
+ type: heuristic
4
+ version: 1.0.0
5
+ phase: 28.5
6
+ tags: [cache, layer-a, layer-b, sha-256, ttl, warm-cache, cache-manager, anthropic-prompt-cache]
7
+ last_updated: 2026-05-18
8
+ ---
9
+
10
+ # Cache Policy (Layer A + Layer B)
11
+
12
+ Extracted from `skills/cache-manager/SKILL.md` and `skills/warm-cache/SKILL.md` per Phase 28.5
13
+ D-10 (extract-then-link, never delete content). The two skills keep their orchestration
14
+ contracts and step-by-step flows; the deeper algorithmic and operational detail moves here
15
+ so the SKILLs stay under the 100-line cap.
16
+
17
+ The two layers (D-08):
18
+
19
+ - **Layer A** — Anthropic's 5-min prompt cache (owned by `warm-cache`). Keyed on shared-preamble-first prompt prefix. No project-local state.
20
+ - **Layer B** — explicit `.design/cache-manifest.json` (owned by `gdd-cache-manager`). Keyed on deterministic SHA-256 of `(agent-path, sorted-input-file-paths, input-content-hashes)`. Per-repo state.
21
+
22
+ ## Deterministic Input-Hash Algorithm (Layer B)
23
+
24
+ The canonical reference implementation (the single source of truth; `hooks/budget-enforcer.js` imports the same primitive via a shared helper):
25
+
26
+ ```js
27
+ // Deterministic cache-key primitive (reference implementation)
28
+ // hash = SHA-256(
29
+ // agent_path + "\n" +
30
+ // sorted(input_file_paths).join("\n") + "\n" +
31
+ // sorted(input_file_paths)
32
+ // .map(p => sha256(readFileSync(p, "utf8")))
33
+ // .join("\n")
34
+ // )
35
+ const crypto = require('crypto');
36
+ const fs = require('fs');
37
+
38
+ function sha256Hex(s) {
39
+ return crypto.createHash('sha256').update(s, 'utf8').digest('hex');
40
+ }
41
+
42
+ function computeInputHash(agentPath, inputFilePaths) {
43
+ const sortedPaths = [...inputFilePaths].sort();
44
+ const contentHashes = sortedPaths.map(p => {
45
+ try { return sha256Hex(fs.readFileSync(p, 'utf8')); }
46
+ catch { return 'MISSING'; }
47
+ });
48
+ const canonical = [
49
+ agentPath,
50
+ sortedPaths.join('\n'),
51
+ contentHashes.join('\n')
52
+ ].join('\n');
53
+ return sha256Hex(canonical);
54
+ }
55
+ ```
56
+
57
+ Notes for maintainers:
58
+
59
+ - **Sorted-unique paths** — ordering must be stable; caller is expected to de-duplicate. If the same path appears twice the hash still matches as long as caller pre-dedupes before invoking.
60
+ - **Missing file** — the string `MISSING` is used in place of the content hash so a missing dependency doesn't silently collide with an empty file (empty file's SHA-256 is `e3b0c44...`). Missing-file hashes naturally miss on the next read because the real file has a different content hash.
61
+ - **Agent-path** — agents changing their own body (role, tools, output contract) invalidate all their cache entries automatically because the agent file's content is not hashed; but the `agent_path` string is concatenated. Upgrading agents between versions naturally busts the cache only when the path changes. Plan 10.1-04 (shared preamble extraction) is expected to slightly adjust agent bodies — consumers should treat the first post-10.1 run as a full cache miss, which is the intended behavior.
62
+
63
+ ## Manifest Shape (Layer B)
64
+
65
+ See `./config-schema.md` §.design/cache-manifest.json Schema (Phase 10.1) for the authoritative schema. Keyed object, flat SHA-256 hex keys. Example:
66
+
67
+ ```json
68
+ {
69
+ "a3f1e...": {
70
+ "agent": "design-verifier",
71
+ "result": "<base64-or-path>",
72
+ "written_at": "2026-04-18T12:00:00Z",
73
+ "ttl_seconds": 3600,
74
+ "expires_at": "2026-04-18T13:00:00Z"
75
+ }
76
+ }
77
+ ```
78
+
79
+ ## TTL Semantics (Layer B)
80
+
81
+ - Default `ttl_seconds` = `.design/budget.json.cache_ttl_seconds` = 3600s (1 hour) per D-10.
82
+ - `expires_at` is computed at write time and stored; readers do not recompute.
83
+ - Lazy cleanup: stale entries are not actively deleted on read (overhead for no benefit in normal operation). A separate reaper is optional and out of v1 scope.
84
+
85
+ ## Concrete Warm-Cache Command Examples (Layer A)
86
+
87
+ Full invocation:
88
+
89
+ ```
90
+ $ /gdd:warm-cache
91
+
92
+ Warming Anthropic prompt cache for 14 agents (5 min TTL)...
93
+ [1/14] design-verifier ... ok (0.3s)
94
+ [2/14] design-planner ... ok (0.3s)
95
+ [3/14] design-integration-checker ... ok (0.3s)
96
+ ...
97
+ [14/14] design-reflector ... ok (0.3s)
98
+
99
+ ## Warm-cache complete
100
+ - Agents warmed: 14
101
+ - Skipped (no shared preamble import): 3 (agents/README.md not an agent; 2 agents not yet migrated to shared preamble)
102
+ - Duration: 4.2s
103
+ - Next 5 min: repeated spawns of these agents pay cached_input_per_1m rate
104
+ ```
105
+
106
+ Filtered invocation:
107
+
108
+ ```
109
+ $ /gdd:warm-cache --agents design-verifier,design-planner
110
+
111
+ Warming Anthropic prompt cache for 2 agents (filtered from 14)...
112
+ [1/2] design-verifier ... ok (0.3s)
113
+ [2/2] design-planner ... ok (0.3s)
114
+
115
+ ## Warm-cache complete
116
+ - Agents warmed: 2
117
+ - Filtered out by --agents: 12
118
+ - Duration: 0.7s
119
+ ```
120
+
121
+ ## Cost Model (Layer A)
122
+
123
+ - Each no-op Haiku ping: ~50 input tokens (shared preamble + "No-op warm: acknowledge..." system+user) + ~5 output tokens ("ok").
124
+ - At Haiku rates (`./model-prices.md`): `(50 / 1e6) * 1.00 + (5 / 1e6) * 5.00 = $0.00005 + $0.000025 = $0.000075` per agent.
125
+ - 14 agents × $0.000075 = **$0.00105** total for a full warm-cache invocation.
126
+ - Payback: a single subsequent Opus spawn with 40k cached input tokens saves `(40000/1e6) * (15.00 - 1.50) = $0.54`. Warm-cache pays for itself ~500× over on the first repeated planner spawn.
@@ -0,0 +1,279 @@
1
+ ---
2
+ name: color-theory
3
+ type: palette
4
+ version: 1.0.0
5
+ phase: 28
6
+ tags: [color, oklch, harmonies, accessibility, motion]
7
+ last_updated: 2026-05-18
8
+ ---
9
+
10
+ # Color Theory
11
+
12
+ The existing [palette catalog](./palette-catalog.md) gives industry-vertical lookup — read a row, adopt the baseline tokens, ship. This file gives the underlying model so an agent can reason about color *before* applying it: which color space to author in, how to construct a harmony that holds together under motion and across viewing conditions, how surrounding context shifts perception, which hue pairs collapse under common color-blindness, and why default sRGB interpolation produces muddy mid-transitions in animation. Where the catalog says "shift the primary hue ±15°", this file replaces that hand-wave with explicit OKLCH ΔL/ΔC/Δh guidance.
13
+
14
+ This is the file an agent should consult any time it is *constructing* color — picking a new palette, generating a harmony, animating a color, or auditing a contrast pair under the color-blindness lens.
15
+
16
+ ---
17
+
18
+ ## Color Spaces — sRGB / HSL / OKLCH / LCH
19
+
20
+ Color is not one thing. Every "color" lives in some color space, and every color space makes a trade between three concerns: device gamut (what monitors can actually display), authoring ergonomics (what a human can predict from the numbers), and perceptual uniformity (whether equal numeric jumps produce equal perceived jumps). Choosing the wrong space costs hours of token tweaking and produces palettes that drift under interpolation.
21
+
22
+ ### sRGB
23
+
24
+ sRGB is the device-coordinate space — three channels (`r`, `g`, `b`), each `0–255` or `0–1`, mapped onto the standard-monitor gamut defined by IEC 61966-2-1 (1996). It models *what the monitor emits*, not *what the eye perceives*. Equal numeric jumps are not equal perceptual jumps: stepping `rgb(50 50 50)` → `rgb(100 100 100)` looks like a much larger lightness change than `rgb(200 200 200)` → `rgb(250 250 250)`, even though both are a +50 step. Use sRGB only at the output layer (final compiled CSS), not as the authoring space for a palette.
25
+
26
+ ### HSL
27
+
28
+ HSL was the first authoring-friendly attempt: three channels (`h` 0–360°, `s` 0–100%, `l` 0–100%) that decompose color into hue, saturation, and lightness — the dimensions a human reasons in. The catch: HSL's `l` is *not* perceptual lightness. `hsl(60 100% 50%)` (pure yellow) and `hsl(240 100% 50%)` (pure blue) both have `l: 50%`, but yellow looks vastly brighter than blue at identical `l`. This means a design instruction like "shift hue 30°, hold lightness constant" can produce wildly different perceived lightnesses across hue ranges. HSL is fine for quick mental math; it is wrong for token-system construction.
29
+
30
+ ### OKLCH
31
+
32
+ OKLCH is the modern authoring default: three channels (`L` 0–1 perceptual lightness, `C` 0–~0.4 chroma, `h` 0–360°), built on the Oklab perceptual color space (Ottosson, 2020). Three properties make it the right choice for design tokens:
33
+
34
+ 1. **Perceptual uniformity in L.** `oklch(0.6 0 0)` and `oklch(0.6 0.2 240)` have the same perceived lightness, regardless of hue. "Hold lightness constant while shifting hue" finally means what it says.
35
+ 2. **Independent C and h axes.** Adjusting chroma does not drift lightness; rotating hue does not drift either. Token systems become predictable.
36
+ 3. **Wide-gamut aware.** OKLCH expresses Display-P3 and Rec.2020 colors that sRGB cannot represent, while remaining a single authoring space.
37
+
38
+ Browser support: CSS Color Module 4 `oklch(L C H)` shipped in Safari 15.4, Chrome 111, Firefox 113 — already production-safe for token authoring with sRGB fallback.
39
+
40
+ ### LCH
41
+
42
+ LCH (CIE Lab-based) is OKLCH's older sibling: same three-axis structure (`L`, `C`, `h`), built on the 1976 CIE L*a*b* color space. It is perceptually uniform but has well-documented hue-rotation kinks in the blue range — straight-line hue interpolation through LCH visibly bends toward purple. OKLCH was specifically designed to fix this. Use LCH only when matching an existing print or video pipeline; otherwise prefer OKLCH.
43
+
44
+ ### Concrete CSS — the same color in four spaces
45
+
46
+ Using `#1A56DB` from the FinTech/Banking row of [./palette-catalog.md](./palette-catalog.md) as the authoritative primary:
47
+
48
+ ```css
49
+ /* The same color, four spaces. Author in OKLCH; output sRGB for fallback. */
50
+ .primary-srgb { color: rgb(26 86 219); } /* device coordinates */
51
+ .primary-hsl { color: hsl(222 81% 48%); } /* hue/sat/light, non-perceptual L */
52
+ .primary-oklch { color: oklch(0.488 0.215 263.5); } /* perceptual L, predictable C and h */
53
+ .primary-lch { color: lch(38 71 290); } /* legacy perceptual, blue-rotation kink */
54
+ ```
55
+
56
+ ```css
57
+ /* Token-system pattern — author OKLCH, ship sRGB fallback in the same declaration. */
58
+ :root {
59
+ --color-primary: #1A56DB; /* sRGB fallback */
60
+ --color-primary: oklch(0.488 0.215 263.5); /* OKLCH wins where supported */
61
+ }
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Color Harmonies
67
+
68
+ All six harmonies expressed in OKLCH — adjust hue offset while holding `L` and `C` constant for perceptual stability. The hue offset is what defines the harmony; the lightness and chroma stay anchored so the relationship reads as a *family*, not a collision.
69
+
70
+ ### Complementary
71
+
72
+ Two hues separated by 180°. Maximum hue contrast, used for accent pairs and dual-action layouts.
73
+
74
+ Formula: `h + 180°`, hold `L` and `C` constant.
75
+
76
+ ```css
77
+ /* Base from FinTech row of ./palette-catalog.md (primary navy + complementary amber accent). */
78
+ :root {
79
+ --primary: oklch(0.488 0.215 263.5); /* navy */
80
+ --complementary: oklch(0.488 0.215 83.5); /* amber, +180° */
81
+ }
82
+ ```
83
+
84
+ ### Analogous
85
+
86
+ Three hues at small offsets — typically 30°. Reads as a single mood with internal modulation; ideal for backgrounds, illustrations, and gentle gradients.
87
+
88
+ Formula: `[h - 30°, h, h + 30°]`, hold `L` and `C` constant.
89
+
90
+ ```css
91
+ /* Base from Healthcare row of ./palette-catalog.md (clinical green + neighbors). */
92
+ :root {
93
+ --analog-a: oklch(0.65 0.15 132); /* yellow-green */
94
+ --analog-b: oklch(0.65 0.15 162); /* green (anchor) */
95
+ --analog-c: oklch(0.65 0.15 192); /* teal */
96
+ }
97
+ ```
98
+
99
+ ### Triadic
100
+
101
+ Three hues evenly spaced 120° apart. High visual energy, balanced — used for playful brand systems and category color coding.
102
+
103
+ Formula: `[h, h + 120°, h + 240°]`, hold `L` and `C` constant.
104
+
105
+ ```css
106
+ /* Base anchored on the SaaS/B2B row periwinkle of ./palette-catalog.md. */
107
+ :root {
108
+ --triad-a: oklch(0.6 0.18 280); /* periwinkle */
109
+ --triad-b: oklch(0.6 0.18 40); /* warm coral, +120° */
110
+ --triad-c: oklch(0.6 0.18 160); /* fresh green, +240° */
111
+ }
112
+ ```
113
+
114
+ ### Split-complement
115
+
116
+ A base hue plus the two hues flanking its complement (180° ± 30°). Retains complementary tension without the dual-action visual collision; the workhorse harmony for dashboards and content-heavy product surfaces.
117
+
118
+ Formula: `[h, h + 150°, h + 210°]`, hold `L` and `C` constant.
119
+
120
+ ```css
121
+ /* Base from the Developer Tools row of ./palette-catalog.md (near-black + warm pair). */
122
+ :root {
123
+ --split-base: oklch(0.6 0.16 260); /* cool blue */
124
+ --split-a: oklch(0.6 0.16 50); /* warm amber, base + 150° */
125
+ --split-b: oklch(0.6 0.16 110); /* lime green, base + 210° */
126
+ }
127
+ ```
128
+
129
+ ### Tetradic
130
+
131
+ Four hues forming a rectangle on the hue wheel — two complementary pairs offset from each other. Very rich; demands one dominant hue and three accents at lower chroma to avoid noise.
132
+
133
+ Formula: `[h, h + 60°, h + 180°, h + 240°]`, hold `L` and `C` constant.
134
+
135
+ ```css
136
+ /* Base anchored on the Gaming/Entertainment row of ./palette-catalog.md (violet primary). */
137
+ :root {
138
+ --tetra-a: oklch(0.55 0.2 300); /* violet (dominant) */
139
+ --tetra-b: oklch(0.55 0.12 0); /* red-magenta, +60° (accent, reduced chroma) */
140
+ --tetra-c: oklch(0.55 0.12 120); /* green, +180° (accent) */
141
+ --tetra-d: oklch(0.55 0.12 180); /* teal, +240° (accent) */
142
+ }
143
+ ```
144
+
145
+ ### Monochromatic
146
+
147
+ One hue, varied only in `L` and/or `C`. Reads as a single material expressed across light and dark surfaces. The natural pattern for elevation systems and dense data displays.
148
+
149
+ Formula: hold `h` constant; vary `L` across `0.95 → 0.15` for a 9-step scale; optionally taper `C` near the L extremes (high `C` collapses to neutral as `L → 1` or `L → 0`).
150
+
151
+ ```css
152
+ /* Base from the Luxury/Fashion row of ./palette-catalog.md (near-black scale). */
153
+ :root {
154
+ --mono-50: oklch(0.97 0.005 270);
155
+ --mono-200: oklch(0.88 0.02 270);
156
+ --mono-400: oklch(0.7 0.04 270);
157
+ --mono-600: oklch(0.5 0.06 270);
158
+ --mono-800: oklch(0.3 0.05 270);
159
+ --mono-950: oklch(0.15 0.02 270);
160
+ }
161
+ ```
162
+
163
+ ### When to use which
164
+
165
+ - **Single brand voice, calm:** monochromatic or analogous.
166
+ - **Two clear actions (primary vs. destructive):** complementary.
167
+ - **Three-category coding (status: ok / warn / error):** triadic.
168
+ - **Dashboard with one hero accent + supporting hues:** split-complement.
169
+ - **Editorial / illustrative / rich brand:** tetradic — but reduce chroma on three of the four hues.
170
+ - **Token system primarily expressing depth, not category:** monochromatic, scaled across `L`.
171
+
172
+ ---
173
+
174
+ ## Simultaneous Contrast and Warm-Cool Effects
175
+
176
+ Color is never seen in isolation. The eye continuously normalizes color relative to its surround — a phenomenon Josef Albers documented exhaustively in *Interaction of Color* (1963) and which the perceptual literature calls *simultaneous contrast*. The same OKLCH value placed against a darker surround reads *lighter and more saturated* than placed against a lighter surround; against a complementary surround, hue itself shifts. Token-level lesson: a contrast ratio measured against pure white at design time is not the contrast a user perceives at runtime in a card-on-card-on-background layout.
177
+
178
+ ```css
179
+ /* Same foreground token, two surrounds. The same token reads as a different color. */
180
+ .fg-on-light {
181
+ background: oklch(0.97 0.01 270); /* near-white surround */
182
+ color: oklch(0.6 0.15 30); /* warm coral — appears darker and richer */
183
+ }
184
+ .fg-on-dark {
185
+ background: oklch(0.18 0.02 270); /* near-black surround */
186
+ color: oklch(0.6 0.15 30); /* same OKLCH — appears lighter and more luminous */
187
+ }
188
+ ```
189
+
190
+ Warm-cool effects are simultaneous contrast's spatial cousin. Warm hues (red through yellow, OKLCH `h` roughly 0–90°) read as *advancing* — they appear closer to the viewer; cool hues (green through blue, OKLCH `h` roughly 140–270°) read as *receding*. Place a warm accent against a cool field and the accent leaps forward; reverse the relationship and the same hue retreats. Use this deliberately: warm accents pull the eye to primary actions and selected states; cool accents recede appropriately for ambient information, hover states, and large background fields where you do not want the surface competing for attention.
191
+
192
+ ---
193
+
194
+ ## Color-Blindness — Deutan / Protan / Tritan
195
+
196
+ Color-vision deficiency is common — roughly 8% of males and 0.5% of females of Northern European descent have some form. The three clinical types collapse different hue pairs:
197
+
198
+ - **Deutan** (deuteranomaly / deuteranopia, ~6% of males — the most common): reduced green sensitivity. Confuses red-green pairs at similar lightness, and green-brown at similar saturation.
199
+ - **Protan** (protanomaly / protanopia, ~1% of males): reduced red sensitivity. Confuses red-green pairs; reds appear darker than to typical vision.
200
+ - **Tritan** (tritanomaly / tritanopia, very rare, <0.01%): reduced blue sensitivity. Confuses blue-yellow pairs and blue-green pairs.
201
+
202
+ Token-level guidance:
203
+
204
+ 1. **Never encode status with red/green alone at similar `L`.** A red-green status pair where both tokens sit at `oklch(0.6 …)` is invisible to a deutan viewer. Either separate `L` by at least 0.15, or distinguish with an icon/shape.
205
+ 2. **Prefer hue pairs separated by ≥ 120° in OKLCH `h` for category coding.** Red (`h ≈ 30°`) vs. blue (`h ≈ 260°`) is ~230° apart and reads reliably across all three types. Red (`h ≈ 30°`) vs. green (`h ≈ 140°`) is only ~110° apart and collapses under deutan.
206
+ 3. **Test the destructive / success pair under deutan simulation.** If a deutan filter renders them indistinguishable, raise their lightness contrast.
207
+ 4. **Add a non-color carrier.** Icons, underlines, bold weight, position — color must never be the *only* differentiator (WCAG 1.4.1, Use of Color).
208
+
209
+ A good starting palette is the **Wong 8-color CB-safe palette** (Bang Wong, *Nature Methods* 2011) — designed for scientific visualization to remain distinguishable under all three CVD types. Concrete OKLCH approximations of three of its colors for direct use in a token system:
210
+
211
+ ```css
212
+ /* Three of the 8 Wong CB-safe palette colors, approximated in OKLCH. */
213
+ :root {
214
+ --cb-blue: oklch(0.55 0.13 240); /* Wong "blue" — #0072B2 */
215
+ --cb-orange: oklch(0.74 0.15 60); /* Wong "orange" — #E69F00 */
216
+ --cb-green: oklch(0.58 0.13 160); /* Wong "bluish green" — #009E73 */
217
+ }
218
+ ```
219
+
220
+ See [./accessibility.md](./accessibility.md) for the WCAG intersection — color must not be the only differentiator (WCAG 1.4.1), and the chosen pair must still satisfy 4.5:1 body-text and 3:1 UI-element contrast thresholds at any combination used.
221
+
222
+ ---
223
+
224
+ ## Color Interpolation in Animation
225
+
226
+ Animating from one color to another is interpolation across a color space, and the choice of space changes what the user sees mid-transition. When CSS animates `background-color` from red to green in default sRGB, the midpoint becomes muddy gray — sRGB's interpolation path crosses the desaturated valley between hues, dragging chroma toward 0 at the midpoint. The same animation in OKLCH walks a perceptually-clean arc along the hue wheel, preserving chroma and lightness across the transition. The user never sees gray.
227
+
228
+ ```css
229
+ /* BAD — default interpolation space is sRGB. Red → green midpoint is muddy gray. */
230
+ .bad {
231
+ background: red;
232
+ transition: background-color 600ms ease;
233
+ }
234
+ .bad:hover { background: green; }
235
+ ```
236
+
237
+ ```css
238
+ /* GOOD — explicit OKLCH interpolation. Red → green midpoint stays chromatic. */
239
+ .good {
240
+ background: oklch(0.6 0.22 25); /* red in OKLCH */
241
+ transition: background-color 600ms ease; /* honored when --start/--end are OKLCH */
242
+ }
243
+ .good:hover { background: oklch(0.6 0.22 145); } /* green in OKLCH, same L and C */
244
+ ```
245
+
246
+ ```css
247
+ /* GOOD — explicit interpolation space via color-mix(in oklch, …). */
248
+ .fade {
249
+ background: color-mix(in oklch, oklch(0.6 0.22 25) 50%, oklch(0.6 0.22 145));
250
+ /* The 50% midpoint is a clean chromatic yellow-green, not gray. */
251
+ }
252
+ ```
253
+
254
+ ```css
255
+ /* GOOD — CSS Color Module 4 explicit interpolation hint on a gradient. */
256
+ .bar {
257
+ background: linear-gradient(in oklch to right, oklch(0.6 0.22 25), oklch(0.6 0.22 145));
258
+ }
259
+ ```
260
+
261
+ Lab-based interpolation (`in lab` or `in oklab`) is also chromatically clean and is the right choice when matching a print pipeline; OKLCH is the right choice for everything else because hue stays on the perceptual wheel and lightness stays steady. Avoid `in hsl` for cross-hue interpolation — it inherits HSL's non-perceptual lightness and produces lightness drift across hue families.
262
+
263
+ Practical defaults:
264
+
265
+ - **Same-hue intensity changes** (e.g., disabled → enabled, hover): any space is acceptable; OKLCH is still preferred for predictability.
266
+ - **Cross-hue transitions** (status changes, theme swaps, brand-moment flourishes): mandate `in oklch` or `color-mix(in oklch, …)`. Default sRGB is the muddy-mid bug.
267
+ - **Dark-mode swap animations**: mandate `in oklch` for the same reason — sRGB midpoints across the L extremes are visibly grayed.
268
+
269
+ See [./motion-interpolate.md](./motion-interpolate.md) for the cross-system motion-interpolation discipline that owns interpolation rules across spaces (timing, easing, value mapping). That file owns the interpolation rules; this section owns the color-specific reasoning.
270
+
271
+ ---
272
+
273
+ ## Cross-References
274
+
275
+ - [./palette-catalog.md](./palette-catalog.md) — industry-vertical lookup table; this file replaces its Step 4 "shift hue ±15°" instruction with explicit OKLCH ΔL/ΔC/Δh guidance and supplies the underlying color-space model.
276
+ - [./motion-interpolate.md](./motion-interpolate.md) — cross-system motion-interpolation discipline; this file's §Color Interpolation in Animation links out to it for the broader interpolation rules.
277
+ - [./accessibility.md](./accessibility.md) — WCAG 2.1 thresholds; this file's §Color-Blindness section intersects with WCAG 1.4.1 (Use of Color) and 1.4.3 (Contrast Minimum).
278
+
279
+ Reciprocal inbound cross-links land in Phase 28-06 (additive-only, D-06) — the other files will gain pointers back to this one without altering their existing content.