get-shit-pretty 0.5.0 → 0.5.2

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 (68) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +1 -1
  3. package/bin/install.js +38 -19
  4. package/gsp/agents/gsp-accessibility-auditor.md +1 -4
  5. package/gsp/agents/gsp-ascii-artist.md +1 -1
  6. package/gsp/agents/gsp-brand-auditor.md +0 -2
  7. package/gsp/agents/gsp-brand-strategist.md +0 -2
  8. package/gsp/agents/gsp-brand-syncer.md +125 -0
  9. package/gsp/agents/gsp-builder.md +11 -14
  10. package/gsp/agents/gsp-campaign-director.md +0 -20
  11. package/gsp/agents/gsp-critic.md +15 -18
  12. package/gsp/agents/gsp-designer.md +6 -6
  13. package/gsp/agents/gsp-identity-designer.md +0 -4
  14. package/gsp/agents/{gsp-system-architect.md → gsp-pattern-architect.md} +5 -67
  15. package/gsp/agents/gsp-project-researcher.md +0 -21
  16. package/gsp/agents/gsp-researcher.md +0 -2
  17. package/gsp/agents/gsp-reviewer.md +4 -14
  18. package/gsp/agents/gsp-scoper.md +1 -22
  19. package/gsp/hooks/hooks.json +11 -0
  20. package/gsp/prompts/01-design-system-architect.md +0 -46
  21. package/gsp/prompts/02-brand-identity-creator.md +1 -14
  22. package/gsp/prompts/03-ui-ux-pattern-master.md +1 -21
  23. package/gsp/prompts/04-marketing-asset-factory.md +1 -14
  24. package/gsp/prompts/05-implementation-spec-expert.md +0 -27
  25. package/gsp/prompts/06-design-critique-partner.md +1 -17
  26. package/gsp/prompts/07-design-trend-synthesizer.md +2 -29
  27. package/gsp/prompts/08-accessibility-auditor.md +4 -19
  28. package/gsp/prompts/09-design-to-code-translator.md +21 -20
  29. package/gsp/prompts/10-project-scoper.md +2 -36
  30. package/gsp/prompts/11-deliverable-reviewer.md +1 -50
  31. package/gsp/prompts/12-project-researcher.md +0 -39
  32. package/gsp/references/anti-patterns.md +173 -0
  33. package/gsp/references/block-patterns.md +135 -0
  34. package/gsp/references/chunk-format.md +31 -0
  35. package/gsp/references/phase-transitions.md +78 -33
  36. package/gsp/references/style-preset-schema.md +63 -0
  37. package/gsp/references/visual-effects.md +475 -0
  38. package/gsp/references/visual-taste.md +120 -0
  39. package/gsp/skills/gsp-accessibility/SKILL.md +1 -1
  40. package/gsp/skills/gsp-brand-audit/SKILL.md +1 -3
  41. package/gsp/skills/gsp-brand-identity/SKILL.md +1 -4
  42. package/gsp/skills/gsp-brand-patterns/SKILL.md +30 -50
  43. package/gsp/skills/gsp-brand-research/SKILL.md +7 -4
  44. package/gsp/skills/gsp-brand-strategy/SKILL.md +1 -4
  45. package/gsp/skills/gsp-brand-sync/SKILL.md +101 -0
  46. package/gsp/skills/gsp-design-system/SKILL.md +1 -1
  47. package/gsp/skills/gsp-doctor/SKILL.md +7 -7
  48. package/gsp/skills/gsp-help/SKILL.md +2 -1
  49. package/gsp/skills/gsp-launch/SKILL.md +2 -3
  50. package/gsp/skills/gsp-project-brief/SKILL.md +7 -22
  51. package/gsp/skills/gsp-project-build/SKILL.md +108 -26
  52. package/gsp/skills/gsp-project-critique/SKILL.md +5 -33
  53. package/gsp/skills/gsp-project-design/SKILL.md +25 -26
  54. package/gsp/skills/gsp-project-research/SKILL.md +8 -17
  55. package/gsp/skills/gsp-project-review/SKILL.md +6 -37
  56. package/gsp/skills/gsp-start/SKILL.md +29 -12
  57. package/gsp/skills/gsp-style/SKILL.md +20 -223
  58. package/gsp/skills/gsp-typescale/SKILL.md +23 -319
  59. package/gsp/skills/gsp-update/SKILL.md +18 -10
  60. package/gsp/templates/branding/brief.md +13 -1
  61. package/gsp/templates/branding/roadmap.md +2 -2
  62. package/gsp/templates/branding/state.md +1 -1
  63. package/gsp/templates/phases/brief.md +1 -1
  64. package/gsp/templates/phases/{system.md → patterns.md} +3 -3
  65. package/gsp/templates/phases/review.md +1 -1
  66. package/package.json +1 -1
  67. package/scripts/gsp-context-recovery.sh +71 -0
  68. package/scripts/gsp-statusline.js +5 -1
