@autono/create-open-pages 0.1.0 → 0.3.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 (94) hide show
  1. package/README.md +6 -3
  2. package/dist/cli.js +1 -1
  3. package/package.json +1 -1
  4. package/template/.agents/skills/apply-comments/SKILL.md +4 -4
  5. package/template/.agents/skills/create-page/SKILL.md +26 -8
  6. package/template/.agents/skills/create-theme/SKILL.md +137 -150
  7. package/template/.agents/skills/current-page/SKILL.md +1 -1
  8. package/template/.agents/skills/page-authoring/SKILL.md +97 -42
  9. package/template/.agents/skills/page-authoring/references/interactivity.md +70 -22
  10. package/template/.agents/skills/page-authoring/references/layout-and-responsive.md +38 -17
  11. package/template/.agents/skills/page-authoring/references/typography-and-color.md +50 -32
  12. package/template/.agents/skills/shadcn/SKILL.md +277 -0
  13. package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  14. package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
  15. package/template/.agents/skills/shadcn/cli.md +290 -0
  16. package/template/.agents/skills/shadcn/customization.md +209 -0
  17. package/template/.agents/skills/shadcn/mcp.md +105 -0
  18. package/template/.agents/skills/shadcn/registry.md +277 -0
  19. package/template/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
  20. package/template/.agents/skills/shadcn/rules/chat.md +224 -0
  21. package/template/.agents/skills/shadcn/rules/composition.md +213 -0
  22. package/template/.agents/skills/shadcn/rules/forms.md +192 -0
  23. package/template/.agents/skills/shadcn/rules/icons.md +101 -0
  24. package/template/.agents/skills/shadcn/rules/styling.md +185 -0
  25. package/template/AGENTS.md +7 -4
  26. package/template/README.md +21 -4
  27. package/template/components.json +9 -0
  28. package/template/hooks/use-mobile.ts +19 -0
  29. package/template/lib/utils.ts +6 -0
  30. package/template/package.json +24 -2
  31. package/template/pages/getting-started/index.tsx +51 -45
  32. package/template/styles/globals.css +118 -0
  33. package/template/tsconfig.json +13 -2
  34. package/template/ui/accordion.tsx +64 -0
  35. package/template/ui/alert-dialog.tsx +196 -0
  36. package/template/ui/alert.tsx +66 -0
  37. package/template/ui/aspect-ratio.tsx +11 -0
  38. package/template/ui/attachment.tsx +204 -0
  39. package/template/ui/avatar.tsx +107 -0
  40. package/template/ui/badge.tsx +48 -0
  41. package/template/ui/breadcrumb.tsx +109 -0
  42. package/template/ui/bubble.tsx +125 -0
  43. package/template/ui/button-group.tsx +83 -0
  44. package/template/ui/button.tsx +64 -0
  45. package/template/ui/calendar.tsx +218 -0
  46. package/template/ui/card.tsx +92 -0
  47. package/template/ui/carousel.tsx +241 -0
  48. package/template/ui/chart.tsx +374 -0
  49. package/template/ui/checkbox.tsx +32 -0
  50. package/template/ui/collapsible.tsx +31 -0
  51. package/template/ui/combobox.tsx +308 -0
  52. package/template/ui/command.tsx +182 -0
  53. package/template/ui/context-menu.tsx +252 -0
  54. package/template/ui/dialog.tsx +156 -0
  55. package/template/ui/direction.tsx +22 -0
  56. package/template/ui/drawer.tsx +133 -0
  57. package/template/ui/dropdown-menu.tsx +257 -0
  58. package/template/ui/empty.tsx +104 -0
  59. package/template/ui/field.tsx +246 -0
  60. package/template/ui/form.tsx +167 -0
  61. package/template/ui/hover-card.tsx +42 -0
  62. package/template/ui/input-group.tsx +170 -0
  63. package/template/ui/input-otp.tsx +77 -0
  64. package/template/ui/input.tsx +21 -0
  65. package/template/ui/item.tsx +193 -0
  66. package/template/ui/kbd.tsx +28 -0
  67. package/template/ui/label.tsx +22 -0
  68. package/template/ui/marker.tsx +69 -0
  69. package/template/ui/menubar.tsx +276 -0
  70. package/template/ui/message-scroller.tsx +128 -0
  71. package/template/ui/message.tsx +92 -0
  72. package/template/ui/native-select.tsx +62 -0
  73. package/template/ui/navigation-menu.tsx +168 -0
  74. package/template/ui/pagination.tsx +127 -0
  75. package/template/ui/popover.tsx +87 -0
  76. package/template/ui/progress.tsx +31 -0
  77. package/template/ui/radio-group.tsx +43 -0
  78. package/template/ui/resizable.tsx +53 -0
  79. package/template/ui/scroll-area.tsx +56 -0
  80. package/template/ui/select.tsx +190 -0
  81. package/template/ui/separator.tsx +26 -0
  82. package/template/ui/sheet.tsx +143 -0
  83. package/template/ui/sidebar.tsx +726 -0
  84. package/template/ui/skeleton.tsx +13 -0
  85. package/template/ui/slider.tsx +61 -0
  86. package/template/ui/sonner.tsx +40 -0
  87. package/template/ui/spinner.tsx +16 -0
  88. package/template/ui/switch.tsx +33 -0
  89. package/template/ui/table.tsx +116 -0
  90. package/template/ui/tabs.tsx +89 -0
  91. package/template/ui/textarea.tsx +18 -0
  92. package/template/ui/toggle-group.tsx +81 -0
  93. package/template/ui/toggle.tsx +47 -0
  94. package/template/ui/tooltip.tsx +55 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @autono/create-open-pages
