@autono/create-open-pages 0.1.0 → 0.4.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.
- package/README.md +6 -3
- package/dist/cli.js +1 -1
- package/package.json +1 -1
- package/template/.agents/skills/apply-comments/SKILL.md +4 -4
- package/template/.agents/skills/create-page/SKILL.md +26 -8
- package/template/.agents/skills/create-theme/SKILL.md +137 -150
- package/template/.agents/skills/current-page/SKILL.md +1 -1
- package/template/.agents/skills/page-authoring/SKILL.md +97 -42
- package/template/.agents/skills/page-authoring/references/interactivity.md +71 -23
- package/template/.agents/skills/page-authoring/references/layout-and-responsive.md +38 -17
- package/template/.agents/skills/page-authoring/references/typography-and-color.md +50 -32
- package/template/.agents/skills/shadcn/SKILL.md +277 -0
- package/template/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/template/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/template/.agents/skills/shadcn/cli.md +290 -0
- package/template/.agents/skills/shadcn/customization.md +209 -0
- package/template/.agents/skills/shadcn/mcp.md +105 -0
- package/template/.agents/skills/shadcn/registry.md +277 -0
- package/template/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/template/.agents/skills/shadcn/rules/chat.md +224 -0
- package/template/.agents/skills/shadcn/rules/composition.md +213 -0
- package/template/.agents/skills/shadcn/rules/forms.md +192 -0
- package/template/.agents/skills/shadcn/rules/icons.md +101 -0
- package/template/.agents/skills/shadcn/rules/styling.md +185 -0
- package/template/AGENTS.md +7 -4
- package/template/README.md +21 -4
- package/template/components.json +9 -0
- package/template/hooks/use-mobile.ts +19 -0
- package/template/lib/utils.ts +6 -0
- package/template/package.json +27 -5
- package/template/pages/getting-started/index.tsx +51 -45
- package/template/styles/globals.css +118 -0
- package/template/tsconfig.json +13 -2
- package/template/ui/accordion.tsx +64 -0
- package/template/ui/alert-dialog.tsx +196 -0
- package/template/ui/alert.tsx +66 -0
- package/template/ui/aspect-ratio.tsx +11 -0
- package/template/ui/attachment.tsx +204 -0
- package/template/ui/avatar.tsx +107 -0
- package/template/ui/badge.tsx +48 -0
- package/template/ui/breadcrumb.tsx +109 -0
- package/template/ui/bubble.tsx +125 -0
- package/template/ui/button-group.tsx +83 -0
- package/template/ui/button.tsx +64 -0
- package/template/ui/calendar.tsx +218 -0
- package/template/ui/card.tsx +92 -0
- package/template/ui/carousel.tsx +241 -0
- package/template/ui/chart.tsx +374 -0
- package/template/ui/checkbox.tsx +32 -0
- package/template/ui/collapsible.tsx +31 -0
- package/template/ui/combobox.tsx +308 -0
- package/template/ui/command.tsx +182 -0
- package/template/ui/context-menu.tsx +252 -0
- package/template/ui/dialog.tsx +156 -0
- package/template/ui/direction.tsx +22 -0
- package/template/ui/drawer.tsx +133 -0
- package/template/ui/dropdown-menu.tsx +257 -0
- package/template/ui/empty.tsx +104 -0
- package/template/ui/field.tsx +246 -0
- package/template/ui/form.tsx +167 -0
- package/template/ui/hover-card.tsx +42 -0
- package/template/ui/input-group.tsx +170 -0
- package/template/ui/input-otp.tsx +77 -0
- package/template/ui/input.tsx +21 -0
- package/template/ui/item.tsx +193 -0
- package/template/ui/kbd.tsx +28 -0
- package/template/ui/label.tsx +22 -0
- package/template/ui/marker.tsx +69 -0
- package/template/ui/menubar.tsx +276 -0
- package/template/ui/message-scroller.tsx +128 -0
- package/template/ui/message.tsx +92 -0
- package/template/ui/native-select.tsx +62 -0
- package/template/ui/navigation-menu.tsx +168 -0
- package/template/ui/pagination.tsx +127 -0
- package/template/ui/popover.tsx +87 -0
- package/template/ui/progress.tsx +31 -0
- package/template/ui/radio-group.tsx +43 -0
- package/template/ui/resizable.tsx +53 -0
- package/template/ui/scroll-area.tsx +56 -0
- package/template/ui/select.tsx +190 -0
- package/template/ui/separator.tsx +26 -0
- package/template/ui/sheet.tsx +143 -0
- package/template/ui/sidebar.tsx +726 -0
- package/template/ui/skeleton.tsx +13 -0
- package/template/ui/slider.tsx +61 -0
- package/template/ui/sonner.tsx +40 -0
- package/template/ui/spinner.tsx +16 -0
- package/template/ui/switch.tsx +33 -0
- package/template/ui/table.tsx +116 -0
- package/template/ui/tabs.tsx +89 -0
- package/template/ui/textarea.tsx +18 -0
- package/template/ui/toggle-group.tsx +81 -0
- package/template/ui/toggle.tsx +47 -0
- 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
|
|
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
package/package.json
CHANGED
|
@@ -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 `<
|
|
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
|
|
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,
|
|
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.
|
|
17
|
-
- If the user picks "no theme", or `themes/` contains no theme markdown files:
|
|
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 —
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
6
|
+
# Create a theme
|
|
7
7
|
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
22
|
+
A theme can be derived from any combination of:
|
|
22
23
|
|
|
23
|
-
- **
|
|
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
|
|
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
|
-
- **
|
|
32
|
-
- **
|
|
33
|
-
- **
|
|
34
|
-
|
|
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 (
|
|
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>.
|
|
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
|
-
##
|
|
115
|
+
## Tokens
|
|
59
116
|
|
|
60
|
-
|
|
|
117
|
+
| Token | Light | Dark | Role in pages |
|
|
61
118
|
| --- | --- | --- | --- |
|
|
62
|
-
| background | `
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
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
|
-
-
|
|
72
|
-
- Type-scale overrides (only
|
|
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
|
-
-
|
|
82
|
-
-
|
|
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
|
-
|
|
140
|
+
## Components in this theme
|
|
129
141
|
|
|
130
|
-
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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`,
|
|
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'
|
|
189
|
-
- **One default-exported component** — a single scrolling page that exercises the
|
|
190
|
-
-
|
|
191
|
-
-
|
|
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
|
|
180
|
+
## Step 7 — Self-review
|
|
195
181
|
|
|
196
|
-
- [ ]
|
|
197
|
-
- [ ]
|
|
198
|
-
- [ ]
|
|
199
|
-
- [ ]
|
|
200
|
-
- [ ]
|
|
201
|
-
- [ ]
|
|
202
|
-
- [ ]
|
|
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
|
|
190
|
+
## Step 8 — Hand off
|
|
206
191
|
|
|
207
192
|
Tell the user:
|
|
208
193
|
|
|
209
|
-
- The theme id and the
|
|
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
|
-
-
|
|
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
|
-
- ❌
|
|
218
|
-
- ❌
|
|
219
|
-
- ❌
|
|
220
|
-
- ❌
|
|
221
|
-
- ❌
|
|
222
|
-
- ❌
|
|
223
|
-
- ❌
|
|
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.
|