@zohofinance/commerce 1.0.0 → 1.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 (127) hide show
  1. package/README.md +59 -0
  2. package/package.json +2 -2
  3. package/ts-dist/mocks/init-theme/.claude/CLAUDE.md +6 -0
  4. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/SKILL.md +242 -0
  5. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/figma.md +81 -0
  6. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/screenshot.md +54 -0
  7. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/inputs/url.md +88 -0
  8. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/spec-table.md +102 -0
  9. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/accessibility.md +110 -0
  10. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/performance.md +127 -0
  11. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/tokens.md +87 -0
  12. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-section-from-design.20260528/verification/visual-diff.md +123 -0
  13. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/SKILL.md +605 -0
  14. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/design-tokens.md +105 -0
  15. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/page-json-contract.md +58 -0
  16. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/qa-accessibility.md +35 -0
  17. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/reference-lookup.md +94 -0
  18. package/ts-dist/mocks/init-theme/.claude/skills/.archive/zcommerce-theme-builder.20260528/section-anatomy.md +109 -0
  19. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/SKILL.md +313 -0
  20. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/agent-hierarchy.md +142 -0
  21. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/ask-developer.md +113 -0
  22. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/bootstrap.md +260 -0
  23. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/build-metrics.md +89 -0
  24. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/code-quality.md +186 -0
  25. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/common-pages-agent.md +97 -0
  26. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/dev-server-and-urls.md +136 -0
  27. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/exemplars.md +79 -0
  28. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/figma-discovery.md +138 -0
  29. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/figma-extraction.md +132 -0
  30. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/image-sources.md +84 -0
  31. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/inputs/guidelines-frame.md +178 -0
  32. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/page-builder.md +322 -0
  33. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/page-orchestrator.md +199 -0
  34. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/parallel-fanout.md +152 -0
  35. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/a11y.mjs +129 -0
  36. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/lint-section.mjs +502 -0
  37. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/perf.mjs +134 -0
  38. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/pixel-diff.mjs +206 -0
  39. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/scripts/record-build-metrics.mjs +118 -0
  40. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/section-builder.md +131 -0
  41. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/subagent-escalation.md +75 -0
  42. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/transcription-rules.md +98 -0
  43. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/verification.md +227 -0
  44. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/visual-verify-loop.md +117 -0
  45. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/_index.md +4 -0
  46. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/assets.md +105 -0
  47. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/best-practices.md +212 -0
  48. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/custom-scripts.md +294 -0
  49. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/i18n.md +155 -0
  50. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/introduction.md +91 -0
  51. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/layouts.md +158 -0
  52. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/pages.md +156 -0
  53. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/_index.md +4 -0
  54. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/filters.md +419 -0
  55. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/global-objects.md +415 -0
  56. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/schema-types.md +926 -0
  57. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/reference/tags.md +259 -0
  58. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/sections.md +203 -0
  59. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/setup-guide.md +424 -0
  60. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/snippets.md +70 -0
  61. package/ts-dist/mocks/init-theme/.claude/skills/theme-from-figma/zcommerce-docs/theme-structure.md +252 -0
  62. package/ts-dist/mocks/init-theme/.cursor/PLAYBOOK.md +144 -0
  63. package/ts-dist/mocks/init-theme/.cursor/README.md +6 -0
  64. package/ts-dist/mocks/init-theme/.cursor/agents/figma-desktop-mobile-parallel.md +48 -0
  65. package/ts-dist/mocks/init-theme/.cursor/agents/visual-compare.md +221 -0
  66. package/ts-dist/mocks/init-theme/.cursor/commands/add-field.md +83 -0
  67. package/ts-dist/mocks/init-theme/.cursor/commands/add-theme-setting.md +200 -0
  68. package/ts-dist/mocks/init-theme/.cursor/commands/assemble-page.md +72 -0
  69. package/ts-dist/mocks/init-theme/.cursor/commands/audit-page.md +57 -0
  70. package/ts-dist/mocks/init-theme/.cursor/commands/build-page-sections.md +110 -0
  71. package/ts-dist/mocks/init-theme/.cursor/commands/build-section.md +418 -0
  72. package/ts-dist/mocks/init-theme/.cursor/commands/build-theme.md +307 -0
  73. package/ts-dist/mocks/init-theme/.cursor/commands/compare-section.md +358 -0
  74. package/ts-dist/mocks/init-theme/.cursor/commands/create-theme.md +77 -0
  75. package/ts-dist/mocks/init-theme/.cursor/commands/extract-tokens.md +43 -0
  76. package/ts-dist/mocks/init-theme/.cursor/commands/fix-section.md +92 -0
  77. package/ts-dist/mocks/init-theme/.cursor/commands/impact.md +50 -0
  78. package/ts-dist/mocks/init-theme/.cursor/commands/qa-a11y.md +66 -0
  79. package/ts-dist/mocks/init-theme/.cursor/commands/qa-i18n.md +110 -0
  80. package/ts-dist/mocks/init-theme/.cursor/commands/qa-layout.md +127 -0
  81. package/ts-dist/mocks/init-theme/.cursor/commands/qa-performance.md +72 -0
  82. package/ts-dist/mocks/init-theme/.cursor/commands/qa-section.md +84 -0
  83. package/ts-dist/mocks/init-theme/.cursor/commands/qa-sections.md +48 -0
  84. package/ts-dist/mocks/init-theme/.cursor/commands/qa-theme.md +85 -0
  85. package/ts-dist/mocks/init-theme/.cursor/commands/redesign-section.md +177 -0
  86. package/ts-dist/mocks/init-theme/.cursor/commands/refactor-section.md +185 -0
  87. package/ts-dist/mocks/init-theme/.cursor/commands/sync-theme-settings.md +132 -0
  88. package/ts-dist/mocks/init-theme/.cursor/commands/validate-page.md +60 -0
  89. package/ts-dist/mocks/init-theme/.cursor/commands/validate-section-group.md +88 -0
  90. package/ts-dist/mocks/init-theme/.cursor/commands/validate-theme-settings.md +119 -0
  91. package/ts-dist/mocks/init-theme/.cursor/examples/design-instructions-template.md +151 -0
  92. package/ts-dist/mocks/init-theme/.cursor/mcp.json +18 -0
  93. package/ts-dist/mocks/init-theme/.cursor/rules/README.md +160 -0
  94. package/ts-dist/mocks/init-theme/.cursor/rules/accessibility.mdc +24 -0
  95. package/ts-dist/mocks/init-theme/.cursor/rules/add-field.mdc +222 -0
  96. package/ts-dist/mocks/init-theme/.cursor/rules/add-theme-setting.mdc +39 -0
  97. package/ts-dist/mocks/init-theme/.cursor/rules/assemble-page.mdc +130 -0
  98. package/ts-dist/mocks/init-theme/.cursor/rules/audit-page.mdc +92 -0
  99. package/ts-dist/mocks/init-theme/.cursor/rules/build-section.mdc +178 -0
  100. package/ts-dist/mocks/init-theme/.cursor/rules/build-theme.mdc +47 -0
  101. package/ts-dist/mocks/init-theme/.cursor/rules/compare-section.mdc +94 -0
  102. package/ts-dist/mocks/init-theme/.cursor/rules/create-theme.mdc +78 -0
  103. package/ts-dist/mocks/init-theme/.cursor/rules/css.mdc +137 -0
  104. package/ts-dist/mocks/init-theme/.cursor/rules/design-spec-extraction.mdc +255 -0
  105. package/ts-dist/mocks/init-theme/.cursor/rules/extract-tokens.mdc +43 -0
  106. package/ts-dist/mocks/init-theme/.cursor/rules/figma-mcp-resolution.mdc +40 -0
  107. package/ts-dist/mocks/init-theme/.cursor/rules/fix-section.mdc +154 -0
  108. package/ts-dist/mocks/init-theme/.cursor/rules/general.mdc +30 -0
  109. package/ts-dist/mocks/init-theme/.cursor/rules/i18n.mdc +85 -0
  110. package/ts-dist/mocks/init-theme/.cursor/rules/javascript.mdc +85 -0
  111. package/ts-dist/mocks/init-theme/.cursor/rules/liquid-no-hardcoded-strings.mdc +42 -0
  112. package/ts-dist/mocks/init-theme/.cursor/rules/liquid.mdc +171 -0
  113. package/ts-dist/mocks/init-theme/.cursor/rules/mobile-desktop-setting-meta.mdc +34 -0
  114. package/ts-dist/mocks/init-theme/.cursor/rules/naming-convention.mdc +64 -0
  115. package/ts-dist/mocks/init-theme/.cursor/rules/pages.mdc +120 -0
  116. package/ts-dist/mocks/init-theme/.cursor/rules/performance.mdc +51 -0
  117. package/ts-dist/mocks/init-theme/.cursor/rules/qa-section.mdc +134 -0
  118. package/ts-dist/mocks/init-theme/.cursor/rules/redesign-section.mdc +147 -0
  119. package/ts-dist/mocks/init-theme/.cursor/rules/schema-sync.mdc +110 -0
  120. package/ts-dist/mocks/init-theme/.cursor/rules/schema.mdc +360 -0
  121. package/ts-dist/mocks/init-theme/.cursor/rules/share-urls.mdc +68 -0
  122. package/ts-dist/mocks/init-theme/.cursor/skills/browser-verify.md +128 -0
  123. package/ts-dist/mocks/init-theme/.cursor/skills/design-tokens.md +105 -0
  124. package/ts-dist/mocks/init-theme/.cursor/skills/page-json-contract.md +87 -0
  125. package/ts-dist/mocks/init-theme/.cursor/skills/qa-accessibility.md +35 -0
  126. package/ts-dist/mocks/init-theme/.cursor/skills/reference-lookup.md +88 -0
  127. package/ts-dist/mocks/init-theme/.cursor/skills/section-anatomy.md +173 -0