2
2
 
3
- Scaffold a workspace for [open-pages](https://openpages.sh) — the web page framework built for agents. Your coding agent writes pages as React components or plain HTML; you get a live browser preview, click-to-comment, and static export to any host.
3
+ Scaffold a workspace for [open-pages](https://openpages.sh) — the web page framework built for agents. Your coding agent writes pages as React components or plain HTML, with the full shadcn/ui set already installed; you get a live browser preview, click-to-comment, and static export to any host.
4
4
 
5
5
  ## Usage
6
6
 
@@ -13,12 +13,15 @@ npm run dev
13
13
  This creates a workspace containing:
14
14
 
15
15
  - `pages/getting-started/` — a starter page you can edit or delete.
16
+ - `ui/` — all 61 shadcn/ui components, plus `lib/utils.ts` (`cn`) and `hooks/use-mobile.ts`. Pages import `@/ui/button` and friends; nothing to `add`.
17
+ - `styles/globals.css` — Tailwind v4 entry with the shadcn token theme (`:root` / `.dark`). The runtime uses it for preview and export.
18
+ - `components.json` — shadcn config (new-york, radix, `@/ui` aliases) so `npx shadcn@latest add` works for blocks and other registries, and the bundled `shadcn` skill activates.
16
19
  - `package.json` — depends on `@autono/open-pages`, which provides the runtime (viewer, inspector, export) and the `open-pages` CLI.
17
20
  - `open-pages.config.ts` — optional typed config (pagesDir, port, base).
18
- - `.claude/skills/` and `.agents/skills/` — agent skills (`create-page`, `page-authoring`, `apply-comments`, `create-theme`, `current-page`).
21
+ - `.claude/skills/` and `.agents/skills/` — agent skills (`create-page`, `page-authoring`, `apply-comments`, `create-theme`, `current-page`, `shadcn`).
19
22
  - `AGENTS.md` (linked as `CLAUDE.md`) — agent guide for authoring pages.
20
23
 
21
- You won't see any Vite, React, Tailwind, or tsconfig files in the workspace. They live inside `@autono/open-pages` and you never touch them.
24
+ You won't see any Vite or React config in the workspace. That lives inside `@autono/open-pages`. The shadcn components are yours: real source files under `ui/`, editable like any shadcn project.
22
25
 
23
26
  ## Flags
24
27
 
package/dist/cli.js CHANGED
@@ -102,7 +102,7 @@ async function isDirNonEmpty(target) {
102
102
  return entries.some((e) => !e.startsWith("."));
103
103
  }
104
104
  function coreVersionRange() {
105
- return `^0.1.0`;
105
+ return `^0.3.0`;
106
106
  }
107
107
  async function linkOrCopy(relSrc, dst) {
108
108
  await rm(dst, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autono/create-open-pages",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Scaffold an open-pages workspace — agent skills preconfigured, live real-PDF preview out of the box.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,7 +9,7 @@ The open-pages viewer has an inspector that lets the user click any element on t
9
9
 
10
10
  Your job: read those markers, perform the described edits, and delete the markers.
11
11
 
12
- > **Before making any page edit**, consult the **`page-authoring`** skill — it is the technical reference for how a page is structured (file contract, `className` styling, layout and responsive rules, type scale, interactivity). A comment like *"make this bigger"* or *"change the accent colour"* should be applied in a way that stays consistent with those rules and still works on mobile.
12
+ > **Before making any page edit**, consult the **`page-authoring`** skill (and the **`shadcn`** skill for component props and variants) — it is the technical reference for how a page is structured (file contract, `className` styling, layout and responsive rules, type scale, interactivity). A comment like *"make this bigger"* or *"change the accent colour"* should be applied in a way that stays consistent with those rules and still works on mobile.
13
13
 
14
14
  ## Marker format
15
15
 
@@ -38,8 +38,8 @@ Your job: read those markers, perform the described edits, and delete the marker
38
38
  - If there are no markers, tell the user and stop.
39
39
 
40
40
  3. **Understand each comment in context.**
41
- - The targeted JSX element is the **enclosing** element of the marker — i.e. read upward from the marker line until you reach the unclosed JSX opening tag whose body the marker lives in. That element is the target. (For self-closing elements like `<img />`, the inspector hoists the marker to the nearest non-self-closing ancestor; in that case the comment usually refers to a child of the enclosing element rather than the enclosing element itself — use the `note` text to disambiguate.)
42
- - Read enough surrounding code (parent element, sibling elements, `className` strings, any state the element depends on) to apply the change faithfully. A comment inside a `<button>` with an `onClick` may be about behaviour, not looks.
41
+ - The targeted JSX element is the **enclosing** element of the marker — i.e. read upward from the marker line until you reach the unclosed JSX opening tag whose body the marker lives in. That element is the target. It is often a shadcn component (`<Button>`, `<Card>`, `<TabsTrigger>`): the inspector tags components too, so a click on the rendered button lands on the `<Button>` line in the page, never inside `ui/*.tsx`. (For self-closing elements like `<img />`, the inspector hoists the marker to the nearest non-self-closing ancestor; in that case the comment usually refers to a child of the enclosing element rather than the enclosing element itself — use the `note` text to disambiguate.)
42
+ - Read enough surrounding code (parent element, sibling elements, `className` strings, any state the element depends on) to apply the change faithfully. A comment inside a `<Button>` with an `onClick` may be about behaviour, not looks. Apply look changes with the component's variants and semantic tokens (`variant="outline"`, `bg-muted`), not raw colors; if the comment really wants a different palette across the page, say so — that is a theme change, not a page edit.
43
43
  - If the marker sits inside a `.map` body, the comment applies to the row template — every rendered row changes. If the user clearly meant one item ("make the *middle* one green"), change the data or add a per-item field rather than special-casing the JSX.
44
44
  - If the `note` is ambiguous, do the smallest reasonable interpretation and mention the assumption in your summary.
45
45
 
@@ -81,6 +81,6 @@ You can run this inline via `node -e '...'` if you need to inspect a payload; ot
81
81
 
82
82
  ## Do not
83
83
 
84
- - Do not touch `package.json`, `open-pages.config.ts`, or files outside `pages/`.
84
+ - Do not touch `package.json`, `open-pages.config.ts`, `ui/`, `lib/`, `hooks/`, `styles/globals.css`, or any file outside `pages/`. A comment that asks to change a shared component ("make all buttons rounder") is applied by wrapping in the page, or flagged as a theme/`ui/` change for the user to decide.
85
85
  - Do not add dependencies.
86
86
  - Do not re-introduce markers or leave `TODO` breadcrumbs — the user already has a record in git.
@@ -5,7 +5,9 @@ description: Use this skill when the user wants to create, build, draft, or gene
5
5
 
6
6
  # Create a page in open-pages
7
7
 
8
- This skill owns the **workflow** for building a new page. The technical reference — file contract, Tailwind via `className`, layout and responsive rules, type scale, interactivity, assets — lives in the **`page-authoring`** skill. Read that skill whenever you need details on *how* a page is structured. This skill assumes you'll consult it before writing code.
8
+ This skill owns the **workflow** for building a new page. The technical reference — file contract, composing from the preinstalled shadcn/ui set under `ui/`, semantic tokens, layout and responsive rules, type scale, interactivity, assets — lives in the **`page-authoring`** skill. Read that skill whenever you need details on *how* a page is structured. This skill assumes you'll consult it before writing code. Component-level questions (props, variants, blocks, registries) go to the vendored **`shadcn`** skill.
9
+
10
+ Every workspace already ships the full shadcn/ui set (`ui/`), `lib/utils.ts`, `hooks/`, and `styles/globals.css` with the neutral OKLCH tokens. Nothing needs `npx shadcn add`; pages import `@/ui/<name>` and compose.
9
11
 
10
12
  You only write files under `pages/<id>/`. Never modify `package.json`, `open-pages.config.ts`, or existing pages.
11
13
 
@@ -13,8 +15,8 @@ You only write files under `pages/<id>/`. Never modify `package.json`, `open-pag
13
15
 
14
16
  List files under `themes/`. If any theme markdown files exist (anything other than `README.md`), call `AskUserQuestion` with each theme id as an option plus a final **"no theme — design from scratch"** option. (`AskUserQuestion` holds at most 4 options — with 4+ themes, offer the 3 most topic-relevant plus "no theme"; the auto-added "Other" lets the user name any omitted theme.)
15
17
 
16
- - If the user picks a theme: read `themes/<id>.md` end-to-end. The theme's palette, typography, and fixed components are now authoritative — copy them directly into the page. **Also set `theme: '<theme-id>'` on the `meta` export** so the page back-links to the theme. In Step 2, skip the **visual direction** question (the theme already commits to one); confirm the page's purpose itself before moving on. Sections and interactivity are independent of theme — ask those normally.
17
- - If the user picks "no theme", or `themes/` contains no theme markdown files: proceed to Step 2 unchanged.
18
+ - If the user picks a theme: read `themes/<id>.md` end-to-end. Its direction, fonts, and component notes are now authoritative. **Set `theme: '<theme-id>'` on the `meta` export** — the runtime injects `themes/<id>.css` (the token overrides) into the page, so you keep writing semantic token classes and never paste color values. In Step 2, skip the **visual direction** question (the theme already commits to one); confirm the page's purpose itself before moving on. Sections and interactivity are independent of theme — ask those normally.
19
+ - If the user picks "no theme", or `themes/` contains no theme markdown files: the page uses the default neutral tokens from `styles/globals.css`. Proceed to Step 2 unchanged.
18
20
 
19
21
  If you skip the visual-direction question because a theme was picked, restate the theme name in Step 2 so the user can correct course before you start writing.
20
22
 
@@ -67,17 +69,32 @@ Sketch the page as an ordered list of sections before writing code. Common shape
67
69
 
68
70
  Decide the data shape now: which sections render from a typed const array (`.map`), which are explicit component instances — `page-authoring` explains why this matters for the inspector.
69
71
 
70
- ## Step 5 — Commit to a visual direction
72
+ ## Step 5 — Compose from `ui/`
73
+
74
+ Before writing code, map every planned section to the shadcn components it should be built from. Pages compose `@/ui/*` first and hand-roll only what shadcn lacks (heroes, marketing feature grids, footers). Typical mappings:
75
+
76
+ | Page type | Reach for |
77
+ | --- | --- |
78
+ | Landing / marketing | `navigation-menu` or plain links + `sheet` for mobile nav, `button` (CTAs), `badge` (eyebrows), `card` (features, pricing tiers), `tabs` or `switch` (billing toggle), `accordion` (FAQ), `separator` |
79
+ | Dashboard / app UI | `sidebar` (`SidebarProvider` + `SidebarInset`), `table`, `chart`, `card` (KPIs), `tabs`, `select`, `dropdown-menu`, `badge` (status), `skeleton`, `empty` |
80
+ | Form / signup | `form` (react-hook-form + zod) or `field`, `input`, `select`, `checkbox`, `radio-group`, `switch`, `textarea`, `button`, `alert` |
81
+ | Docs / long-form | `sidebar` or a sticky `scroll-area` TOC, `breadcrumb`, prose in a `max-w-[65ch]` column, `kbd`, `table`, `alert` (callouts) |
82
+ | Portfolio / gallery | `carousel`, `aspect-ratio`, `card`, `dialog` (lightbox), `hover-card` |
83
+ | Internal tool | `command` (palette), `combobox`, `resizable`, `context-menu`, `tooltip`, `sonner` (toasts), `alert-dialog` (confirm) |
84
+
85
+ Write the list down (component per section) so the structure in Step 4 and the code in Step 6 agree. If a section needs something shadcn only ships as a block (`dashboard-01`, `login-03`), the `shadcn` skill explains `npx shadcn@latest view` / `add` for blocks.
86
+
87
+ ## Step 5b — Commit to a visual direction
71
88
 
72
- One palette, one type scale, held for the whole page. The constraints (web type scale, palette structure, contrast) live in `page-authoring` and its `references/typography-and-color.md` — apply them. Define the palette as repeated Tailwind utilities (or a small const map of class strings). Fonts: default to the system stack; load a Google Font or self-hosted file only when the user names one or a theme requires it (`references/assets-and-fonts.md`).
89
+ One type scale, held for the whole page, expressed in the semantic tokens (`bg-background`, `bg-card`, `bg-primary`, `text-muted-foreground`, `border-border`) so a theme can repaint everything. Dark direction = `dark` on the root element, not a hand-picked dark palette. The constraints (web type scale, token system, contrast) live in `page-authoring` and its `references/typography-and-color.md` — apply them. Raw palette classes are for one deliberate brand moment, if any. Fonts: default to the token font; load a Google Font or self-hosted file only when the user names one or a theme requires it (`references/assets-and-fonts.md`).
73
90
 
74
91
  ## Step 6 — Write `pages/<id>/index.tsx`
75
92
 
76
- Read the **`page-authoring`** skill before writing — file contract, `className` styling, layout and responsive rules, interactivity constraints, assets. Its file-contract example is the starter template. Split large pages into `pages/<id>/components/*.tsx` when a section is more than ~80 lines.
93
+ Read the **`page-authoring`** skill before writing — file contract, `@/ui/*` composition, token styling, layout and responsive rules, interactivity constraints, assets. Its file-contract example is the starter template. Never edit files under `ui/`, `lib/`, `hooks/`, or `styles/` for a page; wrap components under `pages/<id>/components/` when they need a page-specific look. Split large pages into `pages/<id>/components/*.tsx` when a section is more than ~80 lines.
77
94
 
78
95
  ## Step 7 — Self-review
79
96
 
80
- Run the checklist in `page-authoring` ("Self-review before finishing"). Check all three viewports.
97
+ Run the checklist in `page-authoring` ("Self-review before finishing"): every button/input/card/dialog/tab is a `@/ui` component, colors are tokens, nothing under `ui/` changed. Check all three viewports.
81
98
 
82
99
  ## Step 8 — Hand off to the user
83
100
 
@@ -85,7 +102,8 @@ Tell the user:
85
102
 
86
103
  - The page id and file path you created.
87
104
  - The preview URL — `http://localhost:5173/p/<id>` — hot-reloads on every edit, with Desktop / Tablet / Mobile toggles and **Open** to view the page by itself.
88
- - That they can hit **Inspect** (or `i`) in the preview, click any element, and leave comments — then ask you to run `apply-comments`.
105
+ - That they can hit **Inspect** (or `i`) in the preview, click any element or component, and leave comments — then ask you to run `apply-comments`.
106
+ - That the look is token-driven: `/create-theme` can restyle the whole page (and every other page) without touching its code.
89
107
  - That `open-pages export <id>` writes `export/<id>/` — a static folder (index.html + assets) they can deploy to Netlify, Vercel, Cloudflare Pages, GitHub Pages, or any static host.
90
108
  - If dev isn't running: run the project's `dev` script from the project root with its package manager (`npm run dev`, `pnpm dev`, … — match the lockfile).
91
109
 
@@ -1,49 +1,106 @@
1
1
  ---
2
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.
3
+ description: Use this skill when the user wants to create, draft, author, or extract a theme in this open-pages repo. Triggers on phrases like "create a theme", "make a theme called X", "extract a theme from <page>", "match our brand", "build a design system from these screenshots", "apply this shadcn preset". Produces a three-file bundle under `themes/` — `<id>.md` (direction, fonts, component notes, token table), `<id>.css` (the shadcn token overrides), and `<id>.demo.tsx` (a demo page composed from `ui/` components that the workspace's Themes panel previews live). Do NOT use for editing real pages — only for authoring the theme bundle.
4
4
  ---
5
5
 
6
- # Create a page theme
6
+ # Create a theme
7
7
 
8
- This skill produces a **theme bundle** under `themes/`: two paired files that together describe a reusable visual identity for web pages.
8
+ A theme is a **token set**. Every workspace ships the full shadcn/ui set under `ui/`, and every component reads its colors, radius, and fonts from the CSS variables in `styles/globals.css` (`--background`, `--primary`, `--radius`, …). A theme overrides those variables; every component and every token-styled page restyles at once. Nothing is copied into pages.
9
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.
10
+ The bundle is three files sharing one stem under `themes/`:
12
11
 
13
- Both files share the same stem so the runtime can pair them automatically.
12
+ 1. `themes/<id>.md` — agent-facing direction: aesthetic, fonts, how to use the components in this theme, and a table of token → value. This is what `create-page` reads when an author picks the theme.
13
+ 2. `themes/<id>.css` — **only** `:root { … }` and `.dark { … }` blocks overriding the shadcn tokens (plus an optional Google Fonts `@import url(…)` at the very top). No `@theme` block, no Tailwind import, no selectors beyond those two.
14
+ 3. `themes/<id>.demo.tsx` — a runnable page module (same shape as `pages/<id>/index.tsx`, **one default-exported component**) composed from `@/ui/*` components so the tokens are shown on real parts. The Themes panel renders it with `<id>.css` injected automatically; the demo does not set `meta.theme`.
14
15
 
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
+ A page opts in with `meta.theme: '<id>'`; the runtime injects `themes/<id>.css` into that page's preview frame and into its export.
16
17
 
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
+ You only write the three theme files. Never modify pages, `ui/`, `styles/globals.css`, or configuration. The token names and how pages consume them live in the **`page-authoring`** skill (`references/typography-and-color.md`) — read it first. Component props and variants: the **`shadcn`** skill.
18
19
 
19
20
  ## Step 1 — Identify the input source
20
21
 
21
- A theme can be derived from any combination of three input shapes:
22
+ A theme can be derived from any combination of:
22
23
 
23
- - **Image references** — paths or URLs to screenshots, mood-board images, brand assets.
24
+ - **A shadcn preset** — a code or URL from https://ui.shadcn.com/create. `npx shadcn@latest preset decode <code>` prints its tokens; or run `npx shadcn@latest apply <code> --only theme,font` in a scratch copy and lift the resulting `:root`/`.dark` values. Never run `apply` against the workspace's `styles/globals.css` directly — that changes the default for every page.
25
+ - **Image references / brand guidelines** — paths or URLs to screenshots, mood boards, logo files, a brand PDF. You will translate them into OKLCH tokens.
24
26
  - **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.
27
+ - **An existing page** — `pages/<id>/index.tsx` whose look should become reusable.
26
28
 
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.
29
+ 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, preset code, page id, prose) only as needed.
28
30
 
29
31
  ## Step 2 — Gather raw inputs
30
32
 
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.
33
+ - **Preset**: take its tokens as the baseline; adjust only what the user asked to change.
34
+ - **Images**: read each path with the `Read` tool (it accepts images). Note dominant colors (write them as hex, then convert to OKLCH), type family feel, corner radius, surface treatment (flat vs. cards vs. borders), light or dark default, and chrome (nav style, footer).
35
+ - **Text**: extract explicit values (hex codes, font names, "rounded", "sharp", "dense") and resolve vague language into concrete decisions before writing.
36
+ - **Existing page**: read `pages/<id>/index.tsx` (and `components/`) and pull any raw palette classes or hex values into token roles (the page's `bg-[#0b0b10]` root → `--background`; its CTA fill → `--primary`; its card border → `--border`), plus fonts and radius.
39
37
 
40
- When inputs disagree (e.g. images use blue but the description says green), ask the user which to honor.
38
+ Every color ends up as `oklch(L C H)` — the same format as `styles/globals.css`. When inputs disagree (images use blue but the description says green), ask the user which to honor.
41
39
 
42
40
  ## Step 3 — Pick a theme id
43
41
 
44
42
  Use **kebab-case**, short, descriptive. Examples: `dark-launch`, `clean-saas`, `editorial-warm`, `ops-console`. Check `themes/` to avoid collisions.
45
43
 
46
- ## Step 4 — Write `themes/<id>.md`
44
+ ## Step 4 — Write `themes/<id>.css`
45
+
46
+ Override the full token list for both modes, even when a value equals the default, so the file is self-describing:
47
+
48
+ ```css
49
+ @import url('https://fonts.googleapis.com/css2?family=Inter+Tight:wght@500;700&family=Inter:wght@400;500&display=swap');
50
+
51
+ :root {
52
+ --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
53
+ --font-heading: 'Inter Tight', var(--font-sans);
54
+ --radius: 0.75rem;
55
+ --background: oklch(1 0 0);
56
+ --foreground: oklch(0.145 0 0);
57
+ --card: oklch(1 0 0);
58
+ --card-foreground: oklch(0.145 0 0);
59
+ --popover: oklch(1 0 0);
60
+ --popover-foreground: oklch(0.145 0 0);
61
+ --primary: oklch(0.55 0.2 265);
62
+ --primary-foreground: oklch(0.985 0 0);
63
+ --secondary: oklch(0.97 0 0);
64
+ --secondary-foreground: oklch(0.205 0 0);
65
+ --muted: oklch(0.97 0 0);
66
+ --muted-foreground: oklch(0.5 0 0);
67
+ --accent: oklch(0.97 0 0);
68
+ --accent-foreground: oklch(0.205 0 0);
69
+ --destructive: oklch(0.577 0.245 27.325);
70
+ --border: oklch(0.922 0 0);
71
+ --input: oklch(0.922 0 0);
72
+ --ring: oklch(0.55 0.2 265);
73
+ --chart-1: oklch(0.55 0.2 265);
74
+ --chart-2: oklch(0.6 0.118 184.704);
75
+ --chart-3: oklch(0.398 0.07 227.392);
76
+ --chart-4: oklch(0.828 0.189 84.429);
77
+ --chart-5: oklch(0.769 0.188 70.08);
78
+ --sidebar: oklch(0.985 0 0);
79
+ --sidebar-foreground: oklch(0.145 0 0);
80
+ --sidebar-primary: oklch(0.55 0.2 265);
81
+ --sidebar-primary-foreground: oklch(0.985 0 0);
82
+ --sidebar-accent: oklch(0.97 0 0);
83
+ --sidebar-accent-foreground: oklch(0.205 0 0);
84
+ --sidebar-border: oklch(0.922 0 0);
85
+ --sidebar-ring: oklch(0.55 0.2 265);
86
+ }
87
+
88
+ .dark {
89
+ --background: oklch(0.13 0.01 265);
90
+ --foreground: oklch(0.985 0 0);
91
+ /* … every token again, dark values … */
92
+ }
93
+ ```
94
+
95
+ Rules:
96
+
97
+ - Exactly the shadcn token names (`--background` … `--sidebar-ring`, `--radius`), plus optionally `--font-sans` / `--font-heading` and the font `@import`. Unknown names do nothing; misspelled names silently fall back to the default.
98
+ - `*-foreground` must contrast with its surface (≥ 4.5:1 for body pairs). Check `--muted-foreground` on `--background` and `--primary-foreground` on `--primary` explicitly.
99
+ - A dark-first theme still defines `:root` for light; a page that wants dark puts `dark` on its root element. If the theme is dark-only, make both blocks the dark values.
100
+ - `--radius` sets every radius (`rounded-sm` … `rounded-2xl` scale from it): `0` sharp, `0.5rem` default-ish, `1rem` soft.
101
+ - Fonts load from Google Fonts via `@import url(…)` at the top of this file, or from a self-hosted file the theme tells `create-page` to place under `assets/` (then `@font-face` goes in the page's `styles.css`, not here).
102
+
103
+ ## Step 5 — Write `themes/<id>.md`
47
104
 
48
105
  Produce a file with this exact section order. Section bodies adapt to the theme; the headings stay consistent across all themes.
49
106
 
@@ -55,169 +112,99 @@ description: <one-line elevator pitch>
55
112
 
56
113
  # <Theme name>
57
114
 
58
- ## Palette
115
+ ## Tokens
59
116
 
60
- | Role | Tailwind | Hex | Notes |
117
+ | Token | Light | Dark | Role in pages |
61
118
  | --- | --- | --- | --- |
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 |
119
+ | `--background` / `--foreground` | `oklch(1 0 0)` / `oklch(0.145 0 0)` | … | page root (`bg-background text-foreground`) |
120
+ | `--primary` / `--primary-foreground` | … | … | the one accent: CTAs, active tabs, links |
121
+ | `--card`, `--muted`, `--accent`, `--secondary` | … | … | surfaces |
122
+ | `--border`, `--input`, `--ring` | … | … | rules, fields, focus |
123
+ | `--destructive` | … | … | delete, errors |
124
+ | `--chart-1…5` | … | … | chart series order |
125
+ | `--radius` | `0.75rem` | | rounded-lg cards, pill buttons via `rounded-full` |
126
+
127
+ The full set lives in `themes/<id>.css`; this table is the reference for what each value is *for*.
68
128
 
69
129
  ## Typography
70
130
 
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`
131
+ - Fonts: `--font-sans` / `--font-heading` set in the CSS (how they load: Google Fonts `@import`, or a self-hosted file under `assets/`).
132
+ - Type-scale overrides (only what differs from `page-authoring` defaults): hero `text-5xl sm:text-7xl font-heading tracking-tight`; body `text-lg`; eyebrow `<Badge variant="secondary">`.
77
133
 
78
134
  ## Layout
79
135
 
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
- ```
136
+ - Container: `mx-auto max-w-6xl px-6`; section rhythm `py-20`; separators `border-t border-border`.
137
+ - Default mode: light | dark (`dark` on the page root).
138
+ - Density: airy | standard | dense — how much `gap-*` and padding pages should use.
127
139
 
128
- ### Buttons
140
+ ## Components in this theme
129
141
 
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
- ```
142
+ Notes on how to use the `ui/` set so pages feel like this theme — which variants to prefer, what to avoid:
138
143
 
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
- ```
144
+ - Buttons: primary CTA `<Button size="lg">`; secondary `<Button size="lg" variant="outline">`; pill shape via `className="rounded-full"` (or not).
145
+ - Cards: `<Card>` with `border-border`, no shadow | `shadow-sm`.
146
+ - Nav: `<NavigationMenu>` on desktop, `<Sheet>` on mobile; sticky with `bg-background/90 backdrop-blur`.
147
+ - Data: `<Table>` + `<Badge>` for status; charts use `--chart-*` in order.
148
+ - Feedback: `<Alert>`, `sonner` toasts.
149
+ - Avoid: gradients | shadows | more than one accent | … (whatever the theme forbids).
162
150
 
163
151
  ## Aesthetic
164
152
 
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.
153
+ One paragraph. What it feels like, the references it draws on, what to avoid. Commit to a single direction.
166
154
 
167
155
  ## Example usage
168
156
 
169
157
  ```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" />
158
+ export const meta: PageMeta = { title: '…', theme: '<id>', createdAt: '…' };
159
+
160
+ <main className="min-h-screen bg-background text-foreground antialiased">
161
+ <header className="mx-auto flex max-w-6xl items-center justify-between px-6 py-6">…<Button>Get started</Button></header>
162
+ <section className="mx-auto max-w-6xl px-6 py-20">…</section>
178
163
  </main>
179
164
  ```
180
165
  ````
181
166
 
182
- ## Step 4b — Write `themes/<id>.demo.tsx`
167
+ The markdown never contains color values that are not also in the CSS, and never contains paste-ready components with raw colors — pages compose `ui/` and the tokens do the rest.
168
+
169
+ ## Step 6 — Write `themes/<id>.demo.tsx`
183
170
 
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.
171
+ The demo is a normal page module — same shape as `pages/<id>/index.tsx`, sitting under `themes/` so the runtime knows it's preview-only.
185
172
 
186
173
  Contract:
187
174
 
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.
175
+ - `import type { PageMeta } from '@autono/open-pages';`, `@/ui/*` imports, React hooks as needed. No `meta.theme` (the runtime injects `<id>.css` for demos).
176
+ - **One default-exported component** — a single scrolling page that exercises the tokens on real components: a header with `<Button>`s, a hero, a `<Card>` grid, a `<Tabs>` or `<Accordion>`, a `<Table>` with `<Badge>` status, an `<Input>` + `<Button>` form row, and a footer. Include one dark section (`<div className="dark bg-background text-foreground">`) if the theme is light-first, or one light section if dark-first, so both blocks of the CSS are visible.
177
+ - Root element: `min-h-screen bg-background text-foreground` (with `dark` if the theme is dark by default). Everything token-styled — the demo is the proof that pages need no raw colors.
178
+ - Realistic content, not lorem ipsum. Must look right at Mobile (390px) as well as Desktop. Self-contained: no page-local assets.
193
179
 
194
- ## Step 5 — Self-review
180
+ ## Step 7 — Self-review
195
181
 
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.
182
+ - [ ] `themes/<id>.css` overrides every shadcn token in both `:root` and `.dark`, in OKLCH, with only those two selectors (plus an optional font `@import`).
183
+ - [ ] Every `*-foreground` passes contrast on its surface; `--muted-foreground` is readable on `--background`.
184
+ - [ ] Frontmatter in the `.md` has `name` and `description` only (the runtime reads nothing else).
185
+ - [ ] Typography names only fonts the CSS loads (or the system stack).
186
+ - [ ] "Components in this theme" gives variant guidance for buttons, cards, nav, data, feedback.
187
+ - [ ] Demo `.tsx` default-exports one component, imports only `@/ui/*`, uses semantic tokens only, shows both modes, nothing overflows on mobile.
188
+ - [ ] All three files written with the same stem. No page changes, no `ui/` changes, no `styles/globals.css` changes.
204
189
 
205
- ## Step 6 — Hand off
190
+ ## Step 8 — Hand off
206
191
 
207
192
  Tell the user:
208
193
 
209
- - The theme id and the two file paths.
194
+ - The theme id and the three file paths.
210
195
  - 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).
196
+ - That any existing page can adopt it by setting `meta.theme: '<id>'` — no other change.
197
+ - A one-line summary of the look (accent, mode, radius, fonts).
212
198
 
213
199
  Do not run the dev server. Do not modify real pages — the demo `.tsx` is the demonstration.
214
200
 
215
201
  ## Anti-patterns
216
202
 
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.
203
+ - ❌ Pasting token values into pages, or theme markdown full of `bg-[#hex]` snippets. Tokens live in the CSS; pages stay semantic.
204
+ - ❌ `@theme inline`, `@import "tailwindcss"`, `@source`, or selectors other than `:root`/`.dark` in `themes/<id>.css`.
205
+ - ❌ Editing `styles/globals.css` or running `npx shadcn apply` against the workspace — that silently rethemes every page.
206
+ - ❌ Producing one or two of the three files. A theme is the **bundle** — `.md`, `.css`, `.demo.tsx`, every time.
207
+ - ❌ A demo with raw colors or hand-rolled buttons — it must prove the tokens carry the look through `ui/`.
208
+ - ❌ Naming font families the CSS never loads.
209
+ - ❌ Inventing values when the user supplied a preset, images, or an existing page. Extract, don't fabricate.
210
+ - ❌ Editing `pages/`, `ui/`, `packages/`, `package.json`, or `open-pages.config.ts`.
@@ -49,7 +49,7 @@ Path is relative to the project root (the user's `cwd`, the directory that conta
49
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
50
  - `selection` — `null` if nothing is selected. Otherwise, the JSX element the user picked in the inspector:
51
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"`).
52
+ - `tagName` is the rendered HTML tag, lowercased (`"h1"`, `"div"`, `"button"`). The source line it points at may be a shadcn component rather than that tag — a `"button"` selection usually lands on a `<Button>` line in the page, because `ui/` components spread the inspector tag onto their root. Edit the page line; never follow it into `ui/*.tsx`.
53
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
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
55
  - `updatedAt` — ISO timestamp of the last navigation or selection change. Use it to detect staleness.