@@ -30,13 +30,11 @@ Apply a named style preset to produce production-ready design tokens and foundat
30
30
  @${CLAUDE_SKILL_DIR}/styles/INDEX.yml
31
31
  @${CLAUDE_SKILL_DIR}/../../references/design-tokens.md
32
32
  @${CLAUDE_SKILL_DIR}/../../references/chunk-format.md
33
- @${CLAUDE_SKILL_DIR}/../../templates/phases/system.md
33
+ @${CLAUDE_SKILL_DIR}/../../templates/phases/patterns.md
34
34
  </execution_context>
35
35
 
36
36
  <rules>
37
37
  - Always use `AskUserQuestion` for user interaction — never prompt via plain text
38
- - Presets are the source of truth — expand tokens deterministically, don't improvise values
39
- - Foundation chunks follow `references/chunk-format.md` format exactly
40
38
  - `tokens.json` follows W3C Design Tokens format from `references/design-tokens.md`
41
39
  - When mixing styles, later style values override earlier ones (last-wins precedence)
42
40
  - Never mix clashing styles — check the compatibility matrix first
@@ -163,18 +161,18 @@ Determine where to write the system output:
163
161
 
164
162
  ### Within a brand
165
163
  If a brand context exists (`.design/branding/{brand}/`):
166
- - Write to `{BRAND_PATH}/system/`
167
- - This replaces the system phase of the branding diamond
164
+ - Write to `{BRAND_PATH}/patterns/`
165
+ - This replaces the patterns phase of the branding diamond
168
166
 
169
167
  ### Within a project (quick mode)
170
168
  If invoked from a project context (`.design/projects/{project}/`):
171
169
  - Check if a `brand.ref` exists pointing to a brand with a completed system
172
- - If no brand system exists, write to `.design/branding/_style-{preset-name}/system/`
170
+ - If no brand system exists, write to `.design/branding/_style-{preset-name}/patterns/`
173
171
  - Create a minimal brand directory with just the system output
174
172
  - Update the project's `brand.ref` to point to this auto-generated brand
175
173
 
176
174
  ### Standalone (no .design/ context)
177
- - Write to `.design/branding/_style-{preset-name}/system/`
175
+ - Write to `.design/branding/_style-{preset-name}/patterns/`
178
176
  - Create minimal brand directory structure
179
177
 
180
178
  ## Step 5: Preview mode (`--preview`)
@@ -221,226 +219,25 @@ Stop here. Do not write any files.
221
219
 
222
220
  Transform the YAML preset tokens into the full W3C Design Tokens JSON structure.
223
221
 
