figura-cli 0.18.1 → 0.20.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 +12 -10
- package/dist/index.js +202 -155
- package/dist/mcp.js +38 -35
- package/package.json +2 -1
- package/skills/fig/SKILL.md +58 -73
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "figura-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Command-line client for the Figura visualization SaaS",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"@panofm/figura-core": "workspace:*",
|
|
37
37
|
"@types/node": "^20.14.0",
|
|
38
38
|
"axios": "^1.7.9",
|
|
39
|
+
"package-manager-detector": "^1.8.0",
|
|
39
40
|
"postgres": "^3.4.9",
|
|
40
41
|
"typescript": "^5.5.0"
|
|
41
42
|
}
|
package/skills/fig/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: fig
|
|
3
3
|
description: "Mock up a screen as an on-brand, shareable HTML fig via your Figura team — render a UI state in seconds before writing the real code. Use when asked to visualize a screen, mock a UI, or 'make a fig'. iPhone-framed by default; browser frame for web/desktop."
|
|
4
4
|
argument-hint: '<what to visualize>'
|
|
5
|
-
allowed-tools: 'mcp__figura__figura_whoami, mcp__figura__figura_fig_scaffold, mcp__figura__figura_generate_fig, mcp__figura__figura_create_fig, mcp__figura__figura_revise_fig, mcp__figura__figura_publish_fig, mcp__figura__figura_commit_fig, Bash(figura *), Bash(bunx figura-cli *)'
|
|
5
|
+
allowed-tools: 'mcp__figura__figura_whoami, mcp__figura__figura_fig_scaffold, mcp__figura__figura_fig_devices, mcp__figura__figura_generate_fig, mcp__figura__figura_create_fig, mcp__figura__figura_revise_fig, mcp__figura__figura_publish_fig, mcp__figura__figura_commit_fig, Bash(figura *), Bash(bunx figura-cli *)'
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# /fig — figure it out before you build it
|
|
@@ -171,7 +171,11 @@ so you hand it the studied structure in the brief (see step 3, "Server render").
|
|
|
171
171
|
change). If you truly couldn't locate the source, say so in the brief and label
|
|
172
172
|
the baseline an approximation, same as the hand-build fallback.
|
|
173
173
|
|
|
174
|
-
4. **
|
|
174
|
+
4. **Verify, then open the HOSTED fig for approval — never a local file.** First
|
|
175
|
+
run **`figura fig verify <id>`**: the component CSS is stamped server-side, so
|
|
176
|
+
only the served bytes can tell a working fig from one that renders as empty
|
|
177
|
+
phones. It exits non-zero if a frame class shipped unsized — fix and re-land
|
|
178
|
+
before a human sees it. Then run
|
|
175
179
|
`figura fig open <id>` (the id `figura_create_fig`/`figura_generate_fig` just
|
|
176
180
|
returned). It opens **`viewUrl`** in the reviewer's browser — the actual
|
|
177
181
|
Figura render (brand chrome, CSP, favicon, responsive frame), team-scoped so
|
|
@@ -227,7 +231,14 @@ truncation, and doesn't need a library):
|
|
|
227
231
|
status chip and ONE condensed context line (`+ / –`). This view is for
|
|
228
232
|
scanning and picking a direction, not for reading detail. The grid must
|
|
229
233
|
wrap to one column before it can overflow — **a fig never scrolls
|
|
230
|
-
horizontally**, at any viewport.
|
|
234
|
+
horizontally**, at any viewport. To shrink the framed phones, set the kit's
|
|
235
|
+
**`--fig-scale`** custom property (e.g. `style="--fig-scale:.42"` on each
|
|
236
|
+
`.fig-device`, or on the grid container — it inherits) — Figura shrinks the
|
|
237
|
+
whole framed phone and reserves the scaled layout box so the minis tile
|
|
238
|
+
without overlapping. **Do NOT** write your own rule on `.fig-device`
|
|
239
|
+
(a `width`/`height` or `transform: scale()`): `--fig-scale` is the one
|
|
240
|
+
sanctioned scaling knob, and hand-sizing the frame fights the injected
|
|
241
|
+
geometry.
|
|
231
242
|
- **Focus — full frame.** One state at a time behind state pills (Today / A /
|
|
232
243
|
B / …), each state framed identically so flipping states in place reads as
|
|
233
244
|
spot-the-difference. This is where the context lives, pinned on the frame
|
|
@@ -242,20 +253,30 @@ truncation, and doesn't need a library):
|
|
|
242
253
|
arguing the pick against the others. Keep the chrome around the frames
|
|
243
254
|
minimal — the frames are the content; no legends (chips label themselves),
|
|
244
255
|
no repeated context, fluid `max-width` layout throughout.
|
|
245
|
-
- **Verify
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
256
|
+
- **Verify the SERVED fig, not your local draft.** The component kit (device
|
|
257
|
+
frame, status bar, control bar) is stamped **server-side at save** — it does
|
|
258
|
+
**not** exist in the HTML you authored locally, so a headless render of your
|
|
259
|
+
own file shows *unstyled, empty* frames whether or not the fig is actually
|
|
260
|
+
correct. A local screenshot is structurally blind to the most common way a
|
|
261
|
+
framed fig breaks. So verify the fig that actually ships:
|
|
262
|
+
1. **Land it first** (`figura_create_fig` / `figura_revise_fig`), then dump
|
|
263
|
+
the stamped bytes: `figura fig open <id> --local --print`. This is the
|
|
264
|
+
served document, kit and all.
|
|
265
|
+
2. **Assert the kit stamped — `figura fig verify <id>`.** One command, and it
|
|
266
|
+
**exits non-zero** if any frame class your markup uses shipped with no CSS
|
|
267
|
+
giving it dimensions. It checks every injected component (device frame,
|
|
268
|
+
status bar, control bar, browser chrome), cross-checks the manifest's
|
|
269
|
+
`components` array, and reports the fig's own `frameKit` / `complete` /
|
|
270
|
+
`doubleFramed` checks; `--json` for machine output. The engine won't
|
|
271
|
+
silently drop the kit anymore, and create/revise now warns loudly if it
|
|
272
|
+
ever did — this is the check that *proves* a frame renders.
|
|
273
|
+
3. **Screenshot THAT** (the printed served HTML, saved to a deterministic
|
|
274
|
+
project-scoped path — the repo's `.figura/figs/` (gitignored), or
|
|
275
|
+
`~/.figura/figs/` outside a bound repo, never `/tmp`/`mktemp`), at a few
|
|
276
|
+
viewport widths: `document.scrollWidth` must equal the viewport in every
|
|
277
|
+
view and state (sideways scroll = broken), and no annotation chip may
|
|
278
|
+
cover the content it annotates. `figura fig open <id> --local` writes the
|
|
279
|
+
same served bytes to `<repo>/.figura/figs/figura-fig-<id>.html`.
|
|
259
280
|
|
|
260
281
|
A **wipe-slider** stays the narrow tool for exactly two states of the same
|
|
261
282
|
layout with pixel-level tweaks. Never ship a squeezed side-by-side as the
|
|
@@ -316,62 +337,26 @@ with two things you do **not** hand-write:
|
|
|
316
337
|
search and the self-improving loop. Artifact-descriptive only — no team/brand
|
|
317
338
|
ids (the block is served on the public link).
|
|
318
339
|
|
|
319
|
-
So when you **hand-build** a fig (the default path), do your part of the
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
-
|
|
336
|
-
-
|
|
337
|
-
`<
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
### The two mobile presentations — pick ONE, never both (#717)
|
|
341
|
-
|
|
342
|
-
A mobile fig is EITHER a frameless single OR a canvas composition. Emitting both
|
|
343
|
-
signals — a whole-fig `figura:artboard` meta AND an in-fig `.fig-device` frame —
|
|
344
|
-
makes the viewer wrap the *whole* composition in one phone (the key, masthead,
|
|
345
|
-
and second screen all crammed inside the bezel). That contradiction is flagged
|
|
346
|
-
(`double-framed`), so choose deliberately:
|
|
347
|
-
|
|
348
|
-
- **Frameless single** — the whole fig IS one screen. Whole-fig `figura:artboard`
|
|
349
|
-
meta, `<body>` sized to exactly W×H, body == the screen, no surrounding HTML.
|
|
350
|
-
The viewer draws the phone around the entire fig. Best fidelity for "just the
|
|
351
|
-
screen".
|
|
352
|
-
- **Canvas composition** — a document that frames one or more devices **in-fig**,
|
|
353
|
-
with author HTML around them (a design-language key, annotations, multiple
|
|
354
|
-
screens, states with controls). **No whole-fig `figura:artboard` meta.** Frame
|
|
355
|
-
each target device as a bounded `.fig-device` element and Figura stamps the
|
|
356
|
-
bezel + Dynamic Island + safe-area insets for that device (do NOT author CSS
|
|
357
|
-
for `.fig-device` / `.fig-screen` / `.fig-di` / `.fig-homebar`):
|
|
358
|
-
|
|
359
|
-
```html
|
|
360
|
-
<div class="fig-device portrait" data-device="iphone-16">
|
|
361
|
-
<div class="fig-screen fig-safe"> …screen content… </div>
|
|
362
|
-
<div class="fig-di"></div> <!-- Dynamic Island / notch, drawn for you -->
|
|
363
|
-
<div class="fig-homebar"></div> <!-- home indicator, drawn for you -->
|
|
364
|
-
</div>
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Use `class="fig-device landscape"` for a landscape device (the island moves to
|
|
368
|
-
the leading edge automatically). `data-device` is any catalog id
|
|
369
|
-
(`figura fig scaffold` / `brand --json` list them); **different `data-device`
|
|
370
|
-
values on one canvas frame different phones** — an `iphone-16` beside an
|
|
371
|
-
`iphone-se-3`, each with its own bezel radius and cutout. Put your key,
|
|
372
|
-
annotations, and any other screens as ordinary HTML AROUND the framed
|
|
373
|
-
device(s). A composition renders full-page (no whole-fig meta) so nothing is
|
|
374
|
-
phone-wrapped as a whole.
|
|
340
|
+
So when you **hand-build** a fig (the default path), you do your part of the
|
|
341
|
+
contract — but the exact rules are **fetched, not restated here**: the
|
|
342
|
+
presentation model (frameless single vs canvas composition), when to emit or
|
|
343
|
+
omit the whole-fig `<meta name="figura:artboard">`, the `.fig-device` /
|
|
344
|
+
`data-device` frame markup (Figura stamps the bezel, Dynamic Island, and
|
|
345
|
+
safe-area insets **before** your `<style>`, so you normally leave those classes
|
|
346
|
+
alone — if you do style one, your rule wins by cascade and the frame still
|
|
347
|
+
works; to shrink a frame use the `--fig-scale` custom property, never a
|
|
348
|
+
hand-written `.fig-device` width/height/transform), the `figura:context` /
|
|
349
|
+
`figura:feature` metas, and the valid devices all live in the canonical scaffold.
|
|
350
|
+
|
|
351
|
+
- **`figura_fig_scaffold`** (CLI: `figura fig scaffold`) is authoritative for the
|
|
352
|
+
presentation model, the frame markup, and the output contract. Fetch it and
|
|
353
|
+
follow it verbatim (step 2 above) — do NOT restate design/format rules from
|
|
354
|
+
memory. A bundled skill can pin stale; the scaffold is always current.
|
|
355
|
+
- **`figura_fig_devices`** (CLI: `figura fig devices`) is the full valid-
|
|
356
|
+
`data-device` catalog — every framed-device id + its geometry (logical dims,
|
|
357
|
+
safe-area insets, cutout, corner radius). Pick a real id from it for a canvas
|
|
358
|
+
composition's `<div class="fig-device" data-device="…">`; an unknown id
|
|
359
|
+
silently gets no frame.
|
|
375
360
|
|
|
376
361
|
## Notes
|
|
377
362
|
|