@starcier/create-builder 0.0.0-stage → 1.0.0-next.1
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/LICENSE +21 -0
- package/README.md +62 -2
- package/dist/api.js +44 -0
- package/dist/args.js +79 -0
- package/dist/auth.js +68 -0
- package/dist/cli.js +23 -0
- package/dist/defaults.js +15 -0
- package/dist/errors.js +10 -0
- package/dist/main.js +162 -0
- package/dist/prompt.js +23 -0
- package/dist/slug.js +20 -0
- package/dist/template.js +61 -0
- package/package.json +34 -4
- package/template/.claude/skills/design-system/SKILL.md +177 -0
- package/template/.claude/skills/design-system-audit/SKILL.md +125 -0
- package/template/.claude/skills/design-work-review/SKILL.md +93 -0
- package/template/.claude/skills/process-interviewer/SKILL.md +124 -0
- package/template/.claude/skills/process-interviewer/references/plan-output-template.md +53 -0
- package/template/.claude/skills/process-interviewer/references/skill-output-template.md +72 -0
- package/template/.claude/skills/prototype-page-builder/SKILL.md +76 -0
- package/template/.cursor/rules/code-review.mdc +30 -0
- package/template/.cursor/rules/prototype-authoring.mdc +31 -0
- package/template/.cursor/rules/tokens.mdc +36 -0
- package/template/.cursor/rules/ui-system.mdc +39 -0
- package/template/.env.example +19 -0
- package/template/AGENTS.md +77 -0
- package/template/CLAUDE.md +19 -0
- package/template/README.md +65 -0
- package/template/_gitignore +15 -0
- package/template/docs/design-system-log.md +17 -0
- package/template/eslint.config.js +23 -0
- package/template/index.html +13 -0
- package/template/package.json +35 -0
- package/template/public/favicon.svg +1 -0
- package/template/src/App.tsx +65 -0
- package/template/src/app.css +5 -0
- package/template/src/brand.ts +2 -0
- package/template/src/config.ts +15 -0
- package/template/src/design-system/ThemeProvider.tsx +25 -0
- package/template/src/design-system/components/Button/Button.tsx +15 -0
- package/template/src/design-system/components/Button/button.css +62 -0
- package/template/src/design-system/components/Button/index.ts +1 -0
- package/template/src/design-system/components/Card/Card.tsx +22 -0
- package/template/src/design-system/components/Card/card.css +27 -0
- package/template/src/design-system/components/Card/index.ts +1 -0
- package/template/src/design-system/components/Field/Field.tsx +28 -0
- package/template/src/design-system/components/Field/field.css +37 -0
- package/template/src/design-system/components/Field/index.ts +1 -0
- package/template/src/design-system/components/Modal/Modal.tsx +55 -0
- package/template/src/design-system/components/Modal/index.ts +1 -0
- package/template/src/design-system/components/Modal/modal.css +39 -0
- package/template/src/design-system/components/ThemeToggle/ThemeToggle.tsx +13 -0
- package/template/src/design-system/components/ThemeToggle/index.ts +1 -0
- package/template/src/design-system/global.css +26 -0
- package/template/src/design-system/palette.ts +40 -0
- package/template/src/design-system/theme.ts +55 -0
- package/template/src/design-system/tokens.ts +126 -0
- package/template/src/main.tsx +13 -0
- package/template/src/prototypes/getting-started/welcome/README.md +6 -0
- package/template/src/prototypes/getting-started/welcome/Welcome.tsx +74 -0
- package/template/src/prototypes/getting-started/welcome/data.ts +14 -0
- package/template/src/prototypes/getting-started/welcome/index.ts +2 -0
- package/template/src/prototypes/getting-started/welcome/welcome.css +71 -0
- package/template/src/prototypes/getting-started/welcome/workflows.ts +51 -0
- package/template/src/prototypes/registry.ts +20 -0
- package/template/src/prototypes/workflows.ts +9 -0
- package/template/tsconfig.app.json +28 -0
- package/template/tsconfig.json +7 -0
- package/template/tsconfig.node.json +26 -0
- package/template/vercel.json +4 -0
- package/template/vite.config.ts +12 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prototype-page-builder
|
|
3
|
+
description: Create a new prototype page in this builder, composed only from the existing design tokens and design-system components, with local mock data, data-tour anchors and a guided tour — no APIs, auth or backend. Prototypes live in folders under src/prototypes/. Use when asked to "build/create a prototype/mockup", "add a prototype for <area>", or "prototype <screen>".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Prototype Page Builder
|
|
7
|
+
|
|
8
|
+
You are creating a new **prototype** in this Prototype Builder — a Vite + React 19 + TypeScript
|
|
9
|
+
app whose prototypes compose the design system with mock data and never touch a backend. The
|
|
10
|
+
builder adds review comments, guided tours and sharing around them. Follow this procedure exactly.
|
|
11
|
+
|
|
12
|
+
## Golden rules
|
|
13
|
+
|
|
14
|
+
- **Compose the existing design system. Never invent one.** Use the components in
|
|
15
|
+
`src/design-system/components/` and the tokens in `src/design-system/tokens.ts` (in CSS, through
|
|
16
|
+
the `--color-*`, `--space-*`, `--radius-*` and `--text-*` custom properties).
|
|
17
|
+
- **No raw values.** No hex / `rgba` / named colors, no raw px design values, no one-off font
|
|
18
|
+
sizes, no bespoke primitives.
|
|
19
|
+
- **No backend.** No API client, query hook, service, auth or `fetch`. All data is local mock data
|
|
20
|
+
in the prototype's own folder.
|
|
21
|
+
- **Don't recreate app chrome.** The top bar, theme toggle and the review and tour controls come
|
|
22
|
+
from the builder shell, configured in `src/App.tsx`.
|
|
23
|
+
- **This is not Next.js.** No `page.tsx`, no App Router, no `'use client'`. Imports are relative.
|
|
24
|
+
- **Only create a new component if none fits** — generic ones go in
|
|
25
|
+
`src/design-system/components/`, token-only, and are flagged for review.
|
|
26
|
+
|
|
27
|
+
## Folders
|
|
28
|
+
|
|
29
|
+
Prototypes are grouped one level deep, e.g. `getting-started/welcome`, and open at
|
|
30
|
+
`/prototypes/<folder>/<id>`. The reference to mirror is `src/prototypes/getting-started/welcome/`.
|
|
31
|
+
|
|
32
|
+
## Procedure
|
|
33
|
+
|
|
34
|
+
1. **Read `AGENTS.md`** and the `design-system` skill.
|
|
35
|
+
2. **Decide the folder.** If none was named, ASK: an existing folder (see `registry.ts`), a new
|
|
36
|
+
one (ask for its name), or none. Derive `folder` (kebab-case) and `folderLabel` (Title Case).
|
|
37
|
+
3. **Read the components** in `src/design-system/components/` you will compose.
|
|
38
|
+
4. **Inspect the reference prototype** and match its shape.
|
|
39
|
+
5. **Create `src/prototypes/<folder>/<id>/`** (`<id>` in kebab-case) with:
|
|
40
|
+
- `<PascalName>.tsx` — the page, composed from components and tokens;
|
|
41
|
+
- `<name>.css` — its layout, using the custom properties only;
|
|
42
|
+
- `data.ts` — all its mock data, static and typed;
|
|
43
|
+
- `workflows.ts` — at least one `OnboardingWorkflow` (type from `@starcier/collab-core`) with
|
|
44
|
+
`prototypeId` = `"<folder>/<id>"`, steps targeting `data-tour` selectors;
|
|
45
|
+
- `README.md` — what it shows and which tours it ships;
|
|
46
|
+
- `index.ts` — exports the page and its tours.
|
|
47
|
+
6. **Add `data-tour` attributes** to the key regions: header, filters, lists, primary actions.
|
|
48
|
+
7. **Register it:** an entry in `src/prototypes/registry.ts` (`slug`, `title`, `description`,
|
|
49
|
+
`folder`, `folderLabel`, `status`, `component`), and its tour in `src/prototypes/workflows.ts`.
|
|
50
|
+
8. **Check it in both themes.**
|
|
51
|
+
9. **Run the quality gate:** `npm run build` and `npm run lint`. Fix everything you introduced.
|
|
52
|
+
10. **Summarise for review:** what it shows, its folder, the components and tokens used, where its
|
|
53
|
+
mock data lives, its tours, and any new component (with the reason).
|
|
54
|
+
|
|
55
|
+
## Tour step options
|
|
56
|
+
|
|
57
|
+
A `TourStep` targets a selector (prefer `[data-tour="…"]`) with a `title`, a `description` and an
|
|
58
|
+
optional `placement`. Two power options:
|
|
59
|
+
|
|
60
|
+
- **`initiateAction: true`** — pressing Next clicks the step's target, so the dialog or drawer it
|
|
61
|
+
opens is present for the next step, which should target something inside it.
|
|
62
|
+
- **`populateInputs: true`** — fills every input inside the target with test data, e.g. to enable
|
|
63
|
+
a disabled submit button. Point the target at the form.
|
|
64
|
+
|
|
65
|
+
Review comments cannot be placed inside dialogs; tours can step into them.
|
|
66
|
+
|
|
67
|
+
## Self-check
|
|
68
|
+
|
|
69
|
+
- [ ] Lives in `src/prototypes/<folder>/<id>/`, registered in `registry.ts` and `workflows.ts`,
|
|
70
|
+
visible in the catalogue.
|
|
71
|
+
- [ ] `slug` and `prototypeId` are both exactly `<folder>/<id>`.
|
|
72
|
+
- [ ] No raw colors, px or fonts; renders in light and dark.
|
|
73
|
+
- [ ] Only existing components and tokens (or a new component, flagged).
|
|
74
|
+
- [ ] All data local; no API, service, auth or `fetch`.
|
|
75
|
+
- [ ] `data-tour` on key regions; a working tour.
|
|
76
|
+
- [ ] `npm run build` and `npm run lint` pass.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How to code-review design work in this repo (a prototype, a design-system component, or tokens) — architecture, layering, reusability, design-system compliance, light and dark, quality gate. Use when asked to review a branch, a pull request, a change or a named component or prototype.
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design work code review
|
|
7
|
+
|
|
8
|
+
For a full review, use the `design-work-review` skill. This is the quick summary — cite
|
|
9
|
+
`file:line`, and review only unless asked to fix.
|
|
10
|
+
|
|
11
|
+
## Check, in order (PASS / FAIL / N/A each)
|
|
12
|
+
|
|
13
|
+
1. **Design-system compliance** — zero raw hex / `rgba` / named colours and zero raw px design
|
|
14
|
+
values; tokens through the CSS custom properties or `tokens.ts`. Renders in light AND dark.
|
|
15
|
+
(A raw hex or px is ≥ High.)
|
|
16
|
+
2. **Reuse, not duplication** — composes `src/design-system/components/`; no forked
|
|
17
|
+
near-duplicate. A new generic component lives in the design system and is flagged.
|
|
18
|
+
(A duplicated component is ≥ High.)
|
|
19
|
+
3. **No backend** — no `fetch` / network / service / auth / query imports in prototypes; data is
|
|
20
|
+
local mock. (A backend import is ≥ High.)
|
|
21
|
+
4. **Prototype features** (if applicable) — `data-tour` on key regions; a working tour
|
|
22
|
+
(`prototypeId` = `<folder>/<id>`, steps target real selectors); registered in `registry.ts`
|
|
23
|
+
and `workflows.ts`.
|
|
24
|
+
5. **Quality gate** — `npm run build` and `npm run lint` pass; no `console.log` or dead code.
|
|
25
|
+
|
|
26
|
+
## Report
|
|
27
|
+
|
|
28
|
+
Verdict (✅ Approve / 🔧 Approve with changes / ❌ Request changes), one PASS/FAIL line per
|
|
29
|
+
section, then ranked findings as `severity — file:line — problem — suggested fix`
|
|
30
|
+
(Blocker / High / Medium / Low), plus the actual build and lint results.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Rules for authoring prototypes under src/prototypes/ — no backend, local mock data, data-tour anchors, workflows, registration. Read when creating or editing a prototype.
|
|
3
|
+
globs: src/prototypes/**
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Prototype authoring rules
|
|
8
|
+
|
|
9
|
+
Full procedure: the `prototype-page-builder` skill. Reference implementation to mirror:
|
|
10
|
+
`src/prototypes/getting-started/welcome/`.
|
|
11
|
+
|
|
12
|
+
## Non-negotiables
|
|
13
|
+
|
|
14
|
+
- **No backend.** No `fetch` / network / API client / service / auth / query hook. All data is
|
|
15
|
+
**local mock data** in the prototype's own folder (`data.ts`).
|
|
16
|
+
- **This is Vite + react-router, NOT Next.js.** No `page.tsx`, no App Router, no
|
|
17
|
+
`'use client'`. Imports are relative — there is no `@/` alias.
|
|
18
|
+
- **Follow the design-system rules** (see the `ui-system` rule): tokens only, reuse components,
|
|
19
|
+
renders in light + dark.
|
|
20
|
+
- **Folder shape** `src/prototypes/<folder>/<id>/`: `<PascalName>.tsx`, `data.ts`,
|
|
21
|
+
`workflows.ts` (`prototypeId` = `"<folder>/<id>"`), `README.md`, `index.ts`.
|
|
22
|
+
- **`data-tour` anchors** on the key regions (header, filters, lists, primary actions).
|
|
23
|
+
- **Register it:** add an entry to `src/prototypes/registry.ts` (`slug` = `"<folder>/<id>"`),
|
|
24
|
+
and its tour to `src/prototypes/workflows.ts`.
|
|
25
|
+
- **Never rename the slug of a prototype that has comments** — the slug is its key in the API.
|
|
26
|
+
- **Don't recreate app chrome** (top bar, theme toggle, review and tour controls) — the builder
|
|
27
|
+
shell provides it.
|
|
28
|
+
|
|
29
|
+
## Before finishing
|
|
30
|
+
|
|
31
|
+
Run `npm run build` and `npm run lint`; fix everything you introduced.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How the design tokens are structured and consumed. Read when editing src/design-system/tokens.ts, theme.ts, ThemeProvider.tsx or palette.ts, or wiring token values into components.
|
|
3
|
+
globs: src/design-system/**
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Design tokens
|
|
8
|
+
|
|
9
|
+
## The source
|
|
10
|
+
|
|
11
|
+
`src/design-system/tokens.ts` holds every design value:
|
|
12
|
+
|
|
13
|
+
- **`colors`** — a `light` and a `dark` set. They MUST stay key-for-key identical (the
|
|
14
|
+
`ColorTokens` type enforces it), so every colour has a value in both themes.
|
|
15
|
+
- **`space`**, **`radius`** — the scales.
|
|
16
|
+
- **`typography`** — text styles by role (`heading`, `title`, `body`, `label`, `caption`,
|
|
17
|
+
`overline`, `mono`).
|
|
18
|
+
- **`zIndex`** — overlays sit between the builder's top bar (200) and its comments and tours
|
|
19
|
+
(9140).
|
|
20
|
+
|
|
21
|
+
## Consuming tokens (never bypass this)
|
|
22
|
+
|
|
23
|
+
- **In CSS:** `ThemeProvider` (`ThemeProvider.tsx`) sets each token as a custom property on the
|
|
24
|
+
document, switching with the theme. Paths become names: `colors.bg.page` →
|
|
25
|
+
`--color-bg-page`, `space.m` → `--space-m`, `typography.body.fontSize` → `--text-body-size`.
|
|
26
|
+
- **In TypeScript:** import the token objects; for colours, read `colors[theme]` with the theme
|
|
27
|
+
from `useTheme()`.
|
|
28
|
+
- **Never hardcode a colour or px value** in a component or prototype.
|
|
29
|
+
|
|
30
|
+
## Changing tokens
|
|
31
|
+
|
|
32
|
+
1. Change or add the value in `tokens.ts` — in both colour sets, if it is a colour.
|
|
33
|
+
2. If the change affects the builder's chrome, update `palette.ts`, which maps tokens onto
|
|
34
|
+
`BuilderPalette`. Its slot names are a contract with the Starcier packages and do not change;
|
|
35
|
+
only the right-hand sides do.
|
|
36
|
+
3. Reference the token by name at call sites; never inline its value.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: UI quality non-negotiables for this design system — tokens only, reuse existing components, single home for reusables, light + dark. Read when building or editing any component or screen.
|
|
3
|
+
globs: src/**/*.tsx
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# UI system rules
|
|
8
|
+
|
|
9
|
+
`AGENTS.md` is the source of truth; this is the summary. For a new prototype use the
|
|
10
|
+
`prototype-page-builder` skill; for any design decision, the `design-system` skill.
|
|
11
|
+
|
|
12
|
+
## Non-negotiables
|
|
13
|
+
|
|
14
|
+
- **Compose the existing design system; never invent one.** Reuse the components in
|
|
15
|
+
`src/design-system/components/` (`Button`, `Card`, `Field`, `Modal`, `ThemeToggle`, and
|
|
16
|
+
whatever has been added since). Never fork a near-duplicate.
|
|
17
|
+
- **Tokens only — no raw values.** In CSS, use the custom properties `ThemeProvider` sets
|
|
18
|
+
(`var(--color-text-secondary)`, `var(--space-m)`, `var(--radius-s)`,
|
|
19
|
+
`var(--text-body-size)`). In TypeScript, import from `src/design-system/tokens.ts`. A raw hex /
|
|
20
|
+
`rgba` / named colour, or a raw px design value, is a failure.
|
|
21
|
+
- **Single home for reusables.** Every generic component lives in
|
|
22
|
+
`src/design-system/components/<Name>/` (`<Name>.tsx`, `<name>.css`, `index.ts`), never inside
|
|
23
|
+
a prototype.
|
|
24
|
+
- **Light AND dark.** Everything renders in both themes; colours from tokens make that automatic.
|
|
25
|
+
- **No raw interactive elements** where a component exists: `Button` (not `<button>`), `Field`
|
|
26
|
+
(not `<input>`), `Modal` (not a bespoke fixed-position panel).
|
|
27
|
+
- **New component only when nothing fits** — token-only, in the design system, and flagged in
|
|
28
|
+
the pull request.
|
|
29
|
+
|
|
30
|
+
## Example
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
// ❌ BAD — raw colour, raw px, raw button
|
|
34
|
+
<button style={{ background: "#4F46E5", padding: "8px 16px" }}>Save</button>
|
|
35
|
+
|
|
36
|
+
// ✅ GOOD — design-system component, styled by tokens
|
|
37
|
+
import { Button } from "../../design-system/components/Button";
|
|
38
|
+
<Button variant="primary" onClick={onSave}>Save</Button>
|
|
39
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# This builder's configuration. None of it is secret: every VITE_ value is
|
|
2
|
+
# compiled into the browser bundle. `npm create @starcier/builder` writes the
|
|
3
|
+
# real values into `.env`; this file documents them.
|
|
4
|
+
#
|
|
5
|
+
# Leave the API and Auth0 values empty to run offline: comments and tours are
|
|
6
|
+
# then kept in the browser, and nobody signs in.
|
|
7
|
+
|
|
8
|
+
# The Starcier API's origin, without /v1.
|
|
9
|
+
VITE_API_BASE_URL=
|
|
10
|
+
# This builder's tenant. Assigned when the builder was created; keep it set even
|
|
11
|
+
# offline, so this builder's local data stays apart from other builders'.
|
|
12
|
+
VITE_TENANT_SLUG=
|
|
13
|
+
# Auth0 sign-in: the tenant's domain, the single-page application's client id,
|
|
14
|
+
# and the API's audience.
|
|
15
|
+
VITE_AUTH0_DOMAIN=
|
|
16
|
+
VITE_AUTH0_CLIENT_ID=
|
|
17
|
+
VITE_AUTH0_AUDIENCE=
|
|
18
|
+
# The passwordless email connection invited reviewers sign in with. Defaults to "email".
|
|
19
|
+
# VITE_AUTH0_PASSWORDLESS_CONNECTION=email
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# AGENTS.md — Prototype Builder
|
|
2
|
+
|
|
3
|
+
Portable guidance for any coding agent (Cursor, Codex, Claude). Cursor also has file-scoped
|
|
4
|
+
rules in `.cursor/rules/`; this file is the always-on summary and the source of truth.
|
|
5
|
+
|
|
6
|
+
Skills (`SKILL.md`) are duplicated per tool because each discovers its own folder only: Cursor
|
|
7
|
+
reads `.cursor/skills/`, Claude Code reads `.claude/skills/`. Keep the two copies in sync.
|
|
8
|
+
Available skills: `design-system` (design principles for every component change),
|
|
9
|
+
`design-system-audit`, `prototype-page-builder`, `design-work-review`, `process-interviewer`.
|
|
10
|
+
|
|
11
|
+
## What this repo is
|
|
12
|
+
|
|
13
|
+
A **Vite + React 19 + TypeScript** app with two parts:
|
|
14
|
+
|
|
15
|
+
1. **The design system** (`src/design-system/`) — tokens and components.
|
|
16
|
+
2. **The prototypes** (`src/prototypes/`) — screens composed from the design system, with mock
|
|
17
|
+
data, shown in a builder that adds review comments, guided tours and sharing.
|
|
18
|
+
|
|
19
|
+
The builder itself — routing, catalogue, sign-in, comments, tours — comes from the
|
|
20
|
+
`@starcier/builder-shell`, `@starcier/collab-ui` and `@starcier/collab-core` packages, configured
|
|
21
|
+
in `src/App.tsx`. **Never copy or reimplement what those packages do.**
|
|
22
|
+
|
|
23
|
+
Styling is plain CSS driven by design tokens. Not Next.js, not Tailwind, no CSS-in-JS runtime.
|
|
24
|
+
|
|
25
|
+
## Commands
|
|
26
|
+
|
|
27
|
+
- `npm run dev` — the builder at http://localhost:5173 (the port is fixed; see `vite.config.ts`)
|
|
28
|
+
- `npm run build` — `tsc -b && vite build`
|
|
29
|
+
- `npm run lint` — ESLint
|
|
30
|
+
|
|
31
|
+
## Design system
|
|
32
|
+
|
|
33
|
+
- **Tokens** live in `src/design-system/tokens.ts`: `colors` (a `light` and a `dark` set with
|
|
34
|
+
identical keys), `space`, `radius`, `typography`, `zIndex`. `ThemeProvider`
|
|
35
|
+
(`src/design-system/ThemeProvider.tsx`, with `useTheme` in `theme.ts`) exposes every token
|
|
36
|
+
as a CSS custom property:
|
|
37
|
+
`colors.bg.page` → `--color-bg-page`, `space.m` → `--space-m`, `typography.body` →
|
|
38
|
+
`--text-body-size` / `-weight` / `-line` / `-tracking` / `-case`.
|
|
39
|
+
- **Components** live in `src/design-system/components/<Name>/` as `<Name>.tsx`, `<name>.css`
|
|
40
|
+
and `index.ts`. Class names are prefixed `ds-`.
|
|
41
|
+
- **`src/design-system/palette.ts`** maps the tokens onto `BuilderPalette`, which colours the
|
|
42
|
+
builder's chrome. When a token is renamed or added, update it there too.
|
|
43
|
+
|
|
44
|
+
## Non-negotiables (UI)
|
|
45
|
+
|
|
46
|
+
- **Compose the existing design system; never invent a parallel one.** Reuse
|
|
47
|
+
`src/design-system/components/`. Never fork a near-duplicate.
|
|
48
|
+
- **Tokens only — no raw values.** Colours, spacing, radii and text styles come from the tokens,
|
|
49
|
+
in CSS through the custom properties. No raw hex / `rgba` / named colours and no raw px design
|
|
50
|
+
values in components or prototypes.
|
|
51
|
+
- **Light AND dark.** Everything must render in both themes; that is why colours come from tokens.
|
|
52
|
+
- **Single home for reusables.** A generic component belongs in `src/design-system/components/`,
|
|
53
|
+
never inside a prototype folder.
|
|
54
|
+
- **No raw interactive elements** where a component exists: `Button` not `<button>`, `Field` not
|
|
55
|
+
`<input>`, `Modal` not a bespoke fixed panel.
|
|
56
|
+
- **Overlays stack between 200 and 9140.** The builder's top bar is at 200 and its comments and
|
|
57
|
+
tours start at 9140. Use `zIndex` from the tokens.
|
|
58
|
+
- **Overlay roots and field wrappers are declared in `src/App.tsx`** (`COLLAB`). A new overlay
|
|
59
|
+
or field component whose root class changes must be added there, or recorded tours and review
|
|
60
|
+
mode will not recognise it.
|
|
61
|
+
|
|
62
|
+
## Non-negotiables (prototypes — `src/prototypes/`)
|
|
63
|
+
|
|
64
|
+
- **No backend.** No `fetch`, API client, service, auth or query hook. All data is local mock
|
|
65
|
+
data in the prototype's own folder.
|
|
66
|
+
- **Folder** `src/prototypes/<folder>/<id>/`: `<PascalName>.tsx`, `data.ts`, `workflows.ts`,
|
|
67
|
+
`README.md`, `index.ts`. Mirror `src/prototypes/getting-started/welcome/`.
|
|
68
|
+
- **`data-tour` anchors** on the key regions, so tours can target stable selectors.
|
|
69
|
+
- **Register it** in `src/prototypes/registry.ts` (`slug` = `"<folder>/<id>"`), and its tour in
|
|
70
|
+
`src/prototypes/workflows.ts` (`prototypeId` = the same slug).
|
|
71
|
+
- **Never rename a slug that has comments**: the slug is the prototype's key in the API.
|
|
72
|
+
- **Don't recreate app chrome** (top bar, theme toggle, review and tour controls): the builder
|
|
73
|
+
shell provides it.
|
|
74
|
+
|
|
75
|
+
## Before you finish
|
|
76
|
+
|
|
77
|
+
Run `npm run build` and `npm run lint`; fix everything you introduced.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
Guidance for Claude Code in this repo. The authoritative, tool-agnostic rules live in
|
|
4
|
+
`AGENTS.md` (shared with Codex and Cursor), imported below so there is a single source of truth.
|
|
5
|
+
|
|
6
|
+
@AGENTS.md
|
|
7
|
+
|
|
8
|
+
## Skills
|
|
9
|
+
|
|
10
|
+
Project skills live in `.claude/skills/` and are discovered by Claude Code:
|
|
11
|
+
|
|
12
|
+
- `design-system` — design principles applied to every component change.
|
|
13
|
+
- `design-system-audit` — a systematic audit of existing components against those principles.
|
|
14
|
+
- `prototype-page-builder` — how to author a new prototype.
|
|
15
|
+
- `design-work-review` — senior front-end review of a branch, a component or a prototype.
|
|
16
|
+
- `process-interviewer` — sharpens a fuzzy idea into a plan before building.
|
|
17
|
+
|
|
18
|
+
They are kept in sync with the Cursor copies in `.cursor/skills/`. If you change one, update the
|
|
19
|
+
other.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Example Client — Prototype Builder
|
|
2
|
+
|
|
3
|
+
A prototype builder: your design system, your prototypes, and Starcier's review comments,
|
|
4
|
+
guided tours and sharing on top. The collaboration features come from the `@starcier/*`
|
|
5
|
+
packages; this repository holds only what is yours.
|
|
6
|
+
|
|
7
|
+
## Run it
|
|
8
|
+
|
|
9
|
+
Node 20 or later.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install
|
|
13
|
+
npm run dev # http://localhost:5173
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`npm run build` type-checks and builds into `dist/`; `npm run lint` lints.
|
|
17
|
+
|
|
18
|
+
The builder signs you in and stores comments in the Starcier API. To work without either, empty
|
|
19
|
+
the API and Auth0 values in `.env`: comments and tours are then kept in your browser.
|
|
20
|
+
|
|
21
|
+
## What is where
|
|
22
|
+
|
|
23
|
+
| Path | What |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `src/design-system/tokens.ts` | Every colour, size and text style. Start here to make it yours. |
|
|
26
|
+
| `src/design-system/palette.ts` | Maps the tokens onto the builder's chrome. Update it with the tokens. |
|
|
27
|
+
| `src/design-system/components/` | Your components. |
|
|
28
|
+
| `src/prototypes/` | Your prototypes, listed in `registry.ts`, their tours in `workflows.ts`. |
|
|
29
|
+
| `src/App.tsx` | The builder itself; you rarely need to touch it. |
|
|
30
|
+
| `.env` | This builder's settings. Nothing in it is secret, so it is committed. |
|
|
31
|
+
| `AGENTS.md`, `.cursor/`, `.claude/` | Instructions and skills for coding agents. |
|
|
32
|
+
|
|
33
|
+
To add a prototype, copy `src/prototypes/getting-started/welcome/`, rename it, and add it to
|
|
34
|
+
`registry.ts` (and its tour to `workflows.ts`). Prototypes use mock data only, never a backend.
|
|
35
|
+
|
|
36
|
+
## Going live
|
|
37
|
+
|
|
38
|
+
Three things cannot be automated. Do them in this order.
|
|
39
|
+
|
|
40
|
+
1. **Deploy.** Any static host works. The build command is `npm run build`, the output folder is
|
|
41
|
+
`dist`, and every path must fall back to `index.html` (share and invite links are opened
|
|
42
|
+
directly). `vercel.json` does that on Vercel; elsewhere, configure the equivalent. Set no
|
|
43
|
+
environment variables: they come from `.env`.
|
|
44
|
+
2. **Tell Starcier the address** it is deployed at. They set it as this builder's base URL, which
|
|
45
|
+
does two things: the API starts accepting requests from it, and password links and email
|
|
46
|
+
invites start pointing at it. Until then, "Share with password" is disabled. Preview
|
|
47
|
+
deployments need their addresses registered too, or the API refuses them.
|
|
48
|
+
3. **Ask Starcier to allow the address for sign-in**, so Auth0 returns there after login. For local
|
|
49
|
+
development, `http://localhost:5173` must be allowed as well.
|
|
50
|
+
|
|
51
|
+
Who can sign in is decided in the Starcier API: your team members are added to this builder, and
|
|
52
|
+
outside reviewers are invited by email to the prototypes they should see.
|
|
53
|
+
|
|
54
|
+
## Updating
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm install @starcier/collab-core@next @starcier/collab-ui@next @starcier/builder-shell@next
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Until `1.0.0` is released the packages are prereleases and need `@next`. If a version is too old
|
|
61
|
+
for the API, comments and tours switch off and a message names the version you need and this
|
|
62
|
+
command; your prototypes keep working.
|
|
63
|
+
|
|
64
|
+
The review and tour controls keep their own colours rather than taking yours. That is deliberate:
|
|
65
|
+
they are a tool on top of your product, and look the same in every builder.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
node_modules
|
|
2
|
+
dist
|
|
3
|
+
*.tsbuildinfo
|
|
4
|
+
*.log
|
|
5
|
+
|
|
6
|
+
# .env holds this builder's public configuration and is committed: every VITE_
|
|
7
|
+
# value ends up in the browser bundle anyway. Anything private goes in a
|
|
8
|
+
# *.local file, which is never committed.
|
|
9
|
+
.env.local
|
|
10
|
+
.env.*.local
|
|
11
|
+
|
|
12
|
+
.DS_Store
|
|
13
|
+
.idea
|
|
14
|
+
.vscode/*
|
|
15
|
+
!.vscode/extensions.json
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Design system log
|
|
2
|
+
|
|
3
|
+
Kept by the `design-system-audit` skill: what was built, what each audit found, and the tech debt
|
|
4
|
+
deliberately deferred. Newest entries first.
|
|
5
|
+
|
|
6
|
+
## Changes
|
|
7
|
+
|
|
8
|
+
- Created from the Starcier builder template: tokens, `Button`, `Card`, `Field`, `Modal`,
|
|
9
|
+
`ThemeToggle`, and the Welcome example prototype.
|
|
10
|
+
|
|
11
|
+
## Audits
|
|
12
|
+
|
|
13
|
+
None yet.
|
|
14
|
+
|
|
15
|
+
## Tech debt
|
|
16
|
+
|
|
17
|
+
None yet.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import globals from 'globals';
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh';
|
|
5
|
+
import tseslint from 'typescript-eslint';
|
|
6
|
+
import { defineConfig, globalIgnores } from 'eslint/config';
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
globalIgnores(['dist']),
|
|
10
|
+
{
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
extends: [
|
|
13
|
+
js.configs.recommended,
|
|
14
|
+
tseslint.configs.recommended,
|
|
15
|
+
reactHooks.configs.flat.recommended,
|
|
16
|
+
reactRefresh.configs.vite,
|
|
17
|
+
],
|
|
18
|
+
languageOptions: {
|
|
19
|
+
ecmaVersion: 2022,
|
|
20
|
+
globals: globals.browser,
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Example Client Prototype Builder</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@starcier/builder-template",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc -b && vite build",
|
|
9
|
+
"lint": "eslint .",
|
|
10
|
+
"preview": "vite preview"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@auth0/auth0-react": "^2.22.1",
|
|
14
|
+
"@starcier/builder-shell": "^1.0.0-next.1",
|
|
15
|
+
"@starcier/collab-core": "^1.0.0-next.3",
|
|
16
|
+
"@starcier/collab-ui": "^1.0.0-next.1",
|
|
17
|
+
"react": "^19.2.0",
|
|
18
|
+
"react-dom": "^19.2.0",
|
|
19
|
+
"react-router": "^8.1.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@eslint/js": "^9.39.1",
|
|
23
|
+
"@types/node": "^24.10.1",
|
|
24
|
+
"@types/react": "^19.2.7",
|
|
25
|
+
"@types/react-dom": "^19.2.3",
|
|
26
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
27
|
+
"eslint": "^9.39.1",
|
|
28
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
29
|
+
"eslint-plugin-react-refresh": "^0.4.24",
|
|
30
|
+
"globals": "^16.5.0",
|
|
31
|
+
"typescript": "~5.9.3",
|
|
32
|
+
"typescript-eslint": "^8.48.0",
|
|
33
|
+
"vite": "^7.3.1"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="8" fill="#4F46E5"/><rect x="8" y="8" width="16" height="16" rx="3" fill="#FFFFFF"/></svg>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { BuilderShell, type BuilderAuthConfig } from '@starcier/builder-shell';
|
|
3
|
+
import { BUILDER_NAME } from './brand';
|
|
4
|
+
import {
|
|
5
|
+
API_BASE_URL,
|
|
6
|
+
AUTH0_AUDIENCE,
|
|
7
|
+
AUTH0_CLIENT_ID,
|
|
8
|
+
AUTH0_DOMAIN,
|
|
9
|
+
AUTH0_PASSWORDLESS_CONNECTION,
|
|
10
|
+
TENANT_SLUG,
|
|
11
|
+
} from './config';
|
|
12
|
+
import { ThemeToggle } from './design-system/components/ThemeToggle';
|
|
13
|
+
import { resolveBuilderPalette } from './design-system/palette';
|
|
14
|
+
import { useTheme } from './design-system/theme';
|
|
15
|
+
import { ThemeProvider } from './design-system/ThemeProvider';
|
|
16
|
+
import { prototypes } from './prototypes/registry';
|
|
17
|
+
import { workflows } from './prototypes/workflows';
|
|
18
|
+
import './app.css';
|
|
19
|
+
|
|
20
|
+
/** Sign-in, when Auth0 is configured; without it the builder runs offline. */
|
|
21
|
+
const AUTH: BuilderAuthConfig | null =
|
|
22
|
+
AUTH0_DOMAIN && AUTH0_CLIENT_ID
|
|
23
|
+
? {
|
|
24
|
+
domain: AUTH0_DOMAIN,
|
|
25
|
+
clientId: AUTH0_CLIENT_ID,
|
|
26
|
+
audience: AUTH0_AUDIENCE,
|
|
27
|
+
passwordlessConnection: AUTH0_PASSWORDLESS_CONNECTION,
|
|
28
|
+
}
|
|
29
|
+
: null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* What the review layer needs to know about this design system: the roots of
|
|
33
|
+
* its overlays, and the wrappers around its form fields. Update these when the
|
|
34
|
+
* design system's class names change.
|
|
35
|
+
*/
|
|
36
|
+
const COLLAB = {
|
|
37
|
+
overlaySelectors: ['.ds-modal'],
|
|
38
|
+
fieldWrapperSelectors: ['.ds-field'],
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
function Builder() {
|
|
42
|
+
const { theme } = useTheme();
|
|
43
|
+
const palette = useMemo(() => resolveBuilderPalette(theme), [theme]);
|
|
44
|
+
return (
|
|
45
|
+
<BuilderShell
|
|
46
|
+
palette={palette}
|
|
47
|
+
prototypes={prototypes}
|
|
48
|
+
workflowSeeds={workflows}
|
|
49
|
+
apiBaseUrl={API_BASE_URL}
|
|
50
|
+
tenant={TENANT_SLUG}
|
|
51
|
+
auth={AUTH}
|
|
52
|
+
collab={COLLAB}
|
|
53
|
+
brand={<span className="app-brand">{BUILDER_NAME}</span>}
|
|
54
|
+
headerActions={<ThemeToggle />}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function App() {
|
|
60
|
+
return (
|
|
61
|
+
<ThemeProvider>
|
|
62
|
+
<Builder />
|
|
63
|
+
</ThemeProvider>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration from the VITE_* values in `.env`. All optional: without the API
|
|
3
|
+
* and Auth0 values the builder runs offline, keeping comments and tours in the
|
|
4
|
+
* browser, which is enough for design work.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const read = (value: string | undefined) => value?.trim() || undefined;
|
|
8
|
+
|
|
9
|
+
export const API_BASE_URL = read(import.meta.env.VITE_API_BASE_URL)?.replace(/\/+$/, '');
|
|
10
|
+
export const TENANT_SLUG = read(import.meta.env.VITE_TENANT_SLUG);
|
|
11
|
+
export const AUTH0_DOMAIN = read(import.meta.env.VITE_AUTH0_DOMAIN);
|
|
12
|
+
export const AUTH0_CLIENT_ID = read(import.meta.env.VITE_AUTH0_CLIENT_ID);
|
|
13
|
+
export const AUTH0_AUDIENCE = read(import.meta.env.VITE_AUTH0_AUDIENCE);
|
|
14
|
+
/** The passwordless email connection invited reviewers sign in with. */
|
|
15
|
+
export const AUTH0_PASSWORDLESS_CONNECTION = read(import.meta.env.VITE_AUTH0_PASSWORDLESS_CONNECTION) ?? 'email';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useCallback, useLayoutEffect, useMemo, useState, type ReactNode } from 'react';
|
|
2
|
+
import { cssVariables, initialTheme, THEME_STORAGE_KEY, ThemeContext } from './theme';
|
|
3
|
+
import type { ThemeName } from './tokens';
|
|
4
|
+
|
|
5
|
+
/** The active theme, applied to the document as CSS custom properties. */
|
|
6
|
+
export function ThemeProvider({ children }: { children: ReactNode }) {
|
|
7
|
+
const [theme, setTheme] = useState<ThemeName>(initialTheme);
|
|
8
|
+
|
|
9
|
+
useLayoutEffect(() => {
|
|
10
|
+
const root = document.documentElement;
|
|
11
|
+
root.dataset.theme = theme;
|
|
12
|
+
root.style.colorScheme = theme;
|
|
13
|
+
for (const [name, value] of Object.entries(cssVariables(theme))) root.style.setProperty(name, value);
|
|
14
|
+
try {
|
|
15
|
+
localStorage.setItem(THEME_STORAGE_KEY, theme);
|
|
16
|
+
} catch {
|
|
17
|
+
/* not remembered: harmless */
|
|
18
|
+
}
|
|
19
|
+
}, [theme]);
|
|
20
|
+
|
|
21
|
+
const toggle = useCallback(() => setTheme((current) => (current === 'light' ? 'dark' : 'light')), []);
|
|
22
|
+
const value = useMemo(() => ({ theme, toggle }), [theme, toggle]);
|
|
23
|
+
|
|
24
|
+
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ButtonHTMLAttributes } from 'react';
|
|
2
|
+
import './button.css';
|
|
3
|
+
|
|
4
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'ghost';
|
|
5
|
+
export type ButtonSize = 'small' | 'medium';
|
|
6
|
+
|
|
7
|
+
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
8
|
+
variant?: ButtonVariant;
|
|
9
|
+
size?: ButtonSize;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function Button({ variant = 'primary', size = 'medium', className, type = 'button', ...rest }: ButtonProps) {
|
|
13
|
+
const classes = ['ds-button', `ds-button--${variant}`, `ds-button--${size}`, className].filter(Boolean).join(' ');
|
|
14
|
+
return <button type={type} className={classes} {...rest} />;
|
|
15
|
+
}
|