@invisibleloop/pulse 0.12.3 → 0.14.1

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 (166) hide show
  1. package/.claude/commands/verify.md +9 -5
  2. package/.claude/pulse-checklist.md +21 -1
  3. package/.github/workflows/publish.yml +1 -0
  4. package/.pulse-verified +1 -0
  5. package/CLAUDE.md +56 -15
  6. package/docs/.claude/commands/verify.md +4 -0
  7. package/docs/.claude/pulse-checklist.md +20 -2
  8. package/docs/public/.pulse-ui-version +1 -1
  9. package/docs/public/andypixel.css +237 -0
  10. package/docs/public/bookworms.css +422 -0
  11. package/docs/public/coutumes.css +584 -0
  12. package/docs/public/images/bookworms/hero-books.jpg +0 -0
  13. package/docs/public/images/bookworms/how-we-read-now.jpg +0 -0
  14. package/docs/public/images/bookworms/lantern-keepers.jpg +0 -0
  15. package/docs/public/images/bookworms/provincial-bookseller.jpg +0 -0
  16. package/docs/public/images/journey/178.jpg +0 -0
  17. package/docs/public/images/journey/29.jpg +0 -0
  18. package/docs/public/images/retrowheels/hero.jpg +0 -0
  19. package/docs/public/images/shop/devbook-pro.jpg +0 -0
  20. package/docs/public/images/suzukibento/1015.jpg +0 -0
  21. package/docs/public/images/suzukibento/1025.jpg +0 -0
  22. package/docs/public/images/suzukibento/1043.jpg +0 -0
  23. package/docs/public/images/suzukibento/1059.jpg +0 -0
  24. package/docs/public/images/suzukibento/1062.jpg +0 -0
  25. package/docs/public/images/suzukibento/1084.jpg +0 -0
  26. package/docs/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  27. package/docs/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  28. package/docs/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  29. package/docs/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  30. package/docs/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  31. package/docs/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  32. package/docs/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  33. package/docs/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  34. package/docs/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  35. package/docs/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  36. package/docs/public/journey.css +528 -0
  37. package/docs/public/pulse-ui.css +1036 -22
  38. package/docs/public/retrowheels.css +402 -0
  39. package/docs/public/shop.css +235 -0
  40. package/docs/public/sparkys.css +349 -0
  41. package/docs/public/suzukibento.css +517 -0
  42. package/docs/public/swish.css +394 -0
  43. package/docs/server.js +19 -4
  44. package/docs/src/lib/nav.js +14 -3
  45. package/docs/src/pages/components/decorate.js +74 -0
  46. package/docs/src/pages/components/gallery.js +102 -0
  47. package/docs/src/pages/components/hero.js +1 -0
  48. package/docs/src/pages/components/marquee.js +76 -0
  49. package/docs/src/pages/components/photo-card.js +74 -0
  50. package/docs/src/pages/components/section.js +40 -1
  51. package/docs/src/pages/meta.js +26 -0
  52. package/docs/src/pages/templates/andypixel.js +260 -0
  53. package/docs/src/pages/templates/bookworms.js +227 -0
  54. package/docs/src/pages/templates/coutumes.js +226 -0
  55. package/docs/src/pages/templates/journey.js +186 -0
  56. package/docs/src/pages/templates/retrowheels.js +342 -0
  57. package/docs/src/pages/templates/shop.js +257 -0
  58. package/docs/src/pages/templates/sparkys.js +249 -0
  59. package/docs/src/pages/templates/suzukibento.js +200 -0
  60. package/docs/src/pages/templates/swish.js +313 -0
  61. package/docs/src/pages/templates.js +313 -2
  62. package/docs/src/pages/testing.js +2 -1
  63. package/examples/andypixel.css +237 -0
  64. package/examples/andypixel.js +258 -0
  65. package/examples/bookworms.css +422 -0
  66. package/examples/bookworms.js +225 -0
  67. package/examples/contact.js +1 -0
  68. package/examples/counter.js +1 -0
  69. package/examples/dev.server.js +17 -0
  70. package/examples/journey.css +528 -0
  71. package/examples/journey.js +186 -0
  72. package/examples/pricing.js +1 -0
  73. package/examples/quiz.js +1 -0
  74. package/examples/retrowheels.css +402 -0
  75. package/examples/retrowheels.js +340 -0
  76. package/examples/shared.js +6 -0
  77. package/examples/suzukibento.css +513 -0
  78. package/examples/suzukibento.js +200 -0
  79. package/examples/swish.css +394 -0
  80. package/examples/swish.js +311 -0
  81. package/examples/todos.js +1 -0
  82. package/package.json +2 -3
  83. package/public/.pulse-ui-version +1 -1
  84. package/public/images/bookworms/hero-books.jpg +0 -0
  85. package/public/images/bookworms/how-we-read-now.jpg +0 -0
  86. package/public/images/bookworms/lantern-keepers.jpg +0 -0
  87. package/public/images/bookworms/provincial-bookseller.jpg +0 -0
  88. package/public/images/journey/178.jpg +0 -0
  89. package/public/images/journey/29.jpg +0 -0
  90. package/public/images/retrowheels/hero.jpg +0 -0
  91. package/public/images/shop/devbook-pro.jpg +0 -0
  92. package/public/images/suzukibento/1015.jpg +0 -0
  93. package/public/images/suzukibento/1025.jpg +0 -0
  94. package/public/images/suzukibento/1043.jpg +0 -0
  95. package/public/images/suzukibento/1059.jpg +0 -0
  96. package/public/images/suzukibento/1062.jpg +0 -0
  97. package/public/images/suzukibento/1084.jpg +0 -0
  98. package/public/images/swish/1469334031218-e382a71b716b.jpg +0 -0
  99. package/public/images/swish/1483985988355-763728e1935b.jpg +0 -0
  100. package/public/images/swish/1485518882345-15568b007407.jpg +0 -0
  101. package/public/images/swish/1490481651871-ab68de25d43d.jpg +0 -0
  102. package/public/images/swish/1496747611176-843222e1e57c.jpg +0 -0
  103. package/public/images/swish/1502716119720-b23a93e5fe1b.jpg +0 -0
  104. package/public/images/swish/1539109136881-3be0616acf4b.jpg +0 -0
  105. package/public/images/swish/1551803091-e20673f15770.jpg +0 -0
  106. package/public/images/swish/1558769132-cb1aea458c5e.jpg +0 -0
  107. package/public/images/swish/1572804013309-59a88b7e92f1.jpg +0 -0
  108. package/public/pulse-ui.css +1036 -22
  109. package/scripts/build.js +72 -18
  110. package/src/agent/checklist.md +20 -2
  111. package/src/agent/commands/verify.md +4 -0
  112. package/src/agent/guide-components.md +145 -7
  113. package/src/agent/guide-design-gallery.md +288 -0
  114. package/src/agent/guide-design-references.md +172 -0
  115. package/src/agent/guide-explore.md +313 -0
  116. package/src/agent/guide-styles.md +197 -11
  117. package/src/agent/guide-templates.md +220 -10
  118. package/src/agent/guide.md +9 -4
  119. package/src/agent/workflow.md +208 -58
  120. package/src/cli/dev.js +39 -7
  121. package/src/cli/fmt.js +113 -0
  122. package/src/cli/index.js +63 -30
  123. package/src/cli/scaffold.js +2 -2
  124. package/src/html.js +6 -1
  125. package/src/mcp/server.js +2415 -101
  126. package/src/mcp/validate-worker.js +34 -5
  127. package/src/runtime/ssr.js +4 -1
  128. package/src/server/index.js +22 -2
  129. package/src/spec/schema.js +5 -0
  130. package/src/testing/html.js +130 -4
  131. package/src/testing/testing.test.js +58 -0
  132. package/src/ui/banner.js +24 -9
  133. package/src/ui/brand-statement.js +58 -0
  134. package/src/ui/button.js +12 -1
  135. package/src/ui/card.js +20 -1
  136. package/src/ui/colophon.js +29 -0
  137. package/src/ui/contact-row.js +41 -0
  138. package/src/ui/cta.js +18 -4
  139. package/src/ui/decorate.js +55 -0
  140. package/src/ui/display-heading.js +44 -0
  141. package/src/ui/drop-cap.js +29 -0
  142. package/src/ui/editorial-hero.js +63 -0
  143. package/src/ui/entry-list.js +36 -0
  144. package/src/ui/feature.js +20 -3
  145. package/src/ui/footer.js +78 -9
  146. package/src/ui/gallery.js +56 -0
  147. package/src/ui/hero.js +68 -18
  148. package/src/ui/image-pair.js +72 -0
  149. package/src/ui/index.js +20 -0
  150. package/src/ui/input.js +1 -0
  151. package/src/ui/marquee.js +48 -0
  152. package/src/ui/nav.js +19 -9
  153. package/src/ui/photo-card.js +44 -0
  154. package/src/ui/product-card.js +65 -0
  155. package/src/ui/pullquote.js +14 -3
  156. package/src/ui/search.js +1 -0
  157. package/src/ui/section-label.js +38 -0
  158. package/src/ui/section.js +1 -1
  159. package/src/ui/service-card.js +47 -0
  160. package/src/ui/stat-grid.js +40 -0
  161. package/src/ui/stat.js +16 -2
  162. package/src/ui/testimonial.js +17 -6
  163. package/src/ui/textarea.js +1 -0
  164. package/src/ui/top-strip.js +47 -0
  165. package/src/ui/trust-list.js +46 -0
  166. package/src/ui/ui.test.js +35 -0