@@ -0,0 +1,260 @@
1
+ # Stage 0 — Bootstrap
2
+
3
+ Serial, single agent, runs once at the start. ~30s budget.
4
+
5
+ **Read first:** `zcommerce-docs/theme-structure.md` (required folder layout, naming conventions) and `zcommerce-docs/setup-guide.md` (CLI commands, `?format=json` data inspection tip). The folder structure bootstrap creates must match exactly what these docs prescribe.
6
+
7
+ **Start the build clock** — write `.claude/scratchpad/<theme>/build-started.json`:
8
+
9
+ ```json
10
+ { "theme": "<theme_name>", "started_at": "<ISO8601>", "figma_file_key": "<key>" }
11
+ ```
12
+
13
+ **Ask developer for dev config** — before any browser work, collect `storeUrl` and confirm page URLs. Write `.claude/scratchpad/<theme>/dev-config.json`:
14
+
15
+ ```json
16
+ {
17
+ "store_url": "",
18
+ "page_urls": {},
19
+ "confirmed_by_developer": false
20
+ }
21
+ ```
22
+
23
+ See `dev-server-and-urls.md`. Do not navigate until `confirmed_by_developer` is true.
24
+
25
+ Stage 2 runs `record-build-metrics.mjs` against build-started.json. See `build-metrics.md`.
26
+
27
+ ## Core principle
28
+
29
+ Bootstrap creates an **empty theme**. It does NOT copy any `.liquid` file, snippet, asset, image, or font from any existing theme. Every visual artefact in the finished theme is either:
30
+
31
+ 1. Generated from the developer's guidelines frame (tokens), or
32
+ 2. Extracted from the developer's per-page Figma frames (sections, assets), or
33
+ 3. Written fresh by the page agents and the common-pages agent (Liquid markup, snippets) from the official docs — never copied from another theme.
34
+
35
+ There is no base theme to copy from. Agents build fresh code for this theme from the official ZCommerce docs (`zcommerce-docs/`).
36
+
37
+ ## What bootstrap produces
38
+
39
+ ```
40
+ <theme_name>/
41
+ assets/
42
+ fingerprint.json (empty {} — populated by agents from Figma assets)
43
+ main.css (Tailwind entry — @import theme-settings.css + @tailwind directives)
44
+ theme-settings.css (utility classes for tokens — sr-only, font-heading, etc.)
45
+ i18n/
46
+ en.json ({} — keys appended by agents during build)
47
+ en.schema.json ({} — keys appended by agents during build)
48
+ layouts/
49
+ theme.liquid (written fresh — see step 3)
50
+ accounts.liquid (written fresh — see step 3)
51
+ sitemap.liquid (written fresh — see step 3)
52
+ pages/ (empty — page JSONs written by page agents + common-pages agent)
53
+ sections/ (empty — section .liquid files written by agents)
54
+ snippets/ (empty — snippets written by agents when needed)
55
+ settings/
56
+ schema.json (generated from guidelines frame)
57
+ theme.json (generated from guidelines frame)
58
+ figma-variables.json (generated from guidelines frame)
59
+ tailwind.config.js (generated from guidelines frame)
60
+ postcss.config.js (generated from a standard template)
61
+ package.json (generated with new theme name)
62
+ project.json (generated with new theme name)
63
+ ```
64
+
65
+ ## Steps
66
+
67
+ ### 1. Validate inputs
68
+
69
+ - Theme name (snake-case, no existing folder with this name).
70
+ - `figma_file_key` from command (required for full theme build).
71
+ - Page map from **auto-discovery** (`figma-discovery.md`) — NOT from developer-pasted URLs unless discovery failed.
72
+ - Guidelines tokens from Guidelines frame inside the discovered file (see `inputs/guidelines-frame.md`).
73
+
74
+ If `figma_file_key` was provided, run discovery first. Only ask for page URLs when discovery fails. Never ask which theme to use as a template.
75
+
76
+ ### 2. Create folder structure
77
+
78
+ ```bash
79
+ THEME=<theme_name> # snake-case, e.g. orange_market
80
+ THEME_KEBAB="${THEME//_/-}"
81
+
82
+ mkdir -p $THEME/{assets,i18n,layouts,sections,snippets,settings,pages,thumbnail_images}
83
+
84
+ # Empty files that need to exist for the build pipeline
85
+ echo '{}' > $THEME/assets/fingerprint.json
86
+ echo '{}' > $THEME/i18n/en.json
87
+ echo '{}' > $THEME/i18n/en.schema.json
88
+ ```
89
+
90
+ Notice: **no `cp` commands.** Bootstrap copies nothing from any theme.
91
+
92
+ ### 3. Synthesize layout files
93
+
94
+ Layout files (`theme.liquid`, `accounts.liquid`, `sitemap.liquid`) are mostly identical across themes by convention — they're HTML wrappers that handle `<head>`, asset/font loading, the `content_for_*` hooks, and footer scripts.
95
+
96
+ Bootstrap synthesizes these by:
97
+ 1. Reading `zcommerce-docs/layouts.md` for the required structure (what `content_for_header` / `content_for_layout` / `content_for_footer` do, where they must go).
98
+ 2. Writing a fresh `layouts/theme.liquid` using the new theme's tokens (font preloads from `theme.json`, asset URLs via `asset_url` filter, semantic HTML).
99
+
100
+ The result must follow the documented layout conventions. The agent reads for *what content goes where* from the docs, not from any other theme file.
101
+
102
+ Same for `accounts.liquid` and `sitemap.liquid`.
103
+
104
+ ### 4. Extract tokens from the guidelines frame
105
+
106
+ Follow `inputs/guidelines-frame.md` end to end:
107
+ 1. Call `get_screenshot` on the guidelines node at `maxDimension: 2400` with `enableBase64Response: true`.
108
+ 2. Read the rendered image with vision — extract fonts, colors, button states, component specs.
109
+ 3. Map names to schema keys (PRIMARY → `color_primary`, BOARDER typo → `color_border`, etc.).
110
+ 4. Derive on-colors via WCAG contrast math.
111
+ 5. Write to `settings/theme.json`, `settings/schema.json`, `figma-variables.json`.
112
+
113
+ ### 5. Generate tailwind.config.js
114
+
115
+ Write a fresh `tailwind.config.js` extending Tailwind with CSS variables for every token in `theme.json`:
116
+ - `theme.extend.colors.primary` → `var(--color-primary)` (and so on for each color)
117
+ - `theme.extend.spacing` for each space token
118
+ - `theme.extend.borderRadius` for each radius
119
+ - `theme.extend.fontFamily.heading` and `.body` from the guidelines frame
120
+
121
+ The content paths array must point at the new theme's directories (paths are relative to the theme root):
122
+ ```js
123
+ content: [
124
+ './pages/*.liquid',
125
+ './sections/*.liquid',
126
+ './snippets/*.liquid',
127
+ './layouts/*.liquid',
128
+ './assets/*.js',
129
+ ],
130
+ ```
131
+
132
+ Use Tailwind v3 conventions (the project's standard).
133
+
134
+ ### 6. Generate postcss.config.js, assets/main.css, package.json, project.json
135
+
136
+ Match the standard multi-theme pattern — do not use bare `npx @zohofinance/commerce` stubs.
137
+
138
+ ```js
139
+ // postcss.config.js
140
+ module.exports = {
141
+ plugins: { tailwindcss: {}, autoprefixer: {} },
142
+ };
143
+ ```
144
+
145
+ ```css
146
+ /* assets/main.css */
147
+ @import 'theme-settings.css';
148
+
149
+ @tailwind base;
150
+ @tailwind components;
151
+ @tailwind utilities;
152
+
153
+ html, body { height: 100%; display: flex; flex-direction: column; }
154
+ footer { margin-top: auto; }
155
+ ```
156
+
157
+ ```css
158
+ /* assets/theme-settings.css — minimal utilities; agents may extend */
159
+ .font-heading { font-family: var(--font-heading); }
160
+ .font-body { font-family: var(--font-body); }
161
+ .max-w-container-theme { max-width: var(--page-width); }
162
+ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border-width: 0; }
163
+ ```
164
+
165
+ **Naming convention:**
166
+ - `package.json` → `"name": "<theme_name>"` (snake_case folder name, e.g. `my_theme`)
167
+ - `project.json` → `"name": "<theme-kebab>"` (underscores → hyphens, e.g. `my-theme`)
168
+
169
+ ```json
170
+ // package.json — replace <theme_name> with the folder name
171
+ {
172
+ "name": "<theme_name>",
173
+ "version": "1.0.0",
174
+ "type": "module",
175
+ "zcommerce": {
176
+ "thumbnail_images": {
177
+ "desktop_image": "thumbnail_images/desktop.png",
178
+ "mobile_image": "thumbnail_images/mobile.png"
179
+ }
180
+ },
181
+ "scripts": {
182
+ "prebuild:dev": "tailwindcss -i ./assets/main.css -o ./assets/style.css",
183
+ "dev": "yarn prebuild:dev && npx @zohofinance/commerce theme dev",
184
+ "build": "npx @zohofinance/commerce theme build"
185
+ },
186
+ "dependencies": {
187
+ "@tailwindcss/typography": "^0.5.16",
188
+ "@zohofinance/commerce": "latest",
189
+ "postcss": "^8.4.38"
190
+ },
191
+ "devDependencies": {
192
+ "autoprefixer": "^10.4.19",
193
+ "tailwindcss": "^3.4.3"
194
+ },
195
+ "volta": {
196
+ "node": "18.20.4",
197
+ "yarn": "1.22.10"
198
+ }
199
+ }
200
+ ```
201
+
202
+ Also create `thumbnail_images/` (empty — designer adds desktop.png / mobile.png before deploy).
203
+
204
+ ### 7. Hard assertions before handing off
205
+
206
+ Bootstrap MUST exit with `FATAL` if any of these are violated:
207
+
208
+ ```bash
209
+ # No .liquid files copied from anywhere
210
+ test "$(find $THEME -name '*.liquid' -not -path '*/layouts/*' | wc -l)" -eq 0 || \
211
+ { echo "FATAL: .liquid files exist outside layouts/ — bootstrap should not create sections/snippets" >&2; exit 1; }
212
+
213
+ # layouts/ has exactly the three expected files
214
+ test "$(ls $THEME/layouts/ | wc -l)" -eq 3 || \
215
+ { echo "FATAL: layouts/ should contain exactly theme.liquid, accounts.liquid, sitemap.liquid" >&2; exit 1; }
216
+
217
+ # assets/ has only bootstrap stubs (no images/fonts copied from sibling themes)
218
+ ALLOWED_ASSETS='^(fingerprint\.json|main\.css|theme-settings\.css)$'
219
+ test "$(ls $THEME/assets/ | grep -Ev "$ALLOWED_ASSETS" | wc -l)" -eq 0 || \
220
+ { echo "FATAL: assets/ should only contain fingerprint.json, main.css, theme-settings.css at bootstrap" >&2; ls $THEME/assets/; exit 1; }
221
+
222
+ # pages/ is empty (page agents create them)
223
+ test "$(ls $THEME/pages/ 2>/dev/null | wc -l)" -eq 0 || \
224
+ { echo "FATAL: pages/ should be empty after bootstrap" >&2; exit 1; }
225
+
226
+ # project.json + package.json have the new name (package = folder, project = kebab)
227
+ grep -q "\"name\": \"$THEME\"" $THEME/package.json || \
228
+ { echo "FATAL: package.json name must be $THEME" >&2; exit 1; }
229
+ grep -q "\"name\": \"$THEME_KEBAB\"" $THEME/project.json || \
230
+ { echo "FATAL: project.json name must be $THEME_KEBAB" >&2; exit 1; }
231
+
232
+ # Tailwind entry exists
233
+ test -f $THEME/assets/main.css || \
234
+ { echo "FATAL: assets/main.css missing" >&2; exit 1; }
235
+
236
+ # theme.json reflects guidelines frame tokens (sanity-check primary is set)
237
+ python3 -c "import json; d=json.load(open('$THEME/settings/theme.json')); assert d['presets']['default']['color_primary'].startswith('#'), 'primary color not set'" \
238
+ || { echo "FATAL: theme.json tokens not populated from guidelines frame" >&2; exit 1; }
239
+ ```
240
+
241
+ ### 8. Emit a stage-0 report
242
+
243
+ ```
244
+ Stage 0 — Bootstrap complete (32s)
245
+ ├─ theme: orange_market
246
+ ├─ folders created: 8 (all empty except config + tokens)
247
+ ├─ tokens: 47 extracted from guidelines frame
248
+ ├─ layouts: 3 written fresh (synthesized from docs)
249
+ ├─ tailwind.config.js + theme.json + figma-variables.json generated
250
+ └─ pages/, sections/, snippets/, assets/ all empty — agents build them
251
+
252
+ Next: stage 1 — index agent (builds header + footer + index sections)
253
+ ```
254
+
255
+ ## Failure modes
256
+
257
+ - **Guidelines frame URL missing or unreadable** → ask developer once. Without the guidelines frame, the skill cannot produce a theme.
258
+ - **Theme name already exists** → ask whether to overwrite. Never silently overwrite — the developer might lose work.
259
+ - **Sandbox can't reach Figma** → fall back to base64 mode for screenshots, surface specific assets the developer needs to export manually.
260
+ - **Hex codes unreadable in the guidelines screenshot** → re-render at `maxDimension: 3600`. If still unreadable, ask developer for the hex values once.
@@ -0,0 +1,89 @@
1
+ # Build metrics — mandatory end-of-run report
2
+
3
+ Every `/build-theme` run MUST end with a metrics block in `.claude/scratchpad/<theme>/report.md`.
4
+
5
+ ## Record start time (Stage 0)
6
+
7
+ At bootstrap, write:
8
+
9
+ ```json
10
+ // .claude/scratchpad/<theme>/build-started.json
11
+ {
12
+ "theme": "<theme_name>",
13
+ "started_at": "2026-06-10T14:32:00.000Z",
14
+ "figma_file_key": "<figma_file_key>"
15
+ }
16
+ ```
17
+
18
+ ## Collect metrics (Stage 2)
19
+
20
+ ```bash
21
+ node .claude/skills/theme-from-figma/scripts/record-build-metrics.mjs <theme_name>
22
+ ```
23
+
24
+ Paste the script output into `report.md` under `## Build metrics`.
25
+
26
+ ## Report template (append to report.md)
27
+
28
+ ```markdown
29
+ ## Build metrics
30
+
31
+ | Metric | Value |
32
+ |---|---|
33
+ | Wall-clock duration | 42m 18s |
34
+ | Bootstrap | 28s |
35
+ | Page builds (parallel) | 38m 52s (slowest: product) |
36
+ | Consolidation | 2m 58s |
37
+ | Sections built | 23 |
38
+ | Snippets built | 14 |
39
+ | Visual verify loops | 31 (avg 1.4 iterations/section) |
40
+ | Sections with 0 CRITICAL after verify | 21/23 |
41
+ | Pages visually verified (desktop+mobile) | 5/5 |
42
+ | Lighthouse a11y (pages) | 5 pass / 0 fail |
43
+ | Lighthouse perf mobile (pages) | avg 91 |
44
+ | Lint failures fixed during build | 6 |
45
+ | verify-theme.mjs | PASS / FAIL |
46
+
47
+ ### Token estimate (approximate)
48
+
49
+ Cursor does not expose per-run token counts to agents. Provide a **range estimate** based on run complexity:
50
+
51
+ | Build profile | Typical agent turns | Approx. tokens |
52
+ |---|---|---|
53
+ | Small theme (≤15 sections, 1 iteration each) | 80–120 | 800K–1.5M |
54
+ | Medium theme (20–30 sections, 1–2 iterations) | 150–250 | 1.5M–3M |
55
+ | Large theme (30+ sections, visual re-loops) | 250–400+ | 3M–6M+ |
56
+
57
+ Record what you observe:
58
+ - **Estimated input tokens:** ~2.8M (based on 5 page orchestrators + 23 section subagents + consolidation)
59
+ - **Estimated output tokens:** ~420K
60
+ - **Confidence:** low / medium / high
61
+
62
+ Factors that increase cost: visual re-loops (>2 per section), stalled subagents, whole-page fixes, large Figma frames.
63
+
64
+ ### Cost / time insights for developers
65
+
66
+ - **Parallel page agents** save wall-clock (~5× vs serial) but do not reduce total tokens.
67
+ - **Per-section Chrome DevTools verify** is the highest-ROI step for Figma fidelity — skipping it is why output drifted.
68
+ - **First-time builds** average 35–60 min wall-clock for a 5-page theme.
69
+ - **Re-runs** on a single page after feedback: 5–15 min.
70
+
71
+ ### Per-page breakdown
72
+
73
+ | Page | Sections | Wall time | Visual iters | CRITICAL remaining |
74
+ |---|---|---|---|---|
75
+ | index | 8 | 12m 04s | 9 | 0 |
76
+ | product | 2 | 8m 22s | 4 | 0 |
77
+ | collection | 2 | 6m 15s | 3 | 0 |
78
+ | blog_list | 2 | 4m 48s | 2 | 0 |
79
+ | blog_detail | 2 | 5m 10s | 2 | 0 |
80
+ ```
81
+
82
+ ## Who writes what
83
+
84
+ | Agent | Writes |
85
+ |---|---|
86
+ | Bootstrap (Stage 0) | `build-started.json` |
87
+ | Section subagent | `pages/<page>/sections/<section>/visual-diff.md` with iteration count |
88
+ | Page orchestrator | `pages/<page>/report.md` with page wall time |
89
+ | Consolidator (Stage 2) | Runs `record-build-metrics.mjs`, final `report.md` |
@@ -0,0 +1,186 @@
1
+ # Code quality — strict budgets, enforced at write time
2
+
3
+ The single biggest source of past iterations was AI-generated code being structurally heavier than necessary. This document defines hard budgets and the write-time lint that enforces them. **The lint script (`scripts/lint-section.mjs`) is the source of truth — these rules describe what it checks.**
4
+
5
+ **Read also:** `zcommerce-docs/best-practices.md` — the official ZCommerce best-practices doc covering performance (minify, defer JS, async, preload), security (escape user output, avoid inline scripts from settings, use `json` filter for data), and accessibility (semantic HTML, alt text, form labels, heading hierarchy). The lint catches the syntactic violations of these rules; the doc explains the reasoning.
6
+
7
+ ## Budgets (calibrated to existing exemplars)
8
+
9
+ | Metric | Budget | Why | Exemplar reference |
10
+ |---|---:|---|---|
11
+ | Tailwind utility classes per element | **≤ 12** | More than ~12 = unreadable class soup; extract to `{% style %}` block. | hero-banner.liquid (max 14 was top of range; we tighten to 12). |
12
+ | DOM nesting depth per section | **≤ 6** | Anything deeper indicates redundant wrappers. | All exemplars are 3–6. |
13
+ | Section file total lines | **≤ 250** | Section files over ~250 lines should be split into snippets. | Largest exemplar is 238 (blog-list); typical 80–170. |
14
+ | Empty wrapper `<div>`s | **0** | A wrapper that contains a single element with no layout role is removable. | All exemplars have zero. |
15
+ | `{% if %}` nesting depth | **≤ 2** | Three-deep `if` chains indicate a `case` is needed. | Exemplars use `case` for branching. |
16
+ | Top-level `{% liquid %}` block | **1** | All `assign`s in one block at the top, not scattered. | Standard hero-banner pattern across themes. |
17
+ | Inline `onclick=` / `onload=` etc. | **0** | All JS via `data-*` + external script. | CLAUDE.md rule. |
18
+ | Hardcoded hex colors | **0** | Always a theme token. | CLAUDE.md rule. |
19
+ | Hardcoded px font-size in inline `style=` | **0** | Use Tailwind class or `{% style %}` block. | CLAUDE.md rule. |
20
+ | Schema fields not wired to markup | **0** | Every `id` in `{% schema %}` settings is referenced by the markup. | The most common build error. |
21
+ | `rounded-*` without spec radius | **0** | Only if `figma-spec.json` has `border_radius > 0` for that element. | `transcription-rules.md` |
22
+ | Product grid images without fixed media box | **flag** | Cards must use spec `w`×`h` + `object-fit` — not natural img height. | Uneven card heights bug |
23
+
24
+ ## Soft signals (warn, don't block)
25
+
26
+ | Signal | Threshold | Comment |
27
+ |---|---|---|
28
+ | Sections that look like header/footer | should never go to `sections/header.liquid` etc — those are locked | If you find yourself wanting to write header content, you took the wrong work. |
29
+ | Use of arbitrary Tailwind values `text-[19px]` | > 3 per section | Means the design isn't on the token grid. Consider adding a token. |
30
+ | `<div>` to `<div class="...">` ratio | > 30% bare divs | Likely missing semantic elements (`<section>`, `<article>`, `<nav>`). |
31
+
32
+ ---
33
+
34
+ ## Pre-write checklist (run mentally before writing each section file)
35
+
36
+ The agent must answer each before writing:
37
+
38
+ 1. **Anchor exemplar identified?** What's the closest match in `exemplars.md` and what are its metrics?
39
+ 2. **Element count?** Roughly how many DOM elements will this section have? If > 1.5× the exemplar's, why?
40
+ 3. **Max class count per element?** Mentally count classes on the most-styled element. If > 12, plan to move them to `{% style %}`.
41
+ 4. **DOM depth?** Sketch the hierarchy. If > 6 levels deep, identify the redundant wrappers.
42
+ 5. **Schema field count?** List the fields you'll define. For each, where will it appear in markup?
43
+ 6. **Liquid logic complexity?** Any `if` inside `if` inside `for`? Refactor before writing.
44
+
45
+ If any answer is suspicious, **re-plan, don't write**. Bad code is harder to delete than to never write.
46
+
47
+ ---
48
+
49
+ ## Write-time lint (run by the agent after writing each section, automated)
50
+
51
+ The agent runs:
52
+
53
+ ```bash
54
+ node .claude/skills/theme-from-figma/scripts/lint-section.mjs \
55
+ sections/<section_name>.liquid
56
+ ```
57
+
58
+ The script outputs a JSON report:
59
+
60
+ ```json
61
+ {
62
+ "file": "lush_market/sections/hero-banner.liquid",
63
+ "lines": 98,
64
+ "checks": {
65
+ "lines_under_250": { "pass": true, "actual": 98 },
66
+ "max_classes_per_el": { "pass": true, "actual": 11, "budget": 12, "elementHint": "<a class=\"...\">" },
67
+ "max_dom_depth": { "pass": true, "actual": 5, "budget": 6 },
68
+ "empty_wrappers": { "pass": true, "count": 0 },
69
+ "if_nesting_depth": { "pass": true, "actual": 1, "budget": 2 },
70
+ "single_liquid_block": { "pass": true, "actual": 1 },
71
+ "inline_event_handlers":{ "pass": true, "count": 0 },
72
+ "hardcoded_hex": { "pass": true, "count": 0 },
73
+ "hardcoded_inline_px": { "pass": true, "count": 0 },
74
+ "schema_fields_wired": { "pass": false, "unused": ["unused_subtext"], "wired": 8, "total": 9 },
75
+ "render_not_include": { "pass": true, "count_include": 0 },
76
+ "escape_user_output": { "pass": true, "warnings": [] }
77
+ },
78
+ "verdict": "FAIL"
79
+ }
80
+ ```
81
+
82
+ If `verdict === "FAIL"`, the agent **must fix** before continuing. The agent is not allowed to silence a check.
83
+
84
+ ## Common rejections and how to fix
85
+
86
+ ### `max_classes_per_el` failure
87
+
88
+ The lint shows the offending element. Move repeating utility classes into a `{% style %}` block:
89
+
90
+ ```liquid
91
+ <!-- BEFORE: 18 classes -->
92
+ <a class="inline-flex items-center justify-center px-theme-8 py-theme-3 bg-primary text-on-primary font-semibold rounded-theme-button hover:bg-primary-hover focus:ring-2 focus:ring-offset-2 transition-colors text-base md:text-lg">
93
+ {{ block.settings.button_label }}
94
+ </a>
95
+
96
+ <!-- AFTER: 1 class, 1 attribute -->
97
+ <a class="cta-btn" href="{{ block.settings.button_link.handle }}">{{ block.settings.button_label }}</a>
98
+
99
+ {% style %}
100
+ #section-{{ section.id }} .cta-btn {
101
+ display: inline-flex; align-items: center; justify-content: center;
102
+ padding: var(--space-3) var(--space-8);
103
+ background: var(--color-primary); color: var(--color-on-primary);
104
+ font-weight: 600; border-radius: var(--radius-button);
105
+ transition: background 0.15s ease;
106
+ }
107
+ #section-{{ section.id }} .cta-btn:hover { background: var(--color-accent); }
108
+ {% endstyle %}
109
+ ```
110
+
111
+ ### `max_dom_depth` failure
112
+
113
+ Walk the tree and find redundant wrappers:
114
+
115
+ ```liquid
116
+ <!-- BEFORE: depth 8 -->
117
+ <section>
118
+ <div>
119
+ <div class="container">
120
+ <div class="row">
121
+ <div class="col">
122
+ <div class="card">
123
+ <div class="card-body">
124
+ <h2>...</h2>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ </div>
130
+ </div>
131
+ </section>
132
+
133
+ <!-- AFTER: depth 4 -->
134
+ <section id="section-{{ section.id }}" class="hero-section">
135
+ <div class="max-w-container-theme mx-auto px-theme-4">
136
+ <article class="hero-card">
137
+ <h2>...</h2>
138
+ </article>
139
+ </div>
140
+ </section>
141
+ ```
142
+
143
+ ### `empty_wrappers` failure
144
+
145
+ A `<div>` whose only child is another single element with no layout role:
146
+
147
+ ```liquid
148
+ <!-- BEFORE -->
149
+ <div>
150
+ <div class="text-center">
151
+ <h2>{{ heading }}</h2>
152
+ </div>
153
+ </div>
154
+
155
+ <!-- AFTER -->
156
+ <h2 class="text-center">{{ heading }}</h2>
157
+ ```
158
+
159
+ ### `schema_fields_wired` failure
160
+
161
+ The schema declares a setting but the markup never references it. Either wire it or remove it:
162
+
163
+ ```liquid
164
+ {% schema %}
165
+ {
166
+ "settings": [
167
+ { "type": "text", "id": "heading", "default": "..." },
168
+ { "type": "text", "id": "subheading", "default": "..." } ← never referenced!
169
+ ]
170
+ }
171
+ {% endschema %}
172
+ ```
173
+
174
+ Remove `subheading` from the schema, or add `{{ section.settings.subheading }}` somewhere.
175
+
176
+ ---
177
+
178
+ ## What the lint does NOT check
179
+
180
+ - Visual fidelity → that's the pixel-diff gate (`verification.md`).
181
+ - Accessibility violations → that's the a11y gate.
182
+ - Performance → that's the perf gate.
183
+ - Semantic correctness (does `<article>` make sense here?) → human judgment.
184
+ - Typos in copy → not the lint's job.
185
+
186
+ The lint exists for structural code quality. The four gates exist for behavioral correctness. Both layers run.
@@ -0,0 +1,97 @@
1
+ # Common-pages agent (Stage 1c)
2
+
3
+ While the index agent and four parallel page agents build the Figma-driven pages, a sixth agent handles the **common pages** that have no Figma: cart, checkout, account flows, 404, signin, signup, forgotpassword, custom-page, payment, sitemap, orders.
4
+
5
+ These pages exist in every theme but don't have per-theme designs in the input. The agent's job: read multiple themes' implementations to learn the LOGIC, then write fresh code that applies the new theme's tokens.
6
+
7
+ ## Why a separate agent
8
+
9
+ Common pages have business logic (cart calculations, checkout steps, account form validation) that the index/page agents don't need to know. Isolating them in one agent:
10
+ 1. Keeps the page agents focused on Figma-driven sections.
11
+ 2. Lets the common-pages agent specialize in reading across many themes for any one archetype.
12
+ 3. Allows parallel work — common-pages agent runs alongside the page agents.
13
+
14
+ ## When it runs
15
+
16
+ Stage 1c runs **in parallel with** Stage 1b (the four page agents that wait for the header-footer-ready marker). It does NOT wait for the marker because the common pages don't render the header/footer during the agent's own per-section verification (those layouts wrap them, but per-section gates use just the section's HTML).
17
+
18
+ ```
19
+ Stage 1a: index agent (header + footer + index sections) ████████████ ~4min
20
+ Stage 1b: listing ─────────────████ ~3min
21
+ product ─────────────█████ ~5min
22
+ blog_list ─────────────███ ~2min
23
+ blog_detail ─────────────███ ~2min
24
+ Stage 1c: common-pages agent (cart, checkout, etc.) ─────────████████ ~5min
25
+ ```
26
+
27
+ ## Inputs
28
+
29
+ From the orchestrator:
30
+ - Theme folder path.
31
+ - Scratchpad path at `.claude/scratchpad/<theme>/common-pages/`.
32
+ - Locked files: `theme.json`, `tailwind.config.js`, `figma-variables.json` (no header/footer lock — they don't exist yet when this agent starts; the agent waits for the header-footer-ready marker before its own per-page verification step, not before writing).
33
+
34
+ ## Pages it owns
35
+
36
+ | Page route | Page JSON | Section files this agent writes |
37
+ |---|---|---|
38
+ | `/cart` | `pages/cart.json` | `cart-list.liquid`, `cart-popup.liquid`, `cart-empty.liquid` snippet |
39
+ | `/checkout` | `pages/checkout.json` | `checkout.liquid` + `checkout-steps.liquid` snippet |
40
+ | `/account/profile` | `pages/account-profile.json` | `account-profile.liquid` + `account-tab-navigation.liquid` |
41
+ | `/account/address` | `pages/account-address.json` | `account-address.liquid` + `account-address-card.liquid` snippet |
42
+ | `/account/orders` | `pages/account-order.json` | `account-order.liquid` |
43
+ | `/account/order/<id>` | `pages/account-order-detail.json` | `accounts-order-details.liquid` |
44
+ | `/account/order/<id>/status` | `pages/account-order-status.json` | `account-order-status.liquid` |
45
+ | `/orders` | `pages/orders.json` | `orders.liquid` |
46
+ | `/payment/<status>` | `pages/payment.json` | (status sections) |
47
+ | `/signin` | `pages/signin.json` | `signin.liquid` |
48
+ | `/signup` | `pages/signup.json` | `signup.liquid` |
49
+ | `/forgotpassword` | `pages/forgotpassword.json` | `forgotpassword.liquid` |
50
+ | `/404` | `pages/404.json` | `404.liquid` |
51
+ | `/page/<slug>` | `pages/page.json` | `page.liquid` |
52
+ | `/sitemap` | `pages/sitemap.json` | (uses `layouts/sitemap.liquid`) |
53
+
54
+ ## Workflow per archetype
55
+
56
+ For each archetype above:
57
+
58
+ 1. **Explore.** Read every theme's implementation of this archetype (per `exemplars.md` § "Archetype → candidate themes"). Read minimum three; ideally all that have one.
59
+ 2. **Synthesize logic.** Identify common patterns:
60
+ - Cart: line-item rendering, quantity controls, totals, coupon, checkout CTA, empty state.
61
+ - Checkout: step navigation, address forms, shipping/payment selection, order summary.
62
+ - Account: tabbed nav, form fields per page, edit/save states.
63
+ 3. **Plan fresh markup.** Sketch DOM, schema fields, snippet decomposition. Apply the new theme's tokens (`var(--color-*)`, `var(--space-*)`, `var(--radius-*)`, `var(--font-*)`).
64
+ 4. **Write fresh.** Each section file goes through the same lint as page agents (`lint-section.mjs`). All lint rules apply — i18n keys, tag validity, filter validity, scope sanity, no hardcoded design.
65
+ 5. **Update page JSON.** Wire the new section into the corresponding `pages/<page>.json`.
66
+ 6. **Append translation keys.** Runtime keys to `en.json`, schema labels to `en.schema.json`.
67
+ 7. **Per-page verify.** Once header/footer-ready marker exists, run the gates against each common page:
68
+ - Pixel-diff: **no Figma to compare against**. Skip this gate for common pages, OR compare against a deterministic baseline (the same rendered page after a no-op rebuild — sanity check, not pixel-accuracy).
69
+ - a11y: MANDATORY. Axe must pass on every common page.
70
+ - Lighthouse: MANDATORY. Perf score ≥ 85 mobile.
71
+ 8. **Iterate** up to 3 passes per page on a11y or perf failures.
72
+ 9. **Report.**
73
+
74
+ ## Hard rules
75
+
76
+ - **No `cp` from any theme.** Every line typed fresh.
77
+ - **Read every available implementation** before writing. If you find yourself ready to write after reading only one, stop and read more.
78
+ - **Common pages use the same design tokens as Figma-driven pages.** The cart on the orange theme has orange CTAs, Lato body font, Oswald headings — derived from `theme.json`, not from any sibling theme's cart styling.
79
+ - **Snippets shared between common pages and page-agent pages** (like `pagination`, `product-card` if cart uses it) — coordinate via filename. If the common-pages agent needs `product-card`, it writes a fresh version OR waits for the listing/product agent (whichever finishes first) and uses theirs. The orchestrator coordinates this by giving the common-pages agent visibility into which snippets the other agents are writing.
80
+
81
+ ## Output
82
+
83
+ ```
84
+ PAGE: cart ✓ 1m22s (3 sections, lint pass, axe pass, perf 91)
85
+ PAGE: checkout ✓ 2m05s (1 section + checkout-steps snippet, all gates pass)
86
+ PAGE: account-profile ✓ 0m48s (1 section + account-tab-navigation, all gates pass)
87
+ PAGE: account-address ✓ 0m45s
88
+ PAGE: account-order ✓ 0m32s
89
+ ... (etc for all common pages)
90
+
91
+ SECTIONS WRITTEN: 14
92
+ SNIPPETS WRITTEN: 6
93
+ ITERATIONS: 2 (one a11y fix on checkout, one perf fix on account-order)
94
+
95
+ NEEDS_REVIEW:
96
+ - checkout/checkout-steps: stepper accent contrast 4.5:1 at WCAG AA minimum
97
+ ```