224
- ### Color tokens
225
- Map preset colors to the W3C structure with `$value` and `$type` fields:
226
-
227
- ```json
228
- {
229
- "color": {
230
- "brand": {
231
- "primary": { "$value": "{preset.color.primary}", "$type": "color" },
232
- "secondary": { "$value": "{preset.color.secondary}", "$type": "color" },
233
- "accent": { "$value": "{preset.color.accent}", "$type": "color" }
234
- },
235
- "semantic": {
236
- "background": { "$value": "{preset.color.background}", "$type": "color" },
237
- "surface": { "$value": "{preset.color.surface}", "$type": "color" },
238
- "on-primary": { "$value": "{preset.color.on-primary}", "$type": "color" },
239
- "on-background": { "$value": "{preset.color.on-background}", "$type": "color" },
240
- "error": { "$value": "{preset.color.error}", "$type": "color" },
241
- "success": { "$value": "{preset.color.success}", "$type": "color" },
242
- "warning": { "$value": "{preset.color.warning}", "$type": "color" },
243
- "info": { "$value": "{preset.color.info}", "$type": "color" }
244
- }
245
- }
246
- }
247
- ```
248
-
249
- ### Typography tokens
250
- ```json
251
- {
252
- "font": {
253
- "family": {
254
- "primary": { "$value": "{preset.typography.font-family-primary}", "$type": "fontFamily" },
255
- "mono": { "$value": "{preset.typography.font-family-mono}", "$type": "fontFamily" }
256
- }
257
- },
258
- "typography": {
259
- "display": {
260
- "$value": {
261
- "fontFamily": "{font.family.primary}",
262
- "fontSize": "48px",
263
- "fontWeight": "{preset.typography.font-weight-heading}",
264
- "lineHeight": 1.1,
265
- "letterSpacing": "-0.02em"
266
- },
267
- "$type": "typography"
268
- },
269
- "heading-1": {
270
- "$value": {
271
- "fontFamily": "{font.family.primary}",
272
- "fontSize": "36px",
273
- "fontWeight": "{preset.typography.font-weight-heading}",
274
- "lineHeight": 1.2,
275
- "letterSpacing": "-0.01em"
276
- },
277
- "$type": "typography"
278
- },
279
- "heading-2": {
280
- "$value": {
281
- "fontFamily": "{font.family.primary}",
282
- "fontSize": "28px",
283
- "fontWeight": "{preset.typography.font-weight-heading}",
284
- "lineHeight": 1.3,
285
- "letterSpacing": "0"
286
- },
287
- "$type": "typography"
288
- },
289
- "heading-3": {
290
- "$value": {
291
- "fontFamily": "{font.family.primary}",
292
- "fontSize": "22px",
293
- "fontWeight": "{preset.typography.font-weight-heading}",
294
- "lineHeight": 1.4,
295
- "letterSpacing": "0"
296
- },
297
- "$type": "typography"
298
- },
299
- "body-large": {
300
- "$value": {
301
- "fontFamily": "{font.family.primary}",
302
- "fontSize": "18px",
303
- "fontWeight": "{preset.typography.font-weight-body}",
304
- "lineHeight": "{preset.typography.line-height-base}",
305
- "letterSpacing": "0"
306
- },
307
- "$type": "typography"
308
- },
309
- "body": {
310
- "$value": {
311
- "fontFamily": "{font.family.primary}",
312
- "fontSize": "{preset.typography.font-size-base}",
313
- "fontWeight": "{preset.typography.font-weight-body}",
314
- "lineHeight": "{preset.typography.line-height-base}",
315
- "letterSpacing": "0"
316
- },
317
- "$type": "typography"
318
- },
319
- "body-small": {
320
- "$value": {
321
- "fontFamily": "{font.family.primary}",
322
- "fontSize": "14px",
323
- "fontWeight": "{preset.typography.font-weight-body}",
324
- "lineHeight": "{preset.typography.line-height-base}",
325
- "letterSpacing": "0"
326
- },
327
- "$type": "typography"
328
- },
329
- "caption": {
330
- "$value": {
331
- "fontFamily": "{font.family.primary}",
332
- "fontSize": "12px",
333
- "fontWeight": "{preset.typography.font-weight-body}",
334
- "lineHeight": 1.4,
335
- "letterSpacing": "0.01em"
336
- },
337
- "$type": "typography"
338
- },
339
- "overline": {
340
- "$value": {
341
- "fontFamily": "{font.family.primary}",
342
- "fontSize": "11px",
343
- "fontWeight": 600,
344
- "lineHeight": 1.5,
345
- "letterSpacing": "0.08em"
346
- },
347
- "$type": "typography"
348
- }
349
- }
350
- }
351
- ```
352
-
353
- ### Spacing tokens
354
- Generate from the preset's spacing scale:
355
-
356
- ```json
357
- {
358
- "spacing": {
359
- "xs": { "$value": "4px", "$type": "dimension" },
360
- "sm": { "$value": "8px", "$type": "dimension" },
361
- "md": { "$value": "16px", "$type": "dimension" },
362
- "lg": { "$value": "24px", "$type": "dimension" },
363
- "xl": { "$value": "32px", "$type": "dimension" },
364
- "2xl": { "$value": "48px", "$type": "dimension" },
365
- "3xl": { "$value": "64px", "$type": "dimension" },
366
- "4xl": { "$value": "96px", "$type": "dimension" }
367
- }
368
- }
369
- ```
222
+ ### Token expansion mapping
370
223
 
371
- ### Shadow tokens
372
- Map preset elevation values to W3C shadow format. Parse the CSS shadow shorthand from the preset into the structured format:
373
-
374
- ```json
375
- {
376
- "shadow": {
377
- "sm": { "$value": "{parsed from preset.elevation.shadow-sm}", "$type": "shadow" },
378
- "md": { "$value": "{parsed from preset.elevation.shadow-md}", "$type": "shadow" },
379
- "lg": { "$value": "{parsed from preset.elevation.shadow-lg}", "$type": "shadow" },
380
- "xl": { "$value": "{parsed from preset.elevation.shadow-xl}", "$type": "shadow" }
381
- }
382
- }
383
- ```
224
+ Transform each YAML preset section into W3C Design Tokens JSON with `$value` and `$type` fields:
384
225
 