@@ -2,6 +2,8 @@
2
2
 
3
3
  Templates are complete, production-ready page specs you can adapt for a new brand. Always start from a template when the user's request matches one — do not build from scratch.
4
4
 
5
+ **A template gives you the right *components and content slots* — not a mandatory section order.** The structural skeleton (hero → features → testimonials → CTA) suits corporate and minimal vibes. For playful, bold, brutalist, retro, and neon vibes, the template is a parts list, not a blueprint. Run `pulse_sketch` to find a layout that matches the emotional intent before you write a line of code.
6
+
5
7
  ---
6
8
 
7
9
  ## When to use a template
@@ -10,22 +12,93 @@ Read the user's request and match against the triggers below. If it matches, use
10
12
 
11
13
  | Template | Route | Triggers |
12
14
  |---|---|---|
13
- | Mobile App Landing | `docs/src/pages/templates/mobile-app.js` | "landing page for a mobile app", "app marketing site", "app homepage", "SaaS landing page" |
14
- | Blog Post | `docs/src/pages/templates/blog-post.js` | "blog post", "article page", "publication", "editorial site", "newsletter with blog" |
15
+ | Mobile App Landing | `docs/src/pages/templates/mobile-app.js` | "landing page for a mobile app", "app marketing site", "app homepage", "SaaS landing page" |
16
+ | Blog Post | `docs/src/pages/templates/blog-post.js` | "blog post", "article page", "publication", "editorial site", "newsletter with blog" |
17
+ | Local Business | `docs/src/pages/templates/local-business.js` | "local business", "dog groomer", "bakery", "physio", "plumber", "florist", "salon", "restaurant", "tradesperson", "small business" |
18
+ | Portfolio | `docs/src/pages/templates/portfolio.js` | "portfolio", "personal site", "freelancer site", "creative professional", "photographer", "designer site", "developer portfolio" |
19
+ | Event / Conference | `docs/src/pages/templates/event.js` | "conference", "event", "festival", "workshop", "concert", "meetup", "summit" |
20
+ | Editorial / Magazine | `docs/src/pages/templates/editorial.js` | "magazine", "publication", "news site", "editorial", "online journal", "newsletter homepage" |
21
+
22
+ **Always fetch `pulse://guide/design-references` after matching a template** — it tells you which vibe and component combinations suit the product's aesthetic, so you don't default to the same SaaS geometry every time.
15
23
 
16
24
  ---
17
25
 
