M6: PDF export depth and REST conditional and variable-mode actions (#65)

PDF export
- Vector masks clip to the mask's outline, luminance masks are luminosity
  soft masks (alpha masks as before).
- Background blur: the backdrop the page draws under the layer is rendered,
  blurred and cut to its shape, under the layer's vector content.
- Text hyperlinks become clickable link annotations (one per line and link).
- Frames-to-PDF shares one path (`frames_pdf`): sRGB conversion for Display
  P3 files, hidden frames left out, the file name as the PDF title.
- `figcraft-cli export -o x.pdf` and `convert x.figcraft x.pdf` write the
  page's frames one PDF page each.
- Tests: mask types, backdrops, links, image deduplication, page sizes in
  points, hostile inputs; CLI end to end. Checked by rendering the PDFs back
  to PNG and diffing against the PNG export.

Prototyping
- Model: conditional actions (if / else if / else blocks), set variable mode,
  and expressions (literals, variable references, + - * /, comparisons,
  and/or/not, negate) for set-variable values and conditions; walk helpers
  for nested actions (remap on paste, colours, destination checks, library
  copies and pruning, canvas connections).
- REST import maps CONDITIONAL, SET_VARIABLE_MODE and SET_VARIABLE with
  variable references and EXPRESSION values; unsupported functions (mode
  lookups) skip the action with a warning.
- The presenter runs them in order (`figcraft_engine::proto_run`); the
  Prototype panel summarises conditionals, edits set-variable-mode, and
  `ui.set {protoEditor}` opens an interaction's editor.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
BFlat
2026-10-10 10:57:58 +07:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 8dff0089e5
commit 044cfef834
33 changed files with 2155 additions and 171 deletions
+4 -3
View File
@@ -97,7 +97,7 @@ text tool).
Invoke a menu item exactly like clicking it (this may open a dialog). Returns `{ok, lastError}`.
### `ui.set {rightTab?, leftTab?, theme?, home?, palette?, mainMenu?, colorPicker?, variables?, layerFilter?, collapseLayers?, exportPreview?, preview?, presentScroll?, colorProfileDialog?, stylePicker?, stylePickerEdit?, stylePickerView?, iconGallery?}`
### `ui.set {rightTab?, leftTab?, theme?, home?, palette?, mainMenu?, colorPicker?, variables?, layerFilter?, collapseLayers?, exportPreview?, preview?, presentScroll?, colorProfileDialog?, stylePicker?, stylePickerEdit?, stylePickerView?, iconGallery?, protoEditor?}`
Switch panels and modes: `rightTab` `design|prototype|inspect`, `leftTab` `file|assets`, `theme`,
`home` (bool), `palette` (bool: the Actions palette), `mainMenu` (bool), `iconGallery` (bool:
@@ -112,8 +112,9 @@ frame id: open the prototype preview pane like `proto.preview`; false or `null`
to what it can scroll), `colorProfileDialog` (`srgb|displayP3`: open File ▸ Color profile with that
profile chosen; `null` closes it), `stylePicker` (`fill|stroke|effect|grid`: open the style picker
for the selection; `null` closes it) with `stylePickerEdit` (a style id or name: open its editor),
`stylePickerView` (`list|grid`). Returns `ui.inspect` (which reports `stylePicker` and
`stylePickerView`).
`stylePickerView` (`list|grid`), `protoEditor` (`[layer id, interaction index]`: open that
interaction's editor in the Prototype panel; `null` closes it). Returns `ui.inspect` (which reports
`stylePicker` and `stylePickerView`).
### `ui.screenshot {path}`