@cs4alhaider/screenbook 0.1.0 → 0.2.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/AGENTS.md +147 -0
- package/CLAUDE.md +4 -184
- package/README.md +140 -162
- package/bridge.js +1 -1
- package/cli/screenbook.js +67 -28
- package/cli/templates.js +54 -1
- package/core/browser.js +22 -7
- package/core/project.js +28 -7
- package/core/serve.js +22 -7
- package/docs/authoring-guide.md +1 -1
- package/docs/cli.md +9 -5
- package/docs/getting-started.md +27 -23
- package/docs/mcp-agents.md +3 -3
- package/docs/shots/rtl-arabic.png +0 -0
- package/examples/qahwa/features/order/screens/010-menu.html +1 -1
- package/examples/qahwa/features/order/screens/020-drink.html +1 -1
- package/examples/qahwa/features/order/screens/030-cart.html +1 -1
- package/examples/qahwa/features/order/screens/040-status.html +1 -1
- package/examples/qahwa/features/order/screens/050-status-android.html +1 -1
- package/examples/qahwa/features/roastery/screens/010-orders.html +1 -1
- package/examples/qahwa/features/roastery/screens/020-menu-editor.html +1 -1
- package/examples/spa-demo/app/index.html +1 -1
- package/examples/tokens-lab/features/lab/screens/010-swatches.html +1 -1
- package/examples/tokens-lab/features/lab/screens/020-typography.html +1 -1
- package/mcp/server.js +2 -2
- package/package.json +3 -2
- package/shell/screenhost.js +1 -1
- package/shell/selftest.js +6 -2
- package/shell/shell.css +17 -9
- package/skill/SKILL.md +1 -1
- package/skill/references/cli-mcp.md +1 -1
- package/skill/references/screen-contract.md +1 -1
package/README.md
CHANGED
|
@@ -1,208 +1,186 @@
|
|
|
1
1
|
# ⧉ ScreenBook
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Your local design studio for prototyping real products with AI agents — offline, versioned, and owned by you.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
device
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
ScreenBook turns a folder on your machine into a professional prototyping studio: every screen
|
|
6
|
+
of your product rendered inside real device frames — iPhone, Android, browser — with live mock
|
|
7
|
+
data, dark mode, right-to-left languages, guided demo walkthroughs, and a built-in design-review
|
|
8
|
+
workflow. AI agents build and revise the screens through a standard interface; you and your
|
|
9
|
+
stakeholders review, comment, and approve. When a screen is final, you hand that same file to
|
|
10
|
+
your agent and say: *now build the native version.*
|
|
10
11
|
|
|
11
|
-

