@autono/create-open-pages 0.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.
@@ -0,0 +1,223 @@
1
+ ---
2
+ name: create-theme
3
+ description: Use this skill when the user wants to create, draft, author, or extract a page theme in this open-pages repo. Triggers on phrases like "create a theme", "make a theme called X", "extract a theme from <page>", "build a design system from these screenshots", "match our brand". Produces two paired files under `themes/` — `<id>.md` (palette, typography, layout, fixed components) and `<id>.demo.tsx` (a runnable demo page the workspace's Themes panel previews live). Do NOT use for editing real pages — only for authoring the theme bundle.
4
+ ---
5
+
6
+ # Create a page theme
7
+
8
+ This skill produces a **theme bundle** under `themes/`: two paired files that together describe a reusable visual identity for web pages.
9
+
10
+ 1. `themes/<id>.md` — agent-facing documentation: palette, typography, layout, fixed components (nav, hero, section wrapper, buttons, card, footer). This is what `create-page` reads when an author picks the theme.
11
+ 2. `themes/<id>.demo.tsx` — a runnable demo page (same module shape as `pages/<id>/index.tsx`: **one default-exported component**) that shows the theme on a single scrolling page. The workspace's Themes panel renders it live, exactly like a real page.
12
+
13
+ Both files share the same stem so the runtime can pair them automatically.
14
+
15
+ The theme markdown is authoring-time direction — `create-page` copies its palette, utilities, and components into a real page's source. The demo `.tsx` is a self-contained preview, not a real page — it does not appear in the pages list.
16
+
17
+ You only write `themes/<id>.md` and `themes/<id>.demo.tsx`. Never modify real pages or configuration. The styling rules and web defaults that themes override live in the **`page-authoring`** skill — read it before writing the theme so your overrides are stated explicitly.
18
+
19
+ ## Step 1 — Identify the input source
20
+
21
+ A theme can be derived from any combination of three input shapes:
22
+
23
+ - **Image references** — paths or URLs to screenshots, mood-board images, brand assets.
24
+ - **Free-text description** — prose describing the desired palette, weight, feel.
25
+ - **An existing page** — `pages/<id>/index.tsx` whose visual identity should be lifted out into a reusable theme.
26
+
27
+ If the user's original message already specifies the inputs unambiguously, skip the question and proceed. Otherwise call `AskUserQuestion` (multi-select) so they can pick one or more sources, and ask follow-ups (paths, page id, prose) only as needed.
28
+
29
+ ## Step 2 — Gather raw inputs
30
+
31
+ - **Images**: read each path with the `Read` tool (it accepts images). Note dominant colors as hex, type weight and family feel, corner radius, surface treatment (flat vs. cards vs. borders), density, and recurring chrome (nav style, footer).
32
+ - **Text**: extract explicit tokens (hex codes, font names, tone words) and resolve vague language into concrete decisions before writing.
33
+ - **Existing page**: read `pages/<id>/index.tsx` (and `components/`) and pull:
34
+ - The Tailwind color utilities used consistently (`bg-…`, `text-…`, accent classes) → Palette section.
35
+ - Type sizes and any font loading (`<link>` to Google Fonts, `font-[…]`) → Typography section.
36
+ - Container widths, section padding, breakpoints used → Layout section.
37
+ - Recurring helper components (nav, hero, cards, buttons, footer) → Fixed components section.
38
+ - The aesthetic feel implied → Aesthetic paragraph.
39
+
40
+ When inputs disagree (e.g. images use blue but the description says green), ask the user which to honor.
41
+
42
+ ## Step 3 — Pick a theme id
43
+
44
+ Use **kebab-case**, short, descriptive. Examples: `dark-launch`, `clean-saas`, `editorial-warm`, `ops-console`. Check `themes/` to avoid collisions.
45
+
46
+ ## Step 4 — Write `themes/<id>.md`
47
+
48
+ Produce a file with this exact section order. Section bodies adapt to the theme; the headings stay consistent across all themes.
49
+
50
+ ````markdown
51
+ ---
52
+ name: <Human title, e.g. "Dark Launch">
53
+ description: <one-line elevator pitch>
54
+ ---
55
+
56
+ # <Theme name>
57
+
58
+ ## Palette
59
+
60
+ | Role | Tailwind | Hex | Notes |
61
+ | --- | --- | --- | --- |
62
+ | background | `bg-[#0b0b10]` | #0b0b10 | page root |
63
+ | surface | `bg-white/[0.04] border-white/10` | — | cards, panels |
64
+ | text | `text-white` | #ffffff | headings, body |
65
+ | muted | `text-white/60` | — | secondary copy, labels |
66
+ | accent | `bg-emerald-400 text-black` / `text-emerald-400` | #34d399 | primary CTA, eyebrows |
67
+ | border | `border-white/10` | — | dividers, card edges |
68
+
69
+ ## Typography
70
+
71
+ - Font: system stack, or a named family with how to load it (Google Fonts `<link>` rendered in the page, or a self-hosted file the page must place under `assets/`).
72
+ - Type-scale overrides (only list what differs from `page-authoring` defaults):
73
+ - Hero heading: `text-5xl sm:text-7xl font-bold leading-[1.02] tracking-tight`
74
+ - Section heading: `text-3xl font-bold tracking-tight`
75
+ - Body: `text-lg text-white/60`
76
+ - Eyebrow: `text-xs font-semibold uppercase tracking-[0.25em] text-emerald-400`
77
+
78
+ ## Layout
79
+
80
+ - Container: `mx-auto max-w-6xl px-6`.
81
+ - Section rhythm: `py-20`, sections separated by `border-t border-white/10`.
82
+ - Breakpoints: single column by default; `sm:grid-cols-3` for feature and pricing grids; nav links `hidden sm:flex`.
83
+ - Radius: `rounded-full` for buttons, `rounded-2xl` for cards.
84
+
85
+ ## Fixed components
86
+
87
+ These are paste-ready React JSX with `className`. Copy them verbatim into a page that uses this theme.
88
+
89
+ ### Nav
90
+
91
+ ```tsx
92
+ const Nav = ({ brand, links, cta }: { brand: string; links: { label: string; href: string }[]; cta: { label: string; href: string } }) => (
93
+ <header className="mx-auto flex max-w-6xl items-center justify-between px-6 py-6">
94
+ <span className="font-semibold tracking-tight">{brand}</span>
95
+ <nav className="hidden gap-8 text-sm text-white/70 sm:flex">
96
+ {links.map((l) => (
97
+ <a key={l.href} href={l.href} className="hover:text-white">{l.label}</a>
98
+ ))}
99
+ </nav>
100
+ <a href={cta.href} className="rounded-full bg-white px-4 py-2 text-sm font-medium text-black hover:bg-white/90">{cta.label}</a>
101
+ </header>
102
+ );
103
+ ```
104
+
105
+ ### Hero
106
+
107
+ ```tsx
108
+ const Hero = ({ eyebrow, title, lede, children }: { eyebrow: string; title: string; lede: string; children?: React.ReactNode }) => (
109
+ <section className="mx-auto max-w-6xl px-6 pt-20 pb-24 text-center">
110
+ <p className="text-xs font-semibold uppercase tracking-[0.25em] text-emerald-400">{eyebrow}</p>
111
+ <h1 className="mx-auto mt-6 max-w-3xl text-5xl font-bold leading-[1.02] tracking-tight sm:text-7xl">{title}</h1>
112
+ <p className="mx-auto mt-6 max-w-xl text-lg text-white/60">{lede}</p>
113
+ <div className="mt-10 flex flex-col justify-center gap-3 sm:flex-row">{children}</div>
114
+ </section>
115
+ );
116
+ ```
117
+
118
+ ### Section
119
+
120
+ ```tsx
121
+ const Section = ({ id, children }: { id?: string; children: React.ReactNode }) => (
122
+ <section id={id} className="border-t border-white/10">
123
+ <div className="mx-auto max-w-6xl px-6 py-20">{children}</div>
124
+ </section>
125
+ );
126
+ ```
127
+
128
+ ### Buttons
129
+
130
+ ```tsx
131
+ const PrimaryButton = ({ href, children }: { href: string; children: React.ReactNode }) => (
132
+ <a href={href} className="rounded-full bg-emerald-400 px-6 py-3 font-medium text-black hover:bg-emerald-300">{children}</a>
133
+ );
134
+ const SecondaryButton = ({ href, children }: { href: string; children: React.ReactNode }) => (
135
+ <a href={href} className="rounded-full border border-white/20 px-6 py-3 font-medium text-white/80 hover:border-white/40">{children}</a>
136
+ );
137
+ ```
138
+
139
+ ### Card
140
+
141
+ ```tsx
142
+ const Card = ({ title, children }: { title: string; children: React.ReactNode }) => (
143
+ <div className="rounded-2xl border border-white/10 bg-white/[0.03] p-6">
144
+ <h3 className="font-semibold">{title}</h3>
145
+ <div className="mt-2 text-white/60">{children}</div>
146
+ </div>
147
+ );
148
+ ```
149
+
150
+ ### Footer
151
+
152
+ ```tsx
153
+ const Footer = ({ left, right }: { left: string; right: string }) => (
154
+ <footer className="border-t border-white/10">
155
+ <div className="mx-auto flex max-w-6xl items-center justify-between px-6 py-8 text-sm text-white/40">
156
+ <span>{left}</span>
157
+ <span>{right}</span>
158
+ </div>
159
+ </footer>
160
+ );
161
+ ```
162
+
163
+ ## Aesthetic
164
+
165
+ One paragraph. What it feels like, the references it draws on, what to avoid (e.g. "no gradients; one accent only; borders over shadows; motion limited to hover color changes"). Commit to a single direction.
166
+
167
+ ## Example usage
168
+
169
+ ```tsx
170
+ <main className="min-h-screen bg-[#0b0b10] text-white antialiased">
171
+ <Nav brand="Meridian" links={links} cta={{ label: 'Get started', href: '#pricing' }} />
172
+ <Hero eyebrow="Now in public beta" title="Your analytics, turned into decisions" lede="…">
173
+ <PrimaryButton href="#pricing">Start free</PrimaryButton>
174
+ <SecondaryButton href="#features">See how it works</SecondaryButton>
175
+ </Hero>
176
+ {/* … */}
177
+ <Footer left="© 2026 Meridian" right="Built with open-pages" />
178
+ </main>
179
+ ```
180
+ ````
181
+
182
+ ## Step 4b — Write `themes/<id>.demo.tsx`
183
+
184
+ The demo is a normal page module — same shape as `pages/<id>/index.tsx`, just sitting under `themes/` so the runtime knows it's preview-only.
185
+
186
+ Contract:
187
+
188
+ - `import type { PageMeta } from '@autono/open-pages';` and React hooks as needed.
189
+ - **One default-exported component** — a single scrolling page that exercises the theme: nav, hero with both buttons, a section with a card grid, a footer.
190
+ - Inline the **same** fixed components defined in the theme markdown — verbatim, no abstractions. Demo and markdown must stay in lockstep so what `create-page` pastes matches what the demo shows.
191
+ - Root element sets `min-h-screen`, the theme background, and text color. Must look right at Mobile (390px) as well as Desktop.
192
+ - Content should be plausible and realistic, not lorem ipsum. Self-contained: no `@/` imports, no page-local assets; if the theme names a Google Font, render the `<link>` tag in the demo too.
193
+
194
+ ## Step 5 — Self-review
195
+
196
+ - [ ] Palette table covers background / surface / text / muted / accent / border as Tailwind utilities, with hex where fixed.
197
+ - [ ] Frontmatter has `name` and `description` only (the runtime reads nothing else).
198
+ - [ ] Typography names only fonts the theme explains how to load (or the system stack).
199
+ - [ ] Layout specifies container width, section rhythm, and breakpoints.
200
+ - [ ] Fixed components are paste-ready React JSX (`className`, typed props, no `@/` imports) and cover nav, hero, section, buttons, card, footer.
201
+ - [ ] Aesthetic paragraph names a single coherent direction.
202
+ - [ ] Both files written: `themes/<id>.md` and `themes/<id>.demo.tsx`. No page changes, no config changes.
203
+ - [ ] Demo `.tsx` default-exports one component and inlines the same fixed components as the markdown; contrast holds; nothing overflows on mobile.
204
+
205
+ ## Step 6 — Hand off
206
+
207
+ Tell the user:
208
+
209
+ - The theme id and the two file paths.
210
+ - That the Themes panel in the workspace (`http://localhost:5173/themes`) previews the demo live, and `/create-page` will list the theme as a picker option on its next run.
211
+ - A one-line summary of the look (palette + aesthetic).
212
+
213
+ Do not run the dev server. Do not modify real pages — the demo `.tsx` is the demonstration.
214
+
215
+ ## Anti-patterns
216
+
217
+ - ❌ Writing executable code in `themes/<id>.md` outside the labeled component snippets — the markdown is documentation.
218
+ - ❌ Producing only the markdown without the demo, or only the demo without the markdown. A theme is the **bundle** — both files, every time.
219
+ - ❌ Desktop-only components: a nav with no mobile behaviour, grids with no stacking fallback.
220
+ - ❌ Naming font families the theme never explains how to load.
221
+ - ❌ Inventing palette / styling when the user supplied images or an existing page. Extract, don't fabricate.
222
+ - ❌ Editing `pages/`, `packages/`, `package.json`, or `open-pages.config.ts`.
223
+ - ❌ Skipping Fixed components. Nav, hero, buttons, and footer are the most common reuse targets — they must be paste-ready.
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: current-page
3
+ description: Resolve which page and (optionally) selected element the user is currently viewing in the open-pages dev server. Consult this whenever the user references "this page", "this site", "this element", "the page I'm on", "the button I clicked", or any deictic reference to page content without naming it. Re-read `node_modules/.open-pages/current.json` at the start of every such turn — the user navigates between turns, so a value you read earlier in the conversation is almost certainly stale.
4
+ ---
5
+
6
+ # Where is the user right now?
7
+
8
+ When the user says "fix this page", "tweak this heading", or "the page I'm looking at", they almost never name the page id or element — they mean wherever they are in the dev viewer. Before asking "which page?" or "which element?", check the file the dev server writes on every navigation and inspector pick.
9
+
10
+ ## Re-read on every deictic turn — never reuse a prior read
11
+
12
+ `current.json` is a live cursor, not a fact about the conversation. The user moves between pages and elements freely between your turns — including while you were doing other work. **Read the file fresh at the start of every new turn that uses a deictic reference**, even if:
13
+
14
+ - you already read it earlier in this same conversation,
15
+ - you just finished editing the page it pointed to,
16
+ - the user's new message sounds like a continuation ("now make it bigger", "also fix this one", "keep going").
17
+
18
+ A "continue editing" follow-up is exactly the case where the user has likely just navigated to a different page or picked a different element. Trusting your last read here will silently edit the wrong file. Re-read, compare `pageId` / `selection` against what you used last time, and act on the new values.
19
+
20
+ ## How to read it
21
+
22
+ ```
23
+ node_modules/.open-pages/current.json
24
+ ```
25
+
26
+ Path is relative to the project root (the user's `cwd`, the directory that contains `pages/` and `package.json`). Use the `Read` tool. The file is JSON.
27
+
28
+ ## What you get
29
+
30
+ ```json
31
+ {
32
+ "pageId": "launch",
33
+ "pageTitle": "Meridian — Launch",
34
+ "view": "pages",
35
+ "pagePath": "pages/launch/index.tsx",
36
+ "selection": {
37
+ "line": 52,
38
+ "column": 8,
39
+ "tagName": "h1",
40
+ "text": "Your analytics, turned into decisions"
41
+ },
42
+ "updatedAt": "2026-08-28T14:32:11.123Z"
43
+ }
44
+ ```
45
+
46
+ - `pageId` — folder name under `pages/`. Use as-is for any `/__pages/<id>/...` API or as the URL segment (`/p/<id>`).
47
+ - `pageTitle` — the page's `meta.title` (or `<title>` for an HTML page), falling back to the id.
48
+ - `pagePath` — page entry path **relative to the project root**: `pages/<id>/index.tsx`, or `pages/<id>/index.html` for a plain HTML page. Prefix it with the project root before handing it to `Read` / `Edit`. Note the selection may point into a file under `pages/<id>/components/` if the page is split — match the line against the file whose JSX contains that tag and text.
49
+ - `view` — `"pages"` when the user is viewing the page, `"assets"` when they are browsing that page's files in the asset manager rather than the page itself.
50
+ - `selection` — `null` if nothing is selected. Otherwise, the JSX element the user picked in the inspector:
51
+ - `line` (1-indexed) and `column` (0-indexed) point to the JSX opening tag in the page source. This is the canonical handle — match against the source line.
52
+ - `tagName` is the rendered HTML tag, lowercased (`"h1"`, `"div"`, `"button"`).
53
+ - `text` is a trimmed text snippet (≤120 chars) of the element's content — a sanity check that you're looking at the right node.
54
+ - Selection auto-clears whenever the user navigates to a different page or clears it in the viewer. HTML pages never produce a selection.
55
+ - `updatedAt` — ISO timestamp of the last navigation or selection change. Use it to detect staleness.
56
+
57
+ ## When to use this
58
+
59
+ - The user references the current page deictically: "this", "here", "the page I'm on", "the site I'm looking at", "what I'm working on".
60
+ - The user references a specific element: "this heading", "this image", "the button I just clicked", "tighten this", "change the color of this". If `selection` is non-null, that's the element they mean.
61
+ - Before asking "which page?" or "which element?" as a clarifying question — check this file first.
62
+ - Before guessing from `git log`, recently-edited files, or the most recent page folder.
63
+
64
+ ## When NOT to use this
65
+
66
+ - The user names a page explicitly ("edit `launch`") — use that name directly.
67
+ - The `apply-comments` workflow already finds the right file via `@page-comment` markers; it doesn't need this skill.
68
+ - For listing or discovering pages — read `pages/` directly.
69
+
70
+ ## Staleness — verify before acting
71
+
72
+ `updatedAt` is the last time the user navigated. Treat it like a cache:
73
+
74
+ - **Fresh (under ~5 minutes old)**: trust it. Open `pagePath`, do the work.
75
+ - **Older than ~5 minutes**: confirm with the user before editing. The dev server may not be running; the user may have switched contexts.
76
+ - **Hours/days old**: ignore it. Ask the user which page they mean.
77
+
78
+ A *newer* `updatedAt` than the one you saw last turn is the normal signal that the user has moved — switch to the new `pageId` / `selection` without asking.
79
+
80
+ ## When the file is missing
81
+
82
+ - The dev server hasn't been opened on a page yet, or has never run.
83
+ - Don't create the file or guess. Ask the user which page they mean, or suggest they open the page in the dev server first.
84
+
85
+ ## Example — page-level reference
86
+
87
+ User: "tighten the spacing on this page"
88
+
89
+ 1. Read `node_modules/.open-pages/current.json`.
90
+ 2. Check `updatedAt` is recent.
91
+ 3. Read `pagePath` (e.g. `pages/launch/index.tsx`).
92
+ 4. If `selection` is set, jump to that line; otherwise identify the relevant section from the user's words.
93
+ 5. Consult the `page-authoring` skill for spacing and layout rules, then edit in place.
94
+
95
+ If `current.json` is missing or stale, ask: "Which page should I tighten? The dev server hasn't published a current page recently."
96
+
97
+ ## Example — element-level reference
98
+
99
+ User: "make this bigger"
100
+
101
+ 1. Read `node_modules/.open-pages/current.json`.
102
+ 2. If `selection` is non-null, the user means that element. Read `pagePath`, jump to `selection.line`, and find the JSX opening tag near that line/column. Confirm with the snippet in `selection.text` and the `tagName`.
103
+ 3. Consult `page-authoring` for type-scale and responsive rules before editing (bigger on desktop usually means a `sm:`/`lg:` step, not a fixed size).
104
+ 4. Edit the JSX node in place.
105
+
106
+ If `selection` is null, fall back to the page-level flow above — and consider asking "which element?" since the user used a deictic but hasn't picked one in the inspector.
@@ -0,0 +1,148 @@
1
+ ---
2
+ name: page-authoring
3
+ description: Technical reference for writing or editing open-pages pages — file contract, Tailwind via `className`, layout and responsive breakpoints, web type scale, interactivity with hooks and state, assets and fonts, plain `index.html` pages, and the self-review checklist. Consult this whenever you are about to write or modify any file under `pages/<id>/`, including from inside the `create-page` or `apply-comments` workflows, or for any ad-hoc page edit. Triggers on phrases like "edit the page", "fix the layout", "change the palette", "add a section", "make it responsive", "add a form", "investigate the page framework", "how do pages work here".
4
+ ---
5
+
6
+ # Authoring open-pages pages
7
+
8
+ This skill is the **technical reference** for everything that happens inside `pages/<id>/`. It does not own a workflow:
9
+
10
+ - `create-page` owns "build a new page" — it asks the user scoping questions, then delegates the *how* to this skill.
11
+ - `apply-comments` owns "process inspector markers" — it finds markers and applies edits, but the edits themselves follow the rules here.
12
+ - `current-page` resolves deictic references ("this page", "this element") to a concrete `pageId` + selection. Consult it **first** when the user references the current page without naming it, then come back here for how to edit it.
13
+ - Any ad-hoc page edit (manual tweak, one-off fix) should also consult this skill before touching the file.
14
+
15
+ A page here is a **real web page**: one React component rendered into a real browser document. The workspace previews it live in an iframe, the inspector maps clicks back to source lines, and `open-pages export` turns it into a static folder you can deploy anywhere. Your job is a good web page; the runtime's job is preview, comments, and export.
16
+
17
+ ## Topic references
18
+
19
+ Details live under `references/` in this skill. **Read the relevant file before using the feature**:
20
+
21
+ | Topic | Read before | File |
22
+ | --- | --- | --- |
23
+ | Layout + responsive | any multi-column layout, nav, hero, grid; anything that must work on mobile | `references/layout-and-responsive.md` |
24
+ | Typography + color | picking a type scale or palette, dark backgrounds, contrast | `references/typography-and-color.md` |
25
+ | Interactivity | state, forms, tabs, toggles, anything with an event handler | `references/interactivity.md` |
26
+ | Assets + fonts | images, icons, custom fonts, Google Fonts | `references/assets-and-fonts.md` |
27
+ | Plain HTML pages | a page authored as `index.html` instead of React | `references/html-pages.md` |
28
+
29
+ ## Hard rules
30
+
31
+ - Put the page under `pages/<kebab-case-id>/`.
32
+ - Entry is `pages/<id>/index.tsx` (or `pages/<id>/index.html` for a plain HTML page — see `references/html-pages.md`).
33
+ - Do **not** touch `package.json`, `open-pages.config.ts`, or other pages.
34
+ - Do not add dependencies. Only `react`, `react-dom`, and `@autono/open-pages` (types) are available, plus browser APIs.
35
+ - A page is `index.tsx` plus, optionally, `components/*.tsx`, `styles.css`, and `assets/` for its images and fonts — all inside `pages/<id>/`. Shared assets live in the root `assets/` folder and import via `@assets/...`. No `README.md`, no config files.
36
+ - Style with Tailwind utilities on `className`. Tailwind is preconfigured and scans `pages/` and `themes/`; there is nothing to set up.
37
+
38
+ ## File contract
39
+
40
+ ```tsx
41
+ // pages/<id>/index.tsx
42
+ import type { PageMeta } from '@autono/open-pages';
43
+ import { useState } from 'react';
44
+
45
+ export const meta: PageMeta = {
46
+ title: 'Meridian — Launch',
47
+ description: 'Meridian turns your analytics into weekly decisions.',
48
+ createdAt: '2026-08-28T12:00:00.000Z',
49
+ };
50
+
51
+ export default function Launch() {
52
+ const [open, setOpen] = useState(false);
53
+ return (
54
+ <main className="min-h-screen bg-white text-slate-900 antialiased">
55
+ {/* sections */}
56
+ </main>
57
+ );
58
+ }
59
+ ```
60
+
61
+ - `export default` is **one zero-prop React component** — the whole page. It owns the viewport: set the page background and text color on the root element (`min-h-screen bg-… text-…`).
62
+ - `meta.title` (optional) becomes the browser tab title and the workspace card label. Default is the folder name.
63
+ - `meta.description` (optional) becomes `<meta name="description">` in the exported HTML.
64
+ - `meta.theme` (optional) marks the page as built from a theme under `themes/`. The id must match a `<id>.md` basename. Omit if not derived from a registered theme.
65
+ - `meta.createdAt` is an **ISO 8601 string literal** set once when the page is scaffolded — **immediately before writing the file, run `node -e "console.log(new Date().toISOString())"` via Bash and paste the exact output**. Must stay a plain string literal (the framework reads it via regex, never by evaluating the module).
66
+ - Hooks, state, event handlers, `fetch`, `window`, client-side routing: all allowed. This is a browser. See `references/interactivity.md` for the constraints that still apply (no `window` at module top level, StrictMode double-invokes effects).
67
+
68
+ ## Styling: Tailwind on `className`
69
+
70
+ Write the HTML you already know — `main`, `header`, `nav`, `section`, `h1`–`h3`, `p`, `ul`/`li`, `button`, `a`, `form`, `table` — styled with **Tailwind v4 utilities via `className`**:
71
+
72
+ ```tsx
73
+ <section className="mx-auto max-w-5xl px-6 py-20">
74
+ <h2 className="text-3xl font-bold tracking-tight">Pricing</h2>
75
+ <p className="mt-3 max-w-xl text-lg text-slate-600">Simple plans that grow with you.</p>
76
+ </section>
77
+ ```
78
+
79
+ - `className`, never a `tw` prop. Arbitrary values are fine (`text-[15px]`, `bg-[#0b0b10]`, `max-w-[72ch]`).
80
+ - Responsive variants are the default tool: `grid sm:grid-cols-2 lg:grid-cols-3`. Mobile-first — unprefixed utilities are the mobile layout.
81
+ - State variants for interactive elements: `hover:`, `focus-visible:`, `disabled:`, `aria-pressed:`.
82
+ - Use inline `style={{ … }}` only for values Tailwind cannot express (computed positions, CSS variables from data).
83
+ - A page may import its own stylesheet (`import './styles.css'`) for keyframes, complex selectors, or a font `@import`. Keep it small; utilities first.
84
+ - Preflight (Tailwind's reset) is applied inside the page, so headings and buttons start unstyled — set sizes and weights explicitly.
85
+
86
+ ## Web type scale and color
87
+
88
+ | Element | Size |
89
+ | --- | --- |
90
+ | Hero heading | 48–72px (`text-5xl`–`text-7xl`), tight leading + tracking |
91
+ | Section heading | 24–36px (`text-2xl`–`text-4xl`) |
92
+ | Body | 16–18px (`text-base`–`text-lg`), `leading-relaxed` |
93
+ | Secondary / captions | 13–14px (`text-sm`), muted color |
94
+ | Labels, eyebrows | 11–12px (`text-xs`), `uppercase tracking-widest` |
95
+
96
+ - One page = one palette: a background, a text color, a muted text color, one accent, one border tint. Hold it for the whole page.
97
+ - Contrast: body text must pass 4.5:1 against its background; muted text on dark backgrounds is `text-white/60`, not `text-white/30`.
98
+ - Details in `references/typography-and-color.md`.
99
+
100
+ ## Data rows vs designed repeats
101
+
102
+ - **Repeated data belongs in a `.map` over a data array** — pricing tiers, feature lists, testimonials pulled from a typed const at the top of the file; keep the row JSX in the map body. A comment on any row means "this row template".
103
+ - **Designed repeats that differ (hero vs. secondary CTA, three distinct feature panels with custom art) are explicit instances** of a small helper component defined in the same file or under `components/`. The inspector targets source JSX; explicit instances give each block its own address, so "make the middle one green" is one edit, not three.
104
+
105
+ ## Editing an existing page
106
+
107
+ Locate the section first instead of reading the whole file:
108
+
109
+ ```bash
110
+ grep -n '<section\|<h[12]\|<header\|<footer' pages/<id>/index.tsx
111
+ ```
112
+
113
+ Landmarks and headings anchor sections; read the target range with `offset` + `limit`. Read the whole file when auditing palette or restructuring.
114
+
115
+ ## Themes
116
+
117
+ If `themes/<id>.md` exists and the page is meant to follow it, **the theme file overrides the defaults in this skill** — its palette, typography, and fixed components are authoritative. Read the theme before applying anything else here. Themes are produced by the `create-theme` skill.
118
+
119
+ ## Runtime behavior you get for free
120
+
121
+ - Home lists every folder under `pages/`; cards show a live, scaled-down preview of the real page.
122
+ - The page view at `http://localhost:5173/p/<id>` renders the page in an iframe with **Desktop / Tablet (820px) / Mobile (390px)** viewport toggles, a reload button, and **Open** (the page by itself in a new tab).
123
+ - **Inspect mode** (toolbar button or `i`): the user clicks any element, sees its tag and source line, and can leave a comment that lands in your source as an `@page-comment` marker (see `apply-comments`). The current selection is always in `node_modules/.open-pages/current.json` (see `current-page`).
124
+ - Hot reload: save any file under `pages/<id>/` and the preview updates in place.
125
+ - `open-pages export <id>` builds `export/<id>/` — `index.html` plus hashed assets with relative URLs. Drop the folder on Netlify, Vercel, Cloudflare Pages, GitHub Pages, or S3.
126
+
127
+ ## Self-review before finishing
128
+
129
+ - [ ] `pages/<id>/index.tsx` default-exports **one** component; `meta` has `title` + fresh `createdAt` literal.
130
+ - [ ] Root element sets `min-h-screen`, background, and text color; the page has a `<main>` landmark.
131
+ - [ ] Preview it at `http://localhost:5173/p/<id>` (or ask the user to). No error banner, no console errors.
132
+ - [ ] Check the **Mobile** viewport: no horizontal overflow, nav collapses or wraps, grids stack, text sizes step down.
133
+ - [ ] Every `className` is Tailwind v4 the scanner will see (literal strings, no runtime-concatenated utility names).
134
+ - [ ] Interactive elements are real `<button>`/`<a>`/`<input>` elements with visible `focus-visible:` styles and labels; images have `alt`.
135
+ - [ ] One coherent palette and type scale across the page; contrast holds on dark sections.
136
+ - [ ] Designed repeats are explicit component instances; data lists are a `.map` over a typed const.
137
+ - [ ] No `window`/`document` access at module top level; effects clean up.
138
+ - [ ] Nothing outside `pages/<id>/` was edited.
139
+
140
+ ## Anti-patterns
141
+
142
+ - ❌ `tw` props, `pageOptions`, fixed-size "page" `<div>`s, or any document/slide thinking. This is a scrolling web page.
143
+ - ❌ Desktop-only layouts: absolute pixel positioning, fixed widths on the root, `grid-cols-3` with no `sm:` fallback.
144
+ - ❌ Building class names at runtime (`` `text-${size}` ``) — Tailwind only generates utilities it can read literally. Map to full class strings instead.
145
+ - ❌ `<div onClick>` where a `<button>` belongs; `<a>` without `href`; icon buttons without `aria-label`.
146
+ - ❌ Tiny typography (11px body). Web body is 16px+.
147
+ - ❌ Global CSS resets or `body {}` rules in `styles.css` that fight Preflight — style the root element instead.
148
+ - ❌ Installing packages, editing `package.json`/config/other pages, adding a `README.md` to the page folder.
@@ -0,0 +1,85 @@
1
+ # Assets and fonts
2
+
3
+ Both images and fonts follow the same rule: put the file under
4
+ `pages/<id>/assets/`, import it, and reference the imported value. Vite
5
+ resolves the import to a URL in the preview and to a hashed file in the
6
+ export.
7
+
8
+ ## Images
9
+
10
+ ```tsx
11
+ import hero from './assets/hero.png';
12
+
13
+ <img src={hero} alt="Dashboard showing the weekly brief" width={1200} height={720} className="w-full rounded-xl" />
14
+ ```
15
+
16
+ - **Always give `width` and `height`** (intrinsic pixels) so the browser
17
+ reserves space and the layout does not shift while loading. Let CSS
18
+ (`w-full h-auto`) size it visually.
19
+ - **Always give `alt`**: descriptive for content images, `alt=""` for purely
20
+ decorative ones.
21
+ - Below-the-fold images: `loading="lazy"`. The hero image: eager, and keep it
22
+ reasonably sized (≤ 1600px wide, WebP or JPEG).
23
+ - Page-local images live in `pages/<id>/assets/`; images shared across pages
24
+ live in the root `assets/` folder and import via `@assets/...`.
25
+ - Inline `<svg>` for logos, icons, and simple illustrations — crisp at any
26
+ size and styleable with `fill-current`/`stroke-current`. Icon-only buttons
27
+ need `aria-label`.
28
+ - Remote images (`https://…`) work but make the export depend on that host.
29
+ Prefer local files; ask the user for their assets rather than inventing
30
+ stock imagery.
31
+
32
+ ## Fonts
33
+
34
+ The default is the system font stack — fast, no files, always correct.
35
+ Register a font only when the user names one or supplies files.
36
+
37
+ ### Google Fonts
38
+
39
+ Render the link tags at the top of the page component:
40
+
41
+ ```tsx
42
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
43
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
44
+ <link
45
+ rel="stylesheet"
46
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
47
+ />
48
+ ```
49
+
50
+ Then use it: `className="font-[Inter,ui-sans-serif,system-ui,sans-serif]"` on
51
+ the root element, or in the page's `styles.css`:
52
+
53
+ ```css
54
+ @import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,600&display=swap');
55
+ ```
56
+
57
+ ### Self-hosted
58
+
59
+ ```css
60
+ /* pages/<id>/styles.css */
61
+ @font-face {
62
+ font-family: 'Satoshi';
63
+ src: url('./assets/Satoshi-Variable.woff2') format('woff2');
64
+ font-weight: 300 900;
65
+ font-display: swap;
66
+ }
67
+ ```
68
+
69
+ `import './styles.css'` in `index.tsx`, then `font-[Satoshi,sans-serif]`.
70
+ Always include a fallback family.
71
+
72
+ ## Favicons and `<head>`
73
+
74
+ - `meta.title` and `meta.description` are written into the exported
75
+ `<head>`. Other head tags (favicon, Open Graph) are not supported yet; note
76
+ this to the user if they ask for them.
77
+
78
+ ## Anti-patterns
79
+
80
+ - ❌ `<img>` without `alt`, or without `width`/`height`.
81
+ - ❌ Multi-megapixel PNG screenshots as hero images.
82
+ - ❌ `fontFamily` naming a font that was never loaded — it silently falls
83
+ back and the page looks nothing like the theme.
84
+ - ❌ Loading four weights of two families for one heading.
85
+ - ❌ Hotlinking images from someone else's site.
@@ -0,0 +1,65 @@
1
+ # Plain HTML pages
2
+
3
+ A page folder may hold an `index.html` instead of a React module. The
4
+ workspace serves it as-is (through Vite, so scripts and styles are
5
+ processed), the home card previews it live, and `open-pages export <id>`
6
+ builds it into a static folder like any other page.
7
+
8
+ ## When to use it
9
+
10
+ - The user hands you existing HTML/CSS/JS to host or tweak.
11
+ - A tiny page where React is overhead: a one-screen announcement, a redirect
12
+ page, an embed target.
13
+ - Prototypes that intentionally avoid a framework.
14
+
15
+ For anything with real layout, state, or reuse, prefer `index.tsx`.
16
+
17
+ ## Contract
18
+
19
+ ```
20
+ pages/<id>/
21
+ index.html entry — must contain <title>
22
+ style.css optional, referenced with a relative href
23
+ main.js optional, referenced with a relative src (type="module" recommended)
24
+ assets/ images, fonts
25
+ ```
26
+
27
+ ```html
28
+ <!doctype html>
29
+ <html lang="en">
30
+ <head>
31
+ <meta charset="UTF-8" />
32
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
33
+ <title>Launch week</title>
34
+ <link rel="stylesheet" href="./style.css" />
35
+ </head>
36
+ <body>
37
+ <main>…</main>
38
+ <script type="module" src="./main.js"></script>
39
+ </body>
40
+ </html>
41
+ ```
42
+
43
+ - Reference siblings with **relative** URLs (`./style.css`, `./assets/logo.svg`,
44
+ `main.js`). Absolute paths (`/style.css`) do not resolve in the preview or
45
+ the export.
46
+ - `<title>` is the card label in the workspace. There is no `meta` export;
47
+ the folder name is the page id.
48
+ - If both `index.tsx` and `index.html` exist, the React entry wins and the
49
+ HTML is treated as a plain asset.
50
+ - Tailwind is **not** wired into HTML pages. Write CSS, or use the React
51
+ entry when you want utilities.
52
+
53
+ ## What you do not get
54
+
55
+ - No inspector, no click-to-comment, no `@page-comment` markers. Feedback on
56
+ an HTML page comes as plain requests; apply them by editing the file.
57
+ - No hot module replacement for the HTML itself — the preview reloads the
58
+ frame on save. CSS and JS changes still hot-update.
59
+
60
+ ## Anti-patterns
61
+
62
+ - ❌ Absolute or root-relative asset paths.
63
+ - ❌ Inline `<script>` blobs of application logic — put them in `main.js`.
64
+ - ❌ Reaching for `index.html` when the request is "a landing page with a
65
+ pricing toggle". That is a React page.