385
- ### Border radius tokens
386
- ```json
387
- {
388
- "radius": {
389
- "none": { "$value": "0px", "$type": "dimension" },
390
- "sm": { "$value": "{preset.shape.border-radius-sm}", "$type": "dimension" },
391
- "md": { "$value": "{preset.shape.border-radius-md}", "$type": "dimension" },
392
- "lg": { "$value": "{preset.shape.border-radius-lg}", "$type": "dimension" },
393
- "full": { "$value": "9999px", "$type": "dimension" }
394
- }
395
- }
396
- ```
226
+ | Preset section | Token path | $type | Notes |
227
+ |---------------|------------|-------|-------|
228
+ | `color.*` | `color.brand.{key}`, `color.semantic.{key}` | `color` | Split into brand (primary, secondary, accent) and semantic (background, surface, on-primary, on-background, error, success, warning, info) |
229
+ | `typography.*` | `font.family.{primary,mono}` | `fontFamily` | — |
230
+ | `typography.*` | `typography.{level}` | `typography` | Composite: fontFamily, fontSize, fontWeight, lineHeight, letterSpacing. 9 levels: display, heading-1 through heading-3, body-large, body, body-small, caption, overline |
231
+ | `spacing.*` | `spacing.{xs,sm,md,lg,xl,2xl,3xl,4xl}` | `dimension` | — |
232
+ | `elevation.*` | `shadow.{sm,md,lg,xl}` | `shadow` | Parse CSS shadow shorthand into structured format |
233
+ | `shape.*` | `radius.{none,sm,md,lg,full}` | `dimension` | `full` = 9999px |
234
+ | `motion.*` | `motion.duration.{fast,normal}`, `motion.easing.default` | `duration`, `cubicBezier` | — |
397
235
 
398
- ### Style-specific token groups
399
- If the preset has extra token groups (e.g., `glass` for glassmorphism, `glow` for cyberpunk, `gradient` for vaporwave, `syntax` for terminal), include them under an `$extensions` key:
400
-
401
- ```json
402
- {
403
- "$extensions": {
404
- "gsp-style": "{preset-name}",
405
- "gsp-style-specific": {
406
- // style-specific tokens preserved as-is from the preset
407
- }
408
- }
409
- }
410
- ```
236
+ **Style-specific tokens:** If preset has extra groups (e.g., `glass`, `glow`, `gradient`, `syntax`), include under `$extensions.gsp-style-specific`.
411
237
 
412
- ### Dark mode
413
- If the preset has a `dark_mode` section, include it under `$extensions.dark`:
414
-
415
- ```json
416
- {
417
- "$extensions": {
418
- "dark": {
419
- "color": {
420
- "semantic": {
421
- "background": { "$value": "{preset.dark_mode.color.background}" },
422
- "surface": { "$value": "{preset.dark_mode.color.surface}" }
423
- }
424
- }
425
- }
426
- }
427
- }
428
- ```
238
+ **Dark mode:** If preset has `dark_mode` section, include under `$extensions.dark` with semantic color overrides.
429
239
 
430
- ### Motion tokens
431
- ```json
432
- {
433
- "motion": {
434
- "duration": {
435
- "fast": { "$value": "{preset.motion.duration-fast}", "$type": "duration" },
436
- "normal": { "$value": "{preset.motion.duration-normal}", "$type": "duration" }
437
- },
438
- "easing": {
439
- "default": { "$value": "{preset.motion.easing}", "$type": "cubicBezier" }
440
- }
441
- }
442
- }
443
- ```
240
+ **Extensions metadata:** Always include `$extensions.gsp-style` with the preset name.
444
241
 
445
242
  ## Step 7: Write tokens.json
446
243
 
@@ -507,7 +304,7 @@ Write `{OUTPUT_PATH}/INDEX.md`:
507
304
  ## Step 10: Update state
508
305
 
509
306
  If a brand STATE.md exists at the brand path:
510
- - Set system phase status to `complete`
307
+ - Set patterns phase status to `complete`
511
308
  - Record style preset name and completion date
512
309
  - Set Prettiness Level to 60% (foundations only, no components)
513
310
 
@@ -34,15 +34,12 @@ Generate a production-ready typography system with fluid responsive sizing, vert
34
34
 
35
35
  <rules>
36
36
  - Always use `AskUserQuestion` for user interaction — never prompt via plain text
37
- - Scales are deterministic — same inputs always produce the same output
38
37
  - Foundation chunks follow `references/chunk-format.md` format exactly
39
38
  - All sizes include px, rem, AND fluid clamp() values for headings
40
39
  - Line heights snap to a 4px grid for vertical rhythm (body 24px = 6 × 4px)
41
40
  - Letter spacing follows the size-dependent curve: negative for large type, positive for small type, wide for all-caps (see reference)
42
- - When loading from a style preset, extract only typography-related tokens
43
41
  - CSS output defaults to Tailwind v4 / shadcn format unless `--vanilla` is passed
44
42
  - WCAG 2.2 AA compliance: body line-height ≥ 1.5, layout must survive SC 1.4.12 text spacing overrides
45
- - Fluid type clamp() must always use rem-based min/max — never pure vw (breaks zoom per WCAG 1.4.4)
46
43
  </rules>
47
44
 
48
45
  <process>
@@ -291,133 +288,17 @@ If a brand context exists (`.design/branding/{brand}/`):
291
288
 
