From 5db4bff4612433b805aa4435684f843567ed1557 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sat, 3 Oct 2026 09:51:22 -0400 Subject: [PATCH] M13.12: docs (pdf README, parity, plug-ins), EPS Type 3 fonts reported Co-Authored-By: Claude Opus 5.5 --- crates/pdf/README.md | 75 +++++++++++++++++++++++++++++++++----------- crates/pdf/src/ps.rs | 5 +++ docs/parity.md | 38 ++++++++++++++++++---- docs/plugins.md | 6 ++-- 4 files changed, 98 insertions(+), 26 deletions(-) diff --git a/crates/pdf/README.md b/crates/pdf/README.md index 43452da9..b7678b09 100644 --- a/crates/pdf/README.md +++ b/crates/pdf/README.md @@ -12,17 +12,22 @@ fonts, images, patterns, transparency (blend modes, soft masks) and optional con **Technical Note #5176** (The Compact Font Format Specification) and **#5177** (The Type 2 Charstring Format) for CFF font programs; **Adobe Type 1 Font Format** (version 1.1) for Type 1 font programs; the **PostScript Language Reference, third edition** and the **Encapsulated -PostScript File Format Specification 3.0** for EPS. TrueType font programs are read through -skrifa and JPEG (DCT) images through zune-jpeg (both permissively licensed, pure Rust). No -third-party PDF/PostScript/font code was read; test files (including the CFF and Type 1 fonts) -are generated in code ([`write`](src/write.rs) and the tests). +PostScript File Format Specification 3.0** for EPS; **ITU-T T.4** (07/2003) and **ITU-T T.6** +(11/1988) for CCITT fax images. TrueType font programs are read through skrifa and JPEG (DCT) +images through zune-jpeg (both permissively licensed, pure Rust). No third-party +PDF/PostScript/font/codec code was read; test files (including the CFF and Type 1 fonts and the +CCITT data) are generated in code ([`write`](src/write.rs) and the tests). One CCITT fixture was +produced once by libtiff's `tiffcp` (an external encoder used only as a fixture generator, like +ffmpeg elsewhere) to check the code tables against an independent implementation. ## What is read - **Structure:** indirect objects found by scanning (damaged or incremental cross-reference sections do not matter), object streams, the page tree with inherited resources, MediaBox / CropBox and `/Rotate`. Filters: Flate (with PNG predictors), LZW, ASCIIHex, ASCII85, - RunLength. Encrypted files are refused. + RunLength, CCITTFax (Group 3 one- and two-dimensional, Group 4; `K`, `Columns`, `Rows`, + `EndOfLine`, `EncodedByteAlign`, `EndOfBlock`, `BlackIs1`; damaged data keeps the rows + decoded before the damage). Encrypted files are refused. - **Content:** `q`/`Q`, `cm`, line width / cap / join / miter / dash, ExtGState (`CA`, `ca`, `LW`, `LC`, `LJ`, `ML`, `D`), all path construction and painting operators (non-zero and even-odd), clipping (`W`, `W*`) as clipping groups, colour in DeviceGray / RGB / CMYK, ICCBased (by @@ -39,7 +44,15 @@ are generated in code ([`write`](src/write.rs) and the tests). construction including `arc`/`arcn` and relative operators, `fill`/`eofill`/`stroke`, `clip`/`eoclip`, `rectfill`/`rectstroke`/`rectclip`, gray / RGB / CMYK / HSB colour. DOS EPS binary headers and `%%HiResBoundingBox` / `%%BoundingBox` are honoured; `%%BeginData` / - `%%BeginBinary` / preview sections are skipped. + `%%BeginBinary` / preview sections are skipped. **Text:** `findfont` / `findresource`, + `scalefont`, `makefont`, `selectfont`, `setfont`, `currentfont`, `definefont` (re-encoded + copies made with `forall` and a new `/Encoding`), `StandardEncoding` / `ISOLatin1Encoding`, + `show`, `ashow`, `widthshow`, `awidthshow`, `xshow` / `yshow` / `xyshow`, `kshow` / `cshow` + (the procedure is not run), `glyphshow`, `charpath` (glyph outlines join the path, e.g. for + clipping) and `stringwidth`. Fonts embedded in the file — Type 1 programs (`… currentfile + eexec … cleartomark`, binary or hexadecimal) and CFF font sets (`StartData`) — are found by + name before the program runs; other fonts are drawn with the bundled fonts as for PDF. Each + `show` becomes one compound shape named "Text: …". - **Text** (§9): text objects and state (`Tc`, `Tw`, `Tz`, `TL`, `Ts`, `Tr`, `Tf`, `Td`, `TD`, `Tm`, `T*`), `Tj`, `TJ` (with kerning), `'` and `"`; render modes fill / stroke / @@ -47,8 +60,9 @@ are generated in code ([`write`](src/write.rs) and the tests). become outlines (one compound shape per show operator, named "Text: …" after the string through `ToUnicode` or the glyph names). Fonts: simple fonts with `/Widths`, base encodings (Standard, WinAnsi, MacRoman), `/Differences` and built-in encodings; composite (Type 0) fonts - with Identity-H / Identity-V and embedded CMaps (`cidrange` / `cidchar`), `/W` and `/DW` - widths and `CIDToGIDMap`. Embedded programs: TrueType (`FontFile2`, cmap (3,1) / (3,0) / + with Identity-H / Identity-V and embedded CMaps (`cidrange` / `cidchar`, `/WMode`), `/W` and + `/DW` widths, vertical metrics (`/W2`, `/DW2`: the vertical displacement and the position + vector from the horizontal to the vertical origin) and `CIDToGIDMap`. Embedded programs: TrueType (`FontFile2`, cmap (3,1) / (3,0) / (1,0) and `post` names), CFF (`FontFile3` `/Type1C`, `/CIDFontType0C`, `/OpenType`; name-keyed and CID-keyed with FDArray / FDSelect, flex, hint masks, `seac`), Type 1 (`FontFile`, eexec, `/Subrs`, flex and hint replacement through othersubrs, `seac`) and Type 3 @@ -64,29 +78,54 @@ are generated in code ([`write`](src/write.rs) and the tests). of the render tree (bilinear, box-filtered when minified). - **Transparency:** blend modes (`/BM`, all 16 PDF modes) and soft masks in the graphics state (`/SMask` with `/S /Luminosity` and `/BC` backdrops, or `/S /Alpha`) as groups of the render - tree, open until the state changes or `Q`. + tree, open until the state changes or `Q`: what is painted while a soft mask is set is + rendered to an offscreen buffer and the mask applies to that combined result. Transparency + group XObjects (§11.6.6) composite as one object: the current alpha, blend mode and soft mask + apply to the group's result, and its contents start from the initial alpha. Isolated groups + (`/I true`) composite over a transparent backdrop; non-isolated groups over the page, with + the backdrop's contribution removed again (§11.4.8) so group alpha and masks apply only to + the group; knockout groups (`/K true`) composite each child with the group's initial + backdrop. Clipping groups are not transparency groups: blend modes inside them reach the + backdrop. - **Patterns:** tiling patterns (coloured and uncoloured, `XStep` / `YStep`, the cell clipped to `/BBox`, at most 4096 tiles per fill) for fills; strokes with a tiling pattern use its colour (uncoloured) or grey. -- **Functions:** sampled, exponential, stitching and PostScript calculator (type 4) functions. +- **Shadings** (§8.7.4.5): axial and radial shadings become gradients. Function-based shadings + (type 1, `Domain` and `Matrix`) and the mesh shadings — free-form (type 4, edge flags 0–2) + and lattice-form (type 5) Gouraud-shaded triangle meshes, Coons patch meshes (type 6) and + tensor-product patch meshes (type 7, flags 0–3 sharing the previous patch's edges) with + `BitsPerCoordinate` / `BitsPerComponent` / `BitsPerFlag` / `Decode` and an optional + parametric `Function` — are rasterised into an image node in page space (up to 4 pixels per + point, at most 1024 pixels a side, 2×2 supersampled): patches are tessellated into triangles + (up to 48×48 cells), colours (or `t`) interpolated across each triangle. They paint through + `sh` (their own extent only) and as shading-pattern fills (clipped to the path). +- **Functions:** sampled (one or several inputs, multilinear interpolation), exponential, + stitching and PostScript calculator (type 4) functions. - **Pages:** any page ([`parse_page`], [`page_count`]); File ▸ Import takes `page` (from 1) and the Import dialog asks for it; footage remembers its page (`Footage::page`). ## Limitations -- Mesh shadings (types 4–7) and function-based shadings (type 1), JPX / CCITT / JBIG2 images, - predefined CJK CMaps other than Identity, vertical metrics (`/W2`; vertical text advances by - the font size) and transfer functions (`/TR`) are not read; knockout and isolated transparency - groups composite as normal groups, and a soft mask applies to each painting operation while - it is set rather than to their composite. What a document skipped is listed in `Doc::skipped`. +- JPX and JBIG2 images, predefined CJK CMaps other than Identity-H / Identity-V, and transfer + functions (`/TR`) are not read. JBIG2 is deferred. Predefined CMaps (`UniGB-UCS2-H`, + `90ms-RKSJ-H` …) need the CMap data, and there is no permissively licensed pure-Rust source + of it (Adobe's CMap resources are Adobe assets, which this project does not ship); text in + such fonts is reported in `Doc::skipped`. Mesh shadings are raster images in the render tree + (sharp to about 4× the document size). Knockout uses each child's coverage as its shape (a + child with constant opacity knocks out fully where it covers). What a document skipped is + listed in `Doc::skipped`. - Illustrator EPS files whose drawing depends on Adobe's procedure-set resources (defined in the file through constructs beyond this subset) and Level 3 `shfill` gradients in EPS draw only what the subset understands; save such artwork as PDF-compatible `.ai` or PDF instead. - EPS text is not drawn. + EPS images are skipped; Type 3 (procedure) fonts defined in EPS files draw nothing (reported). - **Create Shapes from Vector Layer:** clips that enclose the whole page become layer masks (the first clip Add, later ones Intersect). Nested clipping groups become Merge Paths: each closed shape inside them is a group with its geometry merged into one compound path, the clip paths, and Merge Paths ▸ Intersect before its fill and stroke, so fills match exactly and strokes follow the clipped outline; open stroked paths inside clips stay unclipped. Blend - modes become the groups' Blend Mode; images and soft masks are not converted (shape layers - have no images; use the footage, or Import As: Composition). + modes become the groups' Blend Mode. Images become footage layers: each is written as + ` Image .png` next to the source and imported, placed by its matrix (anchor at its + top-left corner; position, rotation and scale — a skew is reported) and parented to the shape + layer; the shapes drawn between images go to shape layers of their own (` Outlines + `), so the layer stack keeps the document's paint order. Soft masks, and the clips and + masks of images, are not converted (the command's `skipped` list says so). diff --git a/crates/pdf/src/ps.rs b/crates/pdf/src/ps.rs index 153956ed..22d2e231 100644 --- a/crates/pdf/src/ps.rs +++ b/crates/pdf/src/ps.rs @@ -1555,6 +1555,11 @@ impl Interp { /// The drawable font of a font dictionary (its base program and encoding) and the matrix /// from text space (font size 1) to user space. fn font_of(&mut self, d: &DictRef) -> Option<(Rc, Affine)> { + if matches!(d.borrow().get("FontType"), Some(V::Num(t)) if *t == 3.0) { + // Type 3 fonts (glyph procedures) are not run. + self.b.skip("EPS Type 3 font"); + return None; + } let (base, names) = { let m = d.borrow(); let base = m.get("__base").or_else(|| m.get("FontName")).map(V::key)?; diff --git a/docs/parity.md b/docs/parity.md index 089a72a1..4c9cf5f3 100644 --- a/docs/parity.md +++ b/docs/parity.md @@ -35,8 +35,8 @@ Tracking 96%, Effects 85%, Web 65%. What is left, in priority order: the web app's depth (threads, storage, audio, non-blocking renders); stroke taper/wave and multi-segment dashes; variable mask feather points; camera iris/bokeh and focus-link commands; -approximated effects (Key Cleaner) and Liquify's viewer brush; mesh shadings and JPX images in -imported PDF/AI files and Illustrator procset EPS; and more codecs. Face tracking and a true Subspace Warp +approximated effects (Key Cleaner) and Liquify's viewer brush; JPX / JBIG2 images in +imported PDF/AI files (mesh shadings and CCITT landed in M13.12) and Illustrator procset EPS; and more codecs. Face tracking and a true Subspace Warp landed in M13.3. ScriptUI (dialogs that block `show()`, palettes, dockable ScriptUI panels, File ▸ Scripts install and sample scripts), puppet pin recording and the remaining "better than After Effects" items — a versioned effect plug-in API with sandboxed WebAssembly plug-ins ([plugins.md](plugins.md)), @@ -128,12 +128,12 @@ the disk cache in the formats wave; the 3D Camera Tracker in M12.6.) | Layers | 88% | 4.8 | frame blending, collapse transformations, slip edit | | Output | 97% | 0.8 | Render Settings complete (field render + 3:2 pulldown, effects/solo/guide/depth/blending/blur overrides, time sampling, storage overflow), Output Module crop/ROI/resize, alpha modes, post-render actions, PCM formats, templates with defaults, render logs, Notify (M10.2); WebM VP9 key + inter frames with motion search, loop filter and rate control. Left: Opus is CELT-only, Photoshop sequence output, overflow for movies only checks at file creation | | Audio | 85% | 0.5 | audio to keyframes | -| Import | 96% | 0.6 | mesh shadings (types 4–7), JPX / CCITT / JBIG2 images and non-Identity CJK CMaps inside PDF/AI files, Illustrator EPS relying on Adobe procsets, PSD 3D layers (M13.6: PDF/AI text with embedded TrueType / CFF / Type 1 / Type 3 fonts and standard-14 fallback to the bundled fonts, Flate / DCT / inline / stencil images with soft masks, Indexed and ICC alternates, luminosity / alpha soft masks, the 16 blend modes, tiling patterns, calculator functions, any page via `file.import page` and the Import dialog, clip groups kept by Create Shapes from Vector Layer as layer masks / Merge Paths; PSD smart-object perspective quads and placed-layer warps — named styles and custom quilt meshes — baked as placed; PDF / PDF-compatible AI / EPS vector footage with Continuously Rasterize, layered composition import and Create Shapes from Vector Layer, and PSD smart objects with embedded files landed in M13.2; PSD as footage/composition/retain layer sizes, SVG footage earlier) | +| Import | 97% | 0.5 | JPX / JBIG2 images and predefined non-Identity CJK CMaps inside PDF/AI files, Illustrator EPS relying on Adobe procsets, PSD 3D layers (M13.12: mesh shadings — free-form / lattice Gouraud triangles, Coons and tensor patches — and function-based shadings, CCITT G3 / G4 images, knockout / isolated transparency groups with group alpha and soft masks on the group's result, `/W2` vertical metrics, EPS text with embedded Type 1 / CFF or bundled fonts, and Create Shapes from Vector Layer keeping images as parented footage layers in paint order; M13.6: PDF/AI text with embedded TrueType / CFF / Type 1 / Type 3 fonts and standard-14 fallback to the bundled fonts, Flate / DCT / inline / stencil images with soft masks, Indexed and ICC alternates, luminosity / alpha soft masks, the 16 blend modes, tiling patterns, calculator functions, any page via `file.import page` and the Import dialog, clip groups kept by Create Shapes from Vector Layer as layer masks / Merge Paths; PSD smart-object perspective quads and placed-layer warps — named styles and custom quilt meshes — baked as placed; PDF / PDF-compatible AI / EPS vector footage with Continuously Rasterize, layered composition import and Create Shapes from Vector Layer, and PSD smart objects with embedded files landed in M13.2; PSD as footage/composition/retain layer sizes, SVG footage earlier) | | Automation | ≈ 99% | 0.1 | `.jsxbin` (AUT-2: ScriptUI resource strings, `onDraw`/ScriptUIGraphics, live `onChanging`, `Socket`, Essential Graphics hooks — `addToMotionGraphicsTemplate(As)`, `canAddToMotionGraphicsTemplate`, `exportAsMotionGraphicsTemplate`, `motionGraphicsTemplateName`, controller count/names — and Watch Folder landed in M13.7; the core object model landed in M14.4; ScriptUI windows/dialogs/dockable panels with `scriptui.*` agent commands, File ▸ Scripts install + sample scripts, and the effect plug-in API (EFF-6, WebAssembly) landed in M13.1) | | Shapes | ≈ 80% | 1.5 | Lottie can't carry stroke taper/wave (stroke Taper and Wave, Dash 2/Gap 2/Dash 3/Gap 3 and radial-gradient Highlight Length/Angle landed in M13.5; pen tool for shape paths and vertex editing in M6.5) | | Compositions | ≈ 80% | 3.5 | Mocha-style planar tracks for templates, Essential Graphics' mirrored properties (CMP-7: Font and uniform Scale controls, Composition ▸ Open in Essential Graphics, Save Frame As ▸ Photoshop Layers / ProEXR and the VR Comp Editor landed in M13.7; the marker dialog, Composition Flowchart, Essential Graphics with master properties, `.ectemplate` templates and Responsive Design — Time landed: CMP-6, CMP-7) | | Animation | 70% | 9.0 | puppet depth beyond pins and recording (puppet pin recording with Record Options landed in M13.1), Wiggler/Smoother/Motion Sketch (motion-path handles and the graph editor transform box landed in M5.8; keyframe colour labels and Select Keyframe Label Group, Graph Editor snapping to markers / layer ends in M13.5) | -| Text | ≈ 95% | 0.4 | no extruded strokes, the Variable Font Axes animator changes outlines but not advances (M13.6: variable font axes in the character style — `layer.setText variations`, the Character panel's Variable Font Axes fields — shape with HVAR / gvar advances and draw at that design-space position; OpenType features — stylistic sets, discretionary ligatures, contextual / stylistic alternates, swash, titling, ordinals, fractions, figure styles, true small caps / all small caps and superior / inferior glyphs with faux fallback — per character with the Character panel's OpenType popup and `text.fontFeatures` landed in M13.2; vertical Roman / Tate-Chu-Yoko, forced LTR paragraphs, caret on animated and path text, Variable Font Axes and Lottie style runs landed in M13.5; extruded, bevelled text in M7.6; per-character styles, paragraph settings, on-canvas editing and the `sourceText` style API in M9.9–M9.10) | +| Text | ≈ 96% | 0.3 | no extruded strokes (M13.12: the Variable Font Axes animator re-spaces the text — advances follow the animated axes; M13.6: variable font axes in the character style — `layer.setText variations`, the Character panel's Variable Font Axes fields — shape with HVAR / gvar advances and draw at that design-space position; OpenType features — stylistic sets, discretionary ligatures, contextual / stylistic alternates, swash, titling, ordinals, fractions, figure styles, true small caps / all small caps and superior / inferior glyphs with faux fallback — per character with the Character panel's OpenType popup and `text.fontFeatures` landed in M13.2; vertical Roman / Tate-Chu-Yoko, forced LTR paragraphs, caret on animated and path text, Variable Font Axes and Lottie style runs landed in M13.5; extruded, bevelled text in M7.6; per-character styles, paragraph settings, on-canvas editing and the `sourceText` style API in M9.9–M9.10) | | Web | 85% | 1.0 | viewer frames and Roto Brush propagation still on the page's thread; GPU effects in the browser (browser storage, Web Audio, Web Worker renders/analyses, WebGPU viewer and offline install landed in M15.2) | | 3D | 88% | 5.5 | multi-view layouts, the Extended Viewer for Advanced 3D comps (Classic 3D Extended Viewer landed in M13.5 UI completion); collapsed precomps of another size seen through the parent's camera render (fixed in M13.2); stereo rigs, orbit nulls, lights controlled by the camera, cameras/lights from glTF models, environment backgrounds, Advanced 3D motion blur, blend modes and track mattes landed in M7.7; Classic 3D iris-shaped bokeh with highlights, progressive depth of field on tilted layers and the focus-link commands landed in M13.5; Advanced 3D depth of field with the iris and highlight options, collapsed precomps as real Advanced 3D geometry and extruded text/shape strokes landed in M13.8; Advanced 3D (glTF/OBJ models, primitives, extruded text and shapes, PBR, image-based light, shadow maps, GPU rasteriser) in M7.4–M7.6 | | Effects | ≈ 80% | 4.0 | GPU versions of the remaining effects (58 run on the GPU since M12.7) and the missing controls listed as partial in [effects.md](effects.md) (every After Effects effect exists since M9.11, M12.5 and M12.6; parameter names, order, twirl-downs, popups, units and defaults were aligned in M9.12) | @@ -180,8 +180,8 @@ Tate-Chu-Yoko, forced LTR paragraphs, the editing caret on animated / path text style runs; the Layer Style dialog (LYR-9); Graph Editor snapping to markers and layer ends (ANM-4; the reference graph existed); viewer ROI resize handles, Pan Behind snapping and 3D Reference Axes; Animate Text ▸ Variable Font Axes. Remaining in these rows: Lottie can't carry -taper/wave and the Variable Font Axes animator doesn't change advances (the Character panel's -axes do since M13.6; Advanced 3D's DOF has iris shapes since M13.8). +taper/wave (the Variable Font Axes animator changes advances since M13.12, the Character panel's +axes since M13.6; Advanced 3D's DOF has iris shapes since M13.8). ## Update: M13.8 Preview panel, Align panel, Advanced 3D completion @@ -241,6 +241,32 @@ menu entries. Not yet: creating a reference frame by editing a still (After Effe Photoshop), Content-Aware Fill's learned model (ours is PatchMatch + flow propagation), and Media Browser in the web app. +## Update: M13.12 import and text leftovers, test hardening + +- **PDF / AI**: mesh shadings — free-form and lattice-form Gouraud triangle meshes (types 4, 5), + Coons and tensor-product patch meshes (6, 7, tessellated to triangles) — and function-based + shadings (type 1, with multi-input sampled functions), for `sh` and shading-pattern fills, + rasterised into image nodes; CCITT Group 3 (1-D and 2-D) and Group 4 images from ITU-T T.4 / + T.6 (checked against an independent encoder's output); knockout and isolated transparency + groups, the current alpha / blend mode / soft mask applied to a transparency group XObject's + combined result, and blend modes inside clipping groups reaching the backdrop; `/W2` / `/DW2` + vertical metrics and CMap `WMode`. Not done: JBIG2 images (deferred) and predefined CJK CMaps (no permissively licensed + pure-Rust source of the CMap data; Adobe's CMap resources are Adobe assets). +- **EPS**: text through the PostScript interpreter — `findfont` / `scalefont` / `makefont` / + `selectfont` / `setfont`, `show`, `ashow`, `widthshow`, `awidthshow`, `xshow` / `yshow` / + `xyshow`, `kshow`, `glyphshow`, `charpath`, `stringwidth`, re-encoded fonts (`definefont` + copies with a new `/Encoding`) — with embedded Type 1 and CFF programs or the bundled fonts. +- **Create Shapes from Vector Layer**: images become PNG footage layers parented to the shape + layer, and the shapes between images are split into layers of their own so the stack keeps + the document's paint order; soft masks and clipped images are reported. +- **Text**: the Variable Font Axes animator re-spaces the text (advances at the animated + design-space position), not only the outlines. +- **Hardening**: PDF / EPS parsers survive truncated and corrupted files (fixed an + out-of-range stream slice and unbounded PostScript recursion); WebAssembly plug-ins get a + memory cap, a manifest length limit and slider schema checks, with tests for missing exports, + wrong signatures and versions, fuel exhaustion, traps and bit-identical output; script + `Socket` validates ports, and ScriptUI resource strings accept trailing array commas. + ## Highest-value gaps, in order 1. ~~On-canvas text editing and per-character styles~~ (landed: M9.9–M9.10). diff --git a/docs/plugins.md b/docs/plugins.md index 5d5b39c0..47ce5caa 100644 --- a/docs/plugins.md +++ b/docs/plugins.md @@ -12,7 +12,7 @@ There are two ways to write one: |---|---|---| | What | a `.wasm` (or `.wat`) module | a type implementing `effectcraft_effects::plugin::EffectPlugin` | | Loaded by | Effect ▸ Load Effect Plug-in…, `effect.plugins.load {path \| folder}`, or the `Plug-ins` folder next to the settings at start-up | `register_plugin(Arc::new(MyEffect))` in an app that links EffectCraft's crates | -| Sandbox | yes: no imports (no files, clock or network), fuel-limited, deterministic floats | none (it is your code) | +| Sandbox | yes: no imports (no files, clock or network), fuel-limited, at most 1 GiB of memory, deterministic floats | none (it is your code) | | Platforms | desktop and CLI (the wasmi interpreter, crate feature `effectcraft-plugin/wasm`); not the web build | everywhere | `effect.plugins.list` lists what is loaded: `{api, wasm, plugins: [{id, name, category, version, @@ -60,7 +60,9 @@ Every plug-in describes itself with a JSON manifest: * Parameter types: `slider` (`default`, `min`, `max`, optional `sliderMin`, `sliderMax`, `decimals`), `angle` (`default` degrees), `checkbox` (`default` bool), `popup` (`options`, `default` index), `point` (`default` as fractions of the layer size, `[0.5, 0.5]` = centre), - `color` (`default` RGBA 0–1). Parameter ids are letters, digits and `_`. + `color` (`default` RGBA 0–1). Parameter ids are letters, digits and `_`, unique; at most 256 + parameters; a slider needs `min ≤ default ≤ max` (and `sliderMin ≤ sliderMax`); the manifest + is at most 1 MiB. ## WebAssembly ABI (v1)