@daydreamui/paper 0.0.0-stage → 0.3.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/README.md CHANGED
@@ -1,3 +1,278 @@
1
- # Temporary Holding Version
1
+ # Paper
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A local Daydream plugin that puts what is open in Paper desktop on the
4
+ canvas. The design stays in Paper; Daydream takes an image of it, or
5
+ converts it into a page of the project, and lets any agent connected to
6
+ Daydream read Paper through eight tools. Paper's export is HTML and CSS in
7
+ all but syntax, so Add as page is a converter and not a prompt: no agent
8
+ is asked, and the page lands in seconds. There is no plugin inside Paper.
9
+ Enable **Paper** in Daydream's Plugins page (⌥⌘P).
10
+
11
+ From this repository, install the plugin with:
12
+
13
+ ```sh
14
+ pnpm install
15
+ pnpm ship plugins/daydream.paper --enable
16
+ ```
17
+
18
+ The build produces `plugins/daydream.paper/dist/index.js`. The install command
19
+ copies the plugin into the user's Daydream plugins folder and records its trust.
20
+
21
+ ## Requirements
22
+
23
+ - Paper desktop, open on this machine, with the file you want to read open
24
+ in it. The plugin reads the file you are viewing.
25
+ - Nothing to turn on in Paper, and no paid seat: Paper serves its MCP server
26
+ on this machine, and the plugin reads it at `http://127.0.0.1:29979/mcp`.
27
+
28
+ What leaves the machine, and what does not. Paper is read locally, and the
29
+ project is never sent anywhere. The image fills a page uses are downloaded
30
+ from Paper's asset host (`app.paper.design` only; a fill served from
31
+ anywhere else is not downloaded, stays a url in the page's sheet and is
32
+ warned about). And a converted page links Google Fonts for the file's
33
+ font families that are not system fonts, one `<link>` per family, so
34
+ opening that page, on the canvas or anywhere, asks `fonts.googleapis.com`
35
+ for them when it renders. The weights a link asks for (and the italic, when
36
+ a node uses one) are the ones the page uses, read from its nodes' styles
37
+ and the tokens they refer to, because Google refuses a range for a static
38
+ family; a weight a static family lacks is the one case in which the link
39
+ still fails, and the page shows that font's fallback.
40
+
41
+ The panel's first line says what Paper answers, probed with one call of
42
+ the host part (the selection's read, which carries the file's name) when
43
+ the panel opens, when a project is opened and when the window comes to the
44
+ front. It
45
+ shows one of these, always in sentence case:
46
+
47
+ - "Looking for Paper desktop…" until the first probe answers.
48
+ - "Paper is not reachable: open Paper desktop with the file you want to
49
+ read" when Paper is closed or its server is off. Each gesture answers the
50
+ same sentence.
51
+ - `Amazing jewel · 3 selected`, the file you are viewing and how many nodes
52
+ are selected in it.
53
+ - `Amazing jewel · nothing selected`.
54
+
55
+ ## The two gestures
56
+
57
+ Both take what is selected in Paper, and nothing else: one artboard, or
58
+ several, up to 12 at once (past that, each gesture refuses in one sentence
59
+ naming the cap). There is nothing to type; select in Paper, press here.
60
+ Each begins by reading the selection, and each kind of answer gets its own
61
+ sentence: nothing selected ("Select an artboard in Paper first."), Paper
62
+ not there (or refusing, in its own sentence), or Paper too slow to answer
63
+ ("Paper took too long to answer; try again.").
64
+
65
+ 1. **Add as image** takes each node's screenshot by its id, copies it into
66
+ the project's `assets/` (named by its bytes, so the same node twice is
67
+ one file), and lands it on the canvas as a `daydream.paper.reference`
68
+ item at free space, selected and brought into view, as one undo step.
69
+ Its title bar carries the node's name, as the selection listed it, and
70
+ renames it; nothing is drawn under the image. A screenshot wider than
71
+ 1200 px lands at that width; a resize keeps the image's proportions,
72
+ and a double-click on a handle resets it. The payload is
73
+ `{src, name, nodeId}`: `src` a file of the project's own
74
+ (`assets/<file>`), `name` the node's, `nodeId` Paper's id. With several
75
+ nodes selected, one screenshot is taken per node and every image lands
76
+ in one row from free space, each 40 px right of the last, side by side
77
+ to compare, all selected, as one undo step; a node whose screenshot
78
+ Paper refuses is left out and named in the error line while the others
79
+ land.
80
+ 2. **Add as page** converts each selected artboard into a page of the
81
+ project and lands it on the canvas, in the selection's order, with no
82
+ agent in between. For each artboard Daydream reads its tree, its
83
+ computed styles, each SVG's markup and the file's tokens from Paper,
84
+ writes the files under What lands, and lands the page as a viewport as
85
+ wide as the artboard. The status says `Added <name> as a page.` or `Added 3 pages:
86
+ Garden, Archive, Notes.`; the error line carries what the conversion
87
+ warned of, the remote files that stayed links, and any artboard that
88
+ failed while the others landed.
89
+
90
+ What the page is: faithful and plain. Every text is a `p`; every box is
91
+ a `div` with a class named after its Paper layer (a layer with a
92
+ default name, such as `Frame`, gets `<type>-<n>`, and every Text node
93
+ gets `text-<n>` whatever its layer is called); an SVG is
94
+ its markup with the class on the root; flex and absolute layout are as
95
+ Paper has them, the width is fixed at the artboard's, and there are no
96
+ media queries; the sheet sets `box-sizing: border-box` on everything,
97
+ as Paper does (its computed styles leave it out). Tokens stay
98
+ `var(--color-ink)`. Every element carries
99
+ `data-paper="<id>"`, the Paper node it came from. Making it semantic
100
+ (headings, lists, landmarks, a layout that flows) is a rework of a page
101
+ already on the canvas, afterwards, which an agent or the Impeccable
102
+ verbs do; the converter does not guess it.
103
+
104
+ ### What lands
105
+
106
+ Add as page, and the `paper_page` tool, write these files at the project's
107
+ root:
108
+
109
+ - `<stem>.css`: the page's sheet. The stem is the artboard's name made
110
+ file-safe (`CSS Zen Garden` becomes `css-zen-garden`), with `-2`, `-3` and on
111
+ while `<stem>.html` or `<stem>.css` is taken.
112
+ - `<file>-tokens.css`: the Paper file's design tokens as a `:root {}`
113
+ sheet, named after the file (`amazing-jewel-tokens.css`), shared by every
114
+ page of that file. It is rebuilt from Paper's tokens, each passed through
115
+ the same guard as the page's styles (a value that would end its rule, or
116
+ load from somewhere a page may not, is left out and named). The
117
+ project's copy is never replaced. It is
118
+ **written** when absent; **kept** when it is there with Paper's text
119
+ already; **differs** when it is there with other text, in which case it
120
+ is kept as it is, the page links it as it is, and the error line says
121
+ "the project's tokens sheet differs from Paper's tokens and was kept";
122
+ and **none** when the file has no tokens, in which case the page links no
123
+ tokens sheet and nothing is written.
124
+ - `assets/paper-<name>-<hash>.<ext>`: each image fill the page uses,
125
+ downloaded from Paper's asset host and named from the whole url (the
126
+ last part of its path, then the first eight hex digits of the url's
127
+ sha256, then the extension the download's content type gives: a fill
128
+ served at a `.html` url that is a PNG is saved as a `.png`), so two
129
+ images from different places never share a file; one
130
+ already there is the same url's and is kept, one that cannot be
131
+ downloaded stays a url and is named in the error line.
132
+ - `<stem>.html`: the page itself, written by Daydream's `createPage` and
133
+ not by the host part, at the path the host chose (`<stem>.html`, `-2` and
134
+ on). Landing it and placing its viewport at the artboard's size is one
135
+ undo step; an undo takes the viewport off and leaves the files, as it
136
+ does for every page Daydream makes.
137
+
138
+ Add as page and the `paper_page` tool are one call of the host part,
139
+ `paper-page`: it reads Paper, writes the files, asks the browser part to
140
+ land the html (`land-page`) and, when that fails, takes its own files back
141
+ before it answers. A page is therefore either landed, with its path and
142
+ viewport, or a rejection that says what became of its files. A landing
143
+ that fails takes back what the call wrote, in three cases and no other.
144
+
145
+ - The host part's own write fails or is late: the call takes back what it
146
+ had written before it answers, and the failure names the cause.
147
+ - `createPage` rejects the page (its path was taken meanwhile, there is no
148
+ room): the host part removes the call's own files — the sheet, the
149
+ tokens sheet if this call wrote it, the assets this call wrote — each
150
+ only while it still holds the bytes the call wrote and no other page
151
+ uses it. The error line follows the failure with one of four sentences,
152
+ by what became of them:
153
+ - "It had written no files." when the call had written none;
154
+ - "The files it had written were removed: a.css, amazing-jewel-tokens.css."
155
+ when all went;
156
+ - "Of the files it had written, a.css was removed and
157
+ assets/paper-3f2a-1c9e04ab.jpg stayed, edited since or used by another page."
158
+ when some stayed, both lists named;
159
+ - "It could not take them back: a.css, assets/paper-3f2a-1c9e04ab.jpg." when
160
+ neither list says anything (files already gone), with no cause guessed at.
161
+
162
+ If the removal itself fails, the line says "Its files could not be
163
+ removed (<why>) and stayed: …".
164
+
165
+ - The canvas answers neither way and the page's html exists as Daydream
166
+ was given it (Daydream wrote it, so the page may be there), or the
167
+ project changed meanwhile: nothing is taken back, and the sentence says
168
+ the files were kept.
169
+
170
+ When the project changed after Paper was read, the files stay in the
171
+ project they were written to, and nothing more is done.
172
+
173
+ ## The agent tools
174
+
175
+ The host part registers eight MCP tools, so any agent connected to Daydream
176
+ reads Paper through it with no Paper setup of its own. Each reads Paper
177
+ only, and answers one sentence as an error result when Paper does not
178
+ answer. A `fileId` left out is the file you are viewing. The reads are
179
+ marked read-only; `paper_screenshot` and `paper_page` are not, since they
180
+ write into the project.
181
+
182
+ | Tool | Takes | Answers |
183
+ | ------------------ | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
184
+ | `paper_info` | optional `fileId` | the file: its id and name, its pages, its artboards with their sizes, its font families, its tokens |
185
+ | `paper_selection` | none | what is selected in Paper: each node's id, name, type and size, with the file they are in |
186
+ | `paper_tree` | `nodeId`, optional `fileId`, optional `depth` (3 by default, at most 10) | the node's subtree as Paper's indented summary: type, layer name, id, size, and a text node's text |
187
+ | `paper_styles` | `nodeIds[]` (at most 500), optional `fileId` | the computed CSS of the nodes, batched: camelCase properties with units, tokens kept as `var(--name)` |
188
+ | `paper_jsx` | `nodeId`, optional `fileId`, optional `format` (`inline-styles` by default, or `tailwind`) | the node as JSX; how an SVG's markup is read |
189
+ | `paper_tokens` | optional `fileId`, optional `format` (`css` by default, or `json`) | the file's design tokens, as a `:root {}` stylesheet or structured |
190
+ | `paper_screenshot` | `nodeId`, optional `fileId` | the node's image as Paper sends it (JPEG today), written into the open project's `.daydream/paper/<node>.jpg` and answered as that path |
191
+ | `paper_page` | `nodeId`, optional `fileId` | the conversion Add as page runs, for the node: the files above written and the page landed on the canvas; the answer names the page's path and its viewport, and any remote file the canvas could not copy |
192
+
193
+ A tool's result cannot return an image, so a screenshot is a file in the
194
+ project's `.daydream/` scratch, never through a link, for the agent to read
195
+ with its own file tools. `paper_page` has the page landed by
196
+ the browser part, so it needs Daydream open on the project in a tab.
197
+
198
+ ## What is not done
199
+
200
+ - No plugin inside Paper: Daydream reads Paper through Paper's own server
201
+ and adds nothing to Paper.
202
+ - No write-back: nothing changes in Paper, ever. A page edited in Daydream
203
+ does not go back to its artboard.
204
+ - No re-sync: a page converted once is the project's own file. Add as page
205
+ again makes a second page (`-2`) beside it; it does not update the first
206
+ from an artboard that changed.
207
+ - No files on disk: only the file open in Paper desktop is read, through
208
+ its server.
209
+ - No shared package with the Figma plugin yet. The transport and the probe
210
+ are copies of `packages/figma-devmode`'s and the unreachable sentence
211
+ follows its pattern; the client's session core, `land.ts` (the page half
212
+ is new) and `ReferenceItem.tsx` are adapted from the Figma package's and
213
+ plugin's. Each is marked as such at the top with the commit it was taken
214
+ at; the file-writing helpers (`bridge/files.ts`) follow the
215
+ Figma bridge's care and carry only the `mirrors-adapted` marker for its
216
+ `.daydream/` gitignore. One shared package is the follow-up.
217
+ - No semantic markup and no responsive rules (above).
218
+
219
+ ## Limits
220
+
221
+ - One file at a time: the one you are viewing in Paper desktop. Another
222
+ file's nodes are read by giving a tool its `fileId`; the panel always
223
+ takes the file in view.
224
+ - Up to 12 nodes per gesture: a screenshot or a conversion each is a round
225
+ trip to Paper.
226
+ - The selection's listing is read under 5 s of its own: past that the
227
+ gesture says Paper was too slow, and nothing is asked further.
228
+ - A request to Paper is given 20 s and one call of the client — its
229
+ handshake, a session opened again and the retry included — 45 s in all,
230
+ under the 50 s the kernel allows a host-part call, so what the panel
231
+ hears is the client's sentence and never the kernel's. A large artboard's
232
+ conversion reads its styles 100 nodes at a time and may come near that.
233
+ - The page call has one budget, 45 s, for the whole of it: the reads, the
234
+ downloads, the writes and the landing, the panel's call and the
235
+ `paper_page` tool's alike, so it ends under the 50 s the kernel allows a
236
+ host-part call. Past it before the writes, the sentence is "Converting
237
+ <name> took longer than 45 s; nothing was written". The landing is given
238
+ what is left of the budget; when the canvas has not answered by then the
239
+ call is rejected with "<name> was converted, but the canvas did not answer
240
+ in time; its files were kept: …" and nothing is taken back, since the page
241
+ may still land.
242
+ - A call's writes are remembered for ten minutes, so the rollback of one
243
+ page never removes a file another page of that time uses; a host restart
244
+ forgets them.
245
+ - An agent calling `paper_page` while the panel lands pages may find an
246
+ asset or the tokens sheet shared between two pages. A rollback never
247
+ removes a file another live call's page uses; it names it as one that
248
+ stayed.
249
+ - A Text node whose text holds a line break cannot be read from Paper's
250
+ tree summary today (whether Paper escapes it is unverified), and fails
251
+ the conversion with a sentence naming the node.
252
+ - Shader and effect nodes (a lens distortion, say) have no HTML: they land
253
+ as plain `div`s and the conversion warns, naming the node.
254
+ - A node selected inside an SVG is refused with a sentence; select the SVG
255
+ itself, or its artboard.
256
+ - An artboard on a page other than the one Paper shows takes the shown
257
+ page's font list, so a font used only there is not linked.
258
+ - Images a page uses are downloaded once into `assets/`; a fill served
259
+ from anywhere but Paper's asset host, or one whose download fails, stays
260
+ a url, and that part of the page works only while that address does.
261
+ - The width is the artboard's. A page converted from a 1440 px artboard
262
+ does not reflow below that.
263
+
264
+ ## Validation
265
+
266
+ `pnpm test` runs the shared parts (the payload rules, the channel answers'
267
+ shapes, the sentences), the gestures over a fake `dd` (the selection's
268
+ kinds, several nodes, a node refused among several, the pages landed with
269
+ their path and frame, the project changing under a gesture), and the host
270
+ part and the package's converter over their fixtures. `pnpm test:kernel
271
+ <daydream-checkout> plugins/daydream.paper` mounts the real shell with
272
+ host-part replies in memory: the state line in its states, an image landed
273
+ and selected with its file copied, three nodes in a row, nothing selected,
274
+ the unreachable sentence, Add as page landing a page at the artboard's
275
+ frame, one of three refused while two land, a landing the shell refuses
276
+ having its files taken back by the host part, and the handler the host's `paper_page` tool
277
+ lands its page through. The plugin requires a Daydream build reporting API 3.0. See the
278
+ repository’s kernel pin and release gate before shipping.