diff --git a/.gitignore b/.gitignore index dba2b19..2d9cfe2 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,16 @@ dist/ # Remove this line if you want to version client sites inside this monorepo. sites/ +# Per-client design sources and gate configs (same rule as sites/). +design-src/ +scripts/visual-check/*.json +!scripts/visual-check/example.json +!scripts/visual-check/package.json +!scripts/visual-check/package-lock.json + +# Local Claude Code settings +.claude/settings.local.json + # OS noise .DS_Store diff --git a/CLAUDE.md b/CLAUDE.md index 6b1f9e8..45fc36e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,275 +1,203 @@ -# Claude Design → WordPress (ClaudeToWP) +# Claude Design → WordPress (ClaudeToWP) — Keel pipeline Turns a **Claude design** (HTML/Tailwind, or a Claude Design React/JSX bundle) into an -upload-ready **WordPress FSE block theme** (WooCommerce-capable). Claude is the converter: -it emits `theme.json` tokens, a ported stylesheet, native-block **patterns** (one per -section and one per full page), and template parts. The client assembles pages by inserting -the page patterns. +upload-ready **WordPress theme** built on **Keel** — a lean **hybrid-classic** base theme +(PHP template hierarchy + a named hook system + server-rendered React blocks; `theme.json` +tokens as the single source of truth; **no Tailwind**, no FSE `.html` templates). Claude is +the converter: it maps the design's real computed styles into `theme.json` tokens + scoped +CSS, ports each section to a **server-rendered block** or a **pattern**, and composes a +full-page pattern per page. The client creates a Page, inserts the pattern, edits block +attributes in the normal editor. + +> The base theme (`base-theme/`, slug `tbt`, display "Total Business Theme") is authoritative +> for **theme internals** — read `base-theme/CLAUDE.md`, `base-theme/SPEC.md`, and +> `base-theme/RENAME.md`. THIS file governs the **pipeline** around it (clone → convert → +> gate → package). On any conflict about the theme itself, the base-theme docs win. ## Non-negotiables (break one ⇒ the delivery is not done) 1. **Pixel-perfect, every page.** Reproduce the design exactly — layout, type, spacing, - colour, and POSITION — for *every* page (home, about, services, contact, booking, - shop…), not just home. "Close" is a fail. -2. **Native blocks only — never `wp:html` for content.** The whole point of a theme is that - the client can edit it. (§Conversion) -3. **Fidelity comes from the design's real CSS**, ported into `src/css/app.css` — not from - utilities or guesswork. Read the actual source. (§Use the design's real source) -4. **Page content lives in the Page, not the template** — full-page pattern + content-only - editor; no `front-page.html`, no baked `page-{slug}.html`. (§Page-content model) + colour, and POSITION — for *every* page, not just home. "Close" is a fail. Fidelity comes + from the design's **real computed styles** (§Porting), not guesswork. +2. **Agent-native editability.** Sections are **server-rendered blocks** (editable + attributes) or patterns of native blocks — never `wp:html` for content. The client must be + able to edit it. +3. **`theme.json` is the only token source.** Colours, fluid type, spacing, widths. Component + CSS consumes `--wp--preset--*`; **no raw hex/px where a token exists** (lint-enforced). +4. **Page content lives in the Page**, not the template — full-page pattern inserted into + `post_content`; `page.php` is title-less (designs carry their own hero). 5. **The DONE ledger must print `RESULT: DONE` before you say "done."** Measure, don't eyeball. (§The DONE gate) -6. **Theme-review grade**: Theme Check + WPCS clean, text-domain == slug, escaped output, - GPL, no hotlinked assets. (§Theme-review) +6. **Theme-review grade**: PHPCS (WordPress-Extra + Docs + WPThemeReview + PHPCompatibility) + and Theme Check clean; text-domain == slug; escaped output; GPL; no hotlinked assets. -When the user reports a problem, REPRODUCE AND MEASURE it before answering — never argue -from a proxy (a passing script, a computed `font-family`, a mismatch %). That is exactly -how the font-weight bug shipped. When a gate flags something, decide real-bug vs -gate-false-positive and fix the right one — NEVER loosen a gate to pass a real bug. +When the user reports a problem, REPRODUCE AND MEASURE it before answering — never argue from +a proxy (a passing script, a computed `font-family`, a mismatch %). When a gate flags +something, decide real-bug vs gate-false-positive and fix the right one — **NEVER loosen a +gate to pass a real bug.** ## Layout & build loop ``` -base-theme/ Reusable starter block theme. Clone per client; NEVER edit in place. -scripts/new-site.sh Clones base-theme -> sites/ (rewrites text-domain + prefix to slug). +base-theme/ The Keel base theme. Clone per client; NEVER edit in place. +scripts/new-site.sh Clones base-theme -> sites/, rewrites tbt -> slug (RENAME.md + recipe), then npm install && npm run build. +scripts/package-site.sh Builds blocks (wp-scripts) + lint gate -> dist/.zip. +scripts/visual-check/ The QA harness (the crown jewel — re-point, never rebuild). sites// The per-client theme that ships (git-ignored here). ``` -1. `scripts/new-site.sh ` → `sites//` from `base-theme/`. -2. Convert (§Conversion): `theme.json` + `tailwind.config.js` tokens, port the design CSS - into `src/css/app.css`, a full-page pattern per page + reusable section patterns, native - header/footer parts. -3. `cd sites/ && npm install && npm run build` (or `npm run dev` to watch). -4. QA by RENDERING — boot wp-now and run the DONE ledger (§The DONE gate). Iterate. -5. `scripts/package-site.sh ` → `dist/.zip` (re-runs lint as a blocking - gate; keeps dev tooling out). Upload via wp-admin > Appearance > Themes > Add New. +1. `scripts/new-site.sh "Display Name"` → `sites//` from `base-theme/`, + with every identifier rewritten to the slug (text domain, `tbt_`/`Tbt_`/`TBT_` prefixes, + block namespace `tbt/`→`/`, CSS `--tbt-`→`---`) and blocks built. +2. Convert (§Conversion): fold the design's computed styles into `theme.json` tokens + scoped + CSS; port each section to a Keel block or pattern; compose a full-page pattern per page. +3. `cd sites/ && npm run build` (wp-scripts) after block/source edits. +4. QA by RENDERING — boot WordPress and run the DONE ledger (§The DONE gate). Iterate. +5. `scripts/package-site.sh ` → `dist/.zip` (runtime tree only: PHP hierarchy, + `inc/`, `template-parts/`, `patterns/`, `assets/`, `build/`; excludes block source, deps, + tooling). Upload via wp-admin > Appearance > Themes > Add New. ## Use the design's real source -A Claude Design link returns a gzipped tar of a React/JSX project -([[claude-design-export-format]]). Extract it to a **readable** dir (repo or `/tmp`, NOT -`~/Documents` — the gates can't read TCC-protected dirs). Then: -- `src/styles.css` → the exact tokens and CSS. Port it faithfully into `src/css/app.css`; - fidelity comes from this CSS, not from utilities. -- `app.jsx` `TWEAK_DEFAULTS` → defaults that change the whole look. e.g. `headers:"sans"` - ⇒ headings are Inter, NOT a serif. Getting this wrong was the single biggest miss. +A Claude Design link returns a gzipped tar of a React/JSX project. Extract it to a **readable** +dir (repo or `/tmp`, NOT `~/Documents` — the gates can't read TCC-protected dirs). Then read +the actual rendered CSS — fidelity comes from what the design **computes**, not from utilities. +Annotated designs (per `base-theme/RENAME.md` §4 / the design contract) take a fast path +(`:root` tokens + `data-wp-role` routing); legacy Tailwind/HTML designs fall back to full +computed-style extraction below. ## Conversion (how each piece is built) -**Tokens → BOTH `theme.json` and `tailwind.config.js`.** Palette, fonts, spacing, -content/wide widths. They must agree (native blocks read theme.json, utilities read the -Tailwind config) — parallel sources synced by hand, not Global-Styles-drives-Tailwind. - -**Each section → one pattern in `patterns/`** (follow `patterns/hero.php`): -- Structure with native blocks (`group`, `columns`, `cover`, `image`, `heading`, - `paragraph`, `buttons`, `list`). Special bits are ALSO native: brand = Site Title + Site - Tagline; menus = Navigation block; search = core Search; socials = Social Icons - (`core/social-links`). -- Tailwind utilities ride on `className` — keep the rendered `class` attribute in sync with - the block's `className` (WP needs the class in saved HTML). -- Custom CSS for the last 5% goes in `src/css/app.css`, scoped to a section className, - never global. -- **Match every element's exact treatment** per section: font family/weight/style, colour, - size, position. Real misses to avoid: prices/labels serif-italic + muted (not sans + - wine); hero CTA bottom-RIGHT with lede bottom-LEFT (a `hero-meta` flex row, - `justify-content:space-between`); a single `→` on arrow links; footer socials in a white - horizontal row. - -**Video hero** → `core/cover` with `"backgroundType":"video"` and a `