18
- ## Before writing any code — mandatory pre-build questions
26
+ ## Creative-override rule — when to ignore the template structure
27
+
28
+ When the vibe is **playful, bold, brutalist, retro, or neon**, run `pulse_sketch` before writing any code and **treat the template section order as optional**. These vibes require structural decisions that the template's default skeleton actively works against.
29
+
30
+ | Signal | What to do |
31
+ |---|---|
32
+ | Vibe is playful / bold / brutalist / retro / neon | Run `pulse_sketch` — pick one of 3 layout directions |
33
+ | User says "fun", "pop-art", "loud", "unexpected", "editorial", "raw" | Run `pulse_sketch` — section order is your call |
34
+ | User says "professional", "clean", "trustworthy", "corporate", "minimal" | Template structure is fine — adapt content only |
35
+
36
+ **What this means in practice for expressive vibes:**
37
+
38
+ - The template tells you *what to include* (a hero, features, social proof, CTA). It does **not** tell you how to arrange them or what shape they take.
39
+ - Full-colour section blocks, oversized typography heroes, marquee strips, dense grids, and palette-as-structure are all fair game.
40
+ - The `phoneFrame` in Mobile App Landing is **not mandatory** — a full-bleed game board, an oversized illustration, or a typography-only hero may serve the brief better.
41
+ - `feature()` in a 3-column grid is the most predictable layout on the web. If the brief is "fun and bold", use a marquee strip of features, a zigzag alternating layout, or full-bleed feature sections instead.
42
+
43
+ ---
44
+
45
+ ## Template-mode: lighter planning
46
+
47
+ When using a template, skip the full plan-and-confirm ceremony. Instead, output a single compact confirmation before writing:
48
+
49
+ ```
50
+ Template: Mobile App Landing
51
+ App name: Nova
52
+ Substitutions: name, tagline, 5 features, 3 pricing tiers, palette, font
53
+ Theme: light (palette: #6366f1 primary, #f8fafc bg)
54
+ Files: src/pages/nova.js, public/themes/nova.css
55
+ Confirm to proceed — or reply with changes.
56
+ ```
57
+
58
+ Wait one turn for confirmation. This replaces the full plan/build/confirm cycle. It is enough — the user can see exactly what will change.
19
59
 
20
- Ask these **before** presenting a plan. Do not skip them.
60
+ **Do not skip the confirmation.** Even for templates, one turn of "does this look right?" prevents throwing away a completed build because the app name or palette was wrong.
21
61
 
22
- 1. **Colour palette** — "Do you have a colour palette, or should I choose one?"
23
- 2. **Brand fonts** — "Any brand fonts, or system-ui is fine?"
24
- 3. **Theme** — "Light or dark theme preference?"
62
+ ### One-shot builds without a template
25
63
 
26
- Record the answers. If the user provides palette colours, note which are light/mid/dark toned so you can plan contrast strategy before writing any CSS.
64
+ For a one-shot "build me X" request that doesn't use a named template, use the same compact style — a 3–5 line brief, not a full phase-2 plan:
27
65
 
28
- **Why this matters:** Building with placeholder colours and retrofitting a palette requires rebuilding components, fixing WCAG contrast failures, and touching multiple files. Getting the palette upfront avoids that loop entirely.
66
+ ```
67
+ Building: Chess Club landing page (/chess-club)
68
+ Vibe: editorial · dark navy + gold · brutalist structure
69
+ Sections: hero, about, schedule, join CTA
70
+ Files: src/pages/chess-club.js, public/themes/chess-club.css
71
+ Confirm to proceed — or reply with changes.
72
+ ```
73
+
74
+ Reserve the full plan-and-confirm ceremony (route / state / mutations / actions / server fetchers) for multi-page builds, pages with complex state, or when the user hasn't confirmed the scope yet.
75
+
76
+ ---
77
+
78
+ ## Before writing any code — mandatory product intake
79
+
80
+ Run `pulse_intake` before presenting the confirmation. It collects the product details that make template content directionally right instead of fiction.
81
+
82
+ **How to gather the intake information** — ask questions one at a time as plain prose, never as a batch with multiple-choice options. Product details are open-ended and free-form; preset choice lists don't fit and cause tool errors. Ask the simplest possible version of each question:
83
+
84
+ 1. "What's the name of the app or product?"
85
+ 2. "One sentence — what does it do?"
86
+ 3. "What are its main features? Give me 3–6."
87
+ 4. "Who's it for?" *(optional — skip if obvious from context)*
88
+ 5. "Do you have brand colours? If so, paste the hex values."
89
+ 6. "Any specific font, or system-ui?"
90
+ 7. "Light or dark theme preference?"
91
+ 8. "How should it feel visually? (e.g. warm and friendly, editorial and sharp, playful, minimal, bold — or describe in your own words)"
92
+
93
+ Ask each question and wait for the answer before asking the next. Do not present a list of preset choices for any of these — the answers are arbitrary text.
94
+
95
+ Once you have the answers, call `pulse_intake` with the collected details. It returns a product brief + early contrast warnings.
96
+
97
+ **If `pulse_intake` is unavailable**, gather the answers via the questions above and use them directly when adapting the template — replace every placeholder with real content.
98
+
99
+ **Do not invent app content.** Placeholder copy ("Lorem ipsum", "Feature A", "Benefit here") is thrown away immediately and makes the build feel broken. Real answers mean the first build is shippable copy.
100
+
101
+ Record the intake answers. If the user provides palette hex values, note which are light/mid/dark toned before writing any CSS — this is when to spot contrast problems, not after Lighthouse runs.
29
102
 
30
103
  ---
31
104
 
@@ -237,7 +310,144 @@ Do NOT set `meta.theme: 'light'` on dark templates — the default pulse-ui them
237
310
 
238
311
  ---
239
312
 
