@friedbotstudio/create-baseline 0.1.0

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 (197) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +222 -0
  3. package/bin/cli.js +247 -0
  4. package/obj/template/.claude/agents/swarm-worker.md +52 -0
  5. package/obj/template/.claude/bin/LICENSE +201 -0
  6. package/obj/template/.claude/bin/NOTICE +48 -0
  7. package/obj/template/.claude/commands/approve-spec.md +29 -0
  8. package/obj/template/.claude/commands/approve-swarm.md +27 -0
  9. package/obj/template/.claude/commands/grant-commit.md +19 -0
  10. package/obj/template/.claude/commands/init-project.md +191 -0
  11. package/obj/template/.claude/hooks/artifact_template_guard.sh +141 -0
  12. package/obj/template/.claude/hooks/consent_gate_grant.sh +89 -0
  13. package/obj/template/.claude/hooks/destructive_cmd_guard.sh +42 -0
  14. package/obj/template/.claude/hooks/env_guard.sh +36 -0
  15. package/obj/template/.claude/hooks/git_commit_guard.sh +93 -0
  16. package/obj/template/.claude/hooks/harness_continuation.sh +121 -0
  17. package/obj/template/.claude/hooks/lib/__pycache__/resume_writer.cpython-314.pyc +0 -0
  18. package/obj/template/.claude/hooks/lib/common.sh +328 -0
  19. package/obj/template/.claude/hooks/lib/resume_writer.py +341 -0
  20. package/obj/template/.claude/hooks/lint_runner.sh +55 -0
  21. package/obj/template/.claude/hooks/memory_pre_compact.sh +36 -0
  22. package/obj/template/.claude/hooks/memory_session_start.sh +244 -0
  23. package/obj/template/.claude/hooks/memory_stop.sh +173 -0
  24. package/obj/template/.claude/hooks/plantuml_syntax_guard.sh +161 -0
  25. package/obj/template/.claude/hooks/process_lifecycle_guard.sh +89 -0
  26. package/obj/template/.claude/hooks/setup_guard.sh +50 -0
  27. package/obj/template/.claude/hooks/spec_approval_guard.sh +81 -0
  28. package/obj/template/.claude/hooks/spec_design_calls_guard.sh +183 -0
  29. package/obj/template/.claude/hooks/spec_diagram_presence_guard.sh +141 -0
  30. package/obj/template/.claude/hooks/swarm_approval_guard.sh +39 -0
  31. package/obj/template/.claude/hooks/swarm_boundary_guard.sh +136 -0
  32. package/obj/template/.claude/hooks/tdd_order_guard.sh +176 -0
  33. package/obj/template/.claude/hooks/test_runner.sh +75 -0
  34. package/obj/template/.claude/hooks/tests/fixtures/ac008_byte_equal_reference.txt +12 -0
  35. package/obj/template/.claude/hooks/tests/memory_session_start_test.sh +285 -0
  36. package/obj/template/.claude/hooks/track_guard.sh +127 -0
  37. package/obj/template/.claude/hooks/verify_pass_guard.sh +88 -0
  38. package/obj/template/.claude/memory/README.md +108 -0
  39. package/obj/template/.claude/memory/_pending.md +15 -0
  40. package/obj/template/.claude/memory/_resume.md +12 -0
  41. package/obj/template/.claude/memory/conventions.md +26 -0
  42. package/obj/template/.claude/memory/decisions.md +29 -0
  43. package/obj/template/.claude/memory/landmarks.md +26 -0
  44. package/obj/template/.claude/memory/landmines.md +27 -0
  45. package/obj/template/.claude/memory/libraries.md +27 -0
  46. package/obj/template/.claude/memory/pending-questions.md +28 -0
  47. package/obj/template/.claude/project.json +221 -0
  48. package/obj/template/.claude/settings.json +110 -0
  49. package/obj/template/.claude/skills/archive/SKILL.md +48 -0
  50. package/obj/template/.claude/skills/archive/archive.sh +145 -0
  51. package/obj/template/.claude/skills/audit-baseline/SKILL.md +80 -0
  52. package/obj/template/.claude/skills/audit-baseline/audit.sh +919 -0
  53. package/obj/template/.claude/skills/brd/SKILL.md +44 -0
  54. package/obj/template/.claude/skills/brd/template.md +83 -0
  55. package/obj/template/.claude/skills/chore/SKILL.md +99 -0
  56. package/obj/template/.claude/skills/claude-automation-recommender/LICENSE +202 -0
  57. package/obj/template/.claude/skills/claude-automation-recommender/NOTICE +69 -0
  58. package/obj/template/.claude/skills/claude-automation-recommender/SKILL.md +358 -0
  59. package/obj/template/.claude/skills/claude-automation-recommender/references/hooks-patterns.md +226 -0
  60. package/obj/template/.claude/skills/claude-automation-recommender/references/mcp-servers.md +263 -0
  61. package/obj/template/.claude/skills/claude-automation-recommender/references/plugins-reference.md +98 -0
  62. package/obj/template/.claude/skills/claude-automation-recommender/references/skills-reference.md +408 -0
  63. package/obj/template/.claude/skills/claude-automation-recommender/references/subagent-templates.md +181 -0
  64. package/obj/template/.claude/skills/code-structure/SKILL.md +204 -0
  65. package/obj/template/.claude/skills/commit/SKILL.md +21 -0
  66. package/obj/template/.claude/skills/copywriting/SKILL.md +252 -0
  67. package/obj/template/.claude/skills/copywriting/evals/evals.json +111 -0
  68. package/obj/template/.claude/skills/copywriting/references/ai-writing-detection.md +200 -0
  69. package/obj/template/.claude/skills/copywriting/references/copy-frameworks.md +344 -0
  70. package/obj/template/.claude/skills/copywriting/references/natural-transitions.md +272 -0
  71. package/obj/template/.claude/skills/design-ui/SKILL.md +175 -0
  72. package/obj/template/.claude/skills/design-ui/references/design-vs-development.md +89 -0
  73. package/obj/template/.claude/skills/design-ui/references/intent-table.md +64 -0
  74. package/obj/template/.claude/skills/design-ui/references/orchestration.md +121 -0
  75. package/obj/template/.claude/skills/design-ui/references/state-machine.md +125 -0
  76. package/obj/template/.claude/skills/document/SKILL.md +66 -0
  77. package/obj/template/.claude/skills/documentation/SKILL.md +50 -0
  78. package/obj/template/.claude/skills/harness/SKILL.md +169 -0
  79. package/obj/template/.claude/skills/humanizer/SKILL.md +489 -0
  80. package/obj/template/.claude/skills/humanizer/references/ai-writing-detection.md +208 -0
  81. package/obj/template/.claude/skills/impeccable/PROJECT_NOTES.md +22 -0
  82. package/obj/template/.claude/skills/impeccable/SKILL.md +153 -0
  83. package/obj/template/.claude/skills/impeccable/agents/openai.yaml +4 -0
  84. package/obj/template/.claude/skills/impeccable/reference/adapt.md +190 -0
  85. package/obj/template/.claude/skills/impeccable/reference/animate.md +173 -0
  86. package/obj/template/.claude/skills/impeccable/reference/audit.md +134 -0
  87. package/obj/template/.claude/skills/impeccable/reference/bolder.md +113 -0
  88. package/obj/template/.claude/skills/impeccable/reference/brand.md +104 -0
  89. package/obj/template/.claude/skills/impeccable/reference/clarify.md +174 -0
  90. package/obj/template/.claude/skills/impeccable/reference/cognitive-load.md +106 -0
  91. package/obj/template/.claude/skills/impeccable/reference/color-and-contrast.md +105 -0
  92. package/obj/template/.claude/skills/impeccable/reference/colorize.md +154 -0
  93. package/obj/template/.claude/skills/impeccable/reference/craft.md +138 -0
  94. package/obj/template/.claude/skills/impeccable/reference/critique.md +213 -0
  95. package/obj/template/.claude/skills/impeccable/reference/delight.md +302 -0
  96. package/obj/template/.claude/skills/impeccable/reference/distill.md +111 -0
  97. package/obj/template/.claude/skills/impeccable/reference/document.md +427 -0
  98. package/obj/template/.claude/skills/impeccable/reference/extract.md +70 -0
  99. package/obj/template/.claude/skills/impeccable/reference/harden.md +347 -0
  100. package/obj/template/.claude/skills/impeccable/reference/heuristics-scoring.md +234 -0
  101. package/obj/template/.claude/skills/impeccable/reference/interaction-design.md +195 -0
  102. package/obj/template/.claude/skills/impeccable/reference/layout.md +141 -0
  103. package/obj/template/.claude/skills/impeccable/reference/live.md +513 -0
  104. package/obj/template/.claude/skills/impeccable/reference/motion-design.md +99 -0
  105. package/obj/template/.claude/skills/impeccable/reference/onboard.md +234 -0
  106. package/obj/template/.claude/skills/impeccable/reference/optimize.md +258 -0
  107. package/obj/template/.claude/skills/impeccable/reference/overdrive.md +130 -0
  108. package/obj/template/.claude/skills/impeccable/reference/personas.md +178 -0
  109. package/obj/template/.claude/skills/impeccable/reference/polish.md +232 -0
  110. package/obj/template/.claude/skills/impeccable/reference/product.md +62 -0
  111. package/obj/template/.claude/skills/impeccable/reference/quieter.md +99 -0
  112. package/obj/template/.claude/skills/impeccable/reference/responsive-design.md +114 -0
  113. package/obj/template/.claude/skills/impeccable/reference/shape.md +136 -0
  114. package/obj/template/.claude/skills/impeccable/reference/spatial-design.md +100 -0
  115. package/obj/template/.claude/skills/impeccable/reference/teach.md +137 -0
  116. package/obj/template/.claude/skills/impeccable/reference/typeset.md +124 -0
  117. package/obj/template/.claude/skills/impeccable/reference/typography.md +159 -0
  118. package/obj/template/.claude/skills/impeccable/reference/ux-writing.md +107 -0
  119. package/obj/template/.claude/skills/impeccable/scripts/cleanup-deprecated.mjs +284 -0
  120. package/obj/template/.claude/skills/impeccable/scripts/command-metadata.json +94 -0
  121. package/obj/template/.claude/skills/impeccable/scripts/design-parser.mjs +820 -0
  122. package/obj/template/.claude/skills/impeccable/scripts/detect-csp.mjs +198 -0
  123. package/obj/template/.claude/skills/impeccable/scripts/is-generated.mjs +69 -0
  124. package/obj/template/.claude/skills/impeccable/scripts/live-accept.mjs +465 -0
  125. package/obj/template/.claude/skills/impeccable/scripts/live-browser.js +4684 -0
  126. package/obj/template/.claude/skills/impeccable/scripts/live-inject.mjs +436 -0
  127. package/obj/template/.claude/skills/impeccable/scripts/live-poll.mjs +187 -0
  128. package/obj/template/.claude/skills/impeccable/scripts/live-server.mjs +679 -0
  129. package/obj/template/.claude/skills/impeccable/scripts/live-wrap.mjs +395 -0
  130. package/obj/template/.claude/skills/impeccable/scripts/live.mjs +247 -0
  131. package/obj/template/.claude/skills/impeccable/scripts/load-context.mjs +93 -0
  132. package/obj/template/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  133. package/obj/template/.claude/skills/impeccable/scripts/pin.mjs +214 -0
  134. package/obj/template/.claude/skills/implement/SKILL.md +83 -0
  135. package/obj/template/.claude/skills/intake/SKILL.md +46 -0
  136. package/obj/template/.claude/skills/intake/template.md +61 -0
  137. package/obj/template/.claude/skills/integrate/SKILL.md +62 -0
  138. package/obj/template/.claude/skills/memory-flush/SKILL.md +172 -0
  139. package/obj/template/.claude/skills/memory-flush/sweep.py +286 -0
  140. package/obj/template/.claude/skills/memory-flush/tests/run.sh +327 -0
  141. package/obj/template/.claude/skills/prose/SKILL.md +119 -0
  142. package/obj/template/.claude/skills/rca/SKILL.md +42 -0
  143. package/obj/template/.claude/skills/rca/template.md +83 -0
  144. package/obj/template/.claude/skills/research/SKILL.md +75 -0
  145. package/obj/template/.claude/skills/scenario/SKILL.md +64 -0
  146. package/obj/template/.claude/skills/scout/SKILL.md +72 -0
  147. package/obj/template/.claude/skills/security/SKILL.md +75 -0
  148. package/obj/template/.claude/skills/simplify/SKILL.md +67 -0
  149. package/obj/template/.claude/skills/spec/SKILL.md +69 -0
  150. package/obj/template/.claude/skills/spec/template.md +274 -0
  151. package/obj/template/.claude/skills/spec-diagram-review/SKILL.md +81 -0
  152. package/obj/template/.claude/skills/spec-lint/SKILL.md +55 -0
  153. package/obj/template/.claude/skills/spec-lint/lint.sh +218 -0
  154. package/obj/template/.claude/skills/spec-render/SKILL.md +45 -0
  155. package/obj/template/.claude/skills/spec-render/render.sh +109 -0
  156. package/obj/template/.claude/skills/spec-traceability-review/SKILL.md +72 -0
  157. package/obj/template/.claude/skills/swarm-dispatch/SKILL.md +212 -0
  158. package/obj/template/.claude/skills/swarm-dispatch/swarm_merge.sh +154 -0
  159. package/obj/template/.claude/skills/swarm-plan/SKILL.md +90 -0
  160. package/obj/template/.claude/skills/swarm-plan/validate.sh +181 -0
  161. package/obj/template/.claude/skills/tdd/SKILL.md +100 -0
  162. package/obj/template/.claude/skills/technical-tutorials/SKILL.md +569 -0
  163. package/obj/template/.claude/skills/technical-tutorials/references/audience-context-README.md +53 -0
  164. package/obj/template/.claude/skills/technical-tutorials/references/audience-context.md +246 -0
  165. package/obj/template/.claude/skills/technical-tutorials/references/audience-example.md +175 -0
  166. package/obj/template/.claude/skills/technical-tutorials/references/audience-template.md +152 -0
  167. package/obj/template/.claude/skills/triage/SKILL.md +55 -0
  168. package/obj/template/.claude/skills/verify/SKILL.md +74 -0
  169. package/obj/template/.mcp.json +24 -0
  170. package/obj/template/CLAUDE.md +327 -0
  171. package/obj/template/docs/init/seed.md +585 -0
  172. package/obj/template/manifest.json +214 -0
  173. package/package.json +48 -0
  174. package/src/.mcp.template.json +24 -0
  175. package/src/.npmrc.template +2 -0
  176. package/src/CLAUDE.template.md +327 -0
  177. package/src/agents/swarm-worker.template.md +51 -0
  178. package/src/cli/conflict.js +31 -0
  179. package/src/cli/doctor.js +152 -0
  180. package/src/cli/install.js +93 -0
  181. package/src/cli/io.js +27 -0
  182. package/src/cli/manifest.js +38 -0
  183. package/src/cli/mcp.js +54 -0
  184. package/src/cli/merge.js +107 -0
  185. package/src/cli/plantuml.js +121 -0
  186. package/src/cli/util.js +10 -0
  187. package/src/memory/_pending.template.md +15 -0
  188. package/src/memory/_resume.template.md +12 -0
  189. package/src/memory/conventions.template.md +26 -0
  190. package/src/memory/decisions.template.md +29 -0
  191. package/src/memory/landmarks.template.md +26 -0
  192. package/src/memory/landmines.template.md +27 -0
  193. package/src/memory/libraries.template.md +27 -0
  194. package/src/memory/pending-questions.template.md +28 -0
  195. package/src/project.template.json +221 -0
  196. package/src/seed.template.md +585 -0
  197. package/src/settings.template.json +110 -0
