@daydreamui/figma 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 +206 -2
- package/dist/bridge.js +4613 -0
- package/dist/index.js +1545 -0
- package/icon.svg +10 -0
- package/manifest.json +35 -0
- package/package.json +15 -4
package/README.md
CHANGED
|
@@ -1,3 +1,207 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Figma
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A local Daydream plugin that puts what is open in Figma desktop beside the
|
|
4
|
+
real page. The design stays in Figma; Daydream takes an image of it, or
|
|
5
|
+
asks your agent to transcribe it as a page, and lets any agent connected to
|
|
6
|
+
Daydream read Figma through four tools. There is no plugin inside Figma.
|
|
7
|
+
Enable **Figma** in Daydream's Plugins page (⌥⌘P).
|
|
8
|
+
|
|
9
|
+
From this repository, install the plugin with:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm install
|
|
13
|
+
pnpm ship plugins/daydream.figma --enable
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The build produces `plugins/daydream.figma/dist/index.js`. The install command
|
|
17
|
+
copies the plugin into the user's Daydream plugins folder and records its trust.
|
|
18
|
+
|
|
19
|
+
## Requirements
|
|
20
|
+
|
|
21
|
+
- Figma desktop, open on this machine, with the file you want to read open
|
|
22
|
+
in it.
|
|
23
|
+
- Figma's Dev Mode MCP server turned on in Figma's preferences. The plugin
|
|
24
|
+
reads it at `http://127.0.0.1:3845/mcp`, on this machine only; nothing
|
|
25
|
+
leaves it.
|
|
26
|
+
- A Figma seat that Figma gives the Dev Mode MCP server to (a paid plan, as
|
|
27
|
+
Figma requires).
|
|
28
|
+
|
|
29
|
+
The panel's first line says whether Figma answers, probed when the panel
|
|
30
|
+
opens, when a project is opened and when the window comes to the front.
|
|
31
|
+
Figma closed, or the server off, is a normal state: the line says what to
|
|
32
|
+
do, and each gesture answers the same sentence.
|
|
33
|
+
|
|
34
|
+
## The two gestures
|
|
35
|
+
|
|
36
|
+
Both take what is selected in Figma, and nothing else: one frame, or
|
|
37
|
+
several, up to 12 at once (past that, each gesture refuses in one sentence
|
|
38
|
+
naming the cap). There is nothing to type; select in Figma, press here.
|
|
39
|
+
Each begins by reading the selection, and says what it found in its own
|
|
40
|
+
words: nothing selected, Figma not there (or refusing, in the server's own
|
|
41
|
+
sentence), or Figma too slow to answer ("Figma took too long to answer;
|
|
42
|
+
try again"). A frame's id and name are the selection's listing's, so a
|
|
43
|
+
frame whose own metadata is slow to come is still that frame. A layer
|
|
44
|
+
inside a component instance — which Figma lists with an id of its own
|
|
45
|
+
shape and refuses to read by it — is left out before anything is asked,
|
|
46
|
+
and the error line says so: "2 layers inside instances were left out;
|
|
47
|
+
select their frames."
|
|
48
|
+
|
|
49
|
+
1. **Add as image** takes the frame's screenshot by its id, copies it into
|
|
50
|
+
the project's `assets/` (named by its bytes, so the same frame twice is
|
|
51
|
+
one file), and lands it on the canvas as a `daydream.figma.reference`
|
|
52
|
+
item at free space, selected and brought into view, as one undo step.
|
|
53
|
+
Its title bar carries the frame's name, as the selection listed it, and
|
|
54
|
+
renames it; nothing is drawn under the image. With nothing selected, the
|
|
55
|
+
page's screenshot lands, unnamed. A screenshot wider than 1200 px lands at that width; a resize
|
|
56
|
+
keeps the image's proportions, and a double-click on a handle resets it.
|
|
57
|
+
The payload is `{src, name, nodeId}`: `src` a file of the project's own
|
|
58
|
+
(`assets/<file>`), `name` the frame's, `nodeId` Figma's id or null. With
|
|
59
|
+
several frames selected, one screenshot is taken per frame by id and
|
|
60
|
+
every image lands in one row from free space, each 40 px right of the
|
|
61
|
+
last, side by side to compare, all selected, as one undo step; a frame
|
|
62
|
+
whose screenshot Figma refuses is left out and named in the error line
|
|
63
|
+
while the others land. (An earlier build kept a `link` the user had
|
|
64
|
+
typed on the payload; a canvas saved by it still renders, the `link`
|
|
65
|
+
let through and never read.)
|
|
66
|
+
2. **Add as page** asks the project's agent to transcribe the frame as a page
|
|
67
|
+
of the project (Daydream's decision #96: the button is the prompt, and
|
|
68
|
+
nothing starts without it). The prompt names the frame — its id, its
|
|
69
|
+
name and its width — and asks for a
|
|
70
|
+
transcription through the tools below and the dream-author workflow: a
|
|
71
|
+
draft whose HTML and CSS are the project's own, finalized as a new page
|
|
72
|
+
titled after the frame. The plugin holds the project's conversation for
|
|
73
|
+
its own rounds (`contributes.conversation`), so the agent starts whether
|
|
74
|
+
the Agent plugin is on or not, and the panel shows the round it asked
|
|
75
|
+
for under the buttons: a status line — asking the agent, the agent
|
|
76
|
+
working, done with the page it wrote when a tool call named one, or the
|
|
77
|
+
agent's own note of why it stopped — each tool call as one line with a
|
|
78
|
+
mark for its state, the last paragraph of what the agent said, the
|
|
79
|
+
permissions the agent asks during the round with its own options as
|
|
80
|
+
buttons (a minimized panel carries a dot while one waits), and Cancel
|
|
81
|
+
while the turn runs. Every ask is yours, those about the plugin's own
|
|
82
|
+
four tools included: the plugin answers none. Nothing shows before the
|
|
83
|
+
first round; the last round stays when its turn ends. The prompt is a
|
|
84
|
+
turn of the project's one conversation, so the Agent panel shows the
|
|
85
|
+
same turn when it is on, and a turn asked there is not shown here. It
|
|
86
|
+
needs a frame — with nothing selected in Figma, the error line says to
|
|
87
|
+
select one first, and the agent is not started — and an agent
|
|
88
|
+
installed; the error line says which is missing. With several frames
|
|
89
|
+
selected, one prompt names every frame by name and id and asks for one
|
|
90
|
+
page per frame, titled after each, each compared against its own
|
|
91
|
+
screenshot; the panel shows that one round. The one-frame prompt
|
|
92
|
+
carries the frame's width when its metadata answers within 3 s, and
|
|
93
|
+
goes without it otherwise.
|
|
94
|
+
|
|
95
|
+
Under the two buttons sits a settings row, the same the Impeccable box
|
|
96
|
+
shows, hidden on a host that runs no agents. **Agent** is a select of
|
|
97
|
+
the agents Daydream knows, the one the Agent panel would show chosen
|
|
98
|
+
first — the project's conversation's, else the one used last, else the
|
|
99
|
+
first installed — with its state after it in a word or two ("starts on
|
|
100
|
+
Add as page" until a conversation with it is open; starting, ready,
|
|
101
|
+
working, needs a sign-in, stopped). Choosing another starts nothing by
|
|
102
|
+
itself: the next Add as page starts it, as a new conversation when it
|
|
103
|
+
is not the one the project's conversation is with (Daydream's
|
|
104
|
+
`intent: "new"`, the user's one switch). Once a conversation with the
|
|
105
|
+
chosen agent is open, the row adds the agent's **Mode** (unless the
|
|
106
|
+
agent offers its mode among its settings, which then stands for it) and
|
|
107
|
+
each of its settings — a select, or a checkbox — set through Daydream
|
|
108
|
+
as the Agent panel sets them, so the two never disagree. The agent's
|
|
109
|
+
permission behaviour lives there (Claude Code's is its mode), and is
|
|
110
|
+
your choice: pick a mode that asks for each tool, or one that does
|
|
111
|
+
not, before pressing Add as page a second time, or in the row as the
|
|
112
|
+
round runs. Before the first Add as page the row shows the agent alone,
|
|
113
|
+
since modes and settings are a live conversation's.
|
|
114
|
+
|
|
115
|
+
Why the agent and not a converter: Figma's Dev Mode server emits React and
|
|
116
|
+
Tailwind for `get_design_context`, in every configuration it was asked in
|
|
117
|
+
(`clientLanguages` of `html,css`, `clientFrameworks` of `unknown`, `none`,
|
|
118
|
+
`vanilla` and `html`, and `forceCode`), and its own notes say the code must
|
|
119
|
+
be converted. A mechanical rewrite of Tailwind classes into CSS would ship a
|
|
120
|
+
page that looks like the frame only by accident; the transcription is the
|
|
121
|
+
agent's work, with the frame's tree, code and screenshot in front of it.
|
|
122
|
+
|
|
123
|
+
## The agent tools
|
|
124
|
+
|
|
125
|
+
The host part registers four MCP tools, so any agent connected to Daydream
|
|
126
|
+
reads Figma through it with no Figma setup of its own. Each takes an
|
|
127
|
+
optional `node` (an id, or a Figma link with a `node-id`; none for Figma's
|
|
128
|
+
selection — the panel never names one, an agent does), reads Figma only,
|
|
129
|
+
and answers one sentence as an error result when Figma does not answer. `figma_metadata` and `figma_variables` are marked read-only;
|
|
130
|
+
`figma_screenshot` and `figma_design_context` are not, since they write
|
|
131
|
+
the screenshot into the project.
|
|
132
|
+
|
|
133
|
+
| Tool | Answers |
|
|
134
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
135
|
+
| `figma_metadata` | the node's tree as `get_metadata` gives it: XML of ids, layer types, names, positions and sizes, the server's notes after it; with nothing selected, the document's pages |
|
|
136
|
+
| `figma_design_context` | the node as code (`get_design_context`: React and Tailwind, with `data-node-id` attributes) and the notes; with `screenshot: true`, its PNG is written too |
|
|
137
|
+
| `figma_screenshot` | the node's PNG (`get_screenshot`), written into the open project's `.daydream/figma/<node>.png` (`selection.png` for the selection) and answered as that path |
|
|
138
|
+
| `figma_variables` | the variables the node uses (`get_variable_defs`), as the server spells them |
|
|
139
|
+
|
|
140
|
+
A tool's result carries text alone on this plugin API, so a screenshot is a
|
|
141
|
+
file in the project's `.daydream/` scratch, never through a link, for the
|
|
142
|
+
agent to read with its own file tools. The images a design context names
|
|
143
|
+
are served at `http://localhost:3845/assets/…` only while Figma runs; a
|
|
144
|
+
page that uses one copies it into the project's `assets/`.
|
|
145
|
+
|
|
146
|
+
## What is not done
|
|
147
|
+
|
|
148
|
+
- No plugin inside Figma: Daydream reads Figma through Figma's own server
|
|
149
|
+
and adds nothing to Figma.
|
|
150
|
+
- No write-back: nothing changes in Figma, ever.
|
|
151
|
+
- No `.fig` files: only the file open in Figma desktop is read, through its
|
|
152
|
+
server, never a file on disk or Figma's web API.
|
|
153
|
+
- No converter of Figma's code into HTML and CSS (above).
|
|
154
|
+
|
|
155
|
+
## Limits
|
|
156
|
+
|
|
157
|
+
- One file at a time: the one open in Figma desktop. The server reads the
|
|
158
|
+
current page's nodes and the selection, and never takes or tells a file
|
|
159
|
+
key, so a `node` an agent gives a tool as a link is read against the
|
|
160
|
+
open file whichever file the link names: a Share link from another file
|
|
161
|
+
reads that id in the open file, or is refused when the id is not there,
|
|
162
|
+
and nothing on this side can tell. Open the linked file in Figma first.
|
|
163
|
+
- A node that is not on the open page, or an id of a shape the server does
|
|
164
|
+
not take, is Figma's refusal, said in the error line.
|
|
165
|
+
- The image's name and id come from the selection's listing; the
|
|
166
|
+
`figma_screenshot` tool, which takes a node from an agent, names it from
|
|
167
|
+
the frame's metadata, asked under 3 s of its own (a name is a courtesy),
|
|
168
|
+
and names the node the agent gave when that does not answer in time, its
|
|
169
|
+
file named after it. A screenshot of the page itself (nothing selected)
|
|
170
|
+
lands as "Figma image", unnamed, to rename in its title bar.
|
|
171
|
+
- The selection's listing is read under 5 s of its own: past that the
|
|
172
|
+
gesture says Figma was too slow, and nothing is asked further.
|
|
173
|
+
- A streamed answer is buffered to 32 MB at most; a server that streams
|
|
174
|
+
past that without answering is dropped with one sentence.
|
|
175
|
+
- `get_variable_defs` answers a JSON object of the variables the node
|
|
176
|
+
uses, name to value, every value a string
|
|
177
|
+
(`{"Size":"42","White":"#ffffff","Name":"John"}`, seen live; `{}` for
|
|
178
|
+
none; an alias resolved to the value it points at), passed through as
|
|
179
|
+
text, unread.
|
|
180
|
+
- The server's own bounds apply: a very large frame may be answered as
|
|
181
|
+
metadata alone, and one call of the client — its handshake, a session
|
|
182
|
+
opened again and the retry included — is given 45 s in all, under the
|
|
183
|
+
50 s the kernel allows a host-part call, so what the panel hears is the
|
|
184
|
+
client's sentence and never the kernel's.
|
|
185
|
+
|
|
186
|
+
## Validation
|
|
187
|
+
|
|
188
|
+
`pnpm test` runs the host part over a fake client and a fake host (the
|
|
189
|
+
channels, the four tools — the one list the manifest declares — the
|
|
190
|
+
screenshot file under the project, Figma not answering as a sentence), the
|
|
191
|
+
gestures over a fake `dd` (the selection's kinds, a slow metadata read, the
|
|
192
|
+
layers inside instances left out, several frames) and the pure parts (the
|
|
193
|
+
payload rules, a saved `link` let through, the frame read from the metadata
|
|
194
|
+
XML, the prompt). The round reader's three folds carry `mirrors-adapted`
|
|
195
|
+
markers naming the agent panel's thread state in the kernel, so
|
|
196
|
+
`test:kernel` reports when the kernel's changes.
|
|
197
|
+
`pnpm test:kernel <daydream-checkout> plugins/daydream.figma` mounts the
|
|
198
|
+
real shell with host-part replies in memory: the state line, an image
|
|
199
|
+
landed and selected with its file copied, three frames in a row, a saved
|
|
200
|
+
item with its `link` still drawn, nothing selected, the unreachable
|
|
201
|
+
sentence, Add as page with no agent, and — over a scripted `dd.agent` — the round block as the
|
|
202
|
+
agent takes the prompt, calls tools, asks a permission and ends, Cancel,
|
|
203
|
+
a turn asked from the agent panel left alone, and the settings row: the
|
|
204
|
+
project's agent chosen, the mode and settings of the open conversation
|
|
205
|
+
set through the host, and another agent chosen started as a new
|
|
206
|
+
conversation on the next Add as page. The plugin requires a Daydream build reporting API 3.0. See the
|
|
207
|
+
repository’s kernel pin and release gate before shipping.
|