figura-cli 0.19.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "figura-cli",
3
- "version": "0.19.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
  }
@@ -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. **Open the HOSTED fig for approval — never a local file.** Run
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 before publishing.** Render the fig headless at a few viewport
246
- widths: `document.scrollWidth` must equal the viewport in every view and
247
- state (sideways scroll = broken beware CSS `zoom`, which leaks unzoomed
248
- width into scrollable overflow; scale minis with `transform` in
249
- fixed-aspect wrappers instead), and screenshot each state to check no
250
- annotation chip covers the content it annotates.
251
- When you write the fig's HTML out to render/screenshot it, save it to a
252
- **deterministic**, project-scoped path the repo's `.figura/figs/` (already
253
- gitignored), or `~/.figura/figs/` outside a bound repo — never `/tmp` or
254
- `mktemp`. A stable path means a rerun overwrites the same file instead of
255
- littering volatile temp locations, and matches where `figura fig open --local`
256
- writes (`<repo>/.figura/figs/figura-fig-<id>.html`) this is YOUR headless
257
- self-check copy, separate from the hosted `viewUrl` a human reviewer opens
258
- (step 4 above).
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
@@ -320,9 +341,12 @@ So when you **hand-build** a fig (the default path), you do your part of the
320
341
  contract — but the exact rules are **fetched, not restated here**: the
321
342
  presentation model (frameless single vs canvas composition), when to emit or
322
343
  omit the whole-fig `<meta name="figura:artboard">`, the `.fig-device` /
323
- `data-device` frame markup (and NOT authoring its CSS — Figura stamps the bezel,
324
- Dynamic Island, and safe-area insets), the `figura:context` / `figura:feature`
325
- metas, and the valid devices all live in the canonical scaffold.
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.
326
350
 
327
351
  - **`figura_fig_scaffold`** (CLI: `figura fig scaffold`) is authoritative for the
328
352
  presentation model, the frame markup, and the output contract. Fetch it and