@pen.dev/cli 0.3.3 → 0.3.4

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 (82) hide show
  1. package/README.md +13 -6
  2. package/dist/anthropic-messages-COZrsSdY.mjs +40 -0
  3. package/dist/azure-openai-responses-Dmf1EaVz.mjs +2 -0
  4. package/dist/browserAll-BZYrVO32.mjs +2 -0
  5. package/dist/{dist-BEo0Z8Vf.mjs → dist-D9ROAuw3.mjs} +348 -319
  6. package/dist/{dist-BY6vOcMF.mjs → dist-DGrygXHh.mjs} +2 -2
  7. package/dist/{error-body-D2Mrqb4g.mjs → error-body-BBlqjbe7.mjs} +1 -1
  8. package/dist/google-generative-ai-BMEzR_34.mjs +2 -0
  9. package/dist/google-shared-DXgnvvDU.mjs +318 -0
  10. package/dist/google-vertex-In7qdx36.mjs +2 -0
  11. package/dist/index.mjs +2 -2
  12. package/dist/mistral-conversations-DdYjdrRy.mjs +5 -0
  13. package/dist/models-BBd5zwn6.mjs +2 -0
  14. package/dist/{multipart-parser-DX5ZDxQv.mjs → multipart-parser-BdmM0fdd.mjs} +1 -1
  15. package/dist/node_modules/@highagency/pencil-wasm/package.json +1 -1
  16. package/dist/node_modules/@highagency/pencil-wasm/pencil.d.ts +3 -0
  17. package/dist/node_modules/@highagency/pencil-wasm/pencil.js +1 -1
  18. package/dist/node_modules/@highagency/pencil-wasm/pencil.wasm +0 -0
  19. package/dist/openai-CbFQ5q5I.mjs +18 -0
  20. package/dist/openai-codex-responses-CD-2hfWB.mjs +8 -0
  21. package/dist/openai-completions-DamtYjy7.mjs +6 -0
  22. package/dist/openai-responses-DgeWdtm-.mjs +2 -0
  23. package/dist/openai-responses-shared-DKseiGAg.mjs +11 -0
  24. package/dist/{openrouter-images-BbBWg9zF.mjs → openrouter-images-gArAwqnL.mjs} +1 -1
  25. package/dist/out/mcp-server-darwin-arm64 +0 -0
  26. package/dist/out/mcp-server-darwin-x64 +0 -0
  27. package/dist/out/mcp-server-linux-arm64 +0 -0
  28. package/dist/out/mcp-server-linux-x64 +0 -0
  29. package/dist/out/mcp-server-windows-arm64.exe +0 -0
  30. package/dist/out/mcp-server-windows-x64.exe +0 -0
  31. package/dist/out/skills/pen-dev/SKILL.md +204 -0
  32. package/dist/out/skills/pen-dev/execute.md +364 -0
  33. package/dist/out/skills/pen-dev/guide/code.md +198 -0
  34. package/dist/out/skills/pen-dev/guide/components.md +45 -0
  35. package/dist/out/skills/pen-dev/guide/design-system.md +556 -0
  36. package/dist/out/skills/pen-dev/guide/landing-page.md +31 -0
  37. package/dist/out/skills/pen-dev/guide/mobile-app.md +31 -0
  38. package/dist/out/skills/pen-dev/guide/slides.md +222 -0
  39. package/dist/out/skills/pen-dev/guide/table.md +37 -0
  40. package/dist/out/skills/pen-dev/guide/tailwind.md +328 -0
  41. package/dist/out/skills/pen-dev/guide/web-app.md +245 -0
  42. package/dist/out/skills/pen-dev/pen-schema.md +202 -0
  43. package/dist/out/skills/pen-dev/scripts-and-shaders.md +94 -0
  44. package/dist/pi-user-agent-m9a4CjJo.mjs +2 -0
  45. package/dist/{src-B_lvnEtX.mjs → src-KoDMTA_Q.mjs} +1 -1
  46. package/dist/transform-messages-BHnJzowk.mjs +2 -0
  47. package/dist/webworkerAll-CB00nbs9.mjs +2 -0
  48. package/package.json +3 -3
  49. package/dist/anthropic-messages-Bf-fvkNu.mjs +0 -40
  50. package/dist/azure-openai-responses-CzgVqECr.mjs +0 -2
  51. package/dist/browserAll-8jKh1NRi.mjs +0 -2
  52. package/dist/completionchunk-BQtPqA8U.mjs +0 -28
  53. package/dist/google-generative-ai-DSOqI0LF.mjs +0 -2
  54. package/dist/google-shared-CetPT_Vt.mjs +0 -318
  55. package/dist/google-vertex-CPtOc5oU.mjs +0 -2
  56. package/dist/mistral-conversations-CUsdbDQ8.mjs +0 -10
  57. package/dist/models-CwK5xZH9.mjs +0 -2
  58. package/dist/openai-Brr_V-tF.mjs +0 -17
  59. package/dist/openai-codex-responses-Cb5pfH5S.mjs +0 -8
  60. package/dist/openai-completions-BvTlcCeP.mjs +0 -6
  61. package/dist/openai-responses-IuaLTEHh.mjs +0 -2
  62. package/dist/openai-responses-shared-D4d0NbBE.mjs +0 -11
  63. package/dist/otel-CaADOqYZ.mjs +0 -4
  64. package/dist/transform-messages-CSBQpmXO.mjs +0 -2
  65. package/dist/webworkerAll-BD-7VH16.mjs +0 -2
  66. /package/dist/{dist-BnoSGZKP.mjs → dist-D8tvRm1b.mjs} +0 -0
  67. /package/dist/{emscripten-module.browser-F76W5DM6-CNibWX-6.mjs → emscripten-module.browser-F76W5DM6-DWhj_jYh.mjs} +0 -0
  68. /package/dist/{emscripten-module.browser-XIKQQPVU-BNfdGnMe.mjs → emscripten-module.browser-XIKQQPVU-Dmh4no3c.mjs} +0 -0
  69. /package/dist/{ffi-C5tLdQO9.mjs → ffi-BroAqW9B.mjs} +0 -0
  70. /package/dist/{ffi-BuJ13coi.mjs → ffi-DwdyvnFx.mjs} +0 -0
  71. /package/dist/{from-py2TfO8m.mjs → from-Choxbpmr.mjs} +0 -0
  72. /package/dist/{github-copilot-headers-DZOfokGy.mjs → github-copilot-headers-DCj7hJoC.mjs} +0 -0
  73. /package/dist/{hash-Kp92CI9R.mjs → hash-DNYCELl4.mjs} +0 -0
  74. /package/dist/{html-GGJ1fTRB.mjs → html-DEPARSNH.mjs} +0 -0
  75. /package/dist/{init-B9LSomNH.mjs → init-DwIpBeuP.mjs} +0 -0
  76. /package/dist/{module-ES6BEMUI-DwQ9nTMF.mjs → module-ES6BEMUI-DUGQwtIb.mjs} +0 -0
  77. /package/dist/{module-asyncify-2EFITU5U-B54Mkt6K.mjs → module-asyncify-2EFITU5U-U7fqmMTF.mjs} +0 -0
  78. /package/dist/{openai-prompt-cache-t4kk9puG.mjs → openai-prompt-cache-tVHrB8oW.mjs} +0 -0
  79. /package/dist/{photon_rs-BySSRmP5.mjs → photon_rs-o0nbTM4F.mjs} +0 -0
  80. /package/dist/{provider-retry-BM3ArvaW.mjs → provider-retry-wOYAq0sa.mjs} +0 -0
  81. /package/dist/{sanitize-unicode-CHjuq5rK.mjs → sanitize-unicode-Byz9nlLd.mjs} +0 -0
  82. /package/dist/{standalone-DYT2Zg6I.mjs → standalone-DwaYVpTH.mjs} +0 -0
@@ -0,0 +1,556 @@
1
+ # Design System Composition Guidelines
2
+
3
+ Helpful patterns for composing screens and dashboards using design system components in `.pen` files. These are suggestions to get you started—feel free to adapt them to your needs.
4
+
5
+ ---
6
+
7
+ ## 1. Common Component Patterns
8
+
9
+ Component naming patterns you might encounter:
10
+ - `Button/*` — Button variants
11
+ - `Input/*` or `Input Group/*` — Form inputs
12
+ - `Card` — Card containers
13
+ - `Sidebar` — Navigation sidebar
14
+ - `Table` or `Data Table` — Table elements
15
+ - `Alert/*` — Feedback alerts
16
+ - `Modal/*` or `Dialog` — Modal dialogs
17
+
18
+ ---
19
+
20
+ ## 2. Understanding Slots
21
+
22
+ Slots are placeholder frames inside components where you insert child components. They're marked with the `slot` property containing an array of recommended component IDs.
23
+
24
+ ### How to Identify Slots
25
+
26
+ When reading a component, look for frames with slot property:
27
+ ```json
28
+ {
29
+ "id": "slotId",
30
+ "name": "Content Slot",
31
+ "slot": ["recommendedComponentId1", "recommendedComponentId2"]
32
+ }
33
+ ```
34
+
35
+ ### How to Use Slots
36
+
37
+ A typical approach:
38
+ 1. **Insert the parent component** and capture its binding
39
+ 2. **Insert children into the slot** using path: `parentBinding/slotId`
40
+ 3. **Consider using recommended components** listed in the slot's `slot` array (though you can insert other content too)
41
+
42
+ ```javascript
43
+ sidebar=Insert(page, {type: "ref", ref: "sidebarComponentId", height: "fill_container"})
44
+ item1=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarItemId", descendants: {...}})
45
+ item2=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarItemId", descendants: {...}})
46
+ ```
47
+
48
+ If you don't need to use a particular slot in a component instance, mark the slot `enabled: false` to hide it.
49
+
50
+ ---
51
+
52
+ ## 3. Icons
53
+
54
+ ### Available Icon Sets
55
+
56
+ You can use the `icon` type with these libraries:
57
+
58
+ | Library | Style | Example Names |
59
+ |-------------|-------|---------------|
60
+ | `lucide` | Outline, rounded | `home`, `settings`, `user`, `search`, `plus`, `x` |
61
+ | `feather` | Outline, rounded | `home`, `settings`, `user`, `search`, `plus`, `x` |
62
+ | `Material Symbols Outlined` | Outline | `home`, `settings`, `person`, `search`, `add`, `close` |
63
+ | `Material Symbols Rounded` | Rounded | `home`, `settings`, `person`, `search`, `add`, `close` |
64
+ | `Material Symbols Sharp` | Sharp corners | `home`, `settings`, `person`, `search`, `add`, `close` |
65
+
66
+ ### Icon Usage
67
+
68
+ Standalone icon with Lucide, and Material Symbols with weight:
69
+
70
+ ```javascript
71
+ icon=Insert(container, {type: "icon", library: "lucide", icon: "settings", width: 24, height: 24, fill: "$--foreground"})
72
+ icon=Insert(container, {type: "icon", library: "Material Symbols Rounded", icon: "dashboard", width: 24, height: 24, fill: "$--foreground", weight: 400})
73
+ ```
74
+
75
+ ### Overriding Icons in Components
76
+
77
+ When a component contains an icon, override it via descendants. Descendant keys can be node IDs/paths or unique descendant names; use IDs/paths when names are ambiguous:
78
+ ```javascript
79
+ descendants: {
80
+ "iconNodeId": { icon: "settings" }
81
+ }
82
+ ```
83
+
84
+ ### Common Icon Names
85
+
86
+ | Action | Lucide/Feather | Material Symbols |
87
+ |--------|----------------|------------------|
88
+ | Home | `home` | `home` |
89
+ | Settings | `settings` | `settings` |
90
+ | User | `user` | `person` |
91
+ | Search | `search` | `search` |
92
+ | Add | `plus` | `add` |
93
+ | Close | `x` | `close` |
94
+ | Edit | `edit`, `pencil` | `edit` |
95
+ | Delete | `trash`, `trash-2` | `delete` |
96
+ | Check | `check` | `check` |
97
+ | Arrow right | `arrow-right` | `arrow_forward` |
98
+ | Chevron down | `chevron-down` | `expand_more` |
99
+ | Menu | `menu` | `menu` |
100
+ | Dashboard | `layout-dashboard` | `dashboard` |
101
+ | Folder | `folder` | `folder` |
102
+ | File | `file` | `description` |
103
+ | Calendar | `calendar` | `calendar_today` |
104
+ | Mail | `mail` | `mail` |
105
+ | Bell | `bell` | `notifications` |
106
+
107
+ ---
108
+
109
+ ## 4. Sidebar Composition
110
+
111
+ ### Structure
112
+
113
+ ```
114
+ Sidebar Component
115
+ ├── Header (logo, brand)
116
+ ├── Content Slot ← Insert navigation items here
117
+ └── Footer (user profile, settings)
118
+ ```
119
+
120
+ ### Populating Sidebar Navigation
121
+
122
+ Insert the sidebar, then add section title (if available), active item, and default items:
123
+
124
+ ```javascript
125
+ sidebar=Insert(page, {type: "ref", ref: "sidebarId", height: "fill_container"})
126
+ newSectionTitle=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarSectionTitleId", descendants: {"labelTextId": {content: "Main Menu"}}})
127
+ itemDashboard=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarItemActiveId", descendants: {"iconId": {icon: "dashboard"}, "labelId": {content: "Dashboard"}}})
128
+ itemUsers=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarItemDefaultId", descendants: {"iconId": {icon: "users"}, "labelId": {content: "Users"}}})
129
+ itemSettings=Insert(sidebar+"/contentSlotId", {type: "ref", ref: "sidebarItemDefaultId", descendants: {"iconId": {icon: "settings"}, "labelId": {content: "Settings"}}})
130
+ ```
131
+
132
+ ---
133
+
134
+ ## 5. Card Composition
135
+
136
+ ### Structure
137
+
138
+ Cards typically have three slots:
139
+
140
+ ```
141
+ Card Component
142
+ ├── Header Slot ← Title, description
143
+ ├── Content Slot ← Main content
144
+ └── Actions Slot ← Buttons
145
+ ```
146
+
147
+ ### Populating Card Slots
148
+
149
+ Insert card, replace header with custom content, setup content slot for form, setup actions slot with buttons:
150
+
151
+ ```javascript
152
+ card=Insert(container, {type: "ref", ref: "cardId", width: 480})
153
+ newNode=Replace(card+"/headerSlotId", {type: "frame", layout: "vertical", gap: 4, padding: 24, width: "fill_container", children: [
154
+ {type: "text", content: "Card Title", fill: "$--foreground", fontFamily: "$--font-primary", fontSize: 18, fontWeight: "600"},
155
+ {type: "text", content: "Card description goes here", fill: "$--muted-foreground", fontFamily: "$--font-secondary", fontSize: 14}
156
+ ]})
157
+ Update(card+"/contentSlotId", {layout: "vertical", gap: 16, padding: 24})
158
+ input=Insert(card+"/contentSlotId", {type: "ref", ref: "inputGroupId", width: "fill_container", descendants: {"labelId": {content: "Email"}}})
159
+ Update(card+"/actionsSlotId", {gap: 12, justifyContent: "end", padding: 24})
160
+ cancelBtn=Insert(card+"/actionsSlotId", {type: "ref", ref: "buttonOutlineId", descendants: {"iconId": {enabled: false}, "labelId": {content: "Cancel"}}})
161
+ saveBtn=Insert(card+"/actionsSlotId", {type: "ref", ref: "buttonPrimaryId", descendants: {"iconId": {enabled: false}, "labelId": {content: "Save"}}})
162
+ ```
163
+
164
+ ---
165
+
166
+ ## 6. Tab Composition
167
+
168
+ ### Structure
169
+
170
+ ```
171
+ Tabs Container
172
+ └── Direct children: Tab Items (active/inactive)
173
+ ```
174
+
175
+ ### Building Tabs
176
+
177
+ Insert tabs container, then add tab items directly (first one active):
178
+
179
+ ```javascript
180
+ tabs=Insert(container, {type: "ref", ref: "tabsId", width: "fit_content"})
181
+ tab1=Insert(tabs, {type: "ref", ref: "tabItemActiveId", descendants: {"labelId": {content: "General"}}})
182
+ tab2=Insert(tabs, {type: "ref", ref: "tabItemInactiveId", descendants: {"labelId": {content: "Security"}}})
183
+ tab3=Insert(tabs, {type: "ref", ref: "tabItemInactiveId", descendants: {"labelId": {content: "Billing"}}})
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 7. Dropdown Composition
189
+
190
+ ### Structure
191
+
192
+ ```
193
+ Dropdown Container
194
+ └── Direct children: Search, Dividers, Titles, List Items
195
+ ```
196
+
197
+ ### Building Dropdowns
198
+
199
+ Optional search, divider, section title, and items:
200
+
201
+ ```javascript
202
+ dropdown=Insert(container, {type: "ref", ref: "dropdownId", height: "fit_content"})
203
+ search=Insert(dropdown, {type: "ref", ref: "searchBoxId"})
204
+ divider=Insert(dropdown, {type: "ref", ref: "listDividerId"})
205
+ title=Insert(dropdown, {type: "ref", ref: "listTitleId", descendants: {"labelId": {content: "Actions"}}})
206
+ optionA=Insert(dropdown, {type: "ref", ref: "listItemCheckedId", descendants: {"labelId": {content: "Option A"}}})
207
+ optionB=Insert(dropdown, {type: "ref", ref: "listItemUncheckedId", descendants: {"labelId": {content: "Option B"}}})
208
+ ```
209
+
210
+ ---
211
+
212
+ ## 8. Table Composition
213
+
214
+ ### Table Structure
215
+
216
+ ```
217
+ Table (frame)
218
+ ├── Table Header — Search/filter + action buttons
219
+ ├── Table Wrapper — Contains all rows
220
+ │ ├── Header Row (frame)
221
+ │ │ └── Cell (frame)
222
+ │ │ └── Content (text, label, button, etc.)
223
+ │ ├── Data Row 1 (frame)
224
+ │ │ └── Cell (frame)
225
+ │ │ └── Content (text, label, button, etc.)
226
+ │ ├── Data Row 2 (frame)
227
+ │ │ └── Cell (frame)
228
+ │ │ └── Content (text, label, button, etc.)
229
+ │ └── ...
230
+ └── Table Footer — Row count + pagination
231
+ ```
232
+
233
+ ### Building Tables Step by Step
234
+
235
+ ### Table Hierarchy
236
+
237
+ **Important:** Tables follow this strict nesting structure:
238
+ Table → Row → Cell (frame) → Cell Content (text, label, button, etc.)
239
+
240
+ - **Table**: Container with vertical layout holding all rows
241
+ - **Row**: Horizontal container holding cells
242
+ - **Cell**: Frame wrapper that controls column width
243
+ - **Cell Content**: The actual content inside the cell (text, badges, buttons, etc.)
244
+
245
+ **Add data rows with cells**
246
+
247
+ Note: For tables with many rows, split into multiple `execute` calls (e.g., 2-3 rows per call).
248
+
249
+ ```javascript
250
+ row1=Insert(table, {type: "ref", ref: "dataTableRowId", width: "fill_container"})
251
+ nameCell=Insert(row1, {type: "ref", ref: "dataTableCellId", width: "fill_container"})
252
+ nameText=Insert(nameCell, {type: "text", content: "John Doe"})
253
+ emailCell=Insert(row1, {type: "ref", ref: "dataTableCellId", width: "fill_container"})
254
+ emailText=Insert(emailCell, {type: "text", content: "john@example.com"})
255
+ statusCell=Insert(row1, {type: "ref", ref: "dataTableCellId", width: 120})
256
+ statusBadge=Insert(statusCell, {type: "ref", ref: "labelSuccessId", descendants: {"textId": {content: "Active"}}})
257
+ actionsCell=Insert(row1, {type: "ref", ref: "dataTableCellId", width: 100})
258
+ actionBtn=Insert(actionsCell, {type: "ref", ref: "iconButtonId"})
259
+ ```
260
+
261
+ ### Column Width Strategy
262
+
263
+ Suggested starting points (adjust as needed):
264
+
265
+ | Column Type | Typical Width |
266
+ |-------------|-------|
267
+ | Primary identifier (name) | 200-250px |
268
+ | Email, URL | `fill_container` |
269
+ | Status, badge | 100-120px |
270
+ | Date | 120-150px |
271
+ | Actions | 80-100px |
272
+ | Numbers | 80-100px |
273
+
274
+ ---
275
+
276
+ ## 9. Pagination Composition
277
+
278
+ ### Structure
279
+
280
+ ```
281
+ Pagination Component
282
+ ├── Previous Button
283
+ ├── Page Numbers Slot ← Insert page items here
284
+ └── Next Button
285
+ ```
286
+
287
+ ### Building Pagination
288
+
289
+ Insert page numbers into slot:
290
+
291
+ ```javascript
292
+ pagination=Insert(container, {type: "ref", ref: "paginationId"})
293
+ page1=Insert(pagination+"/pageNumbersSlotId", {type: "ref", ref: "paginationItemActiveId", descendants: {"labelId": {content: "1"}}})
294
+ page2=Insert(pagination+"/pageNumbersSlotId", {type: "ref", ref: "paginationItemDefaultId", descendants: {"labelId": {content: "2"}}})
295
+ page3=Insert(pagination+"/pageNumbersSlotId", {type: "ref", ref: "paginationItemDefaultId", descendants: {"labelId": {content: "3"}}})
296
+ ellipsis=Insert(pagination+"/pageNumbersSlotId", {type: "ref", ref: "paginationItemEllipsisId"})
297
+ page10=Insert(pagination+"/pageNumbersSlotId", {type: "ref", ref: "paginationItemDefaultId", descendants: {"labelId": {content: "10"}}})
298
+ ```
299
+
300
+ ---
301
+
302
+ ## 10. Screen Layout Patterns
303
+
304
+ These patterns show the structure for common layouts. Each pattern is typically one execute call. Since `execute` input is JavaScript, use arrays, loops, object spreads, helper objects, and template strings to generate repeated design nodes without hand-writing every operation. Do not include comments in generated `execute` JavaScript.
305
+
306
+ ### Pattern A: Sidebar + Content (Dashboard)
307
+
308
+ ```
309
+ ┌──────────┬────────────────────────────────┐
310
+ │ │ │
311
+ │ Sidebar │ Main Content Area │
312
+ │ 280px │ fill_container │
313
+ │ │ │
314
+ └──────────┴────────────────────────────────┘
315
+ ```
316
+
317
+ ```javascript
318
+ screen=Insert(document, {type: "frame", name: "Dashboard", layout: "horizontal", width: 1440, height: "fit_content(900)", fill: "$--background", placeholder: true})
319
+ sidebar=Insert(screen, {type: "ref", ref: "sidebarId", height: "fill_container"})
320
+ main=Insert(screen, {type: "frame", layout: "vertical", width: "fill_container", height: "fill_container(900)", padding: 32, gap: 24})
321
+ ```
322
+
323
+ ### Pattern B: Header + Content
324
+
325
+ ```
326
+ ┌────────────────────────────────────────────┐
327
+ │ Header Bar (64px) │
328
+ ├────────────────────────────────────────────┤
329
+ │ │
330
+ │ Content Area │
331
+ │ │
332
+ └────────────────────────────────────────────┘
333
+ ```
334
+
335
+ Fixed header and scrollable content:
336
+
337
+ ```javascript
338
+ screen=Insert(document, {type: "frame", layout: "vertical", width: 1200, height: "fit_content(800)", fill: "$--background", placeholder: true})
339
+ header=Insert(screen, {type: "frame", layout: "horizontal", width: "fill_container", height: 64, padding: [0, 24], alignItems: "center", justifyContent: "space_between", strokeAlignment: "inner", stroke: "$--border", strokeWidth: {bottom: 1}})
340
+ content=Insert(screen, {type: "frame", layout: "vertical", width: "fill_container", height: "fit_content(736)", padding: 32, gap: 24})
341
+ ```
342
+
343
+ ### Pattern C: Two-Column Layout
344
+
345
+ ```
346
+ ┌─────────────────────┬─────────────┐
347
+ │ │ │
348
+ │ Main (2/3) │ Side (1/3) │
349
+ │ fill_container │ 360px │
350
+ │ │ │
351
+ └─────────────────────┴─────────────┘
352
+ ```
353
+
354
+ Main column (flexible) and side column (fixed):
355
+
356
+ ```javascript
357
+ columns=Insert(content, {type: "frame", layout: "horizontal", width: "fill_container", height: "fill_container(900)", gap: 24})
358
+ mainCol=Insert(columns, {type: "frame", layout: "vertical", width: "fill_container", height: "fit_content(900)", gap: 24})
359
+ sideCol=Insert(columns, {type: "frame", layout: "vertical", width: 360, height: "fit_content(900)", gap: 24})
360
+ ```
361
+
362
+ ### Pattern D: Card Grid
363
+
364
+ ```
365
+ ┌──────────┐ ┌──────────┐ ┌──────────┐
366
+ │ Card 1 │ │ Card 2 │ │ Card 3 │
367
+ └──────────┘ └──────────┘ └──────────┘
368
+ ```
369
+
370
+ ```javascript
371
+ cardGrid=Insert(container, {type: "frame", layout: "horizontal", width: "fill_container", gap: 16})
372
+ for (const label of ["Overview", "Activity", "Revenue"]) {
373
+ card=Insert(cardGrid, {type: "ref", ref: "cardId", width: "fill_container"})
374
+ Update(card+"/titleId", {content: label})
375
+ }
376
+ ```
377
+
378
+ ---
379
+
380
+ ## 11. Common Compositions
381
+
382
+ These snippets combine with screen layout patterns, or work as standalone execute calls after the initial structure is created. Prefer compact JavaScript generation when a composition has repeated items.
383
+
384
+ ### Page Header with Breadcrumbs + Actions
385
+
386
+ Breadcrumbs on the left, action buttons on the right:
387
+
388
+ ```javascript
389
+ pageHeader=Insert(main, {type: "frame", layout: "horizontal", width: "fill_container", justifyContent: "space_between", alignItems: "center"})
390
+ breadcrumbs=Insert(pageHeader, {type: "frame", layout: "horizontal", gap: 0, alignItems: "center"})
391
+ const crumbs = ["Dashboard", "Users"];
392
+ for (const [index, label] of crumbs.entries()) {
393
+ if (index > 0) Insert(breadcrumbs, {type: "ref", ref: "breadcrumbSeparatorId"})
394
+ Insert(breadcrumbs, {type: "ref", ref: index === crumbs.length - 1 ? "breadcrumbItemActiveId" : "breadcrumbItemId", descendants: {"labelId": {content: label}}})
395
+ }
396
+ actions=Insert(pageHeader, {type: "frame", layout: "horizontal", gap: 12})
397
+ for (const [ref, label] of [["buttonOutlineId", "Export"], ["buttonPrimaryId", "Add User"]]) {
398
+ Insert(actions, {type: "ref", ref, descendants: {"iconId": {enabled: false}, "labelId": {content: label}}})
399
+ }
400
+ ```
401
+
402
+ ### Form Layout
403
+
404
+ Two fields in a row, then full-width fields:
405
+
406
+ ```javascript
407
+ card=Insert(container, {type: "ref", ref: "cardId", width: "fill_container"})
408
+ form=Insert(card+"/contentSlotId", {type: "frame", layout: "vertical", gap: 16, width: "fill_container"})
409
+ row=Insert(form, {type: "frame", layout: "horizontal", gap: 16, width: "fill_container"})
410
+ for (const label of ["First Name", "Last Name"]) {
411
+ Insert(row, {type: "ref", ref: "inputGroupId", width: "fill_container", descendants: {"labelId": {content: label}}})
412
+ }
413
+ for (const field of [
414
+ {ref: "inputGroupId", label: "Email"},
415
+ {ref: "textareaGroupId", label: "Message"}
416
+ ]) {
417
+ Insert(form, {type: "ref", ref: field.ref, width: "fill_container", descendants: {"labelId": {content: field.label}}})
418
+ }
419
+ ```
420
+
421
+ ### Metric Cards
422
+
423
+ Replace header with custom metric content, disable unused slots:
424
+
425
+ ```javascript
426
+ metrics=Insert(content, {type: "frame", layout: "horizontal", gap: 16, width: "fill_container"})
427
+ const textBase = {type: "text", fontFamily: "$--font-primary"};
428
+ for (const metric of [
429
+ {label: "Total Users", value: "12,543"},
430
+ {label: "Revenue", value: "$48.2K"},
431
+ {label: "Conversion", value: "7.4%"}
432
+ ]) {
433
+ metricCard=Insert(metrics, {type: "ref", ref: "cardId", width: "fill_container"})
434
+ header=Replace(metricCard+"/headerSlotId", {type: "frame", layout: "vertical", gap: 4, padding: 24, width: "fill_container"})
435
+ Insert(header, {...textBase, content: metric.label, fill: "$--muted-foreground", fontSize: 14})
436
+ Insert(header, {...textBase, content: metric.value, fill: "$--foreground", fontSize: 32, fontWeight: "600"})
437
+ Update(metricCard+"/contentSlotId", {enabled: false})
438
+ Update(metricCard+"/actionsSlotId", {enabled: false})
439
+ }
440
+ ```
441
+
442
+ ---
443
+
444
+ ## 12. Spacing Reference
445
+
446
+ Common spacing values as a starting point:
447
+
448
+ | Context | Gap | Padding |
449
+ |---------|-----|---------|
450
+ | Screen sections | 24-32 | — |
451
+ | Card grid | 16-24 | — |
452
+ | Form fields (vertical) | 16 | — |
453
+ | Form row (horizontal) | 16 | — |
454
+ | Button groups | 12 | — |
455
+ | Inside cards | — | 24 |
456
+ | Inside buttons | — | [10, 16] |
457
+ | Inside inputs | — | [8, 16] |
458
+ | Page content area | — | 32 |
459
+ | Sidebar items | 0 | [12, 16] |
460
+
461
+ ---
462
+
463
+ ## 13. Button Hierarchy
464
+
465
+ A good rule of thumb: one primary action per section helps users focus. Rough priority order:
466
+
467
+ | Priority | Variant | Often used for |
468
+ |----------|---------|---------|
469
+ | 1 | Primary/Default | Main action (Save, Submit, Create) |
470
+ | 2 | Secondary | Alternative actions |
471
+ | 3 | Outline | Tertiary, Cancel, Back |
472
+ | 4 | Ghost | Inline actions, navigation |
473
+ | 5 | Destructive | Delete, Remove |
474
+
475
+ ### Button Actions Alignment
476
+
477
+ Common conventions:
478
+ - **Cards/Modals:** Right-align actions (`justifyContent: "end"`)
479
+ - **Forms:** Right-align submit buttons
480
+ - **Toolbars:** Left-align primary, right-align secondary
481
+ - **Destructive + Cancel:** Cancel on left, Destructive on right
482
+
483
+ ---
484
+
485
+ ## 14. Design Tokens
486
+
487
+ Using design token variables helps keep things consistent:
488
+
489
+ ### Colors
490
+ | Token | Usage |
491
+ |-------|-------|
492
+ | `$--background` | Page background |
493
+ | `$--foreground` | Primary text |
494
+ | `$--muted-foreground` | Secondary text, placeholders |
495
+ | `$--card` | Card backgrounds |
496
+ | `$--border` | Borders, dividers |
497
+ | `$--primary` | Primary actions, brand |
498
+ | `$--secondary` | Secondary elements |
499
+ | `$--destructive` | Danger actions |
500
+
501
+ ### Semantic Colors
502
+ | State | Background | Foreground |
503
+ |-------|------------|------------|
504
+ | Success | `$--color-success` | `$--color-success-foreground` |
505
+ | Warning | `$--color-warning` | `$--color-warning-foreground` |
506
+ | Error | `$--color-error` | `$--color-error-foreground` |
507
+ | Info | `$--color-info` | `$--color-info-foreground` |
508
+
509
+ ### Typography
510
+ | Token | Usage |
511
+ |-------|-------|
512
+ | `$--font-primary` | Headings, labels, navigation |
513
+ | `$--font-secondary` | Body text, descriptions, inputs |
514
+
515
+ ### Border Radius
516
+ | Token | Usage |
517
+ |-------|-------|
518
+ | `$--radius-none` | Tables, sharp containers |
519
+ | `$--radius-m` | Cards, modals |
520
+ | `$--radius-pill` | Buttons, inputs, badges |
521
+
522
+ ---
523
+
524
+ ## 15. Design Principles
525
+
526
+ These principles help ensure designs are grounded, consistent, and maintainable.
527
+
528
+ ### Visual Hierarchy
529
+ - One clear focal point per section
530
+ - Use size, weight, and color to establish importance
531
+ - Primary actions should be visually dominant
532
+
533
+ ### Alignment & Grid
534
+ - Align elements to an implicit grid
535
+ - Use consistent edge alignment within containers
536
+ - Avoid orphaned or floating elements
537
+
538
+ ### Spacing Consistency
539
+ - Always use existing gap/padding values from the design system
540
+ - Don't mix arbitrary spacing values - pick from the established scale
541
+ - Maintain consistent vertical rhythm between sections
542
+
543
+ ### Color Usage
544
+ - Always use `$--variable` tokens, never hardcode hex/rgb values
545
+ - Ensure sufficient contrast for text readability
546
+ - Use semantic colors for their intended purpose (error for errors, etc.)
547
+
548
+ ### Content Density
549
+ - Don't overcrowd - leave breathing room
550
+ - Cards should contain one primary idea
551
+ - Tables should have reasonable column counts (typically 4-7)
552
+
553
+ ### Grounding Rules
554
+ - Get component list via `get_app_state` and then only read the specific components you need via `Print(Get(componentId))` in `execute`
555
+ - Verify with `TakeScreenshot` after major design operations
556
+ - Use existing components before creating custom frames
@@ -0,0 +1,31 @@
1
+ # Landing Page Design Guidelines
2
+
3
+ ---
4
+
5
+ ## Purpose
6
+
7
+ **Conversion intent.** Drive one action — sign up, buy, request a demo. Make every element move the visitor toward that action. Remove everything that doesn't.
8
+
9
+ **Transformation over features.** Show the outcome, not the tool. Visitors buy a better version of themselves — show them who they become.
10
+
11
+ ## Content
12
+
13
+ **Hero = the entire pitch compressed.** Compress the entire pitch into the first screen. Communicate what this is, why it matters, and what to do next. Use one idea, one headline, one call to action.
14
+
15
+ **Headline strength.** Lead with the strongest headline form. Transformation ("Finally feel in control") beats outcome ("Ship faster"), which beats benefit ("Write 10x faster"), which beats feature ("AI writing assistant").
16
+
17
+ **Imagery.** Show scenes from the visitor's future — people in the outcome state, not product screenshots in isolation. Always add a contrast treatment when placing text over images — overlay, shadow, or text in its own container. Never stretch or distort.
18
+
19
+ **Color for conversion.** Make the CTA the most prominent element on the page. Reserve the accent color for actions — don't dilute it across decorative elements. Ensure sufficient contrast for all text against its background.
20
+
21
+ ## Structure
22
+
23
+ **Composition.** Pick one alignment axis per section — never mix left-aligned and centered content in the same section. Group related elements tightly, separate groups generously — proximity signals relationship.
24
+
25
+ **Rhythm.** Alternate between text-heavy and visual sections. Never stack sections with similar density. Use dark sections for credibility and depth, light sections for explanation and detail.
26
+
27
+ **Typography.** Never set body text below 14px. Choose a typographic scale with clear size jumps between hierarchy levels. Don't center-align more than 2-3 lines of text. Keep body copy line length to 50-75 characters.
28
+
29
+ **Section flow.** Build a narrative arc — promise, proof, action. Move from what it is, to why it works, to why you should trust it, to what to do next.
30
+
31
+ **Content before visuals.** Define the narrative and messaging before making visual decisions. Let the words drive the design, not the other way around.
@@ -0,0 +1,31 @@
1
+ # MOBILE APP SCREEN COMPOSITION
2
+
3
+ You design mobile app screens that feel modern, premium, and easy to scan. Prioritize clarity, hierarchy, and touch ergonomics.
4
+
5
+ ## Layout Structure
6
+
7
+ Ensure the screen is vertically resized to fit the content. The screen should not match the real device height. Use a vertical layout with fit_content(844) height.
8
+ Start with the status bar and the tab bar first, only then fill in the content.
9
+
10
+ 1. **Status Bar** — OS chrome (time, signal, battery). Height 62 px, content vertically centered, "Inter" font. Never place app UI behind it.
11
+ 2. **Content Wrapper** — all app content lives in one wrapper with consistent left/right padding (16–20 px) applied once. Use gap-based vertical spacing between sections (24–32 px major, 12–16 px related items).
12
+ 3. **Tab Bar** (optional) — a bottom-anchored, capsule-ended tab bar for switching between top-level destinations.
13
+
14
+ ## Tab Bar
15
+
16
+ A bottom-anchored, capsule-ended tab bar — the iOS "Liquid Glass" look. Use for 3–5 top-level destinations.
17
+
18
+ - **Bar**: floats inset from the screen edges — ~16 px on the sides, ~12 px above the bottom — never flush. ~56 px tall, corner radius = half the height (true capsule ends), ~6 px inner padding. Frosted glass — fill at 70% opacity, soft shadow.
19
+ - **Items**: rounded icon (~22 px) above a label (10 px, sentence case), centered.
20
+ - **Selected**: accent-tinted icon + label on a soft capsule highlight, filled icon variant. Inactive: muted neutral, unfilled.
21
+ - Make it the last item in the screen's vertical stack — never absolutely positioned. Give that stack ~12 px bottom padding so the capsule clears the edge.
22
+
23
+ ## Rules
24
+
25
+ - One primary intent per screen. Everything else is subordinate.
26
+ - The first 1–2 elements answer "where am I" and "what can I do here".
27
+ - Use the same title font size on every screen — titles must look uniform app-wide.
28
+ - Keep key actions reachable in the lower half for one-handed use.
29
+ - Touch targets need comfortable hit areas.
30
+ - Let the wrapper handle horizontal padding — don't add per-section padding.
31
+ - Use the wrapper's gap for spacing and bottom padding (same value as gap) for empty space — never spacer elements.