tsquare 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +24 -0
- package/README.md +135 -0
- package/bin/tsquare.js +7 -0
- package/package.json +68 -0
- package/skill/tsquare/SKILL.md +87 -0
- package/skill/tsquare/reference.md +196 -0
- package/src/catalog.ts +329 -0
- package/src/cli.ts +75 -0
- package/src/colors.ts +82 -0
- package/src/compile.ts +64 -0
- package/src/components.tsx +1057 -0
- package/src/icons.ts +54 -0
- package/src/index.ts +11 -0
- package/src/layout.ts +63 -0
- package/src/print.ts +73 -0
- package/src/prompt-example.ts +43 -0
- package/src/prompt.ts +121 -0
- package/src/render.ts +178 -0
- package/src/schema.ts +43 -0
- package/src/suggest.ts +34 -0
- package/src/text.ts +333 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Vogeleer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The Inter font (the @fontsource/inter dependency) is licensed separately under
|
|
24
|
+
the SIL Open Font License 1.1.
|
package/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<p align="center"><img src="https://raw.githubusercontent.com/tsquare-js/tsquare/main/assets/logo.png" alt="tsquare" width="160"></p>
|
|
2
|
+
|
|
3
|
+
# tsquare
|
|
4
|
+
|
|
5
|
+
Wireframes in plain text: easy for LLMs to write, fast to render as SVG or PNG. A small text language for low-fidelity screens, with several devices side by side and notes beside them. Built for LLMs to write: the prompt comes from the component catalog, and errors come back with line numbers so a model can fix its own output.
|
|
6
|
+
|
|
7
|
+
```tsquare
|
|
8
|
+
board "Login"
|
|
9
|
+
screen phone "Sign in"
|
|
10
|
+
heading "Welcome back"
|
|
11
|
+
input "Email" placeholder="you@example.com"
|
|
12
|
+
input password "Password"
|
|
13
|
+
checkbox "Remember me" checked
|
|
14
|
+
button primary "Sign in" fullWidth
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Save that as `login.tsq`, then:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx tsquare render login.tsq -o login.png --scale 2
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires Node 20 or newer. To work on tsquare itself, clone the repo, run `npm install`, and use `npm run render -- examples/notes-mobile.tsq -o notes.png --scale 2`.
|
|
24
|
+
|
|
25
|
+
## Docs
|
|
26
|
+
|
|
27
|
+
[Getting started](docs/getting-started.md) · [The language](docs/language.md) · [Components](docs/components/README.md) · [Icons](docs/icons.md) · [Colors](docs/colors.md) · [Using it with AI](docs/ai.md)
|
|
28
|
+
|
|
29
|
+
## Playground
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run playground # http://localhost:4321
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **Editor:** live render as you type, problems listed by line (click one to jump there), and SVG/PNG export. Paste a whole model reply and it keeps just the code block.
|
|
36
|
+
- **Components:** every component with its props and a rendered example you can open in the editor. It's generated from the catalog, so it can't drift from what the renderer accepts.
|
|
37
|
+
- **Prompt:** the system prompt for models, with a copy button.
|
|
38
|
+
|
|
39
|
+
It renders on a local Node server using the same code as the CLI.
|
|
40
|
+
|
|
41
|
+
## The language
|
|
42
|
+
|
|
43
|
+
One element per line; children are indented two spaces under their parent. The first line is the board.
|
|
44
|
+
|
|
45
|
+
| You write | It means |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `button "Sign in"` | a quoted string sets the main text (label, title, text…) |
|
|
48
|
+
| `button primary lg` | bare words set options: `phone`, `desktop`, `primary`, `ghost`, `row`, `sm`, `left`, `bottom`, `password`… |
|
|
49
|
+
| `checkbox checked`, `toggle off` | a prop name turns a boolean on; `off` / `unchecked` / `no-<prop>` turn it off |
|
|
50
|
+
| `stack width=240 gap=8` | `key=value` sets any prop |
|
|
51
|
+
| `tabs items=[All notes, Pinned]` | lists in `[ ]`, items separated by commas; an item can contain spaces |
|
|
52
|
+
| `data=[["$1,200", "Smith, J"]]` | quote an item that contains a comma (`\"` for a quote inside quotes) |
|
|
53
|
+
| `tabbar items=[{label=Home icon=home}]` | objects in `{ }` |
|
|
54
|
+
| `# note to self` | comment |
|
|
55
|
+
|
|
56
|
+
If a bare word could mean two props (for example `start`, which is both an `align` and a `justify` value), write it as `key=value`. Code fences (```` ``` ````) are ignored, so a model's reply can be rendered as-is.
|
|
57
|
+
|
|
58
|
+
**Structure**
|
|
59
|
+
|
|
60
|
+
- The top element is a **board**. Its children are **screens**, plus optional **notes** beside them.
|
|
61
|
+
- A screen stacks its children vertically. A **navbar** is pinned to the top and a **tabbar** to the bottom.
|
|
62
|
+
- **modal** and **drawer** are overlays and must be direct children of a screen.
|
|
63
|
+
|
|
64
|
+
## Colors
|
|
65
|
+
|
|
66
|
+
Wireframes are grayscale. There are three deliberate exceptions in the UI itself:
|
|
67
|
+
|
|
68
|
+
| You write | It colors |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `board "App" accent=blue` | primary buttons, solid badges, checked checkboxes and radios, toggles that are on, the active tab and tab-bar item, ghost button text |
|
|
71
|
+
| `badge "Failed" tone=danger` | one badge: `success`, `warning` or `danger` |
|
|
72
|
+
| `input "Email" error helper="Required"` | the field's border and helper text, in red |
|
|
73
|
+
|
|
74
|
+
`accent` takes `blue`, `indigo`, `violet`, `pink`, `red`, `orange`, `green` or `teal`, or a hex color like `#1a73e8`. With a light hex color, text on it switches to dark and accent-colored text is darkened so it stays readable. There are no other UI color props, on purpose.
|
|
75
|
+
|
|
76
|
+
Sticky notes beside the wireframe have their own colors, since they're annotations rather than part of the UI: `note "TBD" color=pink` (`yellow` is the default, plus `blue`, `pink` and `green`). See [Colors](docs/colors.md) for more.
|
|
77
|
+
|
|
78
|
+
## Components
|
|
79
|
+
|
|
80
|
+
| Group | Components |
|
|
81
|
+
|---|---|
|
|
82
|
+
| Canvas | board, screen (`phone` 390×844, `tablet` 820×1180, `desktop` 1280×800, `custom`), note |
|
|
83
|
+
| Layout | stack, grid, card, divider, spacer |
|
|
84
|
+
| Content | heading, text (`lines=3` draws placeholder lines), image (X-box placeholder), icon (any [Lucide](https://lucide.dev/icons) name, see [Icons](docs/icons.md)), avatar, badge |
|
|
85
|
+
| Controls | button, input (`multiline=4` for a textarea), checkbox, radio, toggle, select |
|
|
86
|
+
| Navigation & data | navbar, tabbar, tabs, list, listitem, table |
|
|
87
|
+
| Overlays | modal, drawer (`left`, `right`, `bottom` sheet) |
|
|
88
|
+
|
|
89
|
+
Each component has its own page with a rendered example and its props: see [Components](docs/components/README.md).
|
|
90
|
+
|
|
91
|
+
## CLI
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
tsquare render <file.tsq|-> [-o out.svg|out.png] [--scale 2]
|
|
95
|
+
tsquare check <file.tsq|-> # problems by line number
|
|
96
|
+
tsquare fmt <file.tsq|-> [-w] # canonical formatting (drops comments)
|
|
97
|
+
tsquare prompt # system prompt for models
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Use `-` to read from stdin. In this repo, run them through npm: `npm run check -- file.tsq`. Files use the `.tsq` extension; the CLI reads any text file.
|
|
101
|
+
|
|
102
|
+
## Using it with Claude (skill)
|
|
103
|
+
|
|
104
|
+
`skill/tsquare/` is a Claude skill: the syntax, the component reference, and a workflow of write → `tsquare check` → `tsquare render` → look at the PNG and fix. Copy it to `~/.claude/skills/tsquare` (all projects) or `<project>/.claude/skills/tsquare`, and make the `tsquare` command available (`npm link` in this repo). Rebuild it after catalog changes with `npm run skill`.
|
|
105
|
+
|
|
106
|
+
## How it works
|
|
107
|
+
|
|
108
|
+
Text is parsed into a [json-render](https://github.com/vercel-labs/json-render) spec and validated against Zod schemas. It's then laid out and drawn by [Satori](https://github.com/vercel/satori) into SVG; PNG output goes through resvg.
|
|
109
|
+
|
|
110
|
+
| File | Contents |
|
|
111
|
+
|---|---|
|
|
112
|
+
| `src/text.ts` | parser |
|
|
113
|
+
| `src/print.ts` | formatter (spec → text) |
|
|
114
|
+
| `src/compile.ts` | parse + validate with line numbers, `renderWireframe` |
|
|
115
|
+
| `src/prompt.ts` | model prompt, generated from the catalog |
|
|
116
|
+
| `src/catalog.ts` | components and their props |
|
|
117
|
+
| `src/components.tsx` | Satori renderers |
|
|
118
|
+
| `src/render.ts` | validation, board sizing, SVG/PNG |
|
|
119
|
+
| `src/layout.ts` | colors, device sizes, spacing |
|
|
120
|
+
|
|
121
|
+
## Measured
|
|
122
|
+
|
|
123
|
+
How often models write valid tsquare on the first try, with no repair round:
|
|
124
|
+
|
|
125
|
+
| | Sonnet | Haiku |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| Valid on the first try (20 requests) | 100% | 85% |
|
|
128
|
+
| Median tokens per wireframe (JSON took about 4× as many) | 184 | 210 |
|
|
129
|
+
| Color checks passed (7 requests) | 11/11 | 11/11 |
|
|
130
|
+
|
|
131
|
+
How it was measured, the tasks, every model output, and the scripts: [`eval/`](eval/).
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT. The Inter font comes from the `@fontsource/inter` dependency, under the SIL Open Font License 1.1. Icons are from [Lucide](https://lucide.dev), under the ISC license.
|
package/bin/tsquare.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tsquare",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Wireframes in plain text: easy for LLMs to write, fast to render as SVG or PNG.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"wireframe",
|
|
7
|
+
"mockup",
|
|
8
|
+
"ui",
|
|
9
|
+
"diagram",
|
|
10
|
+
"llm",
|
|
11
|
+
"ai",
|
|
12
|
+
"svg",
|
|
13
|
+
"text-to-diagram",
|
|
14
|
+
"claude"
|
|
15
|
+
],
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/tsquare-js/tsquare.git"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/tsquare-js/tsquare#readme",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/tsquare-js/tsquare/issues"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"tsquare": "bin/tsquare.js"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"bin/",
|
|
31
|
+
"src/",
|
|
32
|
+
"skill/tsquare/",
|
|
33
|
+
"LICENSE",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"render": "tsx src/cli.ts render",
|
|
41
|
+
"check": "tsx src/cli.ts check",
|
|
42
|
+
"fmt": "tsx src/cli.ts fmt",
|
|
43
|
+
"prompt": "tsx src/cli.ts prompt",
|
|
44
|
+
"playground": "tsx playground/server.ts",
|
|
45
|
+
"skill": "tsx skill/build.ts",
|
|
46
|
+
"docs": "tsx docs/build.ts",
|
|
47
|
+
"typecheck": "tsc",
|
|
48
|
+
"examples": "for f in examples/*.tsq; do tsx src/cli.ts render $f -o ${f%.tsq}.png --scale 2; done",
|
|
49
|
+
"eval:prompts": "tsx eval/prompts.ts",
|
|
50
|
+
"eval:score": "tsx eval/score.ts"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@fontsource/inter": "5.3.0",
|
|
54
|
+
"@json-render/core": "^0.21.0",
|
|
55
|
+
"@json-render/image": "^0.21.0",
|
|
56
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
57
|
+
"lucide": "1.48.0",
|
|
58
|
+
"react": "^19.3.0",
|
|
59
|
+
"tsx": "^4.23.15",
|
|
60
|
+
"zod": "^4.6.5"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/node": "^26.6.3",
|
|
64
|
+
"@types/react": "^19.3.0",
|
|
65
|
+
"gpt-tokenizer": "^4.0.0",
|
|
66
|
+
"typescript": "^7.0.2"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tsquare
|
|
3
|
+
description: Create low-fidelity UI wireframes and mockups (app screens, several devices side by side, boards for specs and docs) as tsquare text, then render them to PNG or SVG with the tsquare CLI. Use when asked to wireframe, mock up or sketch a UI screen, page or flow, or to add a UI mockup to a document.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# tsquare wireframes
|
|
7
|
+
|
|
8
|
+
tsquare is a small text language for UI wireframe boards. You write a `.tsq` file; the `tsquare` CLI checks it and renders it to a clean, grayscale PNG or SVG.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. **Write** the wireframe to `<name>.tsq`, following the syntax below. Every component and prop is listed in [reference.md](reference.md); read it before using a component you haven't used yet.
|
|
13
|
+
2. **Check:** `tsquare check <name>.tsq`. It lists problems by line, with the valid options or a "did you mean". Fix every one and check again until it says the file is valid.
|
|
14
|
+
3. **Render:** `tsquare render <name>.tsq -o <name>.png --scale 2` (use `-o <name>.svg` for docs that take SVG).
|
|
15
|
+
4. **Look at the PNG** before showing it. The checker can't see layout, so check for:
|
|
16
|
+
- content cut off at the bottom of a screen (screens have a fixed height; nothing warns about clipping). Remove content, split it into another screen, or use `device=custom` with a larger `height`.
|
|
17
|
+
- cramped rows, or text squeezed into narrow columns.
|
|
18
|
+
- anything the request asked for that's missing.
|
|
19
|
+
Fix the `.tsq` and render again.
|
|
20
|
+
5. **Deliver** the image path and the `.tsq` source, so the user can edit it later.
|
|
21
|
+
|
|
22
|
+
If `tsquare` isn't found, stop and ask the user how it's installed. From a checkout of the repo, `npm link` makes the command available.
|
|
23
|
+
|
|
24
|
+
## Keep in mind
|
|
25
|
+
|
|
26
|
+
- One wireframe is one **board**: several **screens** side by side (phone, tablet, desktop or custom sizes), plus **notes** beside them. Show states or steps of a flow as separate screens.
|
|
27
|
+
- Wireframes are low fidelity: placeholders (`image`, `text lines=3`) beat invented copy, unless the copy matters.
|
|
28
|
+
- Stay grayscale unless the user asks for color or a brand. Then set `accent` on the board; don't look for other color props, there aren't any.
|
|
29
|
+
|
|
30
|
+
## Output format: wireframe text
|
|
31
|
+
One element per line. Indent children two spaces under their parent. The first line is the board.
|
|
32
|
+
|
|
33
|
+
A line is the component name in lowercase, followed by arguments separated by spaces:
|
|
34
|
+
- "a quoted string" sets the component's main text prop (marked "main text" in reference.md)
|
|
35
|
+
- a bare word that is one of the component's option values sets that option: phone, desktop, primary, ghost, row, sm, left, bottom, password, …
|
|
36
|
+
- a bare prop name sets a boolean prop to true: checked, fullWidth, grow, muted. `off` and `unchecked` set on/checked to false
|
|
37
|
+
- key=value sets any prop. Values: "string", number, true/false, bare word, [list, of, values], {key=value key=value}
|
|
38
|
+
- # starts a comment
|
|
39
|
+
|
|
40
|
+
Lists: items are separated by commas, and an item can contain spaces without quotes: [All notes, Pinned, Shared]. To put a comma inside an item, quote the item: ["$1,200", "Smith, J"]. Inside quotes, write \" for a quote character. Numbers in a list of text are fine: [2023, 2024].
|
|
41
|
+
|
|
42
|
+
If a bare word could mean more than one prop, write it as key=value.
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
1. The top element is a Board. The Board's children are Screens, plus optional Notes beside them.
|
|
46
|
+
2. Each Screen is one view of the product. Use several Screens to show several views or states.
|
|
47
|
+
3. A Screen lays out its children top to bottom. Use Stack (direction row or column) and Grid to arrange content.
|
|
48
|
+
4. NavBar is pinned to the top of its Screen and TabBar to the bottom.
|
|
49
|
+
5. Modal and Drawer are overlays. They must be direct children of a Screen.
|
|
50
|
+
6. This is a low-fidelity wireframe. Prefer placeholders (Image boxes, Text with lines) over invented copy unless the copy matters.
|
|
51
|
+
7. Only use the components and props listed below. All props are optional unless marked required.
|
|
52
|
+
8. Wireframes are grayscale. The only UI colors: Board accent (one color for primary buttons, checked controls, toggles, active tabs and ghost buttons), Badge tone (success, warning, danger) and Input error. Only add an accent if the request asks for color or a brand.
|
|
53
|
+
|
|
54
|
+
## Example
|
|
55
|
+
|
|
56
|
+
Request: Two phone screens for a recipe app: a browse screen with search, category tabs, a grid of recipe cards and a tab bar; and a recipe detail screen with its options sheet open.
|
|
57
|
+
|
|
58
|
+
```tsquare
|
|
59
|
+
board "Recipe app"
|
|
60
|
+
screen phone "Browse"
|
|
61
|
+
navbar "Recipes" leading=menu actions=[bell]
|
|
62
|
+
input search placeholder="Search recipes"
|
|
63
|
+
tabs items=[All, Quick, Vegetarian] active=0
|
|
64
|
+
grid columns=2 gap=12
|
|
65
|
+
card padding=10
|
|
66
|
+
image height=110
|
|
67
|
+
text "Tomato soup" bold
|
|
68
|
+
text sm "25 min" muted
|
|
69
|
+
card padding=10
|
|
70
|
+
image height=110
|
|
71
|
+
text lines=2
|
|
72
|
+
tabbar items=[{label=Browse icon=book-open}, {label=Saved icon=heart}, {label=Profile icon=user}] active=0
|
|
73
|
+
screen phone "Recipe"
|
|
74
|
+
navbar leading=back actions=[share, more-horizontal]
|
|
75
|
+
image "Photo" height=200
|
|
76
|
+
heading "Tomato soup" level=1
|
|
77
|
+
stack row gap=8
|
|
78
|
+
badge outline "25 min"
|
|
79
|
+
badge outline "Vegan"
|
|
80
|
+
text lines=4
|
|
81
|
+
button primary "Start cooking" fullWidth
|
|
82
|
+
drawer bottom "Options" size=260
|
|
83
|
+
toggle "Metric units" on
|
|
84
|
+
select "Servings" value="4"
|
|
85
|
+
checkbox "Add to shopping list"
|
|
86
|
+
note "Detail screen shown with the options sheet open."
|
|
87
|
+
```
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# tsquare components
|
|
2
|
+
|
|
3
|
+
Every component and its props, generated from the catalog. All props are optional unless marked required. "main text" is the prop a quoted string fills.
|
|
4
|
+
|
|
5
|
+
### Board
|
|
6
|
+
Root canvas (artboard). Holds Screens side by side, plus optional Notes. Must be the root element.
|
|
7
|
+
- title: string (main text)
|
|
8
|
+
- layout: "row" | "grid" — row = all screens side by side; grid = wrap every `columns` screens
|
|
9
|
+
- columns: number
|
|
10
|
+
- gap: number
|
|
11
|
+
- padding: number
|
|
12
|
+
- accent: string — The one UI color: primary buttons, solid badges, checked controls, toggles, active tabs, ghost buttons. blue, indigo, violet, pink, red, orange, green, teal, or a hex color like #1a73e8. Omit for grayscale.
|
|
13
|
+
|
|
14
|
+
### Screen
|
|
15
|
+
One view of the product in a device frame. Children stack vertically.
|
|
16
|
+
- name: string (main text) — Label shown above the screen
|
|
17
|
+
- device: "phone" | "tablet" | "desktop" | "custom"
|
|
18
|
+
- width: number — Only for device=custom
|
|
19
|
+
- height: number — Only for device=custom
|
|
20
|
+
- chrome: boolean — Phone status bar / desktop browser bar. Default true for phone and desktop.
|
|
21
|
+
- padding: number
|
|
22
|
+
- gap: number
|
|
23
|
+
|
|
24
|
+
### Note
|
|
25
|
+
Sticky-note annotation. Put it on the Board beside screens, or inside a Screen next to what it explains.
|
|
26
|
+
- text (required): string (main text)
|
|
27
|
+
- color: "yellow" | "blue" | "pink" | "green"
|
|
28
|
+
- width: number
|
|
29
|
+
|
|
30
|
+
### Stack
|
|
31
|
+
Flex container. The main layout primitive (rows, columns, sidebars, toolbars).
|
|
32
|
+
- direction: "row" | "column"
|
|
33
|
+
- gap: number
|
|
34
|
+
- padding: number
|
|
35
|
+
- align: "start" | "center" | "end" | "stretch"
|
|
36
|
+
- justify: "start" | "center" | "end" | "between" | "around"
|
|
37
|
+
- wrap: boolean
|
|
38
|
+
- grow: boolean — Fill remaining space in the parent
|
|
39
|
+
- width: number | string — Fixed width, e.g. 240 for a sidebar
|
|
40
|
+
- border: "none" | "right" | "left" | "top" | "bottom" | "all"
|
|
41
|
+
- fill: boolean — Light gray background
|
|
42
|
+
|
|
43
|
+
### Grid
|
|
44
|
+
Equal-width columns that wrap. Good for card grids and galleries.
|
|
45
|
+
- columns (required): number
|
|
46
|
+
- gap: number
|
|
47
|
+
- padding: number
|
|
48
|
+
|
|
49
|
+
### Card
|
|
50
|
+
Bordered container with optional title. Children stack vertically.
|
|
51
|
+
- title: string (main text)
|
|
52
|
+
- padding: number
|
|
53
|
+
- gap: number
|
|
54
|
+
- variant: "outline" | "filled"
|
|
55
|
+
- grow: boolean
|
|
56
|
+
- width: number | string — Fixed width, e.g. 320. Default fills the space.
|
|
57
|
+
|
|
58
|
+
### Divider
|
|
59
|
+
Thin separator line.
|
|
60
|
+
- vertical: boolean
|
|
61
|
+
|
|
62
|
+
### Spacer
|
|
63
|
+
Empty space. Without a size it grows to push siblings apart.
|
|
64
|
+
- size: number — Fixed size in px. Omit to fill remaining space.
|
|
65
|
+
|
|
66
|
+
### Heading
|
|
67
|
+
Heading text, level 1 (largest) to 3.
|
|
68
|
+
- text (required): string (main text)
|
|
69
|
+
- level: 1 | 2 | 3
|
|
70
|
+
- align: "left" | "center" | "right"
|
|
71
|
+
|
|
72
|
+
### Text
|
|
73
|
+
Body text, or placeholder lines when `lines` is set and `text` is not.
|
|
74
|
+
- text: string (main text)
|
|
75
|
+
- lines: number — Draw N placeholder lines instead of real text
|
|
76
|
+
- size: "sm" | "md" | "lg"
|
|
77
|
+
- muted: boolean
|
|
78
|
+
- bold: boolean
|
|
79
|
+
- align: "left" | "center" | "right"
|
|
80
|
+
|
|
81
|
+
### Image
|
|
82
|
+
Image placeholder: a box with an X through it.
|
|
83
|
+
- height: number
|
|
84
|
+
- width: number | string — Default fills the container width
|
|
85
|
+
- label: string (main text)
|
|
86
|
+
- rounded: boolean
|
|
87
|
+
|
|
88
|
+
### Icon
|
|
89
|
+
Line icon from Lucide.
|
|
90
|
+
- name: string (main text) — Lucide icon name in kebab-case, e.g. menu, search, arrow-left, settings, bell, user
|
|
91
|
+
- size: number
|
|
92
|
+
|
|
93
|
+
### Avatar
|
|
94
|
+
Round avatar with initials or a person silhouette.
|
|
95
|
+
- initials: string (main text)
|
|
96
|
+
- size: number
|
|
97
|
+
|
|
98
|
+
### Badge
|
|
99
|
+
Small pill label for counts or statuses.
|
|
100
|
+
- label (required): string (main text)
|
|
101
|
+
- variant: "solid" | "outline"
|
|
102
|
+
- tone: "neutral" | "success" | "warning" | "danger" — Status color. Default neutral (the accent for solid badges)
|
|
103
|
+
|
|
104
|
+
### Button
|
|
105
|
+
Button. Primary is filled, secondary is outlined, ghost is text only.
|
|
106
|
+
- label: string (main text)
|
|
107
|
+
- variant: "primary" | "secondary" | "ghost"
|
|
108
|
+
- size: "sm" | "md" | "lg"
|
|
109
|
+
- icon: string — Lucide icon name in kebab-case, e.g. menu, search, arrow-left, settings, bell, user
|
|
110
|
+
- fullWidth: boolean
|
|
111
|
+
|
|
112
|
+
### Input
|
|
113
|
+
Text field with optional label. Set multiline for a textarea.
|
|
114
|
+
- label: string (main text)
|
|
115
|
+
- placeholder: string
|
|
116
|
+
- value: string
|
|
117
|
+
- type: "text" | "password" | "search" | "email"
|
|
118
|
+
- multiline: number — Number of rows; 2 or more makes a textarea
|
|
119
|
+
- helper: string
|
|
120
|
+
- error: boolean — Validation error: red border and red helper text
|
|
121
|
+
- grow: boolean — Fill the remaining space in a row
|
|
122
|
+
- width: number | string — Fixed width, e.g. 320. Default fills the space.
|
|
123
|
+
|
|
124
|
+
### Checkbox
|
|
125
|
+
Checkbox with label.
|
|
126
|
+
- label: string (main text)
|
|
127
|
+
- checked: boolean
|
|
128
|
+
|
|
129
|
+
### Radio
|
|
130
|
+
Radio button with label.
|
|
131
|
+
- label: string (main text)
|
|
132
|
+
- checked: boolean
|
|
133
|
+
|
|
134
|
+
### Toggle
|
|
135
|
+
On/off switch with label on the left.
|
|
136
|
+
- label: string (main text)
|
|
137
|
+
- on: boolean
|
|
138
|
+
|
|
139
|
+
### Select
|
|
140
|
+
Dropdown field (closed state).
|
|
141
|
+
- label: string (main text)
|
|
142
|
+
- value: string
|
|
143
|
+
- placeholder: string
|
|
144
|
+
- width: number | string — Fixed width, e.g. 320. Default fills the space.
|
|
145
|
+
|
|
146
|
+
### NavBar
|
|
147
|
+
Top app bar. Place first in a Screen.
|
|
148
|
+
- title: string (main text)
|
|
149
|
+
- leading: "none" | "menu" | "back" | "close" | "logo"
|
|
150
|
+
- actions: array of string — Icon names shown on the right
|
|
151
|
+
- align: "left" | "center"
|
|
152
|
+
|
|
153
|
+
### TabBar
|
|
154
|
+
Bottom tab bar for mobile. Place last in a Screen (before overlays).
|
|
155
|
+
- items (required): array of { label: string, icon: string }
|
|
156
|
+
- active: number
|
|
157
|
+
|
|
158
|
+
### Tabs
|
|
159
|
+
In-page tabs with an underline on the active one.
|
|
160
|
+
- items (required): array of string
|
|
161
|
+
- active: number
|
|
162
|
+
|
|
163
|
+
### List
|
|
164
|
+
Vertical list of ListItems.
|
|
165
|
+
- dividers: boolean
|
|
166
|
+
- grow: boolean
|
|
167
|
+
|
|
168
|
+
### ListItem
|
|
169
|
+
Row in a List. Omit title for a placeholder bar.
|
|
170
|
+
- title: string (main text)
|
|
171
|
+
- subtitle: string
|
|
172
|
+
- leading: "none" | "icon" | "avatar" | "image" | "checkbox"
|
|
173
|
+
- icon: string — Lucide icon name in kebab-case, e.g. menu, search, arrow-left, settings, bell, user
|
|
174
|
+
- trailing: "none" | "chevron" | "toggle" | "text" | "badge" | "icon"
|
|
175
|
+
- trailingText: string
|
|
176
|
+
- trailingIcon: string — Lucide icon name in kebab-case, e.g. menu, search, arrow-left, settings, bell, user
|
|
177
|
+
|
|
178
|
+
### Table
|
|
179
|
+
Table with headers. Rows are placeholder bars unless `data` is given.
|
|
180
|
+
- columns (required): array of string
|
|
181
|
+
- rows: number — Placeholder rows when `data` is not given
|
|
182
|
+
- data: array of array of string
|
|
183
|
+
|
|
184
|
+
### Modal
|
|
185
|
+
Centered dialog over the screen. Must be a direct child of a Screen, listed last.
|
|
186
|
+
- title: string (main text)
|
|
187
|
+
- width: number
|
|
188
|
+
- scrim: boolean — Dim the screen behind. Default true.
|
|
189
|
+
|
|
190
|
+
### Drawer
|
|
191
|
+
Panel sliding in from an edge: side nav (left), filters/details (right), or bottom sheet. Must be a direct child of a Screen, listed last.
|
|
192
|
+
- side: "left" | "right" | "bottom"
|
|
193
|
+
- title: string (main text)
|
|
194
|
+
- size: number — Width for left/right, height for bottom
|
|
195
|
+
- scrim: boolean — Dim the screen behind. Default true.
|
|
196
|
+
- handle: boolean — Grab handle on bottom sheets. Default true for bottom.
|