240
- ## Adding a new template
313
+ ## Local Business Landing Page
314
+
315
+ **Design direction:** Warm Local Business · **Vibe:** `warm` · **Theme:** `light`
316
+
317
+ ### What it includes
318
+
319
+ | Section | Component(s) |
320
+ |---|---|
321
+ | Sticky nav | `nav` with logo, links, Book Now CTA |
322
+ | Hero | `hero(layout:'split')` with real photo of the business |
323
+ | Stats strip | `stat` × 4 in `grid` — clients, rating, years, availability |
324
+ | Services | `card` × 6 in `grid` with name, description, and price |
325
+ | About | Two-column: photo + team bio with trust badges |
326
+ | Reviews | `testimonial` × 3 in `grid` |
327
+ | Contact / Hours | Two-column: address/phone/hours + booking form |
328
+ | CTA banner | `cta` with offer (e.g. 10% off first visit) |
329
+ | Footer | `footer` with address in `legal` |
330
+
331
+ ### Files to create
332
+
333
+ | File | Purpose |
334
+ |---|---|
335
+ | `src/pages/[name].js` | The page spec |
336
+ | `public/themes/[name].css` | Brand theme — warm palette, `[data-theme="light"]` |
337
+
338
+ ### Adapting the template
339
+
340
+ 1. **Business name** — replace "Pawfect Grooming" everywhere.
341
+ 2. **Service type** — update service names, descriptions, and prices to match the business.
342
+ 3. **Photo** — the hero image and about section both use real photos; provide Unsplash URLs or placeholder paths. **If using external images**, add the host to `csp` in `pulse.config.js` (see pulse://guide/styles for examples).
343
+ 4. **Palette** — earthy, warm tones work best. Terracotta, sage, cream, amber — avoid corporate blues.
344
+ 5. **Contact details** — update address, phone, and opening hours in the contact section.
345
+ 6. **Vibe** — always `warm` for local business; pairs with rounded cards and soft section dividers.
346
+
347
+ ---
348
+
349
+ ## Portfolio / Personal Site
350
+
351
+ **Design direction:** Minimal Portfolio · **Vibe:** `minimal` · **Theme:** dark (default)
352
+
353
+ ### What it includes
354
+
355
+ | Section | Component(s) |
356
+ |---|---|
357
+ | Nav | Minimal nav — name as logo, text links, no CTA |
358
+ | Hero | `hero(layout:'centered', align:'left')` — title and short bio |
359
+ | Work grid | `card` × 6 with image, project name, description, skill badges |
360
+ | About | Single-column `container(size:'sm')` with `prose`-style paragraphs + skill badges |
361
+ | Contact | Centered section with email link, GitHub link, CV download |
362
+ | Footer | Minimal — name, 3 links, legal |
363
+
364
+ ### Files to create
365
+
366
+ | File | Purpose |
367
+ |---|---|
368
+ | `src/pages/[name].js` | The page spec |
369
+
370
+ Portfolio templates rarely need a separate theme CSS — the default dark palette with a single accent colour is sufficient. If the user has a brand colour, add it as a one-liner: `--ui-accent: #hex;` in `:root`.
371
+
372
+ ### Adapting the template
373
+
374
+ 1. **Name** — replace "Alex Mercer" everywhere, including the nav logo.
375
+ 2. **Profession** — update the eyebrow and hero subtitle.
376
+ 3. **Work grid** — replace with real project images, names, and descriptions. Use Unsplash or actual project screenshots. **If using external images**, add the host to `csp` in `pulse.config.js` (see pulse://guide/styles).
377
+ 4. **Skills badges** — update to match the person's actual disciplines.
378
+ 5. **Contact** — replace email, GitHub handle, and CV download link.
379
+ 6. **Vibe** — `minimal` keeps the focus on the work; do not add excess decoration.
380
+
381
+ ---
382
+
383
+ ## Event / Conference Landing Page
384
+
385
+ **Design direction:** Event / Conference · **Vibe:** `bold` · **Theme:** dark (default)
386
+
387
+ ### What it includes
388
+
389
+ | Section | Component(s) |
390
+ |---|---|
391
+ | Nav | `nav` with event logo, links, Get Tickets CTA |
392
+ | Hero | `hero(size:'xl', align:'center')` with gradient background |
393
+ | Stats strip | `stat` × 4 — days, speakers, attendees, tracks |
394
+ | Sponsor logos | `marquee` with sponsor names/logos |
395
+ | Speakers | `card` × 8 in `grid` with photo, name, role, topic |
396
+ | Schedule | `accordion` — one item per day with time/session/location |
397
+ | Venue | Two-column: venue info + photo |
398
+ | Tickets CTA | `cta` with prominent ticket button |
399
+ | Footer | `footer` with event links and company legal |
400
+
401
+ ### Files to create
402
+
403
+ | File | Purpose |
404
+ |---|---|
405
+ | `src/pages/[name].js` | The page spec |
406
+ | `public/themes/[name].css` | Optional — if brand has a specific accent colour |
407
+
408
+ ### Adapting the template
409
+
410
+ 1. **Event name and dates** — replace "SIGNAL", "14–16 October 2026", and "London" everywhere.
411
+ 2. **Speakers** — replace with real speaker names, roles, photos, and talk topics.
412
+ 3. **Schedule** — update accordion items with real session titles and times.
413
+ 4. **Venue** — update name, address, capacity, and photo.
414
+ 5. **Ticket price and URL** — update the ticket CTA with real link and price.
415
+ 6. **Gradient hero** — adjust the gradient colours to match the event brand.
416
+ 7. **Vibe** — `bold` for impact; consider `neon` for gaming/tech events.
417
+
418
+ ---
419
+
420
+ ## Editorial / Magazine Landing Page
421
+
422
+ **Design direction:** Editorial / Publication · **Vibe:** `editorial` · **Theme:** dark (default)
423
+
424
+ ### What it includes
425
+
426
+ | Section | Component(s) |
427
+ |---|---|
428
+ | Nav | `nav` with publication name + category links + Subscribe CTA |
429
+ | Hero | `hero` with featured article title, deck, and author byline |
430
+ | Pullquote | `pullquote` from the featured article |
431
+ | Article grid | `card` × 6 with image, category badge, title, deck, author, date, read time |
432
+ | Newsletter signup | `section(variant:'spotlight')` with email input and subscribe button |
433
+ | Footer | `footer` with publication logo, category links, legal |
434
+
435
+ ### Files to create
436
+
437
+ | File | Purpose |
438
+ |---|---|
439
+ | `src/pages/[name].js` | The page spec |
440
+
441
+ ### Adapting the template
442
+
443
+ 1. **Publication name** — replace "The Signal" everywhere.
444
+ 2. **Navigation categories** — update section names to match the publication's editorial categories.
445
+ 3. **Featured article** — replace hero title and subtitle with the actual lead story.
446
+ 4. **Article grid** — replace all 6 article stubs with real or representative articles.
447
+ 5. **Newsletter copy** — update the newsletter description and subscriber count.
448
+ 6. **Vibe** — `editorial` applies serif display font and zero-radius geometry; critical for the right feel. Do not change it.
449
+
450
+ ---
241
451
 
242
452
  When you build a new template and want it available for future scaffolding:
243
453
 
@@ -497,13 +497,18 @@ Convention: name dynamic-route files [param].js inside a subfolder:
497
497
 
498
498
  This is purely a human readability convention. Pulse does not process [ ] in filenames.
499
499
 
500
- ## UI components — MANDATORY
500
+ ## UI components
501
501
 
502
- **RULE: Before writing any HTML, check whether a Pulse UI component exists for the purpose. If it does, you MUST use it. Raw HTML is only permitted for structural tags with no component equivalent (div, main, aside, footer, header).**
502
+ **Default rule: Before writing any HTML, check whether a Pulse UI component exists for the purpose. If it does, use it.** Components ship with correct ARIA, token-based styling, and responsive behaviour — choosing them over raw HTML means less work, not more.
503
503
 
504
- **RULE: For every feature, page, or UI element you build — regardless of how the request is phrased, whether it came from text or an image — your first step is always to check whether a Pulse UI component exists for it. If it does, you MUST use it. There are no exceptions.**
504
+ **Creative override:** When the design intent genuinely calls for a more expressive or unconventional layout — a distinctive visual identity, an asymmetric or typographically-driven composition, a brutalist or editorial structure that components would constrain — you may build with raw HTML instead. This is not a loophole; it is a deliberate design decision. When taking this path:
505
505
 
506
- Before writing a single line of HTML, mentally scan the task and list which components apply. Only after exhausting the component list should you write raw HTML — and only for structural wrappers (div, main, aside, footer) with no component equivalent.
506
+ 1. **State your intent explicitly** in the build brief: *"Building component-free — raw HTML throughout for maximum creative control."*
507
+ 2. **Pulse-ui.css is still required** — always load it in `meta.styles`. It provides the token system (`--ui-*` variables) that your custom CSS will reference.
508
+ 3. **Functional atoms (`button`, `input`, `badge`, `modal`) should still come from components** unless there is a specific design reason to hand-roll them. These are the hardest to get right for accessibility.
509
+ 4. **The quality gate replaces the component checklist** — 100/100/100/100 Lighthouse (Accessibility, Best Practices, SEO, Agentic Browsing) on both desktop and mobile is the arbiter. A component-free page that passes every Lighthouse audit is correct. A component-heavy page that fails accessibility is not.
510
+
511
+ Before writing a single line of HTML, decide which mode you are in and state it in the build brief:
507
512
 
508
513
  **RULE: All components accept a `class` prop — never `className` (that is React). Use `class` to add utility classes or custom identifiers to any component.**
509
514
 
@@ -1,57 +1,186 @@
1
1
  # Build Workflow
2
2
 
3
- Every task follows this sequence exactly. Each phase has a pass gate — you do not move to the next phase until the gate is cleared. Do not skip phases. Do not reorder them.
3
+ ---
4
+
5
+ ## Quick decision tree
6
+
7
+ | Situation | Start here |
8
+ |---|---|
9
+ | New site, new branded page, or "build me X from scratch" | `pulse_intake` → `pulse_sketch` → `pulse_intent` → build |
10
+ | Editing an existing page, adding a section, fixing a bug | Go straight to Step 1 — Understand |
11
+ | "Add X to the existing Y" (one-liner) | Read the relevant file, make the change, run `/verify` |
12
+ | Stuck on which component to use | `pulse_intent("describe what I'm building")` |
13
+ | Colours failing contrast / unsure about palette | `pulse_check_contrast` |
14
+ | Something looks wrong in the browser | `pulse_restart_server`, then `/verify` |
15
+ | Lighthouse < 100 | Fix the flagged audit, run `/verify` again — do not skip to commit |
4
16
 
5
17
  ---
6
18
 
7
- ## Phase 1 — Understand
19
+ ## New project or new page? Start with Intake
20
+
21
+ For any **new page, landing page, or branded site**, run the intake sequence first:
22
+
23
+ ```
24
+ 0. pulse_extract_inspiration(url/image) → structured design brief [if user shares reference]
25
+ 1. pulse_intake(name, pitch, features, ...) → product brief + contrast check
26
+ 2. pulse_sketch(brief, vibe?, antiStyle?) → 3 layout directions to choose from
27
+ 3. pulse_intent(description) → archetype + scaffold + guide list
28
+ ```
29
+
30
+ - **`pulse_extract_inspiration`** — call this first if the user shares a URL, site name, or image they like. Gives you a structured extraction template: visit the URL or analyse the image with your vision tools, extract colours, layout, typography, and feel, then feed those findings into pulse_intake. If no inspiration is shared, skip this step.
31
+ - **`pulse_intake`** — captures the real content (name, pitch, features, palette, vibe, what it should NOT look like). Returns a brief with copy-ready content and early contrast warnings. Always ask the user one question at a time — never multi-choice for open-ended questions.
32
+ - **`pulse_sketch`** — generates 3 structurally distinct layout directions (full-bleed, asymmetric split, typography-only, editorial, dense grid, story scroll, content-first). **Call this before writing any code.** Prevents defaulting to centred hero + three-column features every time.
33
+ - **Skip `pulse_sketch` only** when the vibe is `corporate` or `minimal` AND the user hasn't expressed any structural preference. For `playful`, `bold`, `brutalist`, `retro`, or `neon` vibes, `pulse_sketch` is mandatory — templates have default section orders that actively fight these vibes.
34
+ - **`pulse_intent`** — maps the chosen direction to a spec scaffold and tells you which guides to read.
35
+
36
+ For **small edits, bug fixes, or "add X to existing Y"** — skip intake/sketch and go straight to Step 0 below.
37
+
38
+ ---
39
+
40
+ ## Step 0 — Intent (always first for non-trivial builds)
41
+
42
+ After intake + sketch (or directly for targeted tasks), call `pulse_intent`:
43
+
44
+ ```
45
+ pulse_intent("a settings page with profile editing and a save action")
46
+ ```
47
+
48
+ It returns a matched archetype, recommended components, a starter spec scaffold, and which guide sections to read. This replaces hunting through guide sections manually.
49
+
50
+ If the user's request is already very specific (a one-liner edit, a bug fix, "add X to the existing Y"), skip this and go straight to Understand.
51
+
52
+ ---
8
53
 
9
- Before writing a single line of code:
54
+ ## Step 1 — Understand
10
55
 
11
- 1. Fetch `pulse://guide` for the guide index.
12
- 2. Fetch any topic sections you need (`pulse://guide/spec`, `pulse://guide/components`, etc.).
13
- 3. Call `pulse_list_structure` to see what pages and components already exist.
56
+ Call `pulse_list_structure` to see what already exists. Fetch only the guide sections relevant to your intent (the `pulse_intent` response tells you which ones).
14
57
 
15
- Do not guess about props, patterns, or rules. If you are unsure, fetch the relevant guide section.
58
+ Do not fetch every guide section for every task. Fetch what you need.
16
59
 
17
60
  ---
18
61
 
19
- ## Phase 2 — Plan (confirmation gate)
62
+ ## Step 2 — Plan
20
63
 
21
- Before building, output a concise plan:
64
+ Decide the complexity tier (see below) and confirm with the user if the task is non-trivial. Output a concise plan:
22
65
 
23
- - What page(s) or component(s) you will create or modify
24
- - The route, state shape, mutations/actions, and server fetchers
66
+ - Route, state shape, mutations/actions, server fetchers
25
67
  - Which UI components you will use
26
- - Any shared components you will create or reuse
68
+ - Files you will create or modify
69
+
70
+ **Skip confirmation for trivially small tasks** (add a button, fix a label, swap a component). When in doubt, confirm.
71
+
72
+ **When asking the user questions:** ask one question at a time. If you present choices, use at most 4 options — the `ask_user` tool enforces this limit and will error if exceeded. For open-ended questions (names, copy, features, hex colours), ask as plain prose with no choices at all.
73
+
74
+ ---
75
+
76
+ ## Complexity tiers
77
+
78
+ Not every task needs all 8 phases. Match the tier to the task:
79
+
80
+ ### Tier 1 — Simple (static or read-only content)
81
+
82
+ *Applies to:* landing pages, blog posts, profile pages, any page with no mutations or actions.
83
+
84
+ | Phase | Action | Gate |
85
+ |---|---|---|
86
+ | 1 | Intent + Understand | — |
87
+ | 2 | Build | announce brief → write files |
88
+ | 3 | Validate | `pulse_validate` clean |
89
+ | 4 | Browser | screenshot + Lighthouse desktop + mobile (100/100/100) |
90
+
91
+ No tests required for pure view specs with no logic. Add tests if the view has non-trivial helper functions.
27
92
 
28
- Wait for the user to confirm or adjust the plan before writing any code.
93
+ ### Tier 2 — Standard (interactive, single-purpose)
29
94
 
30
- **Skip this gate only if the task is unambiguous and small** (e.g. "add a delete button to the existing list page"). When in doubt, confirm.
95
+ *Applies to:* forms, CRUD pages, settings, auth flows, dashboards without complex state machines.
96
+
97
+ | Phase | Action | Gate |
98
+ |---|---|---|
99
+ | 1 | Intent + Understand | — |
100
+ | 2 | Plan | user confirmation (skip if unambiguous) |
101
+ | 3 | Build | announce brief → write files |
102
+ | 4 | Validate | `pulse_validate` clean |
103
+ | 5 | Browser | screenshot → `pulse_design_review` (if intake ran) → `pulse_layout_review` → Lighthouse desktop + mobile (100/100/100) + CLS 0.00 |
104
+ | 6 | Tests | mutations, view landmarks, any utility functions |
105
+ | 7 | Code review | `pulse_review` — only after 4–6 pass |
106
+
107
+ ### Tier 3 — Complex (multi-step, shared state, or security-sensitive)
108
+
109
+ *Applies to:* multi-step wizards, pages with guards and auth, store-connected pages, anything touching sensitive data or complex branching state.
110
+
111
+ All phases as originally defined — full 8-phase flow with every gate.
112
+
113
+ | Phase | Action | Gate |
114
+ |---|---|---|
115
+ | 1 | Intent + Understand | — |
116
+ | 2 | Plan | **user confirmation required** |
117
+ | 3 | Build | announce brief → write files |
118
+ | 4 | Validate | `pulse_validate` clean |
119
+ | 5 | Browser | screenshot → `pulse_design_review` (if intake ran) → `pulse_layout_review` → Lighthouse 100/100/100 + CLS 0.00, desktop + mobile |
120
+ | 6 | Tests | full coverage: mutations, actions, guards, view |
121
+ | 7 | Code review | `pulse_review` |
122
+ | 8 | Fix + re-verify | re-run all gates |
123
+
124
+ **If in doubt, default to Tier 2.** Choosing a lower tier than the task warrants means you'll hit problems at gates — the tiers are a shortcut, not a way to skip quality.
31
125
 
32
126
  ---
33
127
 
34
128
  ## Phase 3 — Build
35
129
 
36
- ### 3a — Announce before writing
130
+ ### 3a — Decide: components or creative override
131
+
132
+ **Two valid modes — choose one and state it in the build brief:**
133
+
134
+ **Mode A — Components first (default)**
135
+ Use Pulse UI components for all standard UI patterns. Before writing any view HTML, grep `src/ui/index.js` for the components you need:
136
+
137
+ ```bash
138
+ grep -E "^export" src/ui/index.js | head -20
139
+ ```
140
+
141
+ Or use the guide-components table. Never write these patterns from scratch in Mode A:
142
+
143
+ - Hero section → `hero()`
144
+ - Product/service cards → `card()`
145
+ - Image + text layouts → `media()`
146
+ - Horizontal strips → `banner()`
147
+ - Feature tiles → `feature()`
148
+ - Testimonials → `testimonial()`
149
+ - CTAs → `cta()`
150
+
151
+ If you're about to type `class="hero"` or `class="product-card"` in Mode A, stop — use the component instead.
152
+
153
+ **Mode B — Creative override (raw HTML throughout)**
154
+ When the design intent calls for a more expressive, unconventional, or typographically-driven layout that components would constrain, you may build with raw HTML throughout. This is a deliberate design decision, not a shortcut.
155
+
156
+ Rules for Mode B:
157
+ - Load `/pulse-ui.css` in `meta.styles` — the token system is still required
158
+ - Functional atoms (`button`, `input`, `badge`, `modal`) should still come from components unless there is a specific design reason
159
+ - The quality gate is 100/100/100/100 Lighthouse on both desktop and mobile — this replaces the component checklist as the pass bar
37
160
 
38
- Before writing any file, output a build brief so the user can see what is being constructed and catch misunderstandings before minutes of work are lost. Format:
161
+ Announce Mode B explicitly in the build brief: *"Mode B — component-free, raw HTML for creative control."*
162
+
163
+ ### 3b — Announce before writing
164
+
165
+ Before writing any file, output a build brief:
39
166
 
40
167
  ```
41
- Building: <page name> (<route>)
42
- State: <fields and types, or "none">
43
- Mutations: <list, or "none">
44
- Actions: <list with brief description, or "none">
45
- Server: <fetcher names and what they fetch, or "none">
46
- View: <key sections / landmarks>
47
- Files: <list of files that will be written>
168
+ Building: <page name> (<route>)
169
+ Mode: A — components first | B — creative override (raw HTML, reason: ...)
170
+ State: <fields and types, or "none">
171
+ Mutations: <list, or "none">
172
+ Actions: <list with brief description, or "none">
173
+ Server: <fetcher names and what they fetch, or "none">
174
+ Components: <which UI components you will use, or "none — Mode B">
175
+ View: <key sections / landmarks>
176
+ Files: <list of files that will be written>
48
177
  ```
49
178
 
50
- Output this before making any tool calls. Do not skip it for "simple" pages — a one-liner is fine for simple pages, but always output something.
179
+ One-liners are fine for simple pages, but always output something. **Declaring the mode upfront** makes the design intent explicit and prevents unnecessary component-reinvention warnings during review.
51
180
 
52
- ### 3b — Write
181
+ ### 3c — Write
53
182
 
54
- Write each file using the **Write tool** — not `pulse_create_page`. This shows the user a readable diff. Before each file write, output a one-line status (present-progressive, no tick — the work hasn't happened yet):
183
+ Write each file using the **Write tool** — not `pulse_create_page`. This shows the user a readable diff. Before each file write, output a one-line status (present-progressive):
55
184
 
56
185
  ```
57
186
  Writing src/pages/my-page.js...
@@ -63,9 +192,11 @@ After the Write tool completes, call `pulse_create_page(name)` to register the p
63
192
  ✓ src/pages/my-page.js written and registered.
64
193
  ```
65
194
 
66
- **Rule: never output `✓` before the tool call that confirms the result. Use present-progressive (`Writing...`, `Running...`, `Checking...`) for pre-tool announcements.**
195
+ ### 3d — Suggest (optional but recommended)
67
196
 
68
- If multiple files are needed (spec + shared component, spec + test stub, etc.), announce and write them one at a time with a status line before each.
197
+ After writing the first draft, call `pulse_suggest(content)` before running the hard validator. It catches obvious omissions collaboratively — a second opinion, not a gate.
198
+
199
+ **Rule: never output `✓` before the tool call that confirms the result.**
69
200
 
70
201
  ---
71
202
 
@@ -74,7 +205,7 @@ If multiple files are needed (spec + shared component, spec + test stub, etc.),
74
205
  Run `pulse_validate` on the spec file.
75
206
 
76
207
  - **If it passes:** output `✓ Validation clean — checking browser...` and continue.
77
- - **If it fails:** fix every error and every warning, then re-run. Repeat until clean. Do not continue until validation is clean.
208
+ - **If it fails:** fix every error and every warning, then re-run. Repeat until clean.
78
209
 
79
210
  ---
80
211
 
@@ -88,63 +219,82 @@ Do this before every screenshot, console check, or visual inspection. Never debu
88
219
 
89
220
  **Run `/verify` now — as soon as the first build is working.** Do not defer it to the end. Do not execute these steps manually.
90
221
 
91
- `/verify` is the canonical implementation of phases 4–7: it validates, screenshots, runs Lighthouse (desktop + mobile), runs the performance trace (LCP + CLS), checks console errors, runs `pulse_review`, and — critically — **writes the `.pulse-verified` stamp** at the end. Running the steps manually without writing the stamp will cause the stop hook to block.
222
+ `/verify` validates, screenshots, runs Lighthouse (desktop + mobile), runs the performance trace (LCP + CLS), checks console errors, runs `pulse_review`, and writes the `.pulse-verified` stamp. Running steps manually does not write the stamp.
223
+
224
+ > **Lighthouse pre-flight:** `/verify` calls `pulse_build` automatically before running Lighthouse, and audits against the production server on port 3001. If you ever call `lighthouse_audit` manually outside `/verify`, you must first run `pulse_build` and navigate to `http://localhost:3001/your-route`. Auditing the dev server (port 3000) will produce misleading results.
225
+
226
+ ### ⛔ After every screenshot — mandatory steps before continuing
227
+
228
+ Taking a screenshot is NOT the end of phase 5. After every screenshot, you **must** run:
229
+
230
+ 1. `pulse_design_review` (if `pulse_intake` ran) — work through all 7 signals, fix any Fail
231
+ 2. `pulse_layout_review <url>` — 390/768/1280px overflow, broken images, collapsed sections
232
+ 3. `/verify` — Lighthouse desktop + mobile (100/100/100) + CLS 0.00 + `pulse_review`
233
+
234
+ **Do not report the page as done until `/verify` writes the `.pulse-verified` stamp.** Skipping Lighthouse means broken contrast, missing landmarks, and Best Practices failures ship to the user.
92
235
 
93
- Pass gates (all must be met before continuing to Phase 6):
236
+ Pass gates:
94
237
  - Screenshot: no layout or rendering issues
238
+ - Design review: all 7 signals pass (or intake didn't run)
239
+ - Layout review: no overflow, broken images, or collapsed sections at any viewport
95
240
  - Lighthouse desktop: Accessibility, Best Practices, SEO all 100
96
- - Lighthouse mobile: same pass bar
97
- - **CLS: 0.00** — any layout shift is a blocker; fix it before proceeding
98
- - LCP: measured and reported; flag any fixable insight (render-blocking resources, large image delay)
241
+ - Lighthouse mobile: same
242
+ - **CLS: 0.00** — any layout shift is a blocker
99
243
  - No console errors
100
244
 
101
- **If any gate fails:** fix the issue and run `/verify` again. Repeat until all gates pass.
245
+ **If any gate fails:** fix and run `/verify` again.
102
246
 
103
- Output after passing: `✓ Verified — writing tests...`
247
+ **Troubleshooting browser profile lock:** If you see "browser already running" or chrome profile errors, another session is using the same Chrome profile. This is a `chrome-devtools-mcp` limitation — only one session can use the profile at a time. Ask the user to close other Claude sessions, or wait for the other session to finish.
248
+
249
+ **CSS-only changes after verification:** If you've already run `/verify` successfully and the user asks for minor CSS tweaks (margins, colours, spacing), you must run the full `/verify` workflow again — the stop hook checks the file mtime against the stamp. There is no lighter CSS-only check. This is by design: even CSS changes can affect CLS, colour contrast, or readability.
104
250
 
105
251
  ---
106
252
 
107
- ## Phase 6 — Tests (pass gate)
253
+ ## Phase 6 — Tests (pass gate, Tier 2+)
108
254
 
109
255
  Write tests for every spec you created or modified. At minimum:
110
256
 
111
- - Each mutation as a pure function (assert the returned state shape)
257
+ - Each mutation as a pure function
112
258
  - View renders expected HTML landmarks
113
259
  - Any utility functions defined in the spec
114
260
 
115
- Run the tests. Fix every failure. Repeat until all tests pass.
116
-
117
- Output after passing: `✓ Tests passing — ready for review.`
261
+ Run the tests. Fix every failure.
118
262
 
119
263
  ---
120
264
 
121
- ## Phase 7 — Review
265
+ ## Phase 7 — Review (Tier 2+)
122
266
 
123
- **Only invoke the Review Agent after all of the above gates have passed.** The reviewer must receive: passing validation, passing Lighthouse (desktop + mobile), and passing tests. Never hand off code that has not cleared every gate.
267
+ Only invoke `pulse_review` after phases 4–6 all pass. It checks the code for correctness, security, accessibility, DRY violations, and checklist adherence.
124
268
 
125
- The Review Agent checks the code for correctness, security, accessibility, DRY violations, and adherence to the checklist. It returns a list of issues.
126
-
127
- > Note: `/verify` includes the review step (`pulse_review`) — if you ran `/verify` and it passed cleanly, the Review Agent has already run. You do not need to invoke it again separately.
269
+ > Note: `/verify` includes the review step — if you ran `/verify` and it passed, the Review Agent has already run.
128
270
 
129
271
  ---
130
272
 
131
- ## Phase 8 — Fix review issues
273
+ ## Phase 8 — Fix review issues (Tier 3)
132
274
 
133
- Fix every issue raised by the Review Agent. If the fixes touch the spec or view, run `/verify` again — it re-runs validation, Lighthouse, the performance trace, console check, and review in one pass and writes a fresh stamp.
275
+ Fix every issue raised. If fixes touch the spec or view, run `/verify` again.
134
276
 
135
- Only declare the task done after phase 8 is complete and all gates still pass.
277
+ Only declare the task done after all gates still pass.
136
278
 
137
279
  ---
138
280
 
139
- ## Gate summary
281
+ ## Summary
140
282
 
141
283
  ```
142
- Phase 1 Understand (no gate — always run)
143
- Phase 2 Plan gate: user confirmation
144
- Phase 3 Build announce brief → write files (no gate, but always narrate)
145
- Phase 4 Validate gate: pulse_validate clean
146
- Phase 5 Browser gate: Lighthouse 100/100/100 (A/BP/SEO) + CLS 0.00, desktop + mobile
147
- Phase 6 Tests gate: all tests pass
148
- Phase 7 Review Agent (only reached after phases 4–6 all pass)
149
- Phase 8 Fix + re-verify gate: all gates still pass
284
+ New project / new page:
285
+ pulse_extract_inspiration → (if user shares a URL or image) extract palette/layout/feel
286
+ pulse_intake → capture real content, palette, vibe, anti-style
287
+ pulse_sketch → choose 1 of 3 structural layout directions
288
+ pulse_intent → get scaffold + guide list
289
+
290
+ Targeted edit / bug fix:
291
+ pulse_intent → (or skip entirely for trivial changes)
292
+
293
+ Step 1 Understand pulse_list_structure + relevant guides
294
+ Step 2 Plan confirm with user if non-trivial
295
+
296
+ Tier 1 Simple → phases 3 → 4 → 5
297
+ Tier 2 Standard → phases 3 → 4 → 5 → 6 → 7
298
+ Tier 3 Complex → phases 3 → 4 → 5 → 6 → 7 → 8
150
299
  ```
300
+