292
289
  Write `{OUTPUT_PATH}/typography.md` as a foundation chunk per `references/chunk-format.md`:
293
290
 
294
- ```markdown
295
- # Typography
291
+ The typography.md chunk must include these sections with calculated values from Step 3:
296
292
 
297
- > Phase: identity | Brand: {name} | Generated: {DATE}
298
-
299
- ---
300
-
301
- ## Font Families
302
-
303
- | Role | Family | Variable | Source | Fallback stack |
304
- |------|--------|----------|--------|----------------|
305
- | Primary | {family} | {yes/no} | Google Fonts | {system fallbacks} |
306
- | Secondary | {family or "—"} | {yes/no} | {source} | {system fallbacks} |
307
- | Monospace | {family or "Geist Mono"} | {yes/no} | Google Fonts | ui-monospace, monospace |
308
-
309
- **Google Fonts URL:**
310
- `https://fonts.googleapis.com/css2?family={primary}:wght@{weights}&family={mono}:wght@400;700&display=swap`
311
-
312
- **Self-hosting recommended** for production — eliminates third-party DNS lookup, improves GDPR compliance, and allows precise subsetting. Use WOFF2 only.
313
-
314
- **Performance budget:** < 100KB total font weight, 2-3 weights max. If using a variable font, a single file replaces all static weights (< 150KB).
315
-
316
- ## Type Scale
317
-
318
- Base: {base}px | Ratio: {ratio} ({ratio name}) | Grid: {grid}px
319
-
320
- | Level | px | rem | Fluid | Weight | Line height | Letter spacing | Tailwind |
321
- |-------|----|-----|-------|--------|-------------|----------------|----------|
322
- | Display | {px} | {rem} | clamp({...}) | {heading wt} | {lh}px / {unitless} | -0.025em | text-[{rem}rem] tracking-tighter |
323
- | H1 | {px} | {rem} | clamp({...}) | {heading wt} | {lh}px / {unitless} | -0.025em | text-4xl tracking-tight font-extrabold |
324
- | H2 | {px} | {rem} | clamp({...}) | {heading wt} | {lh}px / {unitless} | -0.025em | text-3xl tracking-tight font-semibold |
325
- | H3 | {px} | {rem} | clamp({...}) | {heading wt} | {lh}px / {unitless} | -0.015em | text-2xl tracking-tight font-semibold |
326
- | H4 | {px} | {rem} | clamp({...}) | {heading wt} | {lh}px / {unitless} | -0.01em | text-xl tracking-tight font-semibold |
327
- | body-large | {px} | {rem} | — | {body wt} | {lh}px / {unitless} | 0 | text-lg |
328
- | body | {base}px | 1rem | — | {body wt} | {lh}px / {unitless} | 0 | text-base leading-7 |
329
- | body-small | {px} | {rem} | — | {body wt} | {lh}px / {unitless} | 0.01em | text-sm |
330
- | caption | {px} | {rem} | — | {body wt} | {lh}px / {unitless} | 0.015em | text-xs |
331
- | overline | {px} | {rem} | — | 600 | {lh}px / {unitless} | 0.1em | text-xs uppercase tracking-wider |
332
-
333
- ## shadcn/ui Typography Classes
334
-
335
- Ready-to-use className strings for shadcn projects. These match the calculated scale above:
336
-
337
- ```tsx
338
- // Headings
339
- <h1 className="scroll-m-20 text-4xl font-extrabold tracking-tight lg:text-5xl">
340
- <h2 className="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight first:mt-0">
341
- <h3 className="scroll-m-20 text-2xl font-semibold tracking-tight">
342
- <h4 className="scroll-m-20 text-xl font-semibold tracking-tight">
343
-
344
- // Body
345
- <p className="leading-7 [&:not(:first-child)]:mt-6">
346
- <p className="text-xl text-muted-foreground"> {/* Lead */}
347
- <p className="text-lg font-semibold"> {/* Large */}
348
- <p className="text-sm font-medium leading-none"> {/* Small */}
349
- <p className="text-sm text-muted-foreground"> {/* Muted */}
350
-
351
- // Special
352
- <blockquote className="mt-6 border-l-2 pl-6 italic">
353
- <code className="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">
354
- <span className="text-xs uppercase tracking-wider font-semibold"> {/* Overline */}
355
- ```
356
-
357
- To customize these for your exact scale, extend Tailwind with the CSS file below.
358
-
359
- ## Vertical Rhythm
360
-
361
- Grid unit: {grid}px | Body line-height: {body lh}px ({unitless})
362
-
363
- All line-heights are snapped to {grid}px multiples. The body line-height ({body lh}px) serves as the spacing anchor — use multiples of it for consistent vertical spacing:
364
-
365
- | Token | Value | Lines | Usage |
366
- |-------|-------|-------|-------|
367
- | space-xs | {grid}px | {fraction} | Inline element gaps |
368
- | space-sm | {grid*2}px | {fraction} | Related element gaps |
369
- | space-md | {body lh / 2}px | 0.5 | Compact section spacing |
370
- | space-lg | {body lh}px | 1 | Default paragraph spacing |
371
- | space-xl | {body lh * 1.5}px | 1.5 | Section breaks |
372
- | space-2xl | {body lh * 2}px | 2 | Major section breaks |
373
-
374
- CSS `lh` and `rlh` units (94%+ browser support) can reference line-height directly:
375
- ```css
376
- p + p { margin-block: 1lh; } /* one line of spacing */
377
- section { padding-block: 2rlh; } /* two root-line-heights */
378
- ```
379
-
380
- ## Weights
381
-
382
- | Name | Value | Usage |
383
- |------|-------|-------|
384
- | Regular | {body weight} | Body text, descriptions |
385
- | Medium | 500 | Emphasized body, nav items, labels |
386
- | Semibold | 600 | shadcn heading default (H2-H4), overlines |
387
- | Bold / Extrabold | {heading weight} | H1, page titles, CTAs |
388
-
389
- ## Accessibility
390
-
391
- This scale meets WCAG 2.2 AA requirements:
392
- - Body line-height ≥ 1.5× font size (SC 1.4.12) ✓
393
- - Layout survives 200% zoom (SC 1.4.4) — fluid clamp() uses rem bounds ✓
394
- - Minimum text size: {caption px}px (practical floor 12px) ✓
395
- - Max line length recommendation: 60–75 characters (`max-w-prose` in Tailwind = 65ch)
396
-
397
- **SC 1.4.12 resilience:** Layout must not break when users override to: line-height ≥ 1.5×, letter-spacing ≥ 0.12×, word-spacing ≥ 0.16×, paragraph-spacing ≥ 2× font size. Avoid fixed-height text containers.
398
-
399
- ## Variable Font Notes
400
-
401
- {If the primary font is a variable font:}
402
- - Enable optical sizing: `font-optical-sizing: auto` (browser maps opsz to font-size automatically)
403
- - Dark mode grade adjustment: `@media (prefers-color-scheme: dark) { body { font-variation-settings: 'GRAD' -25; } }` — reduces apparent weight of light-on-dark text
404
- - Use `font-variation-settings: 'wght' {value}` for precise weight control beyond standard keywords
405
- {End if}
406
-
407
- ## Modern CSS Enhancements
408
-
409
- ```css
410
- h1, h2, h3, h4 { text-wrap: balance; } /* Auto-balance heading line lengths */
411
- p { text-wrap: pretty; } /* Avoid orphans in paragraphs */
412
- ```
413
-
414
- ---
415
-
416
- ## Related
417
-
418
- - [tailwind.typography.css](./tailwind.typography.css)
419
- - [palettes.json](./palettes.json)
420
- ```
293
+ - **Font Families** table with Role, Family, Variable (yes/no), Source, Fallback stack. Include Google Fonts URL and self-hosting note.
294
+ - **Type Scale** — table with Level, px, rem, Fluid clamp(), Weight, Line height (px + unitless), Letter spacing, Tailwind class. All 10 levels: Display, H1-H4, body-large, body, body-small, caption, overline.
295
+ - **shadcn/ui Typography Classes** — ready-to-use className strings for headings, body, and special elements (blockquote, code, overline). Customize values to match the calculated scale.
296
+ - **Vertical Rhythm** — grid unit, body line-height as spacing anchor, spacing token table (space-xs through space-2xl) with values, lines, and usage. Include CSS `lh`/`rlh` unit examples.
297
+ - **Weights** — table mapping Regular/Medium/Semibold/Bold to values and usage.
298
+ - **Accessibility** — WCAG 2.2 AA compliance notes: body line-height ≥ 1.5, zoom survival, minimum text size, max line length. SC 1.4.12 resilience note.
299
+ - **Variable Font Notes** conditional section: optical sizing, dark mode grade adjustment, precise weight control.
300
+ - **Modern CSS Enhancements** — `text-wrap: balance` for headings, `text-wrap: pretty` for paragraphs.
301
+ - **Related** links to companion files.
421
302
 
422
303
  ## Step 7: Write CSS output
423
304
 
@@ -425,201 +306,24 @@ p { text-wrap: pretty; } /* Avoid orphans in paragraphs */
425
306
 
426
307
  Write `{OUTPUT_PATH}/tailwind.typography.css` — extends Tailwind v4 via `@theme` with the calculated scale. Drop into your project and import in `globals.css`:
427
308
 
428
- ```css
429
- /* Typography — {font family} @ {ratio} ({ratio name})
430
- Generated by /gsp:typescale | {DATE}
431
- Import in globals.css: @import './tailwind.typography.css';
432
- Preview: https://typescale.com/ */
433
-
434
- /* ─── Font imports ─── */
435
- @import url('https://fonts.googleapis.com/css2?family={primary}:wght@{weights}&family={mono}:wght@400;700&display=swap');
436
-
437
- /* ─── Tailwind v4 theme extension ─── */
438
- @theme {
439
- /* Font families */
440
- --font-sans: '{primary}', ui-sans-serif, system-ui, sans-serif;
441
- --font-mono: '{mono}', ui-monospace, 'SFMono-Regular', monospace;
442
-
443
- /* Custom font size tokens (extend Tailwind's built-in scale) */
444
- --text-display: {display rem}rem;
445
- --text-display--line-height: {display lh};
446
- --text-display--letter-spacing: -0.025em;
447
- --text-display--font-weight: {heading weight};
448
-
449
- --text-h1: {h1 rem}rem;
450
- --text-h1--line-height: {h1 lh};
451
- --text-h1--letter-spacing: -0.025em;
452
- --text-h1--font-weight: {heading weight};
453
-
454
- --text-h2: {h2 rem}rem;
455
- --text-h2--line-height: {h2 lh};
456
- --text-h2--letter-spacing: -0.025em;
457
- --text-h2--font-weight: {heading weight};
458
-
459
- --text-h3: {h3 rem}rem;
460
- --text-h3--line-height: {h3 lh};
461
- --text-h3--letter-spacing: -0.015em;
462
- --text-h3--font-weight: 600;
463
-
464
- --text-h4: {h4 rem}rem;
465
- --text-h4--line-height: {h4 lh};
466
- --text-h4--letter-spacing: -0.01em;
467
- --text-h4--font-weight: 600;
468
-
469
- --text-body-large: {body-large rem}rem;
470
- --text-body-large--line-height: {body-large lh};
471
-
472
- --text-overline: {overline rem}rem;
473
- --text-overline--line-height: {overline lh};
474
- --text-overline--letter-spacing: 0.1em;
475
- --text-overline--font-weight: 600;
476
- }
477
-
478
- /* ─── Fluid type (clamp) ─── */
479
- :root {
480
- --fs-display: clamp({display min}rem, {display intercept}rem + {display slope}vw, {display max}rem);
481
- --fs-h1: clamp({h1 min}rem, {h1 intercept}rem + {h1 slope}vw, {h1 max}rem);
482
- --fs-h2: clamp({h2 min}rem, {h2 intercept}rem + {h2 slope}vw, {h2 max}rem);
483
- --fs-h3: clamp({h3 min}rem, {h3 intercept}rem + {h3 slope}vw, {h3 max}rem);
484
- --fs-h4: clamp({h4 min}rem, {h4 intercept}rem + {h4 slope}vw, {h4 max}rem);
485
- }
486
-
487
- /* ─── Typography utility classes ─── */
488
- /* Use these or compose with Tailwind's built-in classes */
489
-
490
- .text-display {
491
- font-size: var(--fs-display);
492
- line-height: {display lh};
493
- letter-spacing: -0.025em;
494
- font-weight: {heading weight};
495
- text-wrap: balance;
496
- }
497
-
498
- .prose-headings h1, .text-h1 {
499
- font-size: var(--fs-h1);
500
- line-height: {h1 lh};
501
- letter-spacing: -0.025em;
502
- font-weight: {heading weight};
503
- text-wrap: balance;
504
- }
505
-
506
- .prose-headings h2, .text-h2 {
507
- font-size: var(--fs-h2);
508
- line-height: {h2 lh};
509
- letter-spacing: -0.025em;
510
- font-weight: 600;
511
- text-wrap: balance;
512
- }
513
-
514
- .prose-headings h3, .text-h3 {
515
- font-size: var(--fs-h3);
516
- line-height: {h3 lh};
517
- letter-spacing: -0.015em;
518
- font-weight: 600;
519
- text-wrap: balance;
520
- }
521
-
522
- .prose-headings h4, .text-h4 {
523
- font-size: var(--fs-h4);
524
- line-height: {h4 lh};
525
- letter-spacing: -0.01em;
526
- font-weight: 600;
527
- text-wrap: balance;
528
- }
529
-
530
- .text-body-large {
531
- font-size: {body-large rem}rem;
532
- line-height: {body-large lh};
533
- }
534
-
535
- .text-overline {
536
- font-size: {overline rem}rem;
537
- line-height: {overline lh};
538
- letter-spacing: 0.1em;
539
- font-weight: 600;
540
- text-transform: uppercase;
541
- }
542
-
543
- /* ─── Optical sizing + dark mode (variable fonts) ─── */
544
- body {
545
- font-optical-sizing: auto;
546
- }
547
-
548
- @media (prefers-color-scheme: dark) {
549
- body {
550
- /* Reduce apparent weight for light-on-dark text */
551
- -webkit-font-smoothing: antialiased;
552
- }
553
- }
554
-
555
- /* ─── Modern CSS enhancements ─── */
556
- h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
557
- p { text-wrap: pretty; }
558
- ```
309
+ The CSS file must include these sections, using calculated values from Step 3:
310
+
311
+ - **Header comment** font family, ratio name, date, import instruction
312
+ - **Font imports** — Google Fonts `@import url()` for primary + mono families
313
+ - **Tailwind v4 @theme extension** — `--font-sans`, `--font-mono` families, plus custom `--text-{level}` tokens for Display, H1-H4, body-large, overline (each with `--line-height`, `--letter-spacing`, `--font-weight` sub-tokens)
314
+ - **Fluid type custom properties** — `:root` block with `--fs-display` through `--fs-h4` using `clamp()` (rem-based min/max, never pure vw — required for WCAG 1.4.4 zoom compliance)
315
+ - **Typography utility classes** `.text-display`, `.text-h1` through `.text-h4`, `.text-body-large`, `.text-overline` with corresponding font-size (using fluid var), line-height, letter-spacing, font-weight, and `text-wrap: balance` for headings
316
+ - **Optical sizing + dark mode** — `font-optical-sizing: auto`, dark mode antialiasing
317
+ - **Modern CSS** — `text-wrap: balance` on headings, `text-wrap: pretty` on paragraphs
559
318
 
560
319
  ### Vanilla mode (`--vanilla`)
561
320
 
562
321
  If `--vanilla` flag is set, write `{OUTPUT_PATH}/typescale.css` instead — plain CSS custom properties without Tailwind-specific syntax:
563
322
 
564
- ```css
565
- /* Typography — {font family} @ {ratio} ({ratio name})
566
- Generated by /gsp:typescale | {DATE} */
567
-
568
- @import url('https://fonts.googleapis.com/css2?family={primary}:wght@{weights}&family={mono}:wght@400;700&display=swap');
569
-
570
- :root {
571
- /* Font families */
572
- --font-primary: '{primary}', {fallback stack};
573
- --font-secondary: '{secondary or primary}', {fallback stack};
574
- --font-mono: '{mono}', ui-monospace, monospace;
575
-
576
- /* Font weights */
577
- --fw-regular: {body weight};
578
- --fw-medium: 500;
579
- --fw-semibold: 600;
580
- --fw-bold: {heading weight};
581
-
582
- /* Type scale — fluid */
583
- --fs-display: clamp({...});
584
- --fs-h1: clamp({...});
585
- --fs-h2: clamp({...});
586
- --fs-h3: clamp({...});
587
- --fs-h4: clamp({...});
588
- --fs-body-large: {rem}rem;
589
- --fs-body: {base}rem;
590
- --fs-body-small: {rem}rem;
591
- --fs-caption: {rem}rem;
592
- --fs-overline: {rem}rem;
593
-
594
- /* Line heights (4px grid-snapped) */
595
- --lh-display: {value};
596
- --lh-h1: {value};
597
- --lh-h2: {value};
598
- --lh-h3: {value};
599
- --lh-h4: {value};
600
- --lh-body-large: {value};
601
- --lh-body: {value};
602
- --lh-body-small: {value};
603
- --lh-caption: {value};
604
- --lh-overline: {value};
605
-
606
- /* Letter spacing */
607
- --ls-display: -0.025em;
608
- --ls-h1: -0.025em;
609
- --ls-h2: -0.025em;
610
- --ls-h3: -0.015em;
611
- --ls-h4: -0.01em;
612
- --ls-body-large: 0;
613
- --ls-body: 0;
614
- --ls-body-small: 0.01em;
615
- --ls-caption: 0.015em;
616
- --ls-overline: 0.1em;
617
-
618
- /* Vertical rhythm */
619
- --grid-unit: {grid}px;
620
- --space-line: {body lh}px;
621
- }
622
- ```
323
+ Plain CSS custom properties (no Tailwind syntax). Include:
324
+
325
+ - **Font imports** Google Fonts `@import`
326
+ - **:root custom properties** — font families (`--font-primary`, `--font-secondary`, `--font-mono`), font weights (`--fw-regular` through `--fw-bold`), fluid font sizes (`--fs-display` through `--fs-overline` with clamp() for headings, rem-based min/max only — never pure vw per WCAG 1.4.4), line heights (`--lh-display` through `--lh-overline`, 4px grid-snapped), letter spacing (`--ls-display` through `--ls-overline`), vertical rhythm (`--grid-unit`, `--space-line`)
623
327
 
624
328
  ## Step 8: Completion output
625
329