wp-demo · diff
git:20261006.c210ce2 to git:20261006.0fb45fc
50 added, 136 removed. Audit A to A.
---
name: wp-demo
- description: Demo HTML methodology — single-file demos with section comment delimiters that convert 1:1 into WordPress template parts, plus the responsive, accessibility, placeholder-image, navigation and footer requirements. Use when writing or editing a demo HTML file with /wp-demo, or converting one with /wp-init, /wp-section or /wp-yolo.
+ description: Defines the demo page contract — single-file demo/index.html and demo/slug.html pages whose SECTION and END SECTION comment delimiters map 1:1 to WordPress template parts — plus the accessibility, navigation and footer markup every demo carries and, in plain mode, the token names, font link and placeholder images. Use when writing or editing a demo page with /wp-demo, or converting one with /wp-init, /wp-section, /wp-seed or /wp-yolo. Craft-mode design rules are in wp-demo-craft, responsive CSS in wp-responsive.
user-invocable: false
---
# Demo HTML Creation Methodology
- This skill defines how to create **static HTML demo pages** that serve as the design prototype and are later converted 1:1 into WordPress templates. Each demo is a single HTML file with all CSS embedded in a `<style>` block.
+ A demo is a static HTML page that serves as the design prototype and is later converted 1:1
+ into WordPress templates: the client approves it in a browser, `/wp-init` carries its tokens
+ into the theme, `/wp-section` turns each delimited section into a template part, and every
+ piece of content becomes an ACF/SCF field.
## Reference files
- [references/demo-skeleton.md](references/demo-skeleton.md) — the plain-mode page skeleton
(font link, `:root` tokens, reset and accessibility rules, section delimiters, header with
language switcher, footer). Read when starting a demo page or writing its footer.
---
## Which parts apply
Read `"demo mode"` from the project's `.wp-create.json` before using this skill; an absent
key means `plain`. `/wp-demo` records it, and nothing downstream re-derives it.
- **Both modes:** file naming, the section delimiters and the 1:1 mapping, accessibility,
navigation and the footer markup contract.
- **Plain mode only:** the single-file rule, the `:root` token vocabulary, the font link and
the placeholder images below.
- **Craft mode:** tokens come from `demo/DESIGN.md` onto the names in
`${CLAUDE_PLUGIN_ROOT}/skills/wp-demo-craft/references/design-md.md`, never the
vocabulary below. Images are real client files or generated plates; a placeholder image
is a craft ship blocker. Compositions, motion and verification are `wp-demo-craft`'s.
---
- ## Purpose of Demos
-
- Demos are the design-first step before WordPress development:
-
- 1. **Design agreement** -- the client reviews a working HTML page in the browser
- 2. **Token carry** -- `/wp-init` reads the demo's colours and fonts and writes them into the theme's Tailwind `@theme` block; each section's CSS moves with its template part when `/wp-section` builds it
- 3. **Section mapping** -- each marked section in the demo maps to a `template-parts/section-*.php` file in WordPress
- 4. **Field definition** -- every piece of content in the demo becomes an ACF/SCF field
-
- ---
-
- ## File Structure
-
- ```
- demo/
- ├── index.html # Homepage demo
- ├── pricing.html # Pricing page demo
- ├── about.html # About page demo
- └── ... # One file per page
- ```
-
- ### Naming Convention
-
- - **Homepage**: `demo/index.html`
- - **Other pages**: `demo/<page-slug>.html` (e.g., `demo/pricing.html`, `demo/software.html`)
-
- ---
-
- ## Single-File HTML Structure
-
- Each demo is a **single HTML file** containing everything: meta tags, embedded CSS, HTML content, and optional inline JS.
-
- ### Template Skeleton
+ ## Files
- Start every page from the skeleton in [references/demo-skeleton.md](references/demo-skeleton.md):
- fonts in `<head>`, then one `<style>` block holding the `:root` tokens, reset, layout and each
- section's rules under `/* ============ Section: Name ============ */`, then the page sections.
- Each section opens with `<!-- ============ SECTION: Name ============ -->` and closes with
- `<!-- ============ END SECTION: Name ============ -->`.
+ One file per page: `demo/index.html` for the homepage, `demo/<page-slug>.html` for the rest
+ (`demo/pricing.html`). In plain mode each is a single file — meta tags, one `<style>` block,
+ the markup and any inline JS — started from
+ [references/demo-skeleton.md](references/demo-skeleton.md).
---
- ## Section Comments
+ ## Section Delimiters
- Every distinct section MUST be wrapped with an HTML comment in this exact format:
+ Every section is wrapped in an opening and a closing comment, exactly:
```html
<!-- ============ SECTION: Hero ============ -->
+ <section class="hero">…</section>
+ <!-- ============ END SECTION: Hero ============ -->
```
- These comments serve as:
- 1. **Visual delimiters** when scanning the HTML source
- 2. **Mapping markers** -- each comment maps to a `template-parts/section-<name>.php` file in WordPress
- 3. **Conversion guide** -- when building the WordPress theme, each section is extracted into its own template part
-
- ### Common Section Names
+ The name is a **verbatim join key**. `/wp-section`, `/wp-seed`, `/wp-polish` and the
+ `wp-normalize` agent extract sections by it, and `demo/.demo-plan.json` records each section
+ under the same name — a plan whose names do not match its own markup is discarded. So the
+ name is identical in both comments, never reworded between them, and unique on the page.
+ `Header` and `Footer` are the names of the shared chrome on every page. The section's CSS
+ sits under the matching `/* ============ Section: Hero ============ */` delimiter, so it moves
+ to its template part whole.
| Comment | WordPress Template Part |
|---|---|
| `SECTION: Header` | `header.php` |
| `SECTION: Hero` | `template-parts/section-hero.php` |
| `SECTION: Services` | `template-parts/section-services.php` |
- | `SECTION: About` | `template-parts/section-about.php` |
| `SECTION: Testimonials` | `template-parts/section-testimonials.php` |
- | `SECTION: CTA` | `template-parts/section-cta.php` |
| `SECTION: Contact` | `template-parts/section-contact.php` |
| `SECTION: Footer` | `footer.php` |
---
- ## Design System Variables in :root
+ ## Design Tokens and Fonts (plain mode)
- In plain mode the `:root` block in the demo `<style>` is the **source of truth** for the design system. When converting to WordPress:
+ The `:root` block in the demo `<style>` is the **source of truth** for the design system:
1. `/wp-init` reads its colour and font values and writes them into the theme's `@theme` block
2. All CSS rules reference these variables (never hardcoded values)
3. The variable names and scale are the `wp-css-system` skill's (`references/tokens.md`):
`--color-background`, `--spacing-md`, `--font-family-primary`, `--transition-base` —
never `--color-bg`, `--space-md`, `--font-heading` or `--transition`
Fonts load from one Google Fonts `<link>` in `<head>`, the only external request a plain demo
makes: `/wp-init` Step 4.5 self-hosts the families it names, so the theme never calls
Google at runtime.
---
## 1:1 Section Mapping to WordPress
- Each section in the demo becomes a WordPress template part. The mapping is direct:
-
```
Demo HTML WordPress
───────────────────────────── ─────────────────────────────
<!-- SECTION: Hero --> → template-parts/section-hero.php
<h1>Static Title</h1> → <h1><?php echo esc_html(prefix_get_field('hero_title')); ?></h1>
<p>Static description</p> → <p><?php echo esc_html(prefix_get_field('hero_subtitle')); ?></p>
<img src="placeholder"> → <?php $img = prefix_get_field('hero_image'); ?>
<img src="<?php echo esc_url($img['url']); ?>"
alt="<?php echo esc_attr($img['alt']); ?>">
```
- ### Conversion Rules
-
- Static text becomes `prefix_get_field('field_name')`
- - Placeholder images become ACF image fields
- - Repeated items (cards, list items) become ACF repeater fields
- - Links become ACF URL or link fields
- - Navigation becomes `wp_nav_menu()`
+ - Images become ACF image fields; repeated items (cards, list items) become repeaters
+ - Links become ACF URL or link fields; navigation becomes `wp_nav_menu()`
- The HTML structure and CSS classes are preserved exactly
---
- ## Responsive Design Requirements
-
- Every demo MUST be fully responsive. See the `wp-responsive` skill for detailed breakpoint and responsive design standards.
-
- - Use mobile-first CSS with `min-width` media queries
- - Test at: 375px, 576px, 768px, 1024px, 1440px
- - No horizontal scrolling at any viewport width
- - Hamburger menu on mobile, horizontal nav on desktop
-
- ---
-
## Accessibility Requirements
- Demos MUST follow semantic HTML5 and accessibility best practices.
-
- ### Semantic Structure
-
- ```html
- <header> <!-- Site header with nav -->
- <nav> <!-- Navigation -->
- <main> <!-- Primary page content -->
- <section> <!-- Thematic content sections -->
- <article> <!-- Self-contained content (blog posts) -->
- <aside> <!-- Supplementary content -->
- <footer> <!-- Site footer -->
- ```
-
- ### ARIA and Accessibility
-
- - All images have descriptive `alt` attributes
- - Interactive elements have `aria-label` when the visible text is insufficient
- - Color contrast meets WCAG AA (4.5:1 for normal text, 3:1 for large text)
- - Focus styles are visible for keyboard navigation
- - Skip-to-content link at the top of the page
- - Form inputs have associated `<label>` elements
- - Hamburger button has `aria-label="Toggle menu"` and `aria-expanded`
-
- ```html
- <!-- Skip to content link -->
- <a href="#main-content" class="sr-only sr-only--focusable">Skip to content</a>
-
- <!-- Hamburger with ARIA -->
- <button class="header__hamburger" aria-label="Toggle menu" aria-expanded="false">
- <span></span><span></span><span></span>
- </button>
+ The skeleton already carries each of these; keep them when editing:
- <!-- Main content landmark -->
- <main id="main-content">
- ```
+ - A skip link first in `<body>`: `<a href="#main-content" class="sr-only sr-only--focusable">Skip to content</a>`,
+ with `.sr-only` and `.sr-only--focusable` defined in the `<style>` block
+ - `<main id="main-content">` as its target
+ - The hamburger button: `aria-label="Toggle menu"`, `aria-expanded="false"`,
+ `aria-controls` naming the mobile menu; its menu behaviour (focus trap, Escape, focus
+ return) is `wp-responsive`'s `references/navigation.md`
+ - A visible `:focus-visible` style
+ - Real `alt` text on every image, a `<label>` on every form input, WCAG AA contrast
---
## Placeholder Images
Plain mode only. A real client image from `docs/` always wins. Where there is none, the
placeholder is an `<img>` whose `src` is an inline SVG at the intended aspect ratio, with
`width`, `height` and real `alt` text — never an external image URL. A placeholder-service
- URL breaks the page offline, and `/wp-seed` imports every
- `img[src]` URL it finds into the media library. Keeping the `<img>` element, rather than a
- coloured CSS box, keeps the 1:1 mapping to an ACF image field.
+ URL breaks the page offline, and `/wp-seed` imports every `img[src]` URL it finds into the
+ media library. Keeping the `<img>` element, rather than a coloured CSS box, keeps the 1:1
+ mapping to an ACF image field.
```html
<!-- Hero image, 3:2 -->
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 400'%3E%3Crect width='600' height='400' fill='%23e5e5e5'/%3E%3C/svg%3E"
width="600" height="400" alt="Description of hero image" fetchpriority="high">
<!-- Team member photo, 1:1 -->
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 300'%3E%3Crect width='300' height='300' fill='%23e5e5e5'/%3E%3C/svg%3E"
width="300" height="300" alt="Team member name" loading="lazy">
```
- Choose dimensions that match the expected aspect ratio in the final design:
- - Hero images: 16:9 or 3:2 (e.g., 600x400, 800x450)
- - Thumbnails: 16:10 or 4:3 (e.g., 400x250, 300x225)
- - Avatars/portraits: 1:1 (e.g., 300x300)
- - Logos: wide ratio (e.g., 180x50, 200x60)
-
---
## Navigation Structure
- The demo navigation must match the planned WordPress site structure. Navigation items should reflect the actual pages and sections that will exist.
+ The demo navigation matches the planned WordPress site structure: the pages and sections that
+ will exist.
```html
<nav class="header__nav">
<a href="index.html" class="nav__link nav__link--active">Home</a>
<a href="#services" class="nav__link">Services</a>
<a href="pricing.html" class="nav__link">Pricing</a>
<a href="#contact" class="nav__link">Contact</a>
</nav>
```
- - Internal page links use relative HTML file paths (`pricing.html`)
- - Section anchors use `#id` links (`#services`, `#contact`)
- - Active page gets the `--active` modifier class
+ Internal pages link by relative file path (`pricing.html`), sections by `#id`, and the active
+ page carries the `--active` modifier. The header also carries a language switcher with one
+ link per configured language.
---
## Footer Pattern
- The footer follows a consistent pattern matching the WordPress settings page architecture:
- four columns (brand and logo, quick links, contact info, social) above a bottom bar carrying
+ Four columns (brand and logo, quick links, contact info, social) above a bottom bar carrying
the copyright and legal links. Markup: the footer in
[references/demo-skeleton.md](references/demo-skeleton.md).
The demo's contract with WordPress is the **class names**, not field names: `/wp-seed` reads
`.footer__description` (the tagline) and `.footer__copyright` out of the demo, and `/wp-footer`
owns which settings-page fields they become. Keep both classes: under any other class, or
in a bare `<p>`, the seeder skips the line. The
copyright line carries no year: a year typed into the demo is stale by the next January, and
`/wp-footer`'s fallback prints the current one.
---
- ## Summary Checklist
+ ## Responsive Design and Verification
- - [ ] Single HTML file per page in `demo/` directory
- - [ ] All CSS embedded in `<style>` block (no external CSS files)
- - [ ] `:root` variables match the design system (wp-css-system skill)
- - [ ] Every section wrapped with `<!-- ============ SECTION: Name ============ -->` comment
- - [ ] CSS uses section comment delimiters: `/* ============ Section: Name ============ */`
- - [ ] BEM class names used throughout
- - [ ] Fully responsive at all breakpoints (375px to 1440px+)
- - [ ] Semantic HTML5 elements (header, nav, main, section, footer)
- - [ ] ARIA attributes on interactive elements
- - [ ] WCAG AA color contrast
- - [ ] Placeholder images with realistic dimensions
- - [ ] Navigation matches planned site structure
- - [ ] Footer includes: logo, copyright, social links, contact info, legal links
- - [ ] Each section maps 1:1 to a future WordPress template part
+ Every demo is mobile-first with `min-width` queries only; the breakpoints, the mobile menu and
+ the touch-target rules are the `wp-responsive` skill's. Then:
+
+ 1. Run `/wp-demo-verify demo/` (or on one page).
+ 2. Fix every overflow and clipped-copy finding at the element it names.
+ 3. Run it again. Stop when it reports no overflow and no clipped copy at any width.