@@ -0,0 +1,159 @@
1
+ # Typography
2
+
3
+ ## Classic Typography Principles
4
+
5
+ ### Vertical Rhythm
6
+
7
+ Your line-height should be the base unit for ALL vertical spacing. If body text has `line-height: 1.5` on `16px` type (= 24px), spacing values should be multiples of 24px. This creates subconscious harmony—text and space share a mathematical foundation.
8
+
9
+ ### Modular Scale & Hierarchy
10
+
11
+ The common mistake: too many font sizes that are too close together (14px, 15px, 16px, 18px...). This creates muddy hierarchy.
12
+
13
+ **Use fewer sizes with more contrast.** A 5-size system covers most needs:
14
+
15
+ | Role | Typical Ratio | Use Case |
16
+ |------|---------------|----------|
17
+ | xs | 0.75rem | Captions, legal |
18
+ | sm | 0.875rem | Secondary UI, metadata |
19
+ | base | 1rem | Body text |
20
+ | lg | 1.25-1.5rem | Subheadings, lead text |
21
+ | xl+ | 2-4rem | Headlines, hero text |
22
+
23
+ Popular ratios: 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth). Pick one and commit.
24
+
25
+ ### Readability & Measure
26
+
27
+ Use `ch` units for character-based measure (`max-width: 65ch`). Line-height scales inversely with line length—narrow columns need tighter leading, wide columns need more.
28
+
29
+ **Non-obvious**: Light text on dark backgrounds needs compensation on three axes, not just one. Bump line-height by 0.05–0.1, add a touch of letter-spacing (0.01–0.02em), and optionally step the body weight up one notch (regular → medium). The perceived weight drops across all three; fix all three.
30
+
31
+ **Paragraph rhythm**: Pick either space between paragraphs OR first-line indentation. Never both. Digital usually wants space; editorial/long-form can justify indent-only.
32
+
33
+ ## Font Selection & Pairing
34
+
35
+ The tactical selection procedure and the reflex-reject list live in [reference/brand.md](brand.md) under **Font selection procedure** and **Reflex-reject list** (loaded for brand-register tasks). The rest of this section covers the adjacent knowledge: anti-reflex corrections, system font use, and pairing rules.
36
+
37
+ ### Anti-reflexes worth defending against
38
+
39
+ - A technical/utilitarian brief does NOT need a serif "for warmth." Most tech tools should look like tech tools.
40
+ - An editorial/premium brief does NOT need the same expressive serif everyone is using right now. Premium can be Swiss-modern, can be neo-grotesque, can be a literal monospace, can be a quiet humanist sans.
41
+ - A children's product does NOT need a rounded display font. Kids' books use real type.
42
+ - A "modern" brief does NOT need a geometric sans. The most modern thing you can do is not use the font everyone else is using.
43
+
44
+ **System fonts are underrated**: `-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui` looks native, loads instantly, and is highly readable. Consider this for apps where performance > personality.
45
+
46
+ ### Pairing Principles
47
+
48
+ **The non-obvious truth**: You often don't need a second font. One well-chosen font family in multiple weights creates cleaner hierarchy than two competing typefaces. Only add a second font when you need genuine contrast (e.g., display headlines + body serif).
49
+
50
+ When pairing, contrast on multiple axes:
51
+ - Serif + Sans (structure contrast)
52
+ - Geometric + Humanist (personality contrast)
53
+ - Condensed display + Wide body (proportion contrast)
54
+
55
+ **Never pair fonts that are similar but not identical** (e.g., two geometric sans-serifs). They create visual tension without clear hierarchy.
56
+
57
+ ### Web Font Loading
58
+
59
+ The layout shift problem: fonts load late, text reflows, and users see content jump. Here's the fix:
60
+
61
+ ```css
62
+ /* 1. Use font-display: swap for visibility */
63
+ @font-face {
64
+ font-family: 'CustomFont';
65
+ src: url('font.woff2') format('woff2');
66
+ font-display: swap;
67
+ }
68
+
69
+ /* 2. Match fallback metrics to minimize shift */
70
+ @font-face {
71
+ font-family: 'CustomFont-Fallback';
72
+ src: local('Arial');
73
+ size-adjust: 105%; /* Scale to match x-height */
74
+ ascent-override: 90%; /* Match ascender height */
75
+ descent-override: 20%; /* Match descender depth */
76
+ line-gap-override: 10%; /* Match line spacing */
77
+ }
78
+
79
+ body {
80
+ font-family: 'CustomFont', 'CustomFont-Fallback', sans-serif;
81
+ }
82
+ ```
83
+
84
+ Tools like [Fontaine](https://github.com/unjs/fontaine) calculate these overrides automatically.
85
+
86
+ **`swap` vs `optional`**: `swap` shows fallback text immediately and FOUT-swaps when the web font arrives. `optional` uses the fallback if the web font misses a small load budget (~100ms) and avoids the shift entirely. Pick `optional` when zero layout shift matters more than seeing the branded font on slow networks.
87
+
88
+ **Preload the critical weight only**: typically the regular-weight body font used above the fold. Preloading every weight costs more bandwidth than it saves.
89
+
90
+ **Variable fonts for 3+ weights or styles**: a single variable font file is usually smaller than three static weight files, gives fractional weight control, and pairs well with `font-optical-sizing: auto`. For 1–2 weights, static is fine.
91
+
92
+ ## Modern Web Typography
93
+
94
+ ### Fluid Type
95
+
96
+ Fluid typography via `clamp(min, preferred, max)` scales text smoothly with the viewport. The middle value (e.g., `5vw + 1rem`) controls scaling rate—higher vw = faster scaling. Add a rem offset so it doesn't collapse to 0 on small screens.
97
+
98
+ **Use fluid type for**: Headings and display text on marketing/content pages where text dominates the layout and needs to breathe across viewport sizes.
99
+
100
+ **Use fixed `rem` scales for**: App UIs, dashboards, and data-dense interfaces. No major app design system (Material, Polaris, Primer, Carbon) uses fluid type in product UI — fixed scales with optional breakpoint adjustments give the spatial predictability that container-based layouts need. Body text should also be fixed even on marketing pages, since the size difference across viewports is too small to warrant it.
101
+
102
+ **Bound your clamp()**: keep `max-size ≤ ~2.5 × min-size`. Wider ratios break the browser's zoom and reflow behaviour and make large viewports feel like the page is shouting.
103
+
104
+ **Scale container width and font-size together** so effective character measure stays in the 45–75ch band at every viewport. A heading that widens faster than its container drifts out of the comfortable measure at the top end.
105
+
106
+ ### OpenType Features
107
+
108
+ Most developers don't know these exist. Use them for polish:
109
+
110
+ ```css
111
+ /* Tabular numbers for data alignment */
112
+ .data-table { font-variant-numeric: tabular-nums; }
113
+
114
+ /* Proper fractions */
115
+ .recipe-amount { font-variant-numeric: diagonal-fractions; }
116
+
117
+ /* Small caps for abbreviations */
118
+ abbr { font-variant-caps: all-small-caps; }
119
+
120
+ /* Disable ligatures in code */
121
+ code { font-variant-ligatures: none; }
122
+
123
+ /* Enable kerning (usually on by default, but be explicit) */
124
+ body { font-kerning: normal; }
125
+ ```
126
+
127
+ Check what features your font supports at [Wakamai Fondue](https://wakamaifondue.com/).
128
+
129
+ ### Rendering polish
130
+
131
+ ```css
132
+ /* Even out heading line lengths (browser picks better break points) */
133
+ h1, h2, h3 { text-wrap: balance; }
134
+
135
+ /* Reduce orphans and ragged endings in long prose */
136
+ article p { text-wrap: pretty; }
137
+
138
+ /* Variable fonts: pick the right optical-size master automatically */
139
+ body { font-optical-sizing: auto; }
140
+ ```
141
+
142
+ **ALL-CAPS tracking**: capitals sit too close at default spacing. Add 5–12% letter-spacing (`letter-spacing: 0.05em` to `0.12em`) to short all-caps labels, eyebrows, and small headings. Real small caps (via `font-variant-caps`) need the same treatment, slightly gentler.
143
+
144
+ ## Typography System Architecture
145
+
146
+ Name tokens semantically (`--text-body`, `--text-heading`), not by value (`--font-size-16`). Include font stacks, size scale, weights, line-heights, and letter-spacing in your token system.
147
+
148
+ ## Accessibility Considerations
149
+
150
+ Beyond contrast ratios (which are well-documented), consider:
151
+
152
+ - **Never disable zoom**: `user-scalable=no` breaks accessibility. If your layout breaks at 200% zoom, fix the layout.
153
+ - **Use rem/em for font sizes**: This respects user browser settings. Never `px` for body text.
154
+ - **Minimum 16px body text**: Smaller than this strains eyes and fails WCAG on mobile.
155
+ - **Adequate touch targets**: Text links need padding or line-height that creates 44px+ tap targets.
156
+
157
+ ---
158
+
159
+ **Avoid**: More than 2-3 font families per project. Skipping fallback font definitions. Ignoring font loading performance (FOUT/FOIT). Using decorative fonts for body text.
@@ -0,0 +1,107 @@
1
+ # UX Writing
2
+
3
+ ## The Button Label Problem
4
+
5
+ **Never use "OK", "Submit", or "Yes/No".** These are lazy and ambiguous. Use specific verb + object patterns:
6
+
7
+ | Bad | Good | Why |
8
+ |-----|------|-----|
9
+ | OK | Save changes | Says what will happen |
10
+ | Submit | Create account | Outcome-focused |
11
+ | Yes | Delete message | Confirms the action |
12
+ | Cancel | Keep editing | Clarifies what "cancel" means |
13
+ | Click here | Download PDF | Describes the destination |
14
+
15
+ **For destructive actions**, name the destruction:
16
+ - "Delete" not "Remove" (delete is permanent, remove implies recoverable)
17
+ - "Delete 5 items" not "Delete selected" (show the count)
18
+
19
+ ## Error Messages: The Formula
20
+
21
+ Every error message should answer: (1) What happened? (2) Why? (3) How to fix it? Example: "Email address isn't valid. Please include an @ symbol." not "Invalid input".
22
+
23
+ ### Error Message Templates
24
+
25
+ | Situation | Template |
26
+ |-----------|----------|
27
+ | **Format error** | "[Field] needs to be [format]. Example: [example]" |
28
+ | **Missing required** | "Please enter [what's missing]" |
29
+ | **Permission denied** | "You don't have access to [thing]. [What to do instead]" |
30
+ | **Network error** | "We couldn't reach [thing]. Check your connection and [action]." |
31
+ | **Server error** | "Something went wrong on our end. We're looking into it. [Alternative action]" |
32
+
33
+ ### Don't Blame the User
34
+
35
+ Reframe errors: "Please enter a date in MM/DD/YYYY format" not "You entered an invalid date".
36
+
37
+ ## Empty States Are Opportunities
38
+
39
+ Empty states are onboarding moments: (1) Acknowledge briefly, (2) Explain the value of filling it, (3) Provide a clear action. "No projects yet. Create your first one to get started." not just "No items".
40
+
41
+ ## Voice vs Tone
42
+
43
+ **Voice** is your brand's personality—consistent everywhere.
44
+ **Tone** adapts to the moment.
45
+
46
+ | Moment | Tone Shift |
47
+ |--------|------------|
48
+ | Success | Celebratory, brief: "Done! Your changes are live." |
49
+ | Error | Empathetic, helpful: "That didn't work. Here's what to try..." |
50
+ | Loading | Reassuring: "Saving your work..." |
51
+ | Destructive confirm | Serious, clear: "Delete this project? This can't be undone." |
52
+
53
+ **Never use humor for errors.** Users are already frustrated. Be helpful, not cute.
54
+
55
+ ## Writing for Accessibility
56
+
57
+ **Link text** must have standalone meaning—"View pricing plans" not "Click here". **Alt text** describes information, not the image—"Revenue increased 40% in Q4" not "Chart". Use `alt=""` for decorative images. **Icon buttons** need `aria-label` for screen reader context.
58
+
59
+ ## Writing for Translation
60
+
61
+ ### Plan for Expansion
62
+
63
+ German text is ~30% longer than English. Allocate space:
64
+
65
+ | Language | Expansion |
66
+ |----------|-----------|
67
+ | German | +30% |
68
+ | French | +20% |
69
+ | Finnish | +30-40% |
70
+ | Chinese | -30% (fewer chars, but same width) |
71
+
72
+ ### Translation-Friendly Patterns
73
+
74
+ Keep numbers separate ("New messages: 3" not "You have 3 new messages"). Use full sentences as single strings (word order varies by language). Avoid abbreviations ("5 minutes ago" not "5 mins ago"). Give translators context about where strings appear.
75
+
76
+ ## Consistency: The Terminology Problem
77
+
78
+ Pick one term and stick with it:
79
+
80
+ | Inconsistent | Consistent |
81
+ |--------------|------------|
82
+ | Delete / Remove / Trash | Delete |
83
+ | Settings / Preferences / Options | Settings |
84
+ | Sign in / Log in / Enter | Sign in |
85
+ | Create / Add / New | Create |
86
+
87
+ Build a terminology glossary and enforce it. Variety creates confusion.
88
+
89
+ ## Avoid Redundant Copy
90
+
91
+ If the heading explains it, the intro is redundant. If the button is clear, don't explain it again. Say it once, say it well.
92
+
93
+ ## Loading States
94
+
95
+ Be specific: "Saving your draft..." not "Loading...". For long waits, set expectations ("This usually takes 30 seconds") or show progress.
96
+
97
+ ## Confirmation Dialogs: Use Sparingly
98
+
99
+ Most confirmation dialogs are design failures—consider undo instead. When you must confirm: name the action, explain consequences, use specific button labels ("Delete project" / "Keep project", not "Yes" / "No").
100
+
101
+ ## Form Instructions
102
+
103
+ Show format with placeholders, not instructions. For non-obvious fields, explain why you're asking.
104
+
105
+ ---
106
+
107
+ **Avoid**: Jargon without explanation. Blaming users ("You made an error" → "This field is required"). Vague errors ("Something went wrong"). Varying terminology for variety. Humor for errors.
@@ -0,0 +1,284 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cleans up deprecated Impeccable skill files, symlinks, and
4
+ * skills-lock.json entries left over from previous versions.
5
+ *
6
+ * Safe to run repeatedly -- it is a no-op when nothing needs cleaning.
7
+ *
8
+ * Usage (from the project root):
9
+ * node {{scripts_path}}/cleanup-deprecated.mjs
10
+ *
11
+ * What it does:
12
+ * 1. Finds every harness-specific skills directory (.claude/skills,
13
+ * .cursor/skills, .agents/skills, etc.).
14
+ * 2. For each deprecated skill name (with and without i- prefix),
15
+ * checks if the directory exists and its SKILL.md mentions
16
+ * "impeccable" (to avoid deleting unrelated user skills).
17
+ * 3. Deletes confirmed matches (files, directories, or symlinks).
18
+ * 4. Removes the corresponding entries from skills-lock.json.
19
+ */
20
+
21
+ import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync, statSync, lstatSync, unlinkSync } from 'node:fs';
22
+ import { join, resolve } from 'node:path';
23
+
24
+ // Skills that were renamed, merged, or folded in v2.0, v2.1, and v3.0.
25
+ const DEPRECATED_NAMES = [
26
+ // v2.0 renames
27
+ 'frontend-design', // renamed to impeccable
28
+ 'teach-impeccable', // folded into /impeccable teach
29
+ // v2.1 merges
30
+ 'arrange', // renamed to layout
31
+ 'normalize', // merged into polish
32
+ 'onboard', // merged into harden
33
+ 'extract', // merged into /impeccable extract
34
+ // v3.0 consolidation: all standalone skills -> /impeccable sub-commands
35
+ 'adapt',
36
+ 'animate',
37
+ 'audit',
38
+ 'bolder',
39
+ 'clarify',
40
+ 'colorize',
41
+ 'critique',
42
+ 'delight',
43
+ 'distill',
44
+ 'harden',
45
+ 'layout',
46
+ 'optimize',
47
+ 'overdrive',
48
+ 'polish',
49
+ 'quieter',
50
+ 'shape',
51
+ 'typeset',
52
+ ];
53
+
54
+ // All known harness directories that may contain a skills/ subfolder.
55
+ const HARNESS_DIRS = [
56
+ '.claude', '.cursor', '.gemini', '.codex', '.agents',
57
+ '.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',
58
+ ];
59
+
60
+ // Per-skill fingerprints for SKILL.md bodies that never mentioned
61
+ // "impeccable" in their v2.x source. Used as a last-resort match
62
+ // when no skills-lock.json exists and the word heuristic fails.
63
+ // The strings are lifted verbatim from the v2.x frontmatter
64
+ // descriptions, so collisions with hand-written user skills are
65
+ // vanishingly unlikely.
66
+ const SKILL_FINGERPRINTS = {
67
+ harden: 'Make interfaces production-ready: error handling, empty states',
68
+ optimize: 'Diagnoses and fixes UI performance across loading speed',
69
+ };
70
+
71
+ /**
72
+ * Walk up from startDir until we find a directory that looks like a
73
+ * project root (has package.json, .git, or skills-lock.json).
74
+ */
75
+ export function findProjectRoot(startDir = process.cwd()) {
76
+ let dir = resolve(startDir);
77
+ const { root } = { root: '/' };
78
+ while (dir !== root) {
79
+ if (
80
+ existsSync(join(dir, 'package.json')) ||
81
+ existsSync(join(dir, '.git')) ||
82
+ existsSync(join(dir, 'skills-lock.json'))
83
+ ) {
84
+ return dir;
85
+ }
86
+ const parent = resolve(dir, '..');
87
+ if (parent === dir) break;
88
+ dir = parent;
89
+ }
90
+ return resolve(startDir);
91
+ }
92
+
93
+ /**
94
+ * Load skills-lock.json from the project root, or null if missing/unreadable.
95
+ */
96
+ export function loadLock(projectRoot) {
97
+ const lockPath = join(projectRoot, 'skills-lock.json');
98
+ if (!existsSync(lockPath)) return null;
99
+ try {
100
+ return JSON.parse(readFileSync(lockPath, 'utf-8'));
101
+ } catch {
102
+ return null;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Check whether a skill directory belongs to Impeccable. Three layered
108
+ * signals, in order of reliability:
109
+ * 1. Lock source equals "pbakaus/impeccable" (authoritative).
110
+ * 2. SKILL.md body contains the word "impeccable".
111
+ * 3. SKILL.md body contains a per-skill fingerprint (for harden and
112
+ * optimize, whose v2.x SKILL.md never mentioned the pack name).
113
+ */
114
+ export function isImpeccableSkill(skillDir, { skillName, lock } = {}) {
115
+ // 1. Authoritative: the lock file claims this skill is ours.
116
+ if (skillName && lock?.skills?.[skillName]?.source === 'pbakaus/impeccable') {
117
+ return true;
118
+ }
119
+ const skillMd = join(skillDir, 'SKILL.md');
120
+ if (!existsSync(skillMd)) return false;
121
+ let content;
122
+ try {
123
+ content = readFileSync(skillMd, 'utf-8');
124
+ } catch {
125
+ return false;
126
+ }
127
+ // 2. Word-level content heuristic.
128
+ if (/impeccable/i.test(content)) return true;
129
+ // 3. Per-skill fingerprint for old skills that never mentioned the pack.
130
+ // Strip the i- prefix so both `harden` and `i-harden` resolve to the
131
+ // same fingerprint entry.
132
+ const unprefixed = skillName?.startsWith('i-') ? skillName.slice(2) : skillName;
133
+ const fingerprint = unprefixed && SKILL_FINGERPRINTS[unprefixed];
134
+ if (fingerprint && content.includes(fingerprint)) return true;
135
+ return false;
136
+ }
137
+
138
+ /**
139
+ * Build the full list of names to check: each deprecated name, plus
140
+ * its i-prefixed variant.
141
+ */
142
+ export function buildTargetNames() {
143
+ const names = [];
144
+ for (const name of DEPRECATED_NAMES) {
145
+ names.push(name);
146
+ names.push(`i-${name}`);
147
+ }
148
+ return names;
149
+ }
150
+
151
+ /**
152
+ * Find every skills directory across all harness dirs in the project.
153
+ * Returns absolute paths that exist on disk.
154
+ */
155
+ export function findSkillsDirs(projectRoot) {
156
+ const dirs = [];
157
+ for (const harness of HARNESS_DIRS) {
158
+ const candidate = join(projectRoot, harness, 'skills');
159
+ if (existsSync(candidate)) {
160
+ dirs.push(candidate);
161
+ }
162
+ }
163
+ return dirs;
164
+ }
165
+
166
+ /**
167
+ * Remove deprecated skill directories/symlinks from all harness dirs.
168
+ * Reads skills-lock.json so the authoritative "source" field can
169
+ * drive deletion even when SKILL.md never mentions impeccable.
170
+ * Returns an array of paths that were deleted.
171
+ */
172
+ export function removeDeprecatedSkills(projectRoot, lock) {
173
+ if (lock === undefined) lock = loadLock(projectRoot);
174
+ const targets = buildTargetNames();
175
+ const skillsDirs = findSkillsDirs(projectRoot);
176
+ const deleted = [];
177
+
178
+ for (const skillsDir of skillsDirs) {
179
+ for (const name of targets) {
180
+ const skillPath = join(skillsDir, name);
181
+
182
+ // Use lstat to detect symlinks (existsSync follows symlinks and
183
+ // returns false for dangling ones).
184
+ let stat;
185
+ try {
186
+ stat = lstatSync(skillPath);
187
+ } catch {
188
+ continue; // does not exist at all
189
+ }
190
+
191
+ if (stat.isSymbolicLink()) {
192
+ // Symlink: check the target if it's alive, otherwise treat
193
+ // dangling symlinks to deprecated names as safe to remove.
194
+ const targetAlive = existsSync(skillPath);
195
+ const isMatch = targetAlive
196
+ ? isImpeccableSkill(skillPath, { skillName: name, lock })
197
+ : true;
198
+ if (isMatch) {
199
+ unlinkSync(skillPath);
200
+ deleted.push(skillPath);
201
+ }
202
+ continue;
203
+ }
204
+
205
+ // Regular directory -- verify it belongs to impeccable
206
+ if (isImpeccableSkill(skillPath, { skillName: name, lock })) {
207
+ rmSync(skillPath, { recursive: true, force: true });
208
+ deleted.push(skillPath);
209
+ }
210
+ }
211
+ }
212
+
213
+ return deleted;
214
+ }
215
+
216
+ /**
217
+ * Remove deprecated entries from skills-lock.json.
218
+ * Only removes entries whose source is "pbakaus/impeccable".
219
+ * Returns the list of removed skill names.
220
+ */
221
+ export function cleanSkillsLock(projectRoot) {
222
+ const lockPath = join(projectRoot, 'skills-lock.json');
223
+ if (!existsSync(lockPath)) return [];
224
+
225
+ let lock;
226
+ try {
227
+ lock = JSON.parse(readFileSync(lockPath, 'utf-8'));
228
+ } catch {
229
+ return [];
230
+ }
231
+
232
+ if (!lock.skills || typeof lock.skills !== 'object') return [];
233
+
234
+ const targets = buildTargetNames();
235
+ const removed = [];
236
+
237
+ for (const name of targets) {
238
+ const entry = lock.skills[name];
239
+ if (!entry) continue;
240
+ // Only remove if it belongs to impeccable
241
+ if (entry.source === 'pbakaus/impeccable') {
242
+ delete lock.skills[name];
243
+ removed.push(name);
244
+ }
245
+ }
246
+
247
+ if (removed.length > 0) {
248
+ writeFileSync(lockPath, JSON.stringify(lock, null, 2) + '\n', 'utf-8');
249
+ }
250
+
251
+ return removed;
252
+ }
253
+
254
+ /**
255
+ * Run the full cleanup. Returns a summary object.
256
+ *
257
+ * Order matters: read the lock and delete directories first, then
258
+ * strip lock entries. Otherwise the authoritative signal is gone by
259
+ * the time directory deletion runs.
260
+ */
261
+ export function cleanup(projectRoot) {
262
+ const root = projectRoot || findProjectRoot();
263
+ const lock = loadLock(root);
264
+ const deletedPaths = removeDeprecatedSkills(root, lock);
265
+ const removedLockEntries = cleanSkillsLock(root);
266
+ return { deletedPaths, removedLockEntries, projectRoot: root };
267
+ }
268
+
269
+ // CLI entry point
270
+ if (process.argv[1] && resolve(process.argv[1]) === resolve(new URL(import.meta.url).pathname)) {
271
+ const result = cleanup();
272
+ if (result.deletedPaths.length === 0 && result.removedLockEntries.length === 0) {
273
+ console.log('No deprecated Impeccable skills found. Nothing to clean up.');
274
+ } else {
275
+ if (result.deletedPaths.length > 0) {
276
+ console.log(`Removed ${result.deletedPaths.length} deprecated skill(s):`);
277
+ for (const p of result.deletedPaths) console.log(` - ${p}`);
278
+ }
279
+ if (result.removedLockEntries.length > 0) {
280
+ console.log(`Cleaned ${result.removedLockEntries.length} entry/entries from skills-lock.json:`);
281
+ for (const name of result.removedLockEntries) console.log(` - ${name}`);
282
+ }
283
+ }
284
+ }
@@ -0,0 +1,94 @@
1
+ {
2
+ "craft": {
3
+ "description": "Full shape-then-build flow with visual iteration. Plans the UX with /impeccable shape, loads the right reference files, then builds and iterates visually until the result is delightful. Use when building a new feature end-to-end.",
4
+ "argumentHint": "[feature description]"
5
+ },
6
+ "teach": {
7
+ "description": "Gathers design context for a project. Runs a short discovery interview and writes PRODUCT.md (strategic: users, brand, principles) and, when code exists to analyze, DESIGN.md (visual: colors, typography, components). Every other command reads these files before doing work. Use once per project.",
8
+ "argumentHint": ""
9
+ },
10
+ "document": {
11
+ "description": "Generate a DESIGN.md file that captures the current visual design system. Auto-extracts colors, typography, spacing, radii, and component patterns from the codebase, then asks the user to confirm descriptive language for atmosphere and color character. Follows the Google Stitch DESIGN.md format so the file is tool-compatible. Use when you need a visual design spec an AI agent can follow to stay on-brand.",
12
+ "argumentHint": ""
13
+ },
14
+ "extract": {
15
+ "description": "Pull reusable patterns, components, and design tokens into the design system. Identifies repeated patterns and consolidates them. Use when you have drift across the codebase and want to bring things back to a consistent system.",
16
+ "argumentHint": "[target]"
17
+ },
18
+ "live": {
19
+ "description": "Interactive live variant mode. Select elements in the browser, pick a design action, and get AI-generated HTML+CSS variants hot-swapped via HMR. Requires a running dev server. Use when you want to visually experiment with design alternatives in real time.",
20
+ "argumentHint": ""
21
+ },
22
+ "adapt": {
23
+ "description": "Adapt designs to work across different screen sizes, devices, contexts, or platforms. Implements breakpoints, fluid layouts, and touch targets. Use when the user mentions responsive design, mobile layouts, breakpoints, viewport adaptation, or cross-device compatibility.",
24
+ "argumentHint": "[target] [context (mobile, tablet, print...)]"
25
+ },
26
+ "animate": {
27
+ "description": "Review a feature and enhance it with purposeful animations, micro-interactions, and motion effects that improve usability and delight. Use when the user mentions adding animation, transitions, micro-interactions, motion design, hover effects, or making the UI feel more alive.",
28
+ "argumentHint": "[target]"
29
+ },
30
+ "audit": {
31
+ "description": "Run technical quality checks across accessibility, performance, theming, responsive design, and anti-patterns. Generates a scored report with P0-P3 severity ratings and actionable plan. Use when the user wants an accessibility check, performance audit, or technical quality review.",
32
+ "argumentHint": "[area (feature, page, component...)]"
33
+ },
34
+ "bolder": {
35
+ "description": "Amplify safe or boring designs to make them more visually interesting and stimulating. Increases impact while maintaining usability. Use when the user says the design looks bland, generic, too safe, lacks personality, or wants more visual impact and character.",
36
+ "argumentHint": "[target]"
37
+ },
38
+ "clarify": {
39
+ "description": "Improve unclear UX copy, error messages, microcopy, labels, and instructions to make interfaces easier to understand. Use when the user mentions confusing text, unclear labels, bad error messages, hard-to-follow instructions, or wanting better UX writing.",
40
+ "argumentHint": "[target]"
41
+ },
42
+ "colorize": {
43
+ "description": "Add strategic color to features that are too monochromatic or lack visual interest, making interfaces more engaging and expressive. Use when the user mentions the design looking gray, dull, lacking warmth, needing more color, or wanting a more vibrant or expressive palette.",
44
+ "argumentHint": "[target]"
45
+ },
46
+ "critique": {
47
+ "description": "Evaluate design from a UX perspective, assessing visual hierarchy, information architecture, emotional resonance, cognitive load, and overall quality with quantitative scoring, persona-based testing, automated anti-pattern detection, and actionable feedback. Use when the user asks to review, critique, evaluate, or give feedback on a design or component.",
48
+ "argumentHint": "[area (feature, page, component...)]"
49
+ },
50
+ "delight": {
51
+ "description": "Add moments of joy, personality, and unexpected touches that make interfaces memorable and enjoyable to use. Elevates functional to delightful. Use when the user asks to add polish, personality, animations, micro-interactions, delight, or make an interface feel fun or memorable.",
52
+ "argumentHint": "[target]"
53
+ },
54
+ "distill": {
55
+ "description": "Strip designs to their essence by removing unnecessary complexity. Great design is simple, powerful, and clean. Use when the user asks to simplify, declutter, reduce noise, remove elements, or make a UI cleaner and more focused.",
56
+ "argumentHint": "[target]"
57
+ },
58
+ "harden": {
59
+ "description": "Make interfaces production-ready: error handling, i18n, text overflow, edge case management, and resilience under real-world data. Use when the user asks to harden, make production-ready, handle edge cases, add error states, or fix overflow and i18n issues.",
60
+ "argumentHint": "[target]"
61
+ },
62
+ "onboard": {
63
+ "description": "Design onboarding flows, first-run experiences, and empty states that guide new users to value. Covers welcome screens, account setup, progressive disclosure, contextual tooltips, feature announcements, and activation moments. Use when the user mentions onboarding, first-time users, empty states, activation, getting started, new user flows, or the aha moment.",
64
+ "argumentHint": "[target]"
65
+ },
66
+ "layout": {
67
+ "description": "Improve layout, spacing, and visual rhythm. Fixes monotonous grids, inconsistent spacing, and weak visual hierarchy. Use when the user mentions layout feeling off, spacing issues, visual hierarchy, crowded UI, alignment problems, or wanting better composition.",
68
+ "argumentHint": "[target]"
69
+ },
70
+ "optimize": {
71
+ "description": "Diagnoses and fixes UI performance across loading speed, rendering, animations, images, and bundle size. Use when the user mentions slow, laggy, janky, performance, bundle size, load time, or wants a faster, smoother experience.",
72
+ "argumentHint": "[target]"
73
+ },
74
+ "overdrive": {
75
+ "description": "Pushes interfaces past conventional limits with technically ambitious implementations — shaders, spring physics, scroll-driven reveals, 60fps animations. Use when the user wants to wow, impress, go all-out, or make something that feels extraordinary.",
76
+ "argumentHint": "[target]"
77
+ },
78
+ "polish": {
79
+ "description": "Performs a final quality pass fixing alignment, spacing, consistency, and micro-detail issues before shipping. Use when the user mentions polish, finishing touches, pre-launch review, something looks off, or wants to go from good to great.",
80
+ "argumentHint": "[target]"
81
+ },
82
+ "quieter": {
83
+ "description": "Tones down visually aggressive or overstimulating designs, reducing intensity while preserving quality. Use when the user mentions too bold, too loud, overwhelming, aggressive, garish, or wants a calmer, more refined aesthetic.",
84
+ "argumentHint": "[target]"
85
+ },
86
+ "shape": {
87
+ "description": "Plan the UX and UI for a feature before writing code. Runs a structured discovery interview, then produces a design brief that guides implementation. Use during the planning phase to establish design direction, constraints, and strategy before any code is written.",
88
+ "argumentHint": "[feature to shape]"
89
+ },
90
+ "typeset": {
91
+ "description": "Improves typography by fixing font choices, hierarchy, sizing, weight, and readability so text feels intentional. Use when the user mentions fonts, type, readability, text hierarchy, sizing looks off, or wants more polished, intentional typography.",
92
+ "argumentHint": "[target]"
93
+ }
94
+ }