@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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -2
  3. package/dist/api.js +44 -0
  4. package/dist/args.js +79 -0
  5. package/dist/auth.js +68 -0
  6. package/dist/cli.js +23 -0
  7. package/dist/defaults.js +15 -0
  8. package/dist/errors.js +10 -0
  9. package/dist/main.js +162 -0
  10. package/dist/prompt.js +23 -0
  11. package/dist/slug.js +20 -0
  12. package/dist/template.js +61 -0
  13. package/package.json +34 -4
  14. package/template/.claude/skills/design-system/SKILL.md +177 -0
  15. package/template/.claude/skills/design-system-audit/SKILL.md +125 -0
  16. package/template/.claude/skills/design-work-review/SKILL.md +93 -0
  17. package/template/.claude/skills/process-interviewer/SKILL.md +124 -0
  18. package/template/.claude/skills/process-interviewer/references/plan-output-template.md +53 -0
  19. package/template/.claude/skills/process-interviewer/references/skill-output-template.md +72 -0
  20. package/template/.claude/skills/prototype-page-builder/SKILL.md +76 -0
  21. package/template/.cursor/rules/code-review.mdc +30 -0
  22. package/template/.cursor/rules/prototype-authoring.mdc +31 -0
  23. package/template/.cursor/rules/tokens.mdc +36 -0
  24. package/template/.cursor/rules/ui-system.mdc +39 -0
  25. package/template/.env.example +19 -0
  26. package/template/AGENTS.md +77 -0
  27. package/template/CLAUDE.md +19 -0
  28. package/template/README.md +65 -0
  29. package/template/_gitignore +15 -0
  30. package/template/docs/design-system-log.md +17 -0
  31. package/template/eslint.config.js +23 -0
  32. package/template/index.html +13 -0
  33. package/template/package.json +35 -0
  34. package/template/public/favicon.svg +1 -0
  35. package/template/src/App.tsx +65 -0
  36. package/template/src/app.css +5 -0
  37. package/template/src/brand.ts +2 -0
  38. package/template/src/config.ts +15 -0
  39. package/template/src/design-system/ThemeProvider.tsx +25 -0
  40. package/template/src/design-system/components/Button/Button.tsx +15 -0
  41. package/template/src/design-system/components/Button/button.css +62 -0
  42. package/template/src/design-system/components/Button/index.ts +1 -0
  43. package/template/src/design-system/components/Card/Card.tsx +22 -0
  44. package/template/src/design-system/components/Card/card.css +27 -0
  45. package/template/src/design-system/components/Card/index.ts +1 -0
  46. package/template/src/design-system/components/Field/Field.tsx +28 -0
  47. package/template/src/design-system/components/Field/field.css +37 -0
  48. package/template/src/design-system/components/Field/index.ts +1 -0
  49. package/template/src/design-system/components/Modal/Modal.tsx +55 -0
  50. package/template/src/design-system/components/Modal/index.ts +1 -0
  51. package/template/src/design-system/components/Modal/modal.css +39 -0
  52. package/template/src/design-system/components/ThemeToggle/ThemeToggle.tsx +13 -0
  53. package/template/src/design-system/components/ThemeToggle/index.ts +1 -0
  54. package/template/src/design-system/global.css +26 -0
  55. package/template/src/design-system/palette.ts +40 -0
  56. package/template/src/design-system/theme.ts +55 -0
  57. package/template/src/design-system/tokens.ts +126 -0
  58. package/template/src/main.tsx +13 -0
  59. package/template/src/prototypes/getting-started/welcome/README.md +6 -0
  60. package/template/src/prototypes/getting-started/welcome/Welcome.tsx +74 -0
  61. package/template/src/prototypes/getting-started/welcome/data.ts +14 -0
  62. package/template/src/prototypes/getting-started/welcome/index.ts +2 -0
  63. package/template/src/prototypes/getting-started/welcome/welcome.css +71 -0
  64. package/template/src/prototypes/getting-started/welcome/workflows.ts +51 -0
  65. package/template/src/prototypes/registry.ts +20 -0
  66. package/template/src/prototypes/workflows.ts +9 -0
  67. package/template/tsconfig.app.json +28 -0
  68. package/template/tsconfig.json +7 -0
  69. package/template/tsconfig.node.json +26 -0
  70. package/template/vercel.json +4 -0
  71. 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,5 @@
1
+ .app-brand {
2
+ font-size: var(--text-title-size);
3
+ font-weight: var(--text-title-weight);
4
+ line-height: var(--text-title-line);
5
+ }
@@ -0,0 +1,2 @@
1
+ /** The client this builder belongs to, shown in the top bar. */
2
+ export const BUILDER_NAME = 'Example Client';
@@ -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
+ }