|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
grows into a hand-rolled single-page app, and after a month you have a 20k-line runtime where
|
|
17
|
-
**an agent can't touch one screen without reading the whole world** — and neither can you.
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g @cs4alhaider/screenbook
|
|
16
|
+
```
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
## Why I built this
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
| Hard-coded demo data | **Seed + scenario overlays** with `{{today±N}}` date tokens — "mid-trip today" is literally today. |
|
|
27
|
-
| CSS forks per restyle | **Design tokens as JSON themes**, flattened to CSS variables, dark mode as a delta. |
|
|
28
|
-
| "Trust me, it works" | **A self-test gate**: every screen × theme × light/dark × LTR/RTL must render with zero console errors. |
|
|
20
|
+
I design and ship products with AI agents every day. The prototyping phase kept failing me in
|
|
21
|
+
the same way: designs lived inside chat windows. A concept would look great in a conversation,
|
|
22
|
+
and then reality arrived — I needed *forty* screens, not one. I needed to see the empty state
|
|
23
|
+
and the busy state. I needed Arabic right-to-left and dark mode. I needed my co-founder to
|
|
24
|
+
point at a button and say "this one, move it." I needed all of it next week, again, revised.
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
Chat canvases aren't built for that. Every iteration re-generates a wall of code inside a
|
|
27
|
+
conversation that will eventually scroll away. Nothing is versioned. Nothing runs offline.
|
|
28
|
+
Reviews happen in screenshots over WhatsApp. And when the design is finally "done," it's
|
|
29
|
+
trapped — there's no clean way to hand it to the next stage of work.
|
|
34
30
|
|
|
35
|
-
|
|
31
|
+
So I built the thing I needed: a studio where **screens are plain files on my disk**, agents
|
|
32
|
+
do the labor, humans do the taste, and the finished prototype becomes the specification for
|
|
33
|
+
the real app.
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
## Why not just design in Claude?
|
|
38
36
|
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
Keep using Claude — that's the point. ScreenBook isn't a competitor to your AI; it's the
|
|
38
|
+
**workspace your AI works in**. The difference is where the output lives and what you can do
|
|
39
|
+
with it:
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
41
|
+
| Designing in a chat window | Designing in ScreenBook |
|
|
42
|
+
|---|---|
|
|
43
|
+
| One artifact per conversation; multi-screen products fall apart | A whole product: features → screens, organized like your app actually is |
|
|
44
|
+
| Output trapped in the thread; gone when context resets | Plain HTML + JSON files in **your git repo** — diff, branch, revert, forever |
|
|
45
|
+
| Needs the vendor's website, account, and connection | Runs from a folder on your machine — **works fully offline** |
|
|
46
|
+
| Tied to one AI vendor's canvas | **Any agent** that speaks MCP (Claude Code today; the protocol is open) — or no agent at all, it's just files |
|
|
47
|
+
| One rendering, usually desktop-ish | Real device frames: iPhone, Android, browser — plus dark/light, LTR/RTL, and named data states you switch live |
|
|
48
|
+
| "Looks right" is the only test | A machine gate: every screen must render in every theme × mode × direction with **zero console errors** |
|
|
49
|
+
| Feedback = screenshots and paragraphs | **Pin comments on the screen itself**; your agent reads them, fixes, and marks them resolved |
|
|
50
|
+
| Regenerates everything each round | Agent edits one small file per screen — faster, cheaper, and nothing else breaks |
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
cd my-prototypes
|
|
49
|
-
node engine/cli/screenbook.js init .
|
|
52
|
+
## What working in it feels like
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# → http://127.0.0.1:4600 · live reload · manifests auto-regenerate · no cache, ever
|
|
54
|
-
```
|
|
54
|
+
A concrete example — a specialty-coffee ordering app (it ships in `examples/qahwa`, so you can
|
|
55
|
+
open exactly this):
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
drops **`CLAUDE.md`** (the authoring contract) plus a **packaged agent skill** into the project,
|
|
58
|
-
so any AI agent that opens it immediately knows the rules.
|
|
57
|
+
**1. You brief your agent, it builds screens.**
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
> *"Create an ordering feature: menu with our drinks from the seed data, a drink detail screen
|
|
60
|
+
> with a size/milk customization sheet, a cart, and a live order-status screen. iPhone frames,
|
|
61
|
+
> match our warm theme."*
|
|
61
62
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
# no Chrome? use: npm i -D playwright && npx playwright install chromium
|
|
65
|
-
```
|
|
63
|
+
The agent creates each screen as its own small HTML file. They appear in your studio's sidebar
|
|
64
|
+
as they land — framed in an iPhone, styled by your design tokens, wired to your mock data.
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
**2. You review like it's a real app.** Click through the flow. Flip the 🎭 scenario dropdown
|
|
67
|
+
from *Regular morning* to *First visit* — the same screens now show the empty state honestly.
|
|
68
|
+
Toggle dark mode. Switch to Arabic and watch the layout mirror right-to-left. Nothing is
|
|
69
|
+
staged; the "order ready by 08:44" timestamp is computed from *today* every time you demo.
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
node engine/cli/screenbook.js serve engine/examples/qahwa # ☕ coffee app: iOS + Android + web
|
|
71
|
-
node engine/cli/screenbook.js serve engine/examples/tokens-lab # 🎨 two themes, live token lab
|
|
72
|
-
```
|
|
71
|
+

