mapples 0.2.0-beta.5 → 0.2.0-beta.7

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 (84) hide show
  1. package/README.md +42 -0
  2. package/dist/api/agent.d.ts +84 -0
  3. package/dist/api/agent.js +92 -0
  4. package/dist/api/agent.js.map +1 -0
  5. package/dist/api/client.d.ts +3 -0
  6. package/dist/api/client.js +2 -0
  7. package/dist/api/client.js.map +1 -1
  8. package/dist/api/commit.js +1 -0
  9. package/dist/api/commit.js.map +1 -1
  10. package/dist/api/errors.js +4 -2
  11. package/dist/api/errors.js.map +1 -1
  12. package/dist/api/objects.d.ts +12 -0
  13. package/dist/api/objects.js +2 -0
  14. package/dist/api/objects.js.map +1 -1
  15. package/dist/commands/agent.d.ts +2 -0
  16. package/dist/commands/agent.js +76 -0
  17. package/dist/commands/agent.js.map +1 -0
  18. package/dist/commands/create.js +1 -0
  19. package/dist/commands/create.js.map +1 -1
  20. package/dist/commands/impl/adoptImpl.js +3 -0
  21. package/dist/commands/impl/adoptImpl.js.map +1 -1
  22. package/dist/commands/impl/agentImpl.d.ts +10 -0
  23. package/dist/commands/impl/agentImpl.js +349 -0
  24. package/dist/commands/impl/agentImpl.js.map +1 -0
  25. package/dist/commands/impl/createImpl.js +19 -0
  26. package/dist/commands/impl/createImpl.js.map +1 -1
  27. package/dist/commands/impl/initImpl.js +19 -0
  28. package/dist/commands/impl/initImpl.js.map +1 -1
  29. package/dist/commands/impl/syncImpl.js +9 -3
  30. package/dist/commands/impl/syncImpl.js.map +1 -1
  31. package/dist/commands/init.js +1 -0
  32. package/dist/commands/init.js.map +1 -1
  33. package/dist/index.js +12 -1
  34. package/dist/index.js.map +1 -1
  35. package/dist/project/agentState.d.ts +24 -0
  36. package/dist/project/agentState.js +42 -0
  37. package/dist/project/agentState.js.map +1 -0
  38. package/dist/project/secret.d.ts +6 -2
  39. package/dist/project/secret.js +11 -5
  40. package/dist/project/secret.js.map +1 -1
  41. package/dist/services/agentInstall.d.ts +35 -0
  42. package/dist/services/agentInstall.js +180 -0
  43. package/dist/services/agentInstall.js.map +1 -0
  44. package/dist/services/agentLease.d.ts +2 -0
  45. package/dist/services/agentLease.js +32 -0
  46. package/dist/services/agentLease.js.map +1 -0
  47. package/dist/services/clientFactory.d.ts +2 -0
  48. package/dist/services/clientFactory.js +16 -1
  49. package/dist/services/clientFactory.js.map +1 -1
  50. package/dist/services/scaffold.js +4 -0
  51. package/dist/services/scaffold.js.map +1 -1
  52. package/dist/services/syncEngine.js +51 -18
  53. package/dist/services/syncEngine.js.map +1 -1
  54. package/dist/style/theme.js +17 -1
  55. package/dist/style/theme.js.map +1 -1
  56. package/dist/types.d.ts +2 -0
  57. package/dist/types.js.map +1 -1
  58. package/package.json +3 -3
  59. package/templates/app.json +0 -1
  60. package/templates/claude/CLAUDE.md +7 -0
  61. package/templates/claude/mapples.md +118 -0
  62. package/templates/claude/mcp.json +11 -0
  63. package/templates/claude/skills/mapples-conventions/SKILL.md +136 -0
  64. package/templates/claude/skills/mapples-design/SKILL.md +218 -0
  65. package/templates/claude/skills/mapples-design/reference/component-library.md +128 -0
  66. package/templates/claude/skills/mapples-design/reference/design-tokens.md +132 -0
  67. package/templates/claude/skills/mapples-design/reference/layout-contract.md +227 -0
  68. package/templates/claude/skills/mapples-design/reference/lint-checklist.md +51 -0
  69. package/templates/claude/skills/mapples-design/reference/plan.md +95 -0
  70. package/templates/claude/skills/mapples-design/reference/playbooks/empty-states.md +14 -0
  71. package/templates/claude/skills/mapples-design/reference/playbooks/forms-and-auth.md +22 -0
  72. package/templates/claude/skills/mapples-design/reference/playbooks/home-dashboard.md +14 -0
  73. package/templates/claude/skills/mapples-design/reference/playbooks/list-and-detail.md +18 -0
  74. package/templates/claude/skills/mapples-design/reference/playbooks/microcopy.md +20 -0
  75. package/templates/claude/skills/mapples-design/reference/playbooks/navigation-chrome.md +21 -0
  76. package/templates/claude/skills/mapples-design/reference/playbooks/onboarding-flow.md +15 -0
  77. package/templates/claude/skills/mapples-design/reference/playbooks/screen-flow-wiring.md +37 -0
  78. package/templates/claude/skills/mapples-design/reference/playbooks/settings-profile.md +16 -0
  79. package/templates/claude/skills/mapples-design/reference/playbooks/stats-and-progress.md +17 -0
  80. package/templates/claude/skills/mapples-design/reference/playbooks/visual-hierarchy.md +18 -0
  81. package/templates/claude/skills/mapples-design/reference/style-guides.md +92 -0
  82. package/templates/claude/skills/mapples-sync/SKILL.md +93 -0
  83. package/templates/gitignore +2 -0
  84. package/templates/package.json +12 -10
@@ -0,0 +1,136 @@
1
+ ---
2
+ name: mapples-conventions
3
+ description: How Mapples-managed files are written — file layout, $sid rules, $actions/$data/$refs, the @mapples/ui vs @mapples/components import table, token strings and Styler dictionaries. Use whenever editing a route file, mapples/pages, mapples/components or mapples/theme.ts in a Mapples-linked Expo app.
4
+ ---
5
+ <!-- GENERATED by Mapples __CLI_VERSION__ — re-run npx -y mapples@__CLI_VERSION__ agent install --force to refresh -->
6
+ # Mapples conventions
7
+
8
+ Read `.claude/mapples.md` first (the summary). This skill is the reference.
9
+
10
+ ## File layout
11
+
12
+ | File | Role | Editable |
13
+ | --- | --- | --- |
14
+ | `__ROUTES_DIR__/<segment>.tsx`, `__ROUTES_DIR__/(group)/<segment>.tsx` | a screen that is in the navigation; `index.tsx` is the section's first screen | yes — merged with Creator |
15
+ | `__ROUTES_DIR__/**/_layout.tsx` | the navigator (Stack/Tabs/Drawer); regenerated from Creator's navigation on every sync | **no** (handshake only, below) |
16
+ | `__PAGES_DIR__/<Name>.tsx` | a screen not (yet) in the navigation; moves into the routes dir when placed | yes |
17
+ | `__COMPONENTS_DIR__/<Name>.tsx` | a reusable Creator component; instances are `import X from '…/<Name>'` + `<X styled />` | yes |
18
+ | `mapples/theme.ts` | design tokens (`theme`, `typography`, `sizing`) | yes — merged per key |
19
+ | `mapples/assets/`, `mapples/assetMap.ts` | Creator assets | **no** |
20
+ | `mapples/sid.d.ts` | types for the `$sid`/`$refs`/`$data`/`$actions`/`$fallback` attributes | no |
21
+ | `.mapples/` | config, secret, head, base, pages.json, components.json, outbox, agent.json | **no** |
22
+ | `_depr_<ts>_<name>.tsx.old` | your version of a file the CLI had to regenerate | read, never restore |
23
+
24
+ The route marker `// mapples-route: <id> — “<Name>”` on line 1 of a route file is the route's
25
+ identity: keep it verbatim. Renaming the file renames the route in Creator.
26
+
27
+ ## `$sid`
28
+
29
+ - `$sid="nd_…"` is the canvas node id. Opaque: never parse beyond the prefix, never invent,
30
+ never renumber, never copy to another element, never reuse a deleted one.
31
+ - New elements carry **no** `$sid`. `npx -y mapples@__CLI_VERSION__ sync` tags them (report: `tagged N new element(s)`)
32
+ and rewrites the file with the ids — re-read the file after a sync before editing again.
33
+ - Wrapping an existing element (moving it inside a new `View`) keeps its `$sid`; the sync sees a
34
+ move. Removing an element with a `$sid` deletes it in Creator.
35
+ - `$fallback={{ w, h }}` sits on `Custom` nodes (a non-Mapples component the canvas cannot
36
+ render); leave it as the CLI wrote it.
37
+
38
+ ## Transient attributes
39
+
40
+ | Attribute | Shape | Meaning |
41
+ | --- | --- | --- |
42
+ | `$actions` | `{ onPress: { type: 'mapples:navigate', staticData: { pageUuid: '<uuid>' } } }` | Creator prototype connection on that event. Other action types (`mapples:setState`, `mapples:goBack`, `mapples:switchTab`) exist; navigate is the one you write. |
43
+ | `$data` | `{ visible: { key: 'vars.sheetOpen', active: true } }` | a data binding of a prop to a project variable — only when the project already has the variable |
44
+ | `$refs` | `{ source: 'ref(image:<uuid>)' }` | a Creator asset reference — Creator-side; never invent one |
45
+
46
+ `pageUuid` lookup: `.mapples/pages.json` maps `pageId → { file, name, route, routeId }`; the
47
+ uuid the action needs is the `uuid` field of `.mapples/base/pages/<pageId>.json`. Both are
48
+ rewritten by every sync — read them fresh.
49
+
50
+ ## Imports
51
+
52
+ `@mapples/ui` — primitives (the canvas' base element types):
53
+
54
+ `View`, `Container`, `SafeAreaView`, `ScrollView`, `HorizontalScrollView`, `FlatList`,
55
+ `GridTwoColumns`, `GridThreeColumns`, `GridFourColumns`, `GradientBackground`,
56
+ `ImageBackgroundView`, `Typography`, `Text` (never on a screen — use Typography), `Image`,
57
+ `Icon`, `Svg`, `Vector`, `Video`, `QRCode`, `BarCode`, `Pressable`, `IconButton`, `TextInput`,
58
+ `Select`, `FormView`, `TextField`, `SubmitButton`.
59
+
60
+ `@mapples/components` — the themed library (paints itself from the tokens; prefer it):
61
+
62
+ | Group | Types |
63
+ | --- | --- |
64
+ | actions | `Button`, `ButtonGroup`, `Fab`, `TextLink`, `BottomActionBar` |
65
+ | input | `InputField`, `SelectField`, `Checkbox`, `RadioGroup`, `Switch`, `Slider`, `NumberStepper`, `PinInput`, `SearchBar`, `ChatComposer`, `SegmentedControl`, `Rating`, `ChipGroup`, `Chip` |
66
+ | content | `Card`, `MediaCard`, `List`, `ListItem`, `SectionHeader`, `Divider`, `Avatar`, `AvatarGroup`, `Badge`, `StatTile`, `Table`, `Timeline`, `ImageCarousel`, `MessageBubble`, `Accordion`, `Skeleton` |
67
+ | navigation | `TopAppBar`, `BottomNavigationBar`, `Tabs`, `Breadcrumbs`, `Steps`, `PageControl` |
68
+ | feedback | `ProgressBar`, `ProgressCircle`, `Spinner`, `Banner`, `Snackbar`, `EmptyState` |
69
+ | overlays | `Dialog`, `BottomSheet`, `ActionSheet` |
70
+
71
+ Anything else you import (a third-party or hand-written component) becomes an opaque `Custom`
72
+ node on the canvas with a `$fallback` size — allowed, but Creator cannot design inside it.
73
+
74
+ `Styler` comes from `@mapples/style`; `router` from `expo-router`.
75
+
76
+ ## Styling
77
+
78
+ ```tsx
79
+ <View styled={{ style: styles.row }}>
80
+ <Icon iconName="checkmark-circle" styled={{ styleSvg: styles.icon }} />
81
+ <Typography text="Done" variant="Label" styled={{ styleTypography: styles.done }} />
82
+ </View>
83
+
84
+ const styles = Styler.create({
85
+ row: { flexDirection: 'row', alignItems: 'center', gap: 'sizing.sm' },
86
+ icon: { width: 20, height: 20, color: 'theme.system.success' },
87
+ done: { color: 'theme.text.secondary' },
88
+ });
89
+ ```
90
+
91
+ - `styled={{ style }}` is the element's own box; `styleTypography` the text of a control
92
+ (Button label, ListItem title); `styleSvg` an Icon's glyph (`color`, `width`, `height`);
93
+ `styleImage` the picture inside an Image; `contentContainerStyle` the scrolling content of a
94
+ ScrollView/FlatList/HorizontalScrollView; `placeholderTextColor` a TextInput's placeholder.
95
+ - One `Styler.create` dictionary per file, below the component; keys say what the element shows
96
+ and is (`signInText`, `heroImage`, `listContent`). A `StyleSheet.create` dictionary is also
97
+ read, but write `Styler.create`.
98
+ - A style may be a single dictionary reference (`styles.card`) or a literal; never an array,
99
+ never a computed expression (Creator cannot read it → `NON_LITERAL_PROP`).
100
+ - Token strings: colors `'theme.<group>.<key>'` (`theme.primary.main`, `theme.primary.contrast`,
101
+ `theme.background.primary`, `theme.background.card`, `theme.text.primary|secondary|tertiary`,
102
+ `theme.neutral.n200`, `theme.system.error`); spacing `'sizing.<key>'` (`xs sm md lg xl
103
+ screenPadding gap radius radiusLarge control card icon`) or `'*N'` (N × base). Gradients take
104
+ literal hex/rgba only.
105
+ - `boxShadow` is an object `{ x, y, radius, color }`, never a CSS string.
106
+ - Library components set their own defaults; change their look through `variant`, `size`,
107
+ `tone` props and the slots — never rebuild one from Views.
108
+
109
+ ## Layouts (`_layout.tsx`)
110
+
111
+ The CLI generates every layout from Creator's navigation document. Do not edit or style them
112
+ (header/tab-bar options are set in Creator). To add a **new** section, create the directory
113
+ with a layout whose first line is `// GENERATED by Mapples`:
114
+
115
+ ```tsx
116
+ // GENERATED by Mapples — this layout is owned by the CLI and regenerated from the navigation document.
117
+ import { Tabs } from 'expo-router';
118
+
119
+ export default function MainLayout() {
120
+ return <Tabs />;
121
+ }
122
+ ```
123
+
124
+ `npx -y mapples@__CLI_VERSION__ sync --yes` then adopts the directory as a tabs navigator (`<Stack>` → stack,
125
+ `<Drawer>` from `expo-router/drawer` → drawer; no layout → stack) and regenerates the file. A
126
+ layout **without** the header is treated as yours and deprecated on the first sync.
127
+
128
+ ## What not to do
129
+
130
+ - Do not run `npx -y mapples@__CLI_VERSION__ init`, `npx -y mapples@__CLI_VERSION__ create`, or edit `.mapples/config.json`.
131
+ - Do not restore a `_depr_` file over the regenerated one.
132
+ - Do not hand-write `$sid`s, `$refs`, or navigator options.
133
+ - Do not put JSX children text inside `Typography` (`text` prop only), and do not use `Text`.
134
+ - Do not spread props or map arrays into JSX inside a managed element tree — Creator reads
135
+ literal trees; put dynamic lists behind a `FlatList`/`List` with literal `items` where
136
+ possible, or accept the `NON_LITERAL_PROP` note.
@@ -0,0 +1,218 @@
1
+ ---
2
+ name: mapples-design
3
+ description: Build a Mapples-linked Expo app from a product brief the way the Creator's in-app AI does — design tokens, an implementation plan, one screen per phase from the design playbooks, wiring and a review — writing route files and mapples/theme.ts and pushing each phase with `npx -y mapples@__CLI_VERSION__ sync` while holding the project's agent lease. Use when the user asks to design, generate or build the app, its screens or its design system.
4
+ argument-hint: "<product brief> [--scope single|minimal|basic|advanced]"
5
+ ---
6
+ <!-- GENERATED by Mapples __CLI_VERSION__ — re-run npx -y mapples@__CLI_VERSION__ agent install --force to refresh -->
7
+ # /mapples-design — build the app from a brief
8
+
9
+ You are the product designer and builder for this app. Your bar is a finished screen a
10
+ designer would ship — not a wireframe. Everything you make is a file in this repo; every phase
11
+ ends with `npx -y mapples@__CLI_VERSION__ sync --yes --json`, which pushes it to Creator where the user watches it land.
12
+
13
+ Read `.claude/mapples.md` and the `mapples-conventions` and `mapples-sync` skills before the
14
+ first file. Reference material for this skill lives next to it:
15
+
16
+ - `reference/style-guides.md` — art directions and style guides (phase 1)
17
+ - `reference/design-tokens.md` — the `mapples/theme.ts` contract and template (phase 2)
18
+ - `reference/plan.md` — scopes and the implementation plan (phase 3)
19
+ - `reference/layout-contract.md` — the rules every screen obeys (phases 5…)
20
+ - `reference/component-library.md` — what to reach for, by need
21
+ - `reference/lint-checklist.md` — the review pass (phase N)
22
+ - `reference/playbooks/<name>.md` — screen-kind playbooks, loaded per screen
23
+
24
+ ## Preconditions
25
+
26
+ 1. `.mapples/config.json` must exist (the app is linked). If not: stop and ask the user to run
27
+ `npx -y mapples@__CLI_VERSION__ init --secret <key> --agent claude` — never run it yourself.
28
+ 2. `npx -y mapples@__CLI_VERSION__ agent status --json`. If `session` is non-null with `status: "active"` and
29
+ `holdsLease` is false, another agent is working on this project: stop and ask whether to take
30
+ over (`--takeover` disconnects it). Never take over silently.
31
+ 3. `npx -y mapples@__CLI_VERSION__ sync --yes --json` — be current before designing. Exit 2 here means the repo already
32
+ had conflicts: resolve them (see `mapples-sync`) before going on.
33
+ 4. Read `mapples/design.md` if it exists: a previous run's brief, chosen style and plan. Resume
34
+ from the first phase whose output is missing rather than redoing everything.
35
+
36
+ ## Steps and the lease
37
+
38
+ The run is one agent session. Steps have a **fixed index convention** shared with Creator's
39
+ progress log:
40
+
41
+ ```
42
+ 0 Brief · 1 Style guides · 2 Design tokens · 3 Plan · 4 Scaffold navigation & screens ·
43
+ 5…N-2 one per plan step ("Build the Home screen", …) · N-1 Wiring · N Review
44
+ ```
45
+
46
+ Start the session as soon as the brief and scope are known, pre-declaring every step title:
47
+
48
+ ```bash
49
+ npx -y mapples@__CLI_VERSION__ agent start --label "Claude Code" --steps "Brief,Style guides,Design tokens,Plan,Scaffold navigation & screens" --json
50
+ ```
51
+
52
+ Exit 4 = busy (see precondition 2). After the plan exists (phase 3), the remaining titles are
53
+ declared as they run: `npx -y mapples@__CLI_VERSION__ agent step --index 5 --title "Build the Home screen" --status running`
54
+ creates the step. Wrap **every** phase:
55
+
56
+ ```bash
57
+ npx -y mapples@__CLI_VERSION__ agent step --index <i> --title "<title>" --status running --json
58
+ # … the work …
59
+ npx -y mapples@__CLI_VERSION__ agent step --index <i> --title "<title>" --status done --detail "<one line>" --json
60
+ ```
61
+
62
+ Exit 3 from any `agent` or `sync` command = the lease is gone (Creator disconnected you or the
63
+ lease expired). Stop immediately, do not sync again, and tell the user what was finished.
64
+
65
+ Always end the run — success or not:
66
+
67
+ ```bash
68
+ npx -y mapples@__CLI_VERSION__ agent stop --status done --json
69
+ npx -y mapples@__CLI_VERSION__ agent stop --status failed --error "<what blocked the run>" --json
70
+ ```
71
+
72
+ A phase's syncs are labelled with the running step in Creator's history automatically.
73
+
74
+ ## Phase 0 — Brief and scope
75
+
76
+ Input: `$ARGUMENTS` (the brief, optionally `--scope single|minimal|basic|advanced`). If the
77
+ brief is missing or too thin to name the audience, the core value and the mood, ask **one**
78
+ round of questions (AskUserQuestion) — audience, the one thing the app must do well, the
79
+ feeling it should have, and the scope if absent (default `basic`). Then write
80
+ `mapples/design.md`:
81
+
82
+ ```md
83
+ # <App name>
84
+ ## Brief
85
+ <the brief, cleaned up, 3–8 lines: audience, core value, mood, must-haves, non-goals>
86
+ ## Scope
87
+ <single|minimal|basic|advanced> — <one line why>
88
+ ```
89
+
90
+ Report the step done with the scope in `--detail`.
91
+
92
+ ## Phase 1 — Style guides
93
+
94
+ Follow `reference/style-guides.md`: propose 3 art directions **for this product**, then 3
95
+ compact style guides. Show them to the user as a table (name, direction, palette swatches as
96
+ hex, headline/body fonts, radius, elevation language, one don't) and ask which one — or accept
97
+ the user's pick from the brief. Append the chosen guide to `design.md` under `## Style guide`.
98
+
99
+ ## Phase 2 — Design tokens
100
+
101
+ Follow `reference/design-tokens.md` exactly: write `mapples/theme.ts` (create it — a missing
102
+ file and an empty project is a no-op, so the file is what pushes the tokens). Then
103
+
104
+ ```bash
105
+ npx -y mapples@__CLI_VERSION__ sync --yes --json
106
+ ```
107
+
108
+ Assert: `exitCode` 0, `pushedOps` ≥ 3 (Theme, Typography, Sizing updates) and no
109
+ `conflicts`. If `pushedOps` is 0, the file did not parse as three literal exports — fix the
110
+ file, do not move on. Record the token summary (primary, background, fonts, radius) in
111
+ `design.md` under `## Tokens`.
112
+
113
+ ## Phase 3 — Plan
114
+
115
+ Follow `reference/plan.md`: decisions, navigation (sections → screens), entry screen, ordered
116
+ build steps. Append it to `design.md` under `## Plan` **and** declare the remaining steps:
117
+
118
+ ```bash
119
+ npx -y mapples@__CLI_VERSION__ agent step --index 5 --title "<plan step 1 title>" --status pending --json
120
+ …
121
+ npx -y mapples@__CLI_VERSION__ agent step --index <N-1> --title "Wiring" --status pending --json
122
+ npx -y mapples@__CLI_VERSION__ agent step --index <N> --title "Review" --status pending --json
123
+ ```
124
+
125
+ Show the plan to the user in 6–10 lines; continue unless they object.
126
+
127
+ ## Phase 4 — Scaffold navigation and screens
128
+
129
+ Read `.mapples/config.json` for `routesDir` (`__ROUTES_DIR__` here). Then, for the plan's
130
+ navigation:
131
+
132
+ - The root layout already exists and is CLI-owned — leave it.
133
+ - One directory per section: `<routesDir>/(<section-slug>)/` with a `_layout.tsx` whose first
134
+ line is `// GENERATED by Mapples` and whose body renders `<Stack />`, `<Tabs />` (from
135
+ `expo-router`) or `<Drawer />` (from `expo-router/drawer`) per the section's type. This header
136
+ is the handshake: the CLI adopts the navigator kind from it and owns the file from then on.
137
+ - One **minimal** route file per screen: `index.tsx` for the section's first screen, `<slug>.tsx`
138
+ for the rest — a `View` with one `Typography` (`variant="Headline"`, the screen name). Real
139
+ content comes per screen later; the scaffold only mints ids. When the plan has a single
140
+ section, put its files at the root of the routes dir instead of a group.
141
+ - Do not write to `.mapples/`, do not touch the root `_layout.tsx`, do not create pages under
142
+ `pagesDir`.
143
+
144
+ ```bash
145
+ npx -y mapples@__CLI_VERSION__ sync --yes --json
146
+ ```
147
+
148
+ Assert no conflicts, then read `.mapples/pages.json`: every scaffolded file must be a value's
149
+ `file` with a `routeId`. Note the `pageId` per screen; the `uuid` for `$actions` is in
150
+ `.mapples/base/pages/<pageId>.json`. Screens now exist as empty pages in Creator. Re-read each
151
+ route file — the CLI added the `// mapples-route:` marker and `$sid`s.
152
+
153
+ Navigator and route options (headers, tab icons, initial route, modal presentation) are set in
154
+ Creator, not from code, in this version: describe the intended chrome in `design.md` under
155
+ `## Navigation chrome` so the user can apply it.
156
+
157
+ ## Phases 5…N-2 — one screen step at a time
158
+
159
+ For each plan step, in order:
160
+
161
+ 1. `agent step … --status running`.
162
+ 2. Load the matching playbook(s) from `reference/playbooks/` (read the file; once per run):
163
+ `onboarding-flow`, `home-dashboard`, `list-and-detail`, `forms-and-auth`, `empty-states`,
164
+ `stats-and-progress`, `settings-profile`, `navigation-chrome`; `visual-hierarchy` and
165
+ `microcopy` with the first screen step.
166
+ 3. Re-read the route file. Write the **whole screen** in one edit: keep the marker line, keep
167
+ every existing `$sid` on the element it is on, add none. Obey `reference/layout-contract.md`
168
+ and the chosen style guide's instructions (they outrank the contract where they differ).
169
+ Real copy from the brief; picsum photos in every hero/featured/thumb slot.
170
+ 4. `npx -y mapples@__CLI_VERSION__ sync --yes --json`. Assert `exitCode` 0; read `warnings` and fix what is yours
171
+ (NON_LITERAL_PROP on a value you can make literal, UNKNOWN_ELEMENT). Exit 2 → resolve per
172
+ `mapples-sync`, sync again.
173
+ 5. Re-read the file (it now carries `$sid`s), run it through `reference/lint-checklist.md`
174
+ mentally, fix, sync again if you changed anything.
175
+ 6. `agent step … --status done --detail "<screen>: <what it shows>"`.
176
+
177
+ Two screens in one plan step: do them one after the other inside the step, syncing after each.
178
+
179
+ ## Phase N-1 — Wiring
180
+
181
+ Load `playbooks/screen-flow-wiring.md`. For every navigation the plan names, add to the source
182
+ element's primary event both the Creator connection and the runtime handler:
183
+
184
+ ```tsx
185
+ <Button
186
+ label="Get started"
187
+ variant="filled"
188
+ size="lg"
189
+ fullWidth
190
+ onPress={() => router.push('/(main)')}
191
+ $actions={{ onPress: { type: 'mapples:navigate', staticData: { pageUuid: '<uuid from base>' } } }}
192
+ />
193
+ ```
194
+
195
+ (`import { router } from 'expo-router'`.) Rows and cards use their own `onPress`. Walk the golden
196
+ path from the entry screen; every screen reachable, every flow with an exit. Sync; the report's
197
+ `pushedOps` must cover every action you added.
198
+
199
+ ## Phase N — Review
200
+
201
+ Load `reference/lint-checklist.md`. For every screen: re-read the file, check each item, fix.
202
+ Then `npx -y mapples@__CLI_VERSION__ doctor --json` (no `duplicate`/`missing` issues; `drift` is fine before the final
203
+ sync) and a final `npx -y mapples@__CLI_VERSION__ sync --yes --json` with exit 0. Update `design.md` with a `## Status`
204
+ line (screens built, what was cut, the one decision the user may want to change). Then
205
+ `npx -y mapples@__CLI_VERSION__ agent stop --status done`.
206
+
207
+ Reply to the user in 3–5 lines: what was built, where to look in Creator, the one decision to
208
+ revisit. No headings.
209
+
210
+ ## Working style
211
+
212
+ - One screen, one edit — never element by element across many edits (each sync tags ids; many
213
+ partial syncs mean many rewrites).
214
+ - After every sync, re-read before editing. Never keep a stale copy of a file in your head.
215
+ - Prefer fewer screens fully designed over more screens sketched.
216
+ - Ask only when a product decision is genuinely ambiguous; otherwise decide, state it in
217
+ `design.md`, move on.
218
+ - Never emoji. Never lorem ipsum. Never `Text`. Never a hand-written `$sid`.
@@ -0,0 +1,128 @@
1
+ <!-- GENERATED by Mapples __CLI_VERSION__ — re-run npx -y mapples@__CLI_VERSION__ agent install --force to refresh -->
2
+ # Component library — what to reach for
3
+
4
+ Two packages, one canvas. Everything below is a registered canvas type: Creator renders it,
5
+ its style panel edits it, and `npx -y mapples@__CLI_VERSION__ sync` round-trips it. Import primitives from
6
+ `@mapples/ui`, the themed library from `@mapples/components`. Anything else you import is an
7
+ opaque `Custom` node (allowed, but Creator cannot design inside it).
8
+
9
+ ## `@mapples/ui` — primitives
10
+
11
+ | Type | Use | Notes |
12
+ | --- | --- | --- |
13
+ | `Container` | the screen root or a flex: 1 region | full-size column by default |
14
+ | `View` | any column/row | width 100% in a column; content-sized in a row |
15
+ | `SafeAreaView` | root that respects the notch | or paddingTop ≥ 48 on the root |
16
+ | `ScrollView` | vertical scrolling content | spacing in `styled.contentContainerStyle` |
17
+ | `HorizontalScrollView` | a rail of cards | full-bleed; `contentContainerStyle: { gap: 12, paddingHorizontal: 20 }` |
18
+ | `FlatList` | long uniform lists | prefer `List` + `ListItem` for designed rows |
19
+ | `GridTwoColumns` / `GridThreeColumns` / `GridFourColumns` | tile grids | children tile automatically |
20
+ | `GradientBackground` | the one gradient accent per screen | `gradient` prop with literal hex stops |
21
+ | `ImageBackgroundView` | photo with content over it | `source` + `overflow: 'hidden'` + a scrim child |
22
+ | `Typography` | every piece of text | `text` + `variant` (Headline, Subtitle, Body, Caption, Overline, Button, Link, Label, Code) |
23
+ | `Text` | never on a screen | bypasses the type scale |
24
+ | `Image` | a picture | `source` (picsum URL), `contentFit="cover"`, explicit width/height |
25
+ | `Icon` | a glyph from the project icon family | `iconName`; color/size in `styled.styleSvg` |
26
+ | `IconButton` | icon-only tap target | `iconName`, `accessibilityLabel` (required), `badgeCount` |
27
+ | `Pressable` | a custom tappable region | only when no library control fits |
28
+ | `TextInput` | raw input | in forms use `InputField` instead |
29
+ | `Select` | raw select | in forms use `SelectField` instead |
30
+ | `Svg` / `Vector` / `Video` / `QRCode` / `BarCode` | media specials | as needed |
31
+ | `FormView` / `TextField` / `SubmitButton` | form primitives | the library's `InputField`/`Button` are the designed versions |
32
+
33
+ ## `@mapples/components` — the themed library
34
+
35
+ Library types paint themselves from the tokens; change their look through `variant`, `size`
36
+ and `tone` props and the style slots — never rebuild one from Views. Array props (`options`,
37
+ `items`, `columns`) are literal arrays.
38
+
39
+ ### actions
40
+
41
+ | Type | Props to know | Use |
42
+ | --- | --- | --- |
43
+ | `Button` | `label`, `variant` filled\|outlined\|text\|tonal, `size` sm\|md\|lg, `fullWidth`, `leadingIconName`, `tone` | the primary action (filled lg fullWidth), secondary actions (outlined/text) |
44
+ | `ButtonGroup` | `options` [{label, value}], `value` | a segmented pair of actions |
45
+ | `Fab` | `iconName`, `accessibilityLabel`, `label`, `extended` | one floating primary action |
46
+ | `TextLink` | `label`, `tone`, `underline` | Skip, Forgot password?, Sign in |
47
+ | `BottomActionBar` | `sticky`; children | the sticky bar holding price + CTA on detail/checkout screens |
48
+
49
+ ### input
50
+
51
+ | Type | Props to know | Use |
52
+ | --- | --- | --- |
53
+ | `InputField` | `label`, `placeholder`, `helperText`, `errorText`, `leadingIconName`, `keyboardType`, `autoCapitalize`, `secureTextEntry`, `showPasswordToggle`, `variant` outlined\|filled | every text field in a form |
54
+ | `SelectField` | `label`, `options`, `placeholder`, `value` | dropdowns |
55
+ | `Checkbox` | `label`, `value` | yes/no that lists |
56
+ | `RadioGroup` | `options`, `value` | one exclusive choice |
57
+ | `Switch` | `label`, `value` | a toggle |
58
+ | `Slider` | `min`, `max`, `value`, `showValue` | a range |
59
+ | `NumberStepper` | `min`, `max`, `value` | quantity |
60
+ | `PinInput` | `length` | one-time codes |
61
+ | `SearchBar` | `placeholder`, `value` | search (a filled pill by default) |
62
+ | `ChatComposer` | `placeholder`, `leadingIconName` | the chat input pinned to the bottom |
63
+ | `SegmentedControl` | `options`, `value` | switching a view mode |
64
+ | `Rating` | `value`, `max`, `readOnly` | stars |
65
+ | `ChipGroup` | `options` [{label, value, iconName?}], `value`, `variant` filter\|choice, `scrollable` | filters and tags |
66
+ | `Chip` | `label`, `variant` assist\|filter\|suggestion, `selected` | a single tag (content-sized; inside a row) |
67
+
68
+ ### content
69
+
70
+ | Type | Props to know | Use |
71
+ | --- | --- | --- |
72
+ | `Card` | `variant` elevated\|filled\|outlined; children | any surface that groups content |
73
+ | `MediaCard` | `source`, `title`, `subtitle`, `meta`, `aspectRatio` | a photo-topped tile (rails, grids) |
74
+ | `List` | `variant` plain\|inset\|card, `header`; `ListItem` children | rows — the List draws dividers and the surface |
75
+ | `ListItem` | `title`, `subtitle`, `leading` icon\|avatar\|image\|none, `leadingIconName`, `source`, `trailing` chevron\|text\|switch\|checkbox\|none, `trailingText`, `tone` | one row |
76
+ | `SectionHeader` | `title`, `actionLabel` | "Popular · See all" |
77
+ | `Divider` | `inset` | a hairline between groups |
78
+ | `Avatar` | `name` or `source`, `size` sm\|md\|lg\|xl, `badgeCount` | a person |
79
+ | `AvatarGroup` | `items` [{name, source}], `max` | several people |
80
+ | `Badge` | `label` or `count`, `variant` text\|dot\|count, `tone` | a status pill or a count |
81
+ | `StatTile` | `label`, `value`, `unit`, `caption`, `trend`, `trendValue`, `iconName`, `variant` | a KPI |
82
+ | `Table` | `columns` [{key, title}], `rows` | tabular data |
83
+ | `Timeline` | `items` [{title, subtitle, time, status}] | a sequence of events |
84
+ | `ImageCarousel` | `items` [{source, caption}] | swipeable photos |
85
+ | `MessageBubble` | `text`, `direction` in\|out, `time`, `status` | a chat message |
86
+ | `Accordion` | `items` [{title, content}] | FAQ / expandable rows |
87
+ | `Skeleton` | `variant` text\|rect\|circle, `width`, `height` | a loading placeholder |
88
+
89
+ ### navigation (in-content)
90
+
91
+ | Type | Props to know | Use |
92
+ | --- | --- | --- |
93
+ | `TopAppBar` | `title`, `showBack`, `actions` [{iconName, value}], `variant` small\|large | an in-content header ONLY when the stack header is hidden |
94
+ | `BottomNavigationBar` | `items` [{label, iconName, value}], `value` | a single-screen demo of a tab shell — real tabs are a navigator |
95
+ | `Tabs` | `items` [{label, value}], `value` | switching panels inside ONE screen |
96
+ | `Breadcrumbs` | `items` [{label, value}], `separator`, `maxItems` | a path |
97
+ | `Steps` | `items` [{label}], `current` | a multi-step progress |
98
+ | `PageControl` | `count`, `value`, `variant` dots\|bars | onboarding page dots |
99
+
100
+ ### feedback
101
+
102
+ | Type | Props to know | Use |
103
+ | --- | --- | --- |
104
+ | `ProgressBar` | `value`, `max`, `showLabel` | a goal or an upload |
105
+ | `ProgressCircle` | `value`, `size`, `showLabel` | a ring |
106
+ | `Spinner` | `size` | loading |
107
+ | `Banner` | `title`, `message`, `tone`, `actionLabel` | an inline notice |
108
+ | `Snackbar` | `message`, `actionLabel`, `visible` | a toast (last in the root, `visible={false}` unless bound) |
109
+ | `EmptyState` | `iconName` or `imageSource`, `title`, `message`, `actionLabel`, `secondaryActionLabel`, `tone` | nothing to show |
110
+
111
+ ### overlays (last in the page root; `visible={false}` unless bound to a variable)
112
+
113
+ | Type | Props to know | Use |
114
+ | --- | --- | --- |
115
+ | `Dialog` | `title`, `message`, `primaryActionLabel`, `secondaryActionLabel`, `tone`, `visible` | a confirmation |
116
+ | `BottomSheet` | `title`, `visible`; children | a picker or a quick detail |
117
+ | `ActionSheet` | `options` [{label, value, iconName?, destructive?}], `visible` | a list of actions |
118
+
119
+ ## Style slots
120
+
121
+ `styled={{ style, styleTypography, styleSvg, styleImage, contentContainerStyle, placeholderTextColor }}` —
122
+ `style` is the element's box; `styleTypography` its text (Button label, ListItem title, StatTile
123
+ value); `styleSvg` its glyph; `contentContainerStyle` the scrolling content. Library components
124
+ expose the same slots; use them for one-off tweaks (a card's `gap`, a rail's padding) and
125
+ props for everything the component already knows how to do.
126
+
127
+ > Prop names above follow the Creator's component digest; when unsure, keep to the ones listed
128
+ > here — an unknown prop is ignored (and reported by the Creator lint as `unknown-prop`).
@@ -0,0 +1,132 @@
1
+ <!-- GENERATED by Mapples __CLI_VERSION__ — re-run npx -y mapples@__CLI_VERSION__ agent install --force to refresh -->
2
+ # Design tokens (phase 2) — `mapples/theme.ts`
3
+
4
+ Ported from the Creator's full-variant generation (`generate.ts` `variantSystem` +
5
+ `schemas.ts` `designVariantSchema`). The output is a file, not a JSON reply: `mapples/theme.ts`
6
+ exports three **literal** objects — `theme`, `typography`, `sizing` — and `npx -y mapples@__CLI_VERSION__ sync` pushes
7
+ them as the project's Theme, Typography and Sizing documents.
8
+
9
+ ## Rules
10
+
11
+ Act as a senior product designer building a design system for this mobile app. The user
12
+ already chose a style guide. Realize EXACTLY this style — same palette family (the preview
13
+ colors are anchors to build around), same fonts, same shape language, same iconFamily.
14
+
15
+ - Colors are hex. Provide BOTH light and dark maps; dark is a real dark design (dark surfaces,
16
+ lighter text), not an inversion. `primary.main` must have ≥ 4.5:1 contrast against
17
+ `primary.contrast`; `text.primary` against `background.primary` likewise. `neutral` runs
18
+ white→n50…n900→black as a smooth ramp in the theme's hue bias.
19
+ - Fonts come ONLY from the library in `style-guides.md` (family + weight); body fonts must be
20
+ sans or a highly legible serif. `fontFamily` values are the registered names
21
+ `"<Family>-<Weight>"` (`"Manrope-SemiBold"`) with `fontWeight` matching the weight (Regular
22
+ 400, Medium 500, SemiBold 600, Bold 700). Never "system", "Helvetica" or any other name: it
23
+ will not render.
24
+ - The type scale is for a phone: Headline 26–34, Subtitle 18–22, Body 15–17, Caption 12–13,
25
+ Overline 10–12, Button 15–17, Link = Body, Code 13–14, Label 13–15. `lineHeight` ≈ 1.25× for
26
+ headlines, 1.5× for body. Headline and Subtitle share the headline font; Body, Caption, Label,
27
+ Link share the body font; Button and Overline share the button font; Code uses the mono font.
28
+ Overline is `textTransform: 'uppercase'`.
29
+ - Sizing: `base` 4; `xs/sm/md/lg/xl` a clear scale (4/8/12–16/24/32), `screenPadding` 16–24,
30
+ `gap` 12–16, `radius` and `radiusLarge` to fit the direction (sharp directions near 0, soft
31
+ ones 16–28; `radiusLarge` ≥ `radius`), `control` 44–56, `card` 16–24, `icon` 20–28. All
32
+ multiples of `base`.
33
+ - `instructions` (write them into `design.md` under `## Design instructions`, not into the
34
+ file): 150–300 words of concrete rules for every future screen — voice and copy tone, spacing
35
+ rules, component style (buttons, cards, inputs, lists), imagery and icon treatment, motion,
36
+ explicit do / don't lists. They MUST state the elevation language as a deliberate choice —
37
+ flat ("1px borders / contrasting surfaces, no shadows") is a first-class option and the right
38
+ one for calm, minimal, editorial or brutalist directions; when shadows are chosen, give the
39
+ exact soft recipe (offsets, blur ≥ 3× offset, rgba alpha ≤ 0.12) AND name the surfaces it
40
+ applies to plus where shadows are forbidden (inputs, chips, in-card rows). Also state the
41
+ corner-radius system (which radius which surface gets, including any top-only/bottom-only
42
+ corner rules for sheets and heroes), where a gradient accent is allowed (if anywhere), and the
43
+ imagery/placeholder style. Written for a designer who has never seen the product.
44
+
45
+ ## Bounds (the schema; a value outside them is a contract violation)
46
+
47
+ - hex: `#rrggbb` or `#rrggbbaa`
48
+ - text scale: `fontSize` 10–48 int, `lineHeight` 12–60 int, `letterSpacing` −2…3
49
+ - sizing: `base` 2–8; `xs` 2–12, `sm` 4–16, `md` 8–24, `lg` 16–40, `xl` 24–64,
50
+ `screenPadding` 12–32, `gap` 8–24, `radius` 0–24, `radiusLarge` 0–40, `control` 40–64,
51
+ `card` 12–32, `icon` 16–32 — all ints
52
+
53
+ ## The file — copy this shape exactly, fill every value
54
+
55
+ ```ts
56
+ // mapples/theme.ts — design tokens, synced with Creator by `npx -y mapples@__CLI_VERSION__ sync`.
57
+ // Edit values freely; keys you add here are pushed to the canvas style config.
58
+
59
+ export const theme = {
60
+ variant: 'auto',
61
+ defaultColor: '#1B1B1F', // = light.text.primary
62
+ light: {
63
+ background: { primary: '#FFFFFF', card: '#F7F7F9', contrast: '#1B1B1F' },
64
+ primary: { main: '#5B4DE0', light: '#8C82F0', dark: '#3D31B5', contrast: '#FFFFFF', background: '#EEECFC' },
65
+ accent: { main: '#F2994A', light: '#F7B980', dark: '#C8792F', contrast: '#1B1B1F', background: '#FDF1E6' },
66
+ text: { primary: '#1B1B1F', secondary: '#5A5B66', tertiary: '#8B8C99' },
67
+ neutral: {
68
+ white: '#FFFFFF', n50: '#F7F7F9', n100: '#EFEFF3', n200: '#E1E1E8', n300: '#C9C9D3',
69
+ n400: '#A6A7B5', n500: '#7F8090', n600: '#5A5B66', n700: '#3F404A', n800: '#2A2B33',
70
+ n900: '#1B1B1F', black: '#000000',
71
+ },
72
+ system: { info: '#2F80ED', success: '#27AE60', warning: '#F2C94C', error: '#EB5757' },
73
+ },
74
+ dark: {
75
+ background: { primary: '#121217', card: '#1C1C24', contrast: '#F5F5FA' },
76
+ primary: { main: '#8C82F0', light: '#B1AAF6', dark: '#5B4DE0', contrast: '#121217', background: '#26224A' },
77
+ accent: { main: '#F7B980', light: '#FAD1A9', dark: '#F2994A', contrast: '#121217', background: '#3A2A1A' },
78
+ text: { primary: '#F5F5FA', secondary: '#B8B9C6', tertiary: '#8B8C99' },
79
+ neutral: {
80
+ white: '#FFFFFF', n50: '#2A2B33', n100: '#3F404A', n200: '#4A4B57', n300: '#5A5B66',
81
+ n400: '#7F8090', n500: '#A6A7B5', n600: '#C9C9D3', n700: '#E1E1E8', n800: '#EFEFF3',
82
+ n900: '#F7F7F9', black: '#000000',
83
+ },
84
+ system: { info: '#5EA0F5', success: '#4CC77F', warning: '#F5D76E', error: '#F27C7C' },
85
+ },
86
+ } as const;
87
+
88
+ export const typography = {
89
+ fontFamily: 'Manrope-Regular', // = the Body font
90
+ color: '#1B1B1F', // = light.text.primary
91
+ default: 'Body',
92
+ typography: {
93
+ Headline: { fontFamily: 'Sora-Bold', fontWeight: '700', fontSize: 30, lineHeight: 38, letterSpacing: -0.5 },
94
+ Subtitle: { fontFamily: 'Sora-SemiBold', fontWeight: '600', fontSize: 20, lineHeight: 26, letterSpacing: -0.2 },
95
+ Body: { fontFamily: 'Manrope-Regular', fontWeight: '400', fontSize: 16, lineHeight: 24, letterSpacing: 0 },
96
+ Caption: { fontFamily: 'Manrope-Regular', fontWeight: '400', fontSize: 13, lineHeight: 18, letterSpacing: 0 },
97
+ Overline: { fontFamily: 'Manrope-SemiBold', fontWeight: '600', fontSize: 11, lineHeight: 16, letterSpacing: 1, textTransform: 'uppercase' },
98
+ Button: { fontFamily: 'Manrope-SemiBold', fontWeight: '600', fontSize: 16, lineHeight: 20, letterSpacing: 0.2 },
99
+ Link: { fontFamily: 'Manrope-Medium', fontWeight: '500', fontSize: 16, lineHeight: 24, letterSpacing: 0 },
100
+ Code: { fontFamily: 'IBMPlexMono-Regular', fontWeight: '400', fontSize: 14, lineHeight: 20, letterSpacing: 0 },
101
+ Label: { fontFamily: 'Manrope-Medium', fontWeight: '500', fontSize: 14, lineHeight: 20, letterSpacing: 0.1 },
102
+ },
103
+ } as const;
104
+
105
+ export const sizing = {
106
+ base: 4,
107
+ sizing: {
108
+ xs: 4, sm: 8, md: 12, lg: 24, xl: 32,
109
+ screenPadding: 20, gap: 12, radius: 12, radiusLarge: 24,
110
+ control: 48, card: 20, icon: 24,
111
+ },
112
+ } as const;
113
+ ```
114
+
115
+ The values above are an example, not the answer — every project gets its own. Keep the
116
+ comments, the `as const`, the three named exports and no other statements: the CLI parses the
117
+ file as literal objects (an import, a spread or a function call makes the whole file
118
+ unreadable and the sync reports `NON_LITERAL_PROP … local style edits ignored`).
119
+
120
+ ## After writing
121
+
122
+ ```bash
123
+ npx -y mapples@__CLI_VERSION__ sync --yes --json
124
+ ```
125
+
126
+ Expect `pushedOps` ≥ 3 and `exitCode` 0. The tokens are now the project's; every style token
127
+ string in a screen (`'theme.primary.main'`, `'sizing.md'`) resolves against them. Later edits to
128
+ `mapples/theme.ts` merge per key with edits made in Creator; a same-key conflict deprecates the
129
+ file and regenerates it from Creator — re-apply, never restore.
130
+
131
+ > Not ported (Creator-only): the live token reveal, the review-feedback regeneration loop and
132
+ > the `iconFamily` project setting (set it in Creator: Project → Settings → Icons).