|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
```html
|
|
79
|
-
<!DOCTYPE html>
|
|
80
|
-
<html lang="en">
|
|
81
|
-
<head>
|
|
82
|
-
<script type="application/json" id="screen-meta">
|
|
83
|
-
{ "title": "Cart", "description": "Lines, totals, checkout.",
|
|
84
|
-
"order": 30, "device": "ios", "status": "wip" }
|
|
85
|
-
</script>
|
|
86
|
-
<script src="../../../engine/bridge.js"></script>
|
|
87
|
-
</head>
|
|
88
|
-
<body>
|
|
89
|
-
<button data-go="040-checkout">Checkout</button>
|
|
90
|
-
<script>
|
|
91
|
-
Engine.ready(function (data) { /* seed ⊕ active scenario, dates resolved */ });
|
|
92
|
-
</script>
|
|
93
|
-
</body>
|
|
94
|
-
</html>
|
|
95
|
-
```
|
|
73
|
+
**3. Your team comments on the pixels, not around them.** Turn on 📌 Review Mode and click
|
|
74
|
+
anywhere: each pin captures the screen, the data state, the theme, the mode, the direction,
|
|
75
|
+
and the exact element under the cursor. Then:
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
iPhone, styled by your tokens (`var(--color-accent)`), live-reloading on every save.
|
|
77
|
+
> *"Read the open review comments, apply the fixes, and resolve them."*
|
|
99
78
|
|
|
100
|
-
|
|
101
|
-
defines and edits them **live against the hosted screens** — color pickers for hex values,
|
|
102
|
-
plain fields for fonts/radii/spacing, a theme switcher, Export, and one-click **Save** straight
|
|
103
|
-
back to `themes/<id>.json` while `serve` runs:
|
|
79
|
+
Your agent does exactly that — it has tools for reading pins and marking them resolved.
|
|
104
80
|
|
|
105
|
-
|
|
81
|
+
**4. The finished screen becomes the spec for the real app.** This is the step that pays for
|
|
82
|
+
everything. When a screen survives review, it's a complete, self-contained HTML file: exact
|
|
83
|
+
layout and spacing, your design tokens, final copy in both languages, all interaction states.
|
|
84
|
+
Now point your agent at it:
|
|
106
85
|
|
|
107
|
-
|
|
86
|
+
> *"Take `features/order/screens/030-cart.html` and build it as a SwiftUI view. Use our design
|
|
87
|
+
> tokens for colors and spacing. Preserve the empty state exactly as the `first-visit` scenario
|
|
88
|
+
> shows it."*
|
|
108
89
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
```
|
|
90
|
+
The prototype you approved *is* the design document — no Figma-to-code guesswork, no "it looked
|
|
91
|
+
different in the mockup." The same works for Jetpack Compose, React Native, Flutter, or web
|
|
92
|
+
components.
|
|
113
93
|
|
|
114
|
-
|
|
115
|
-
captioned story — each step can pin its own scenario, and every state is a shareable URL:
|
|
116
|
-
`…#shop/030-cart?scenario=first-visit&mode=dark&dir=rtl`.
|
|
94
|
+

|
|
117
95
|
|
|
118
|
-
|
|
119
|
-
screen, scenario, theme, mode, direction and the exact element clicked, and syncs to
|
|
120
|
-
`review/comments.json` — where agents read and resolve them.
|
|
96
|
+
## Two commands to your own studio
|
|
121
97
|
|
|
122
|
-
|
|
98
|
+
Requirements: Node ≥ 18. Nothing else — no cloning, no per-project installs. (The automated
|
|
99
|
+
screen checks use your installed Chrome, or download a headless browser once by themselves.)
|
|
123
100
|
|
|
124
101
|
```bash
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
102
|
+
npm install -g @cs4alhaider/screenbook # once, ever
|
|
103
|
+
|
|
104
|
+
cd any-project-you-are-working-on
|
|
105
|
+
screenbook init # creates .screenbook/ — that's the whole setup
|
|
106
|
+
screenbook serve # → http://127.0.0.1:4600 — live reload, no cache headaches
|
|
128
107
|
```
|
|
129
108
|
|
|
130
|
-
|
|
109
|
+
`init` creates a single **`.screenbook/`** folder in your project — the self-contained source
|
|
110
|
+
of truth for the prototype: your **`brief.md`** (requirements — agents read it first), screens,
|
|
111
|
+
mock data, scenarios, themes, review comments, and the agent authoring contract. Commit it or
|
|
112
|
+
gitignore it; that's your call. The studio itself always runs from the installed package —
|
|
113
|
+
your project never carries runtime code.
|
|
131
114
|
|
|
132
|
-
|
|
115
|
+
Connect your agent (Claude Code shown; any MCP client works):
|
|
133
116
|
|
|
134
117
|
```bash
|
|
135
118
|
claude mcp add screenbook -- npx -y @cs4alhaider/screenbook mcp --root .
|
|
136
|
-
# or from a checkout: claude mcp add screenbook -- node engine/cli/screenbook.js mcp --root .
|
|
137
119
|
```
|
|
138
120
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
> *"Add a checkout screen to the shop feature: summary card, payment method list from the seed,
|
|
142
|
-
> a pay button that toasts. Match the existing screens. Validate and show me a screenshot."*
|
|
143
|
-
|
|
144
|
-
The agent never opens `engine/` — it calls `list_screens` → `get_screen` (steals an existing
|
|
145
|
-
screen's idioms) → `add_screen` (which **lints the contract, stamps the date, regenerates the
|
|
146
|
-
manifest, writes atomically**) → `validate` (full headless render matrix) → `screenshot`
|
|
147
|
-
(a PNG inside the real device frame). Human taste, machine discipline.
|
|
148
|
-
|
|
149
|
-
18 tools: `list_features · list_screens · get_screen · add_screen · update_screen ·
|
|
150
|
-
remove_screen · add_feature · get_data · set_data · get_theme · set_theme · get_flows ·
|
|
151
|
-
set_flows · get_review_comments · resolve_comment · validate · screenshot · add_app`.
|
|
152
|
-
|
|
153
|
-
## CLI
|
|
154
|
-
|
|
155
|
-
| Command | Does |
|
|
156
|
-
|---|---|
|
|
157
|
-
| `init [dir] [--name X]` | Scaffold a project + authoring contract + agent skill |
|
|
158
|
-
| `serve [dir] [--port]` | Studio server: live reload, auto-manifests, review sync, `/engine/*` mounted from this package, no-cache always |
|
|
159
|
-
| `manifest [dir]` | Rescan screens → regenerate derived `manifest.json` per feature |
|
|
160
|
-
| `validate [dir] [--static] [--json]` | Contract checks + headless render of every screen × theme × mode × direction |
|
|
161
|
-
| `screenshot [dir] --screen f/s [--mode light,dark] [--dir ltr,rtl] [--scenario id] [--theme id]` | Device-framed PNGs (comma lists = matrix) |
|
|
162
|
-
|
|
163
|
-
## What's in this repo
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
bridge.js the ONLY file screens include (dual-mode: shell-driven / standalone)
|
|
167
|
-
index.html + shell/ the studio: frames, dropdowns, flows, review mode, selftest
|
|
168
|
-
core/ shared project API (scan, manifests, atomic writes, validate, serve, browser)
|
|
169
|
-
cli/ · mcp/ two thin faces over the same core
|
|
170
|
-
CLAUDE.md the authoring contract agents follow (scaffolded into projects)
|
|
171
|
-
skill/ packaged agent skill + reference docs (scaffolded into projects)
|
|
172
|
-
examples/ qahwa (☕ 3-device demo app) · tokens-lab (🎨 multi-theme lab)
|
|
173
|
-
test/ 42-test suite: unit + serve E2E + CLI E2E → npm test
|
|
174
|
-
TESTING.md the full test map and gaps
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
RTL and Arabic are first-class (`dir` flipping, per-screen language dictionaries):
|
|
178
|
-
|
|
179
|
-
<img src="docs/shots/rtl-arabic.png" width="320" alt="RTL Arabic screen in dark mode">
|
|
180
|
-
|
|
181
|
-
## App mode — embed entire existing apps
|
|
182
|
-
|
|
183
|
-
Already have a single-page prototype? Don't rewrite it — **embed it**:
|
|
121
|
+
Want to explore first? Complete demo projects ship inside the package:
|
|
184
122
|
|
|
185
123
|
```bash
|
|
186
|
-
|
|
124
|
+
screenbook serve "$(npm root -g)/@cs4alhaider/screenbook/examples/qahwa" # ☕ iPhone + Android + web
|
|
125
|
+
screenbook serve "$(npm root -g)/@cs4alhaider/screenbook/examples/tokens-lab" # 🎨 two themes, edited live
|
|
187
126
|
```
|
|
188
127
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
128
|
+
## What's in the box
|
|
129
|
+
|
|
130
|
+
- **Device frames** — iPhone (Dynamic Island, status bar), Android (punch-hole), browser
|
|
131
|
+
chrome, or bare; scaled to fit, screenshot-ready.
|
|
132
|
+
- **Data scenarios** — named states over your mock data (*brand-new user*, *mid-trip*,
|
|
133
|
+
*after close*) with date tokens like `{{today+3}}`, so time-based demos are always true.
|
|
134
|
+
- **Theme Lab** — every design token visible and editable live against your screens; save
|
|
135
|
+
writes the JSON back to disk. Dark mode is a delta, not a fork.
|
|
136
|
+
|
|
137
|
+

|
|
138
|
+
- **Flows** — guided, captioned walkthroughs for stakeholder demos; every step is a shareable
|
|
139
|
+
URL that opens in the exact state (screen, data, theme, direction).
|
|
140
|
+
- **Review Mode** — pinned comments with full context, synced to a JSON file your agent reads
|
|
141
|
+
and resolves.
|
|
142
|
+
- **Multilingual by design** — per-feature strings files with side-by-side translations;
|
|
143
|
+
right-to-left is a first-class toggle, not an afterthought.
|
|
144
|
+
- **Embed existing prototypes** — already have a working single-page prototype? One command
|
|
145
|
+
mounts the *whole app* inside the studio without touching its files
|
|
146
|
+
(`screenbook app add legacy/index.html`) — see [App mode](docs/app-mode-guide.md).
|
|
147
|
+
- **A machine-verified quality gate** — `screenbook validate` renders every screen in every
|
|
148
|
+
theme × light/dark × LTR/RTL and fails on any console error. Green means done — for humans
|
|
149
|
+
and agents alike.
|
|
150
|
+
- **CLI + 18 agent tools** — everything above is scriptable and agent-operable:
|
|
151
|
+
create screens, update data, restyle themes, take device-framed screenshots, run the gate.
|
|
152
|
+
|
|
153
|
+
Full guides: **[docs/](docs/README.md)** — getting started, the studio tour, the authoring
|
|
154
|
+
contract, CLI and agent references, troubleshooting.
|
|
155
|
+
|
|
156
|
+
## The shape of a project
|
|
194
157
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
158
|
+
```
|
|
159
|
+
my-product/ ← your real project, any stack, untouched
|
|
160
|
+
└── .screenbook/ ← everything ScreenBook, in one folder
|
|
161
|
+
├── brief.md your requirements — agents read this FIRST
|
|
162
|
+
├── app.config.json product name · features · devices · themes · languages
|
|
163
|
+
├── CLAUDE.md the authoring contract agents follow
|
|
164
|
+
├── themes/default.json design tokens (light + dark)
|
|
165
|
+
├── features/
|
|
166
|
+
│ └── order/
|
|
167
|
+
│ ├── feature.json title, icon, order
|
|
168
|
+
│ ├── flows.json demo walkthroughs
|
|
169
|
+
│ ├── i18n.json strings, side-by-side languages
|
|
170
|
+
│ ├── data/seed.json mock data
|
|
171
|
+
│ ├── data/scenarios.json named data states
|
|
172
|
+
│ └── screens/
|
|
173
|
+
│ ├── 010-menu.html ← one file = one screen
|
|
174
|
+
│ └── 020-drink.html
|
|
175
|
+
└── review/comments.json pinned feedback, read by your agent
|
|
176
|
+
```
|
|
198
177
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
i18n strings ✓ (`Engine.t` + key-first per-feature `i18n.json`, fallback chain, validate
|
|
203
|
-
warnings on gaps) · npm packaging next.
|
|
178
|
+
Everything is a plain file an intern could read. That's the whole trick: it's why agents stay
|
|
179
|
+
fast and cheap (they touch one small file at a time), why git can review every change, why it
|
|
180
|
+
works on a plane, and why the approved prototype can walk straight into production.
|
|
204
181
|
|
|
205
|
-
|
|
206
|
-
prototypes grew to ~22k lines and taught every lesson this engine inverts.
|
|
182
|
+
## Status & license
|
|
207
183
|
|
|
208
|
-
|
|
184
|
+
v0.2.0 — studio, frames, scenarios, themes, flows, review, i18n, app mode, self-test gate,
|
|
185
|
+
CLI, MCP server, docs, and a 64-test suite; built and verified end-to-end with AI agents,
|
|
186
|
+
reviewed by a human with taste. MIT © [Abdullah Alhaider](https://github.com/cs4alhaider).
|
package/bridge.js
CHANGED
package/cli/screenbook.js
CHANGED
|
@@ -10,7 +10,7 @@ import { startServer } from '../core/serve.js';
|
|
|
10
10
|
import * as T from './templates.js';
|
|
11
11
|
|
|
12
12
|
const ENGINE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
|
-
const VERSION = '0.
|
|
13
|
+
const VERSION = '0.2.0';
|
|
14
14
|
|
|
15
15
|
/* ---------------- arg parsing ---------------- */
|
|
16
16
|
|
|
@@ -48,13 +48,17 @@ async function requireRoot() {
|
|
|
48
48
|
/* ---------------- commands ---------------- */
|
|
49
49
|
|
|
50
50
|
async function cmdInit() {
|
|
51
|
-
|
|
51
|
+
/* Everything lands in <project>/.screenbook/ — the self-contained source of
|
|
52
|
+
truth for the prototype. The user decides to commit or gitignore it.
|
|
53
|
+
No cloning, no runtime copy: `serve` mounts the studio from this package. */
|
|
54
|
+
const projectDir = path.resolve(positional[0] || '.');
|
|
55
|
+
const dir = path.join(projectDir, '.screenbook');
|
|
52
56
|
const configPath = path.join(dir, 'app.config.json');
|
|
53
57
|
if (await exists(configPath) && !flags.force) {
|
|
54
|
-
console.error(bad(
|
|
58
|
+
console.error(bad(`.screenbook/ already exists in ${projectDir} — refusing to overwrite (use --force).`));
|
|
55
59
|
process.exit(2);
|
|
56
60
|
}
|
|
57
|
-
const name = flags.name || path.basename(
|
|
61
|
+
const name = flags.name || path.basename(projectDir);
|
|
58
62
|
const day = today();
|
|
59
63
|
|
|
60
64
|
await mkdirp(path.join(dir, 'features/welcome/screens'));
|
|
@@ -63,6 +67,7 @@ async function cmdInit() {
|
|
|
63
67
|
await mkdirp(path.join(dir, 'review'));
|
|
64
68
|
|
|
65
69
|
await writeJSON(configPath, T.APP_CONFIG(name));
|
|
70
|
+
await writeAtomic(path.join(dir, 'brief.md'), T.BRIEF(name));
|
|
66
71
|
await writeJSON(path.join(dir, 'themes/default.json'), T.DEFAULT_THEME);
|
|
67
72
|
await writeJSON(path.join(dir, 'review/comments.json'), { comments: [] });
|
|
68
73
|
await writeJSON(path.join(dir, 'features/welcome/feature.json'), T.WELCOME_FEATURE);
|
|
@@ -71,39 +76,45 @@ async function cmdInit() {
|
|
|
71
76
|
await writeJSON(path.join(dir, 'features/welcome/flows.json'), T.WELCOME_FLOWS);
|
|
72
77
|
await writeAtomic(path.join(dir, 'features/welcome/screens/010-hello.html'), T.WELCOME_SCREEN(day));
|
|
73
78
|
|
|
74
|
-
/*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
/* Agent onboarding, multi-agent (Abdullah's panel picks):
|
|
80
|
+
- the full contract at .screenbook/AGENTS.md (the 2026 open standard —
|
|
81
|
+
Codex, Cursor, Gemini, Copilot AND Claude Code read it natively)
|
|
82
|
+
- .screenbook/CLAUDE.md as a 3-line pointer for older Claude versions
|
|
83
|
+
- the skill in BOTH standard locations: .agents/skills/ + .claude/skills/
|
|
84
|
+
- a marked, idempotent breadcrumb appended to the PROJECT's root AGENTS.md */
|
|
85
|
+
const contract = await readTextSafe(path.join(ENGINE_DIR, 'AGENTS.md'));
|
|
86
|
+
if (contract) await writeAtomic(path.join(dir, 'AGENTS.md'), contract);
|
|
87
|
+
await writeAtomic(path.join(dir, 'CLAUDE.md'), T.CLAUDE_POINTER);
|
|
80
88
|
const skillSrc = path.join(ENGINE_DIR, 'skill');
|
|
81
89
|
if (await exists(skillSrc)) {
|
|
82
|
-
await copyDir(skillSrc, path.join(
|
|
90
|
+
await copyDir(skillSrc, path.join(projectDir, '.claude/skills/screenbook'));
|
|
91
|
+
await copyDir(skillSrc, path.join(projectDir, '.agents/skills/screenbook'));
|
|
83
92
|
}
|
|
93
|
+
await upsertRootPointer(projectDir);
|
|
84
94
|
|
|
85
95
|
await regenAllManifests(dir);
|
|
86
96
|
|
|
87
|
-
/* `init --app <path>`: register an existing SPA
|
|
88
|
-
embedded app
|
|
89
|
-
any folder that already contains an app). */
|
|
97
|
+
/* `init --app <path>`: register an existing SPA from the USER'S project as
|
|
98
|
+
an embedded app — recorded as project/<path>, served via the /project mount. */
|
|
90
99
|
if (flags.app) {
|
|
91
|
-
const rel = path.relative(
|
|
100
|
+
const rel = path.relative(projectDir, path.resolve(flags.app));
|
|
101
|
+
if (rel.startsWith('..')) {
|
|
102
|
+
console.error(bad(`--app must point inside ${projectDir}`));
|
|
103
|
+
process.exit(2);
|
|
104
|
+
}
|
|
92
105
|
const r = await addApp(dir, {
|
|
93
|
-
src: rel.split(path.sep).join('/')
|
|
106
|
+
src: `project/${rel.split(path.sep).join('/')}`,
|
|
94
107
|
driver: !flags.cooperative
|
|
95
108
|
});
|
|
96
109
|
console.log(ok(`✓ app registered: ${r.feature.id}`) + dim(` → ${r.feature.src}`));
|
|
97
|
-
if (r.driver) console.log(` fill in ${bold(r.driver)} to teach ScreenBook the app's internals`);
|
|
110
|
+
if (r.driver) console.log(` fill in ${bold('.screenbook/' + r.driver.replace(/^features\//, 'features/'))} to teach ScreenBook the app's internals`);
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
console.log(ok(`✓ ScreenBook
|
|
101
|
-
console.log(`
|
|
102
|
-
console.log(`
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
console.log(dim(` copy the engine folder in when you want plain static servers to work too.`));
|
|
106
|
-
}
|
|
113
|
+
console.log(ok(`✓ ScreenBook ready — everything lives in ${bold('.screenbook/')}`));
|
|
114
|
+
console.log(` ${bold('brief.md')} ${dim('(write your requirements here — agents read it first)')}`);
|
|
115
|
+
console.log(` app.config.json · themes/ · features/welcome/ · review/ · AGENTS.md ${dim('(+CLAUDE.md pointer)')}`);
|
|
116
|
+
console.log(` agent setup: root AGENTS.md section · .agents/skills/ + .claude/skills/ ${dim('(Claude, Codex, Cursor, Gemini, …)')}`);
|
|
117
|
+
console.log(dim(` commit .screenbook/ or add it to .gitignore — your call; it is the source of truth.`));
|
|
107
118
|
console.log(`\nNext: ${bold(`screenbook serve ${positional[0] || '.'}`)} → http://127.0.0.1:4600`);
|
|
108
119
|
}
|
|
109
120
|
|
|
@@ -112,6 +123,25 @@ async function readTextSafe(p) {
|
|
|
112
123
|
catch { return null; }
|
|
113
124
|
}
|
|
114
125
|
|
|
126
|
+
/* Root AGENTS.md breadcrumb: create the file if missing; if it exists, replace
|
|
127
|
+
only the marked ScreenBook section (or append it) — user content is never touched. */
|
|
128
|
+
async function upsertRootPointer(projectDir) {
|
|
129
|
+
const file = path.join(projectDir, 'AGENTS.md');
|
|
130
|
+
const START = '<!-- screenbook:start -->';
|
|
131
|
+
const END = '<!-- screenbook:end -->';
|
|
132
|
+
const existing = await readTextSafe(file);
|
|
133
|
+
if (existing === null) {
|
|
134
|
+
await writeAtomic(file, T.ROOT_POINTER + '\n');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const s = existing.indexOf(START);
|
|
138
|
+
const e = existing.indexOf(END);
|
|
139
|
+
const next = (s >= 0 && e > s)
|
|
140
|
+
? existing.slice(0, s) + T.ROOT_POINTER + existing.slice(e + END.length)
|
|
141
|
+
: existing.replace(/\s*$/, '') + '\n\n' + T.ROOT_POINTER + '\n';
|
|
142
|
+
if (next !== existing) await writeAtomic(file, next);
|
|
143
|
+
}
|
|
144
|
+
|
|
115
145
|
async function copyDir(src, dest) {
|
|
116
146
|
const fs = await import('node:fs/promises');
|
|
117
147
|
await fs.mkdir(dest, { recursive: true });
|
|
@@ -123,8 +153,8 @@ async function cmdServe() {
|
|
|
123
153
|
const port = parseInt(flags.port || '4600', 10);
|
|
124
154
|
const srv = await startServer({ root, engineDir: ENGINE_DIR, port });
|
|
125
155
|
console.log(bold(`⧉ ScreenBook`) + ` serving ${dim(root)}`);
|
|
126
|
-
console.log(` studio ${ok(srv.url + '/
|
|
127
|
-
console.log(` selftest ${dim(srv.url + '/
|
|
156
|
+
console.log(` studio ${ok(srv.url + '/screenbook/')}`);
|
|
157
|
+
console.log(` selftest ${dim(srv.url + '/screenbook/?selftest=1')}`);
|
|
128
158
|
console.log(` live reload + manifest refresh + review sync ${ok('on')} ${dim('(no-cache always)')}`);
|
|
129
159
|
}
|
|
130
160
|
|
|
@@ -205,8 +235,17 @@ async function cmdApp() {
|
|
|
205
235
|
}
|
|
206
236
|
positional.splice(0, 2, positional[2]); // remaining positional = project dir
|
|
207
237
|
const root = await requireRoot();
|
|
208
|
-
|
|
209
|
-
|
|
238
|
+
|
|
239
|
+
/* Normalize src: apps usually live in the USER'S project. With a .screenbook
|
|
240
|
+
root, record them as project/<path> (served via the /project mount).
|
|
241
|
+
Relative paths are taken relative to the project directory. */
|
|
242
|
+
const isDotRoot = path.basename(root) === '.screenbook';
|
|
243
|
+
const projectDir = isDotRoot ? path.dirname(root) : root;
|
|
244
|
+
const absSrc = path.isAbsolute(srcArg) ? srcArg : path.resolve(projectDir, srcArg);
|
|
245
|
+
const fromRoot = path.relative(root, absSrc);
|
|
246
|
+
const fromProject = path.relative(projectDir, absSrc);
|
|
247
|
+
const rel = !fromRoot.startsWith('..') ? fromRoot.split(path.sep).join('/')
|
|
248
|
+
: isDotRoot && !fromProject.startsWith('..') ? `project/${fromProject.split(path.sep).join('/')}`
|
|
210
249
|
: srcArg;
|
|
211
250
|
const r = await addApp(root, {
|
|
212
251
|
src: rel,
|
package/cli/templates.js
CHANGED
|
@@ -87,7 +87,7 @@ export const WELCOME_SCREEN = (today) => `<!DOCTYPE html>
|
|
|
87
87
|
"updated": "${today}"
|
|
88
88
|
}
|
|
89
89
|
</script>
|
|
90
|
-
<script src="../../../
|
|
90
|
+
<script src="../../../screenbook/bridge.js"></script>
|
|
91
91
|
<style>
|
|
92
92
|
* { box-sizing: border-box; }
|
|
93
93
|
body {
|
|
@@ -137,3 +137,56 @@ export const WELCOME_SCREEN = (today) => `<!DOCTYPE html>
|
|
|
137
137
|
export const GITIGNORE = `node_modules/
|
|
138
138
|
.DS_Store
|
|
139
139
|
`;
|
|
140
|
+
|
|
141
|
+
/* Marked section appended to the PROJECT's root AGENTS.md so every agent
|
|
142
|
+
(Codex, Cursor, Gemini, Claude, …) discovers ScreenBook unprompted.
|
|
143
|
+
Idempotent: init replaces the content between the markers. */
|
|
144
|
+
export const ROOT_POINTER =
|
|
145
|
+
`<!-- screenbook:start -->
|
|
146
|
+
## UI prototyping (ScreenBook)
|
|
147
|
+
|
|
148
|
+
This project's UI prototypes live in **.screenbook/** — a [ScreenBook](https://github.com/cs4alhaider/screenbook) studio.
|
|
149
|
+
Before designing or changing any screen: read **.screenbook/brief.md** (the requirements)
|
|
150
|
+
and **.screenbook/AGENTS.md** (the authoring contract).
|
|
151
|
+
Preview locally: \`screenbook serve\` → http://127.0.0.1:4600
|
|
152
|
+
Agent tools (MCP, 18 tools): \`npx -y @cs4alhaider/screenbook mcp --root .\`
|
|
153
|
+
<!-- screenbook:end -->`;
|
|
154
|
+
|
|
155
|
+
export const CLAUDE_POINTER = `# ScreenBook
|
|
156
|
+
|
|
157
|
+
The authoring contract for this prototype lives in **AGENTS.md** (same folder) — read
|
|
158
|
+
that, plus **brief.md** for the product requirements, before creating or changing any
|
|
159
|
+
screen.
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
export const BRIEF = (name) => `# ${name} — product brief
|
|
163
|
+
|
|
164
|
+
> **AI agents: read this file first, before creating or changing any screen.**
|
|
165
|
+
> It is the source of truth for what we are building and why.
|
|
166
|
+
|
|
167
|
+
## What we're building
|
|
168
|
+
|
|
169
|
+
_One paragraph: the product, who it's for, the core promise._
|
|
170
|
+
|
|
171
|
+
## The screens we need
|
|
172
|
+
|
|
173
|
+
_List the features and screens you expect, roughly in user-journey order.
|
|
174
|
+
Agents: turn each line into screens under features/, and ask (via review
|
|
175
|
+
comments) when something here is ambiguous._
|
|
176
|
+
|
|
177
|
+
- …
|
|
178
|
+
|
|
179
|
+
## Design direction
|
|
180
|
+
|
|
181
|
+
_Tone, references, the feeling. The design tokens in themes/ are the palette —
|
|
182
|
+
change them there, not per-screen._
|
|
183
|
+
|
|
184
|
+
## States that must exist
|
|
185
|
+
|
|
186
|
+
_Empty / first-run · busy / real usage · edge cases. Agents: model these as
|
|
187
|
+
data scenarios so every screen can be reviewed in each state._
|
|
188
|
+
|
|
189
|
+
## Out of scope (for now)
|
|
190
|
+
|
|
191
|
+
- …
|
|
192
|
+
`;
|