diff --git a/AGENTS.md b/AGENTS.md index 3b3b5a4..5f7ed0a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,8 +12,9 @@ follow its standards, and contribute reusable learnings back there. Never code: code. ## Start every session here -1. Read [`ROADMAP.md`](ROADMAP.md): where we stand, the prioritized gap list, and the time estimates. - Unless the user gives you a task, pick work from that list. +1. Read [`ROADMAP.md`](ROADMAP.md) (stage, headline numbers, estimates) and + [`docs/gaps.md`](docs/gaps.md) (the ranked work list). Unless the user gives you a task, pick + work from the top of `docs/gaps.md`. 2. Read `plan/STATUS.md` and `plan/execution-plan.md` (local, gitignored) if present; behaviour reference notes are in `plan/figma/*.md`. 3. Orient → plan → implement + test → verify (screenshot) → record (ROADMAP, devlog) → commit. @@ -103,9 +104,13 @@ to `main`. write manifests atomically, delete your target dir when done (disk is limited). ## Roadmap -`ROADMAP.md` (committed) is the shared picture: status by dimension, the gap list, milestones, the -parity table and time-to-parity estimates. When a task lands, update it in the same commit. Grade by -behaviour against the incumbent, not by whether a menu item exists; err low. +Progress docs follow craftrules `standards/progress-docs.md`: [`ROADMAP.md`](ROADMAP.md) (one-page +summary and stage), [`docs/target-app-parity.md`](docs/target-app-parity.md) (the authoritative +assessment), [`docs/gaps.md`](docs/gaps.md) (ranked work list), [`docs/roadmap.md`](docs/roadmap.md) +(milestones), [`docs/architecture.md`](docs/architecture.md), the per-area `docs/*-parity.md` files +and the generated [`docs/parity-checklist.md`](docs/parity-checklist.md) (`cargo xtask parity`). +When a task lands, update the affected rows and the status line and revision history in the same +commit. Grade by behaviour against the incumbent, not by whether a menu item exists; err low. ## Contributor credits (About window) diff --git a/CLAUDE.md b/CLAUDE.md index 3b3b5a4..5f7ed0a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,8 +12,9 @@ follow its standards, and contribute reusable learnings back there. Never code: code. ## Start every session here -1. Read [`ROADMAP.md`](ROADMAP.md): where we stand, the prioritized gap list, and the time estimates. - Unless the user gives you a task, pick work from that list. +1. Read [`ROADMAP.md`](ROADMAP.md) (stage, headline numbers, estimates) and + [`docs/gaps.md`](docs/gaps.md) (the ranked work list). Unless the user gives you a task, pick + work from the top of `docs/gaps.md`. 2. Read `plan/STATUS.md` and `plan/execution-plan.md` (local, gitignored) if present; behaviour reference notes are in `plan/figma/*.md`. 3. Orient → plan → implement + test → verify (screenshot) → record (ROADMAP, devlog) → commit. @@ -103,9 +104,13 @@ to `main`. write manifests atomically, delete your target dir when done (disk is limited). ## Roadmap -`ROADMAP.md` (committed) is the shared picture: status by dimension, the gap list, milestones, the -parity table and time-to-parity estimates. When a task lands, update it in the same commit. Grade by -behaviour against the incumbent, not by whether a menu item exists; err low. +Progress docs follow craftrules `standards/progress-docs.md`: [`ROADMAP.md`](ROADMAP.md) (one-page +summary and stage), [`docs/target-app-parity.md`](docs/target-app-parity.md) (the authoritative +assessment), [`docs/gaps.md`](docs/gaps.md) (ranked work list), [`docs/roadmap.md`](docs/roadmap.md) +(milestones), [`docs/architecture.md`](docs/architecture.md), the per-area `docs/*-parity.md` files +and the generated [`docs/parity-checklist.md`](docs/parity-checklist.md) (`cargo xtask parity`). +When a task lands, update the affected rows and the status line and revision history in the same +commit. Grade by behaviour against the incumbent, not by whether a menu item exists; err low. ## Contributor credits (About window) diff --git a/README.md b/README.md index 2d9b7b6..9f93625 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ New contributors and AI agents: start with [`AGENTS.md`](AGENTS.md), then [`docs Installers for macOS (universal, signed and notarized), Windows (x64, x86 and arm64), Linux (AppImage, `.deb`, `.rpm`, Flatpak and tarball), FreeBSD and the web are attached to each [GitHub release](https://github.com/storytold/figcraft/releases). Maintainers: [`docs/releasing.md`](docs/releasing.md) explains how releases are built, signed and published. > [!IMPORTANT] -> **Status:** FigCraft is in early alpha. Most of Figma's editor surface exists in some form, and the main menu is almost fully wired ([`docs/parity.md`](docs/parity.md)), but that measures wiring, not behaviour. Multiplayer, comments, version history, plugin UIs beyond parameter forms and Dev Mode depth are not there yet. The honest, area-by-area picture is in the [roadmap](ROADMAP.md). Expect rough edges and please file issues, or tell us what broke on [Discord](https://discord.gg/artcraft). +> **Status:** FigCraft is in **alpha**: about 47% of the way to replacing Figma for real work, by our own estimate. Nearly all of Figma's main menu is wired ([`docs/parity-checklist.md`](docs/parity-checklist.md)) and the core editor works end to end, but FigCraft can't open `.fig` files yet, has no multiplayer yet (its core is in, networking is next), runs its own WebAssembly plugins rather than Figma's, and hasn't been checked against real Figma documents. The honest, area-by-area picture is in the [roadmap](ROADMAP.md) and [`docs/target-app-parity.md`](docs/target-app-parity.md). Expect rough edges and please file issues, or tell us what broke on [Discord](https://discord.gg/artcraft). ## The Crafting Apps diff --git a/ROADMAP.md b/ROADMAP.md index cd62821..0c5d2be 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,411 +1,161 @@ # FigCraft Roadmap -FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow. It -runs on macOS, Windows, Linux, FreeBSD and the web (WASM), and agents can drive it completely through -the CLI, a JSON control channel and MCP. +**Stage: alpha** · next: beta, ~28 points and ~200–365 h away (one Opus 5.5 agent; ~40–80 h wall-clock with 5 agents) -This file tracks **how far we are and what's left**. Time estimates are wall-clock hours of -continuous Claude Opus 5.5 agent work (including builds and the CI gate), for **one agent** and for -**4–6 parallel agents** on disjoint crates. They are counted from the remaining work in the parity -table below and updated as work lands. +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (merged #101–#103: plugins and the multiplayer core; ready ~47%) · **Target:** Figma Design (desktop app 126.10.7) -_Last updated: 2026-10-11 (day 3: paint/effect/grid reordering and bindings, Dev Mode component code, annotations, ready for dev, compare and focus view, interaction-editor conditionals, arc handles, progressive blur, keyboard shortcut parity, SVG import fidelity, PDF print options, components at scale, accessibility, no idle redraws, WASM plugins, the collaboration protocol)._ +FigCraft is a clean-room, open-source, pure-Rust reimplementation of the Figma design workflow, +native on macOS, Windows, Linux and FreeBSD and in the browser, fully drivable by agents through +the CLI, a JSON control channel and MCP. This page is the one-page summary; agents choosing work +start with [`docs/gaps.md`](docs/gaps.md). -## Where we are +## Headline numbers -| Dimension | Status | -|---|---| -| Infrastructure (crates, command registry, undo, renderer, formats, control channel, tests) | **~72%** | -| Look & feel vs the incumbent's 2026 UI (measured side by side) | **~65%** | -| Menu/command breadth (`docs/parity.md`) | **98.5%** (200/203) of the catalogued menu tree has a command | -| Feature depth (weighted rubric below) | **~79%** | -| Parity including interaction fidelity and hardening | **~45–50%** | -| Time to **feature parity** | **~45–85 h** one agent · **~12–25 h** with 4–6 agents | -| Time to **full parity** (feature parity + fidelity pass + hardening) | **~115–195 h** one agent · **~32–55 h** with 4–6 agents | +| | Value | Kind | +|---|---|---| +| Menu/command breadth | **98.5%** (200 / 203) | measured, [`docs/parity-checklist.md`](docs/parity-checklist.md) (`cargo xtask parity`) | +| Feature breadth | **~78%** (core editor ~90%) | estimated, [`docs/target-app-parity.md`](docs/target-app-parity.md) | +| Ready for real work | **~47%** | estimated, same doc (written dimension weights and scores) | +| Essentials user | **~53%** | estimated: core features 77.8% × 0.92 launch/stability × 0.92 discoverability × 0.8 opening files people send ([method](docs/target-app-parity.md#essentials-user)) | +| Mainstream practitioner | **~43%** | estimated: weekly areas 66.5% × 0.9 interaction × 0.9 stability × 0.8 file exchange with Figma users ([method](docs/target-app-parity.md#mainstream-practitioner)) | +| Remaining to beta | **~200–365 h** one agent | estimated | +| Remaining to full parity | **~390–745 h** one agent (~95–170 h wall-clock with 5 agents) | estimated | -## Honest assessment (2026-10-09) +### Readiness by audience -**In one line:** the architecture is complete end to end (document model → commands → renderer → -UI, CLI/MCP and control channel), and the everyday core (frames, shapes, text, auto layout, -components with overrides, variants, styles, variables, effects, booleans, prototyping basics, -SVG/PNG/JPG export) works. What's missing is depth: vector editing, rich text editing, the long tail -of auto-layout and component behaviours, real-file interop and a fidelity pass against the -incumbent. +| Audience | Ready % | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates | +|---|---|---|---| +| Full target (ready for real work) | ~47% | ~375–705 h | multiplayer (45–90), localization (60–100), plugins (25–55), the interaction pass (40–60), `.fig` import (30–60), GPU canvas (30–60), AI (30–60) | +| Mainstream practitioner | ~43% | ~180–330 h | core editor depth incl. `.fig` import (98–188), the interaction pass (40–60), real-file corpus and platform QA (25–50), `.fig` export for handing work back (15–30) | +| Essentials user | ~53% | ~85–160 h | `.fig` import so files people send open (30–60), core tool polish (25–45), interaction pass on the core tools (15–25), stability QA (10–20), onboarding and starter templates (5–10) | -**How much to trust the numbers:** scores are self-graded by the agents that built the features from -public documentation and black-box observation. Treat them as upper bounds. Look & feel is the only -dimension measured side by side. +Hours are one agent working sequentially, calibrated from this repo's history (about 1 agent-hour +per 1,000 added lines, 1–2.5 h per feature PR, ~7 h per honest depth point in the polish tail; see +[how the hours are calibrated](docs/target-app-parity.md#how-the-hours-are-calibrated)). Each audience's work is a subset of +the next. About 70–80% parallelizes across 4–6 agents on disjoint crates (roughly ÷4 in +wall-clock); the `.fig` reader, the multiplayer core and a plugin runtime each need one owner, and +native-speaker review, real-file licensing and screen-reader QA need people. -### Where we're lacking (priority order) +Hours are Opus 5.5 agent wall-clock hours, calibrated from this repo's history: the app was built in +~25 wall-clock hours by 4–6 parallel agents (~110–150 agent-hours, ~1 agent-hour per 1,000 added +lines, a typical feature PR 1–2.5 h). Details and what needs a human: +[`docs/target-app-parity.md`](docs/target-app-parity.md#how-the-hours-are-calibrated). -1. **Vector edit mode**: *landed:* edit-mode toolbar (move, pen, bend, paint bucket, lasso, cut), - pen that extends, branches and closes paths (vector networks), paint bucket fill/unfill of any - closed area (faces with holes), point/segment selection, handle mirroring (none/angle/angle and - length) with a Point panel (position, corner radius, mirroring), smooth/sharp points, join and - merge, delete vs delete-and-heal, nudging, one undo step per gesture, eraser (⇧E), shape builder - (⇧M: the regions of overlapping shapes, click or drag to merge, Alt to remove, curves kept), - variable width strokes (width profile presets with previews in the stroke settings, the Variable - width tool ⇧W: drag the path to add a width point, slide points, drag their handles, Delete; - smooth interpolation per subpath, dashes, caps and joins, canvas/PNG/SVG/PDF and outline stroke), - a transform box around several selected points (corners and edges scale them, Shift keeps - proportions, Alt from the centre; just outside a corner rotates, Shift in 15° steps; drag inside - to move; the Design panel's X/Y/W/H and flip/rotate act on the points), point snapping while - dragging points or handles and with both pens (to the points and segment midpoints of this and - other vectors, the usual layer targets and the pixel grid, with guides and a marker on the point - landed on; Ctrl/Cmd turns it off), arc handles on the canvas (sweep, start and ratio with a - live readout, Shift snapping, closing at the start, the other part from the gap; rotated and - flipped ellipses, any zoom). *Left:* live boolean editing, one-sided widths, Design panel arc - fields. 4–8 h. -2. **Text editing depth**: *landed:* OpenType features panel, small caps, lists, title case, - truncation/max lines, font picker with previews and recents, word/line selection, IME commit, - inline IME composition (underlined at the caret, reflowing, candidate window at the caret; the - document only gets the committed text), variable fonts (axes and named instances read from the - font, named instances as styles, Type settings ▸ Variable sliders, per-range axis values applied - to shaping, outlines and PDF), range-aware Typography panel with "Mixed". Range fills in the Fill - section. Right-to-left and mixed-direction text (Unicode bidi: Arabic shaping, mirrored brackets, - caret, clicks and selection follow the runs; arrow keys move visually). Right-to-left and - mixed-direction names in the panels (layers, pages, Assets, tabs, the file header, canvas frame - titles: visual order, joined Arabic, the ellipsis at a right-to-left name's left end; rename fields - whose caret, clicks, drags and arrow keys follow the shown text; system fonts for scripts the UI - fonts lack). The text style browser in the Typography section (list and grid views in each - style's own font, search, folders, this file's and enabled libraries' styles, apply, detach, edit - the typography, create from the selected chars, hover to preview on the canvas, "Mixed" when the - chars use several styles); text styles link chars, not just layers (editing what a style sets - unlinks the chars edited). Live previews of a hovered named instance or font style and of a - dragged axis slider (one undo step on release, Escape cancels). Visual QA: list markers keep the - paragraph's font, renames start with the name selected and centred, Max lines shows while - truncating. Right-to-left paragraphs mirror lists and indents: bullets and numbers (".1") on - the right, wrapped lines hanging from the right, the paragraph indent on the right, trailing - spaces hanging outside the line (canvas, PNG, PDF and SVG). *Left:* visual QA. 0.5 h. -3. **Auto layout and sections depth**: *landed:* on-canvas padding/gap handles (also wrapped-row - and grid column/row gaps, grid tracks outlined), min/max width/height (UI, Hug/Fill/Fixed, - hugging text wraps at its max), ignore auto layout (absolute position) with constraints, text - baseline alignment, grid tracks (fixed/hug/`fr`), grid cells and spans, wrap row gap UI, - wrap-aware drag-reorder (by row) and dragging into a grid cell, nested hug/fill settling in one - pass (wrapping fill text, three levels deep, grid rows), min/max redistribution, coherent - Fill/Hug rules, drag across nested auto layout frames (deepest one wins, insertion line, out to - the canvas or a plain frame). Arrow keys move auto layout children one place (along the flow - past hidden and absolute siblings, Up/Down between wrapped rows, to the neighbouring grid cell - (automatically placed children swap, anchored ones take or swap cells), and at the end of a - flow or across a row's axis into the neighbouring nested auto layout frame when the frame - around flows that way; one undo step, none when nothing can move). Visual QA of nested - hug/fill/fixed/min/max/wrap/grid samples against the documented rules (Fill turns a hugging - parent Fixed, min/max redistribution, wrap inside fill, absolute children following - constraints as hug frames grow). Sections: hide contents (name, outline and "Contents hidden" - on the canvas; contents skipped by rendering, hit testing and labels; dimmed in the layers - panel; Design panel checkbox and context menu), Wrap in new section, frames in sections get - canvas labels and are top-level frames (flows start there, navigation, Export frames to PDF), - "Navigate to" a section shows its frame shown last, else its first; ready for dev turns - "Changed" when the contents are edited, resolved with a reason; Compare changes shows what a - changed frame or section looked like when it was marked next to how it is now, with the - changed layers and their property changes. *Left:* whether `fr` rows of a fixed-height grid - should make room for fixed-size children (now `minmax(0, 1fr)`-like). 1–2 h. -4. **Components depth**: *landed:* component properties (edit/delete/bind) with the properties - panel, add variant, instance swap UI, per-layer overrides with reset, restore main, instance - structure protection; Assets panel with live thumbnails, search and drag-to-canvas (drops into - the frame or auto layout slot under the pointer); exposed nested instances (their properties - show on the main's instances); component descriptions (edited on the main, shown on - instances); local libraries (publish a file's components, sets and styles with per-asset - versions, enable library files, place library components and apply library styles as - read-only linked copies, "Library updates available" with overrides kept on update); slots - (a frame of a main made a slot property with preferred components; instances fill it with any - content of their own, kept across main updates, variant switches, copy/paste and detach, with - the main's default content until edited; reset slot; slot badges in the layers panel and on the - canvas; fill menu in the properties panel; drops from the Assets panel and the canvas land in - slots); nested overrides kept when the main moves or swaps a nested instance, and on nested - instances copied out of an instance (re-linked to their own main); canvas drags can no longer - pull layers out of an instance; library variables (publishing includes the file's variable - collections with their modes, aliases and scopes, versioned per variable and collection, without - variables hidden from publishing; files using the library see its collections read-only under - the library's name in the Variables editor and the variable pickers; binding, aliasing or setting - a library collection's mode on a frame copies the variables in as read-only linked copies, so the - file renders without the library; library components keep their variable bindings and modes; - "Library updates available" covers changed variables and bound layers follow). Explicit variable - modes in the Design panel: a frame's mode per collection, Auto (inherited) or its own, with - enabled libraries' collections listed under the library's name (picking a mode copies the - collection in). Instance boolean and text properties bound to boolean and string variables - (following modes, renames, reset and detach); layout grid settings in the Design panel whose - count, size, margin/offset and gutter bind to number variables; fills, strokes, effects and - layout grids reordered by dragging their rows, their variable bindings following. Components at - scale, QA'd with a synthetic design system (about 300 components: buttons, inputs, cards, navs - and badges as sets of size × state × type × theme variants, boolean/text/instance swap/slot - properties, instances nested four deep, text and paint styles, light/dark variables bound across - it) used 2,000 times with overrides at every level: main edits keep every override and match a - full rebuild exactly; values from variables (a theme switch, a bound corner radius) are no longer - recorded as overrides; detaching a variable on an instance layer is an override that survives main - edits; exposed nested instances stay exposed and swapped nested instances keep their layer names - through main edits; layers a swapped nested instance's main adds keep their ids and overrides. - Instance swap properties have preferred values (offered first). Alt-drop from the Assets panel - onto an instance swaps it (same-set instance preferred, highlighted while dragging); instances - pasted into other files follow their mains (library copies shared, published components used - from their library, other mains left behind as a restorable missing main). The Assets panel lays - out only the tiles in view and renders thumbnails as they show (cached, re-rendered only for - changed components). *Left:* QA with real-world (not synthetic) libraries. 1 h. -5. **Prototyping depth**: *landed:* on-canvas connections with drag-to-connect, interaction editor, - flows, smart animate, overlays, scroll/fixed/sticky, change-to and set-variable in the presenter. - Custom bezier and custom spring easings with editor fields; device frames (phone, tablet, - laptop, desktop bodies drawn in code) around the presented frame; overlays animate out with - their opening transition reversed; several selected layers edit their interactions together - (or replace mixed ones); scrolling inside device frames (the frame sized to the device's screen, - clipped or scrolling by wheel and drag, fixed layers pinned to the screen by their constraints, - nested "Scroll to", preserve scroll position); a resizable preview pane over the canvas that - plays the selected frame and follows edits live; device rotation (phones and tablets turn to - landscape: saved in the file, imported from REST files, drawn turned in the presenter and the - pane); presentation options (fit, fit width, fill, 100%, with Z to cycle them and R to - restart, the device frame shown or hidden, kept between presentations; what overflows the - window pans); scroll momentum (drags fling and slow down the same at any frame rate, the wheel - coasts, a drag past the ends stretches and springs back); responsive presentation (the presented - frame resized to the device's screen, or the window without a device, its constraints and auto - layout responding live; in the Options menu and the Prototype panel, saved in the file); device - colours (each model's colour variants, bodies drawn in code) and custom device sizes (a bare - screen with width and height fields, imported from REST files); flow descriptions in the - presenter's flow picker and under each flow; conditional actions (if / else if / else over - variable expressions) and set-variable-mode actions run in the presenter (from REST files or - commands). Conditionals are built in the interaction editor: an interaction's actions are a list - (add, reorder by dragging a row's grip, also inside conditional blocks, or from its menu, remove, - open one to edit it; one undo step per move), "Add action ▸ Conditional" adds an if whose - condition comes from a builder (a variable from the variable picker, an operator, a value or - another variable) or is typed as an expression (`count >= 3 and not done`, checked when entered, - what's wrong shown under the field), each block with its own actions (the same editors, - nested), plus "Else if" and "Else"; set variable values can be expressions (`count + 1`, - `"Hi " + name`); expressions read a variable's value in a given mode of its collection - (`accent[Dark]`, also from REST files' variable mode lookups) and the mode a collection is in - where the interaction runs (`mode(Theme) == "Dark"`, following set variable mode actions); every - edit is an undo step (`proto.action.*`, `proto.conditional.*`). Hotspot hints: a click where - nothing reacts flashes the screen's hotspots (an Options menu toggle, on by default); the - presenter's Inspect panel shows the hovered layer's properties. Overlays opened through commands - close on a click outside unless told not to, as in the editor. *Left:* QA against larger - real-world prototypes. 1–2 h. -6. **Interop**: *landed:* image crop handles; REST API file JSON import (`file.open` / `file.import` - / CLI: pages, layer tree, geometry, paints, strokes, effects, text runs, vectors from geometry - paths, auto layout, constraints, grids, components, sets, instances with overrides, component - properties, styles; image fills from an `images` folder or placeholders; warnings for the rest), - now with prototyping (interactions with their triggers, actions, transitions and easing, flows, - scrolling, the prototype device; conditional actions (if / else if / else over expressions), - set variable with variable references and expressions, set variable mode, all run by the - presenter) and variables (the local variables JSON passed along, next to the file or embedded: - collections, modes, aliases, scopes, layer bindings and explicit modes). - Export panel: a row per export setting (typed or preset sizes like `2x` / `512w` / `512h`, PNG, - JPG, WebP, SVG and PDF, suffix), a preview, and "Export N layers" (`file.exportLayers`) in the - panel and the Export dialog. Paste from other apps: images, SVG and text (the newest clipboard - content wins over our own copy; pasted SVG lands centred in the view). SVG import is editable and - checked against a corpus of synthetic files (expected pixels worked out by hand, layer structure, - export and re-import): groups named from their ids with transforms baked into the layers; - rectangles (corner radius), ellipses and lines kept as those shapes; gradients with exact - handles, `reflect`/`repeat` and focal points; patterns as image fills; clip paths and masks as - vector, luminance and alpha masks; shadow and blur filter chains as drop shadows, inner shadows - and layer blurs; blend modes; text as text layers with runs, anchors and stacked lines; images - and nested SVG images; import warnings for what's left out; linked files never read; hostile - input fuzzed. SVG export keeps alpha and luminance masks. PDF export: one page per frame in points (Export frames to - PDF, the Export panel, `figcraft-cli export -o x.pdf`), vectors, gradients and strokes as - vectors, real selectable text in subset fonts with clickable hyperlinks, images embedded once, - opacity and blend modes, clip content, alpha/luminance/vector masks, shadows and layer and - background blurs as images; checked by rendering the PDFs back against PNG exports. PDF print - options in the Export panel (per PDF export setting), the Export dialog, `file.export`, - `file.exportLayers`, `file.exportFramesPdf` and `figcraft-cli export`: a bleed showing what lies - past the frame (its fills reach out, its children are clipped at the bleed), crop and bleed - marks outside it, MediaBox / BleedBox / TrimBox, and CMYK colour (a documented, deterministic - naive conversion; images and rasterised effects too). - *Left:* .fig import (best effort), a CMYK output intent (no CMYK ICC profile can ship in the - repository), SVG filters other than shadows and blurs (left out with a warning). 8–16 h. -7. **Look & feel and interaction-fidelity pass**: *landed:* keyboard shortcuts audited against the - public shortcut reference: one keymap (`figcraft_engine::keymap`) drives the menus, the canvas, - the control channel and MCP, with macOS and Windows/Linux keys where they differ (mask, bring to - front/back, distribute, tidy up, layout grids, pixel preview), Text-only and canvas-only bindings - (Cmd/Ctrl+K: link while typing, Actions on the canvas), Cmd/Ctrl+/ for Actions, `+`/`-` zoom, - Shift+0/1/2 from any layout, Cmd/Ctrl+0, hold Z for the zoom tool (Alt zooms out, drag an area), - two quick digits for an exact opacity, boolean keys (Alt+Shift+U/S/I/E), remove fill/stroke - (Alt+/, Shift+/), outlines on Shift+Cmd+O, pixel grid on Cmd+', Shift+E / Shift+D / Shift+Cmd+ panel keys, Ctrl+Tab between files, B for the paint bucket in vector edit mode; the Keyboard - shortcuts panel docks at the bottom with a tab per group and search, keycaps per platform. - *Left:* tool by tool, panel by panel against the incumbent (cursors, modifier keys while - dragging such as Ctrl to ignore snapping on macOS, hover states, menus, popovers); multiplayer - cursor keys wait for multiplayer. 40–60 h. -8. **Collaboration (local):** comments landed: pins pinned to frames and layers that move with them - (to other pages too) and stay where they were when the layer is deleted, your pins dragged onto - another frame, crowded pins clustered when zoomed out (a click zooms them apart), Shift+C to show - or hide them; threads where you edit and delete your own messages, emoji reactions, @mentions - with a picker of the names used in the file (your name from Preferences), read and unread state, - resolve, and "Copy link" (`figcraft://comment/`: pasting or `comment.open` goes to the page, - zooms to the frame and opens the thread); the Comments panel with search (text, names, frame), - filters (open, resolved, yours, unread), sorting by date or page, each thread's frame and page, - and Up/Down to step through threads; comments on the presented frame (Comments button or - Shift+C: read and reply). All of it through `comment.*` commands. Version history - landed (named versions saved in the `.figcraft` file; restore, rename, duplicate, delete; panel; - view a version on the canvas read-only before restoring it; autosave checkpoints every 30 - minutes, folded in the panel). Real-time collaboration is designed (`docs/collab-protocol.md`: - WebSocket sessions the app can host itself, server-ordered per-property changes, live cursors) - and its core landed (`crates/collab`, no networking yet): client-scoped node ids, every saved - layer field and the document-level data (styles, variables, comments, images…) as synced - properties, diffs after a command that cost the size of the edit, fractional sibling positions, - a session server that orders and validates batches (cycles, deleted layers, id spaces, sizes) - and a client that shows its own edits at once and replays them over others'; derived data - (auto layout, instances, bindings) is repaired by the author after concurrent edits; binary - messages (a moved layer is 43 bytes, a cursor 23) with a JSON form; a randomized multi-client - test over real commands converges. - Plugins landed: sandboxed WebAssembly plugins (a metered wasmi - interpreter with a memory cap and no WASI, also in the browser) whose API is the command - registry; each run is one undo step and is rolled back when it fails (error, trap, endless loop, - memory); a `figcraft-plugin.json` manifest declares menu commands with parameters and read or - write access with an optional command allowlist, and files, other documents, the undo history, - dialogs and other plugins are always off limits. Plugins ▸ Development ▸ Import plugin from - manifest… (kept in the preferences, the module re-read on every run), the installed plugins in - the Plugins menu with a parameters form drawn from the manifest, Run last plugin (⌥⌘P), Manage - plugins, and `plugin.*` commands for scripts, the CLI and MCP; a Rust SDK and two example - plugins (Tidy names, Swatch grid) in `plugins/`, built by `cargo xtask plugins`. *Left:* - plugin-defined UI at run time (forms or panels a plugin returns), plugin settings storage, - distribution; for collaboration, the WebSocket transport, hosting and joining from the app, - live cursors, per-user undo, reconnect, the browser client and a standalone server. 18–45 h. -9. **Hardening and performance**: *landed:* `cargo xtask bench` (synthetic 1k/10k/50k-layer - pages: engine, render and headless UI-frame timings). The canvas keeps its last image and - re-renders only what a pan uncovers or an edit touches: moving one layer at 10k layers re-renders - in ~0.2 ms instead of ~8 ms (0.8 vs 24 ms at 50k zoomed out), a 40 px pan in ~0.7 ms instead of - ~7.5 ms. The layers panel lays out only the rows in view (every screen expanded at 50k: 39 → - 0.6 ms a frame); text layouts are shared instead of re-formatted per lookup; overflowing text is - culled by its glyphs. At 10k: full 1440×900 renders 7–15 ms, single-layer edits ~10 µs, hit - tests ~26 µs. Zoomed out (50% and below) the canvas draws levels of detail: layers under 2 px - land as their averaged colour, text under 4 px is greeked into bars, small rectangles and clip - layers skip the path pipeline (exports and closer zooms stay exact): a whole 50k-layer page - renders in ~8 ms instead of ~50 ms. `.figcraft` at 50k layers saves in ~0.09 s instead of ~1 s - and loads in ~0.16 s instead of ~0.86 s (JSON streamed to and from the document without a - value tree, layer fields at their defaults left out: 63 → 22 MB of JSON, old files still - open). The retained canvas is held to a full render: a seeded random walk (edits, undo/redo, - pans and zooms over nested, rotated and clipping frames, groups, masks, booleans, auto layout, - effects, text, instances, variables and styles) checks every step, and found clip edges on a - pixel boundary letting a column through in some renders. Drags show live on the canvas (every - finished render is shown, not only the newest one asked for), and a button held still no - longer rebuilds the preview and re-renders every frame. - Components at scale (`cargo xtask bench`, synthetic design system of about 300 - components used by 2,000 instances): edits of mains reach their copies directly instead of - rebuilding every instance (value, size and layer added/removed edits; other edits rebuild each - affected instance once, inner mains first), bound variables no longer touch unchanged layers on - every edit, auto layout re-flows only where sizes or places changed: recolouring or resizing a - main's layer used ~900 times 188/226 → 4/18 ms, adding a layer to it 430 → 21 ms, a label style - in all 72 button variants (1,800 copies) 450 → 57 ms, switching a variant, reset, detach, push - and paste ~450 → under 3 ms, accepting a library update 460 → 64 ms; the Assets panel with 2,000 - assets 3.4 → 1.3 ms a frame. Accessibility: the custom-painted - controls name themselves for screen readers (AccessKit on desktop: role, name, value and state - for tools, layer rows with their type, level, selection and hidden/locked state, fields, - dropdowns, tabs, menu items, and the canvas, which describes the selection); keyboard navigation: - F6 / Shift+F6 move between the toolbar, layers, canvas and properties, Tab / Shift+Tab move - within a region with a focus ring, Enter or Space activate, the arrows go along the toolbar and - through the layer rows, menus and tool flyouts opened from the keyboard take it and give it back, - Escape returns to the canvas (where Tab selects the next layer again instead of wandering into - the tab strip); reduced motion follows the system's setting or a preference; secondary and - accent text meet WCAG AA in both themes. - An idle window draws no frames: it redrew ~240 times a second - (the window title was re-sent every frame, and each viewport command asks for another), ~33% of - a core in a debug build, and now sits at 0 frames and ~0% CPU; the toast, the autosave - checkpoint and the presenter's "after delay" timers wake it at their deadline, the interaction - editor's curve preview plays when it shows, changes or is hovered, and a screenshot keeps frames - coming only until it arrives (`ui.inspect` `framesDrawn` and `repaintCauses` show what asked for - frames; headless tests hold it). *Left:* a real-world file corpus, Windows/Linux/browser - QA, runs with real screen readers (NVDA, Narrator, VoiceOver, Orca), the AccessKit tree in the - browser (eframe's web backend doesn't send it yet), keyboard box selection, keyboard rename and - context menus in the layers panel. 28–46 h. +## Stage -### Where we're going +**Alpha.** Core workflows exist end to end (frames, shapes, vectors, text, auto layout, components +with variants and overrides, styles, variables, prototyping, Dev Mode, SVG/PNG/JPG/PDF), but +FigCraft can't open Figma's own `.fig` files, has no multiplayer, and nothing has been checked +against real Figma documents. Ready-for-real-work is ~47%, inside alpha's ~40–75% band, and the alpha gate passes: every daily core workflow (design screens, build a design system, prototype, hand off to developers) works end to end on FigCraft's own files, which save and reopen; review works only asynchronously and `.fig` import is missing, both beta gaps ([alpha gate](docs/roadmap.md#alpha-gate)). Beta needs +~75% **and** reliable `.fig` import: the `.fig` reader (30–60 h), a real-file corpus with measured +fidelity (15–30 h), the interaction pass (25–40 h of the 40–60), core depth to ~80% (40–75 h), +basic multiplayer on the landed core (30–55 h), stability and platform QA (20–40 h), a partial GPU path (15–30 h) and +the localization layer with Figma's own languages (20–35 h). -- **Next:** the fidelity pass (7) and hardening (9: a real-file corpus, platform QA); effects: - glass and progressive blur tuned side by side; the last - text details (right-to-left list markers) and auto layout details (grid `fr` rows around - fixed-size children). -- **Then:** interop depth (6: .fig best effort), multiplayer (8; comments, version history and - plugins are in). -- **Alpha:** release builds on every push to `release` (packaging in progress), demo files, docs. +## By dimension -## Shipped so far +| Dimension | Ready | Hours | Doc | +|---|---|---|---| +| Features (depth) | 57% (core editor 67%) | 78–146 | [target-app-parity](docs/target-app-parity.md) | +| UI/UX fidelity | 58% | 40–60 | [ui-parity](docs/ui-parity.md) | +| File formats | 40% (no `.fig`) | 30–60 | [file-format-parity](docs/file-format-parity.md) | +| Collaboration | 12% (core in, no networking) | 55–110 | [collaboration-parity](docs/collaboration-parity.md) | +| Stability | 55% | 20–40 | [gaps](docs/gaps.md) | +| Performance | 60% | 30–60 | [hardware-parity](docs/hardware-parity.md) | +| Hardware | 50% | 15–30 | [hardware-parity](docs/hardware-parity.md) | +| Localization | 10% (English only) | 60–100 | [localization-parity](docs/localization-parity.md) | +| Platforms | 75% | 10–20 | [hardware-parity](docs/hardware-parity.md) | +| Ecosystem / plugins | 20% (own WASM plugins) | 25–55 | [gaps](docs/gaps.md) | +| AI features | 0% | 30–60 | [gaps](docs/gaps.md) | -- **Architecture:** 15 crates with enforced layering (`cargo xtask layers`): geom, color, doc, - layout, text, pathops, plugin, collab, render, format, svg, engine, ui-egui (+ mcp, pdf). Every action - is a command (~330); undo is unlimited via structural sharing (`Arc` node snapshots); gestures are - one undo step; `command.batch` runs several commands as one step. -- **Document model:** pages, frames, groups, sections, rectangles, ellipses (arcs/rings), polygons, - stars, lines/arrows, vector networks, text with styled runs, boolean groups, components, component - sets (variants), instances with per-layer overrides, slices; fills (solid, linear/radial/angular/ - diamond gradients, images with fill/fit/crop/tile + adjustments), multiple strokes with - inside/center/outside alignment, per-side weights, dashes, caps/arrowheads, joins; effects (drop - and inner shadow with spread that offsets the outline exactly: ellipses, stars, vectors, text; - inner shadows over the fills and under the children and strokes; layer blur; background blur - that sees the whole backdrop, inside clipping frames, faded groups and masks too; both blurs - uniform or progressive (the radius ramps between two points, dragged on the canvas); noise in - mono, duo and multi colour with grain size, density and blend mode; texture with clip to shape; - glass with light angle and intensity, refraction, depth, dispersion, frost and splay; the same in - PNG, PDF and SVG exports, SVG embedding renders of noise grains, texture, progressive and - background blur and glass); corner radii with - smoothing; constraints; auto layout (horizontal, vertical, wrap, grid; hug/fill/fixed; min/max; - absolute children); layout grids; export settings; prototype interactions, flows and transitions; - paint/text/effect/grid styles; variables with collections, modes and aliases. -- **Renderer:** CPU (tiny-skia) scene renderer used for canvas, export and the web: isolated layers - for opacity/blend/effects, clip content, masks, booleans (linesweeper), text (harfrust shaping, - skrifa outlines, font fallback), aligned strokes with caching. -- **Engine:** pointer tools (move/marquee/deep select/resize/rotate/Alt-duplicate with smart-guide - snapping, frame/section/slice/shapes/line/arrow with Shift/Alt, text, pen, pencil, hand, - eyedropper), Cmd/Ctrl-click and Cmd/Ctrl-marquee into nested layers, Shift-marquee toggling, - Select layer (every layer under the click), measuring (Alt-hover distances from the selection to - layers, parents and ruler guides, Cmd+Alt for nested layers, extension lines, one box inside the - other, overlaps, live distances to the neighbours while Alt-dragging, Shift+Alt for auto layout - padding and gaps; labels that never overlap at any zoom), text editing (caret, selection, words, - lines), auto layout reorder by dragging, drop into frames, align/distribute/tidy, z-order, - flip/rotate, the scale tool (panel, and canvas handles that scale everything about its anchor - point or from the centre with Alt, with a live factor, one undo step per drag), booleans, flatten, - outline stroke, components (create, instances, sync with overrides, reset, detach, push changes, - variants, properties, slots), styles and variables, prototype commands, find/replace, batch rename, - copy/paste (internal + SVG/text), file new/open/save/import/export (native `.figcraft`, SVG - in/out, PNG/JPG/WebP), version snapshots. -- **UI (egui, swappable):** the incumbent's 2026 layout: tab strip that is also the window's title - bar (frameless on Windows/Linux with drawn window buttons, drag, double-click maximise and edge - resizing; macOS window buttons inset into it), icon rail, file header, pages and - layers tree (rename, visibility/lock, drag to reorder/reparent), Assets panel, floating bottom - toolbar with flyouts and mode switcher, Design / Prototype / Inspect panels (Dev Mode: properties with their styles and variables, annotations - with pinned properties and categories drawn as coloured callouts on the canvas (filtered by category), - a ready-for-dev list, a focus view on one frame with previous / next, Compare changes since a frame - was marked ready (before / after side by side or overlaid, property-level diffs), CSS/HTML/React/SwiftUI/Compose - code where components take their properties as parameters and instances are calls), colour picker - (HSB square, hue/alpha, hex, gradient stops, image fills), main menu generated from the catalog, - context menu, Actions palette (⌘K), keyboard shortcuts from one keymap per platform (a tabbed, - searchable Keyboard shortcuts panel), keyboard navigation (F6 between regions, Tab within them, a - focus ring) and screen-reader names for the custom controls (AccessKit), presentation player with - transitions, light and dark themes, home screen, About/Preferences/shortcuts/variables dialogs. -- **Automation:** desktop control channel (`--control `: execute commands, inspect document/UI, - synthetic pointer/keys/typing, menu invocation, screenshots, renders). -- **Tests:** ~390 automated tests including junk-parameter sweeps over every command (and every vector-edit command while editing), importer fuzzing and render regressions. +## Features -## Parity estimate (weighted rubric) - -Scores by behaviour, 0–100%. Hours are what remains (one agent). - -| Area | Weight | Score | Remaining work | Hours | +| Area | Breadth | Ready | Hours | Doc | |---|---|---|---|---| -| Canvas & navigation | 6 | 82% | visual QA at extreme zooms | 0.5–1 | -| Selection & transform | 8 | 78% | measuring and transform handles checked side by side, rotated groups and mixed selections QA | 2–4 | -| Layers panel | 5 | 88% | visual QA of long lists and deep trees | 0.5–1 | -| Shapes & vector | 8 | 76% | live boolean editing, Design panel arc fields, shape builder on strokes and open paths, one-sided widths | 4–8 | -| Paint | 7 | 78% | a wide-gamut canvas (egui draws sRGB, so Display P3 colours outside sRGB clip on screen; exports keep them), images' own embedded colour profiles (images are taken as sRGB) | 1–3 | -| Strokes | 3 | 82% | stroke styles | 1–2 | -| Effects | 4 | 84% | glass and progressive blur tuned side by side; SVG draws noise, texture, progressive and background blur as embedded images | 2–4 | -| Frames, groups, sections, masks | 5 | 82% | visual QA | 0.5–1 | -| Auto layout & constraints | 9 | 76% | grid `fr` rows around fixed-size children, QA with real-world files | 1–2 | -| Text | 8 | 79% | visual QA | 0.5–1 | -| Components & variants | 9 | 79% | QA with real-world (not synthetic) libraries | 1 | -| Styles & variables | 5 | 89% | variant properties and gradient stops bound to variables, REST import of bindings past the first paint and on layout grids, a colour picker for layout grid colours | 1 | -| Prototyping | 6 | 91% | QA against larger real-world prototypes | 1–2 | -| Import/export | 6 | 71% | .fig import (best effort), SVG filters beyond shadows and blurs and rotated repeating patterns, a CMYK output intent for print PDFs (needs a CMYK ICC profile) | 8–16 | -| Dev mode / inspect | 2 | 91% | visual QA of the compare and focus views, comparing against an older named version (not only the snapshot taken when a frame first changes) | 1–2 | -| Comments, versions, misc | 3 | 62% | multiplayer; plugin-defined UI at run time, plugin settings storage | 6–11 | +| Canvas & navigation | 95% | 72% | 3–6 | [ui-parity](docs/ui-parity.md) | +| Selection & transform | 95% | 68% | 6–10 | [ui-parity](docs/ui-parity.md) | +| Layers panel | 95% | 78% | 2–4 | [ui-parity](docs/ui-parity.md) | +| Shapes & vector | 92% | 66% | 8–14 | [target-app-parity](docs/target-app-parity.md) | +| Paint | 85% | 66% | 5–9 | [target-app-parity](docs/target-app-parity.md) | +| Strokes | 90% | 72% | 2–4 | [target-app-parity](docs/target-app-parity.md) | +| Effects | 100% | 72% | 3–6 | [target-app-parity](docs/target-app-parity.md) | +| Frames, groups, sections, masks | 95% | 75% | 2–4 | [target-app-parity](docs/target-app-parity.md) | +| Auto layout & constraints | 95% | 68% | 6–12 | [auto-layout-parity](docs/auto-layout-parity.md) | +| Text | 85% | 64% | 8–14 | [target-app-parity](docs/target-app-parity.md) | +| Components & variants | 95% | 68% | 6–12 | [components-parity](docs/components-parity.md) | +| Styles & variables | 85% | 70% | 4–8 | [components-parity](docs/components-parity.md) | +| Prototyping | 88% | 70% | 5–9 | [prototyping-parity](docs/prototyping-parity.md) | +| Import/export | 65% | 35% | 30–60 | [file-format-parity](docs/file-format-parity.md) | +| Dev Mode / inspect | 80% | 62% | 4–8 | [dev-mode-parity](docs/dev-mode-parity.md) | +| Comments, versions, misc | 80% | 58% | 4–8 | [collaboration-parity](docs/collaboration-parity.md) | +| Multiplayer & sharing | 15% | 5% | 45–90 | [collaboration-parity](docs/collaboration-parity.md) | +| Plugins & widgets | 35% | 20% | 25–55 | [plugins](docs/plugins.md) | +| Team libraries | 40% | 25% | 10–20 | [components-parity](docs/components-parity.md) | +| Figma Draw extras | 45% | 30% | 10–18 | [gaps](docs/gaps.md) | +| AI features | 0% | 0% | 30–60 | [gaps](docs/gaps.md) | -Weighted feature depth ≈ **79%** (self-graded, from the table). +## Languages -## Milestones +| Language | Code | Strings | Status | +|---|---|---|---| +| English | en | 100% | full | +| Simplified Chinese | zh-Hans | 0% | none | +| Spanish | es | 0% | none | +| Hindi | hi | 0% | none | +| Arabic | ar | 0% | none | +| French | fr | 0% | none | +| Portuguese | pt | 0% | none | +| Indonesian | id | 0% | none | +| Japanese | ja | 0% | none | +| German | de | 0% | none | +| Korean | ko | 0% | none | +| Vietnamese | vi | 0% | none | -| Milestone | Status | -|---|---| -| M0 Foundation: workspace, model, renderer, engine, UI shell, app, control channel | done (2026-10-09) | -| M0.9 CLI + MCP, web build, release packaging, PDF export | CLI, MCP, web build and PDF export done; release packaging in progress | -| M1 Core editing completeness (tools, panels, menus, clipboard, files) | ~70% | -| M2 Layout depth | ~76% | -| M3 Components & styles depth | ~70% | -| M4 Vector & text depth | ~66% | -| M5 Prototype & present | ~82% | -| M6 Interop & dev mode | ~62% | -| M7 Release (signed builds for all platforms, README screenshots) | started | -| M9 Real-time collaboration (WebSocket sessions hosted from the app, then a self-hosted server; live cursors; see `docs/collab-protocol.md`) | core done (ids, change sets, server ordering, convergence); networking next | +No other languages. Figma ships English, Japanese, Korean, French, German, Spanish and Portuguese +(Brazil); FigCraft has no localization layer yet. Document text in any script (bidi, Arabic +shaping, IME) already works. Detail: [`docs/localization-parity.md`](docs/localization-parity.md). + +## Upcoming + +Ranked; detail and milestones in [`docs/roadmap.md`](docs/roadmap.md). + +1. `.fig` import, best effort, with a synthetic `.fig` corpus: 30–60 h. +2. Real-file corpus and measured fidelity: 15–30 h. +3. Tool-by-tool interaction pass against Figma: 40–60 h. +4. Localization layer, then ja, ko, es, pt-BR, fr, de: 35–55 h. +5. Multiplayer networking on the landed core (M9): 45–90 h. + +## Progress log + +- **2026-10-10** · WASM plugins (#101: sandboxed wasmi runtime, manifest permissions, Plugins menu, + Run last, Manage, Rust SDK and two examples), docs refresh (#102), the multiplayer core without + networking (#103: client-scoped ids, change sets, server ordering and validation, client + reconciliation, convergence tests). Menu breadth 200/203; ready for real work ~47%. +- **2026-10-10** · Full re-measure against Figma desktop 126.10.7 under the craftrules progress-docs + standard: ready for real work ~46%, feature breadth ~76%, stage alpha; progress docs split out + (`docs/target-app-parity.md`, `gaps.md`, `roadmap.md`, `architecture.md`, the per-area parity + docs); `docs/parity.md` renamed `docs/parity-checklist.md`. +- **2026-10-10** · Day 2 (PRs #1–#99): vector edit mode depth (transform box, point snapping, arc + handles, shape builder, variable width), text depth (variable fonts, bidi, RTL names, style + browser), auto layout nesting and keyboard reordering, slots and library variables, components + at scale (2,000 instances), effects fidelity (glass, noise, texture, progressive blur), + prototyping (conditionals, expressions, device frames, responsive presentation), REST import of + prototypes and variables, SVG import fidelity, PDF print options, Dev Mode (code, annotations, + ready for dev, compare changes), comments polish, version history, keyboard shortcut parity, + accessibility, retained canvas and 50k-layer performance, no redraws while idle; v0.2.0 + released for every platform; multiplayer protocol designed. +- **2026-10-09** · Day 1: foundation (13 crates, layering, command registry, renderer, engine, + UI3 frontend, control channel), CLI and MCP, web build, PDF export, packaging, first depth + passes on text, components, prototyping and comments. + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | minor | Readiness by audience with hours to ~95% (full ~400–750, mainstream ~180–330, essentials ~85–160) | +| 2026-10-10 | minor | Added essentials user (~53%) and mainstream practitioner (~43%); ready for real work unchanged at ~46% | +| 2026-10-10 | minor | Alpha gate (core workflows) checked under the revised stage rules: passes, stays alpha | +| 2026-10-10 | major | Rewritten to the craftrules progress-docs shape after a full re-measure; rubric, area narrative and inventory moved to docs/target-app-parity.md, gaps to docs/gaps.md, milestones to docs/roadmap.md. Depth ~79% (self-graded, 16 areas) → ready for real work ~46% (all dimensions); full parity 115–195 h → 420–790 h | +| 2026-10-10 | minor | Day-2 refreshes after each batch of PRs (depth 58% → 79%) | +| 2026-10-09 | major | First roadmap | diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..5d22330 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,83 @@ +# FigCraft architecture + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (added the `plugin` and `collab` crates from #101 and #103) · **Target:** Figma Design + +How FigCraft is built today. Engine first, a thin swappable UI, everything a command; a Figma-shaped +data model (a scene graph of frames with auto layout, components and variables). ~108,800 lines of +Rust (2026-10-10). + +## Crates and layers + +`cargo xtask layers` enforces the layering (`xtask/src/layers.rs`): a crate may depend only on +lower layers. Nothing below L6 depends on egui, eframe, rfd or winit, so the UI crate can be +replaced. + +| Layer | Crate | Lines | Role | +|---|---|---|---| +| L0 | `figcraft-geom` | ~0.5k | Affine transforms, shape path builders (rounded and smoothed corners, polygons, stars, arcs) on kurbo | +| L0 | `figcraft-color` | ~1.3k | Colours (HSB/HSL, hex/CSS, Display P3), paints (solid, gradients, image), blend modes | +| L1 | `figcraft-doc` | ~8.5k | Document model: pages, node tree in a persistent map (`imbl`, stable ids), properties, components, styles, variables, prototype data, comments, versions. Serde everywhere | +| L2 | `figcraft-layout` | ~1.8k | Auto layout (horizontal, vertical, wrap, grid; hug/fill/fixed; min/max), constraints, layout grid geometry | +| L2 | `figcraft-text` | ~3.1k | Font database (optional embedded craft-fonts + system scan), shaping (harfrust), bidi, line layout, glyph outlines (skrifa), variable fonts | +| L2 | `figcraft-collab` | ~3.4k | Real-time collaboration core (no networking): synced object/property model, change sets, fractional positions, server ordering and validation, client reconciliation, wire messages | +| L2 | `figcraft-plugin` | ~1.0k | Plugin manifest and the WebAssembly sandbox (wasmi, metered, memory cap, no file system, network or clock) | +| L2 | `figcraft-pathops` | ~1.1k | Booleans (linesweeper), outline stroke with alignment, arrowheads | +| L3 | `figcraft-render` | ~5.4k | Scene → pixels on tiny-skia (CPU): isolated layers for opacity/blend/effects, clips, masks, shadows, blurs (uniform, progressive, background), noise, texture, glass, text; banded in parallel; retained rendering of only what changed; levels of detail when zoomed out | +| L3 | `figcraft-format` | ~5.2k | Native `.figcraft` (zip of `document.json` + images; streamed JSON), local library files, versions, REST API file JSON import (`rest/`) | +| L4 | `figcraft-svg` | ~3.7k | SVG export and import (usvg) | +| L4 | `figcraft-pdf` | ~2.3k | PDF export (krilla) with print options | +| L5 | `figcraft-engine` | ~39.3k | Sessions, undo history (`Arc` snapshots), the command registry (`cmd/*`, `spec!`), pointer tools and vector edit mode, snapping and measuring, components sync, libraries, prototype runtime, Dev Mode code generation, the menu catalog (`catalog.rs`) and the keymap (`keymap.rs`), a panic guard | +| L6 | `figcraft-ui-egui` | ~31.9k | The UI3-style frontend: canvas (render worker), toolbar, layers, Design/Prototype/Inspect panels, colour picker, menus, dialogs, presenter, comments, accessibility (AccessKit), the control channel server | +| L6 | `figcraft-mcp` | ~2.4k | MCP server (JSON-RPC over stdio), headless or bridged to a running app | +| apps | `figcraft`, `figcraft-cli`, `figcraft-web` | ~1.9k | Desktop app (eframe + wgpu), command line, browser build (WASM, WebGPU/WebGL2) | +| plugins | `plugins/` (own workspace) | | Rust plugin SDK and two example plugins, built for wasm32 by `cargo xtask plugins` ([`plugins.md`](plugins.md)) | +| tools | `xtask` | | `ci`, `layers`, `assets`, `parity`, `version`, `icon`, `wasm`, `plugins`, `bench` | + +## Data model + +A `Document` holds pages, a persistent map of nodes (frames, groups, sections, rectangles, +ellipses, polygons, stars, lines, vector networks, text with styled runs, boolean groups, +components, component sets, instances, slices), styles, variable collections, comments, versions +and images by hash. Instances keep their main's id and per-layer overrides; the engine keeps their +materialised children in sync when a main changes (directly for value, size and add/remove edits, +by a rebuild otherwise). Snapshots are cheap (`Arc` and structural sharing), which gives unlimited +undo with one step per gesture. + +## Commands: one path for every surface + +Every user-visible behaviour is a command in `crates/engine/src/cmd/*` (455 ids after #101) +with an id, label, parameter docs and undo flag. The menus (generated from the catalog), keyboard +shortcuts, Actions palette, CLI (`figcraft-cli run`), JSON control channel (`--control `) and +MCP server all dispatch the same ids, so agents can do anything a person can; WebAssembly plugins call them too, within their manifest's permissions. Commands never open +dialogs themselves; they request UI, and programmatic callers drop those requests. +`cargo xtask parity` measures the catalog's coverage ([`parity-checklist.md`](parity-checklist.md)). + +## Rendering + +The CPU renderer is the single source of pixels for the canvas, exports and the browser. The +desktop canvas renders on a worker thread at the device pixel ratio and keeps its last image, +re-rendering only the region a pan uncovers or an edit touches; overlays (selection, handles, +guides, labels) are drawn by egui on top. A seeded random walk checks the retained canvas against +full renders. SVG and PDF export walk the same scene and embed rasters where those formats can't +express an effect. + +## File I/O + +`.figcraft` is the native format (atomic saves, autosave checkpoints, recovery copies after a +crash). Imports: REST API file JSON with variables and images, SVG, raster images, clipboard +content. Exports: PNG, JPG, WebP, SVG, PDF, code. There is no `.fig` reader yet +([`file-format-parity.md`](file-format-parity.md)). + +## Robustness + +Workspace lints deny `unwrap`, `expect`, `panic!` and friends in shipped code; `unsafe_code` is +forbidden. `figcraft_engine::guard` turns a panicking command into an error and rolls the document +back; the desktop app also guards each UI frame. Junk-parameter sweeps run every command with bad +input. + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | major | Created from the code as of PR #99 | diff --git a/docs/auto-layout-parity.md b/docs/auto-layout-parity.md new file mode 100644 index 0000000..56a5ad3 --- /dev/null +++ b/docs/auto-layout-parity.md @@ -0,0 +1,34 @@ +# Auto layout and constraints parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created from the ROADMAP's auto layout items and `crates/layout`) · **Target:** Figma Design (desktop app 126.10.7) + +Auto layout is the most used layout feature in Figma and the one where small differences (a +hugging frame one pixel off, text wrapping at another width) break real files. **Breadth ~95%, +ready ~68% (estimated)**: everything Figma documents exists, checked against the documented rules +with synthetic samples; nothing yet against real Figma files. Remaining: 6–12 h. + +| Feature | Status | Evidence / notes | +|---|---|---| +| Horizontal, vertical, wrap | done | `crates/layout` | +| Grid auto layout: fixed / hug / `fr` tracks, cells, spans, gaps | done | `fr` rows of a fixed-height grid behave like `minmax(0, 1fr)` around fixed-size children; Figma's exact rule unconfirmed | +| Gap, auto gap, padding (per side), alignment 3×3, space between | done | | +| Text baseline alignment | done | | +| Hug / Fill / Fixed sizing with coherent rules (Fill turns a hugging parent Fixed) | done | `al_nesting_tests.rs` | +| Min/max width and height, redistribution | done | hugging text wraps at its max | +| Nested hug/fill settling in one pass (three levels, wrapping fill text, grid rows) | done | | +| Absolute position (ignore auto layout) with constraints | done | | +| Canvas stacking order (first on top / last on top) | done | | +| On-canvas padding and gap handles, incl. wrap row gap and grid gaps | done | | +| Drag to reorder (wrap-aware, by row), into grid cells, across nested frames | done | `al_drag_tests.rs` | +| Arrow keys move children one place (flows, rows, grid cells, into neighbours) | done | `al_keys_tests.rs` | +| Constraints: left, right, left and right, centre, scale; top/bottom likewise | done | | +| Layout grids: columns, rows, grid; stretch/left/centre/right; variables bound | done | | +| Suggest auto layout / "Add auto layout" on a selection | done | | +| Real Figma files laid out identically | **not checked** | needs `.fig` or REST import of real files ([gaps](gaps.md) #1, #3) | +| Performance: re-flow only where sizes or places changed | done | measured in `cargo xtask bench` (components at scale) | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/collaboration-parity.md b/docs/collaboration-parity.md new file mode 100644 index 0000000..54a8609 --- /dev/null +++ b/docs/collaboration-parity.md @@ -0,0 +1,28 @@ +# Collaboration parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (the multiplayer core landed in #103) · **Target:** Figma Design (desktop app 126.10.7) + +Figma is multiplayer first; FigCraft is local first. **Ready ~12% (estimated):** comments and version +history work inside one file on one machine; the real-time collaboration core landed in #103 +(sync model, server ordering, client reconciliation, convergence tests) without networking, so +nobody can co-edit yet ([`collab-protocol.md`](collab-protocol.md)). Remaining: 55–110 h +(multiplayer 45–90 h, shared libraries 10–20 h), plus branching 8–15 h. + +| Feature | Figma | FigCraft | Hours | +|---|---|---|---| +| Real-time co-editing | yes | **core built, no networking** (#103): client-scoped ids, per-property change sets with fractional positions, server ordering and validation, optimistic clients, binary messages; randomized multi-client convergence tests over real commands. Left: WebSocket transport, hosting and joining, per-user undo, reconnect, browser client, standalone server | 25–55 | +| Live cursors, selections, viewports; follow / observation mode; spotlight | yes | no (presence messages encoded; no UI or transport) | 8–15 | +| Cursor chat, audio, high-fives | yes | no | 4–8 | +| Share links, permissions (view / edit), teams and projects | yes | no | 8–17 | +| Comments: pins on frames and layers, threads, reactions, @mentions, resolve, unread, search and filters, links, in the presenter | yes (shared) | **done, local**: stored in the file, your name from Preferences | (shared once multiplayer lands) | +| Version history: named versions, autosave checkpoints, view before restore, restore, duplicate | yes (cloud) | **done**, saved in the `.figcraft` file | — | +| Branching and merging | yes (paid plans) | no | 8–15 | +| Team / organization libraries | yes | local library files only ([components-parity](components-parity.md)) | 10–20 | +| Notifications, activity | yes | no | with sharing | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/components-parity.md b/docs/components-parity.md new file mode 100644 index 0000000..9d9c4f1 --- /dev/null +++ b/docs/components-parity.md @@ -0,0 +1,54 @@ +# Components, variants, styles and variables parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created from the ROADMAP's components and variables items) · **Target:** Figma Design (desktop app 126.10.7) + +Design systems are why teams adopt Figma. **Components: breadth ~95%, ready ~68%. Styles and +variables: breadth ~85%, ready ~70% (estimated).** QA'd with a synthetic design system of ~300 +components used 2,000 times (`crates/engine/src/synthetic_ds.rs`, `components_scale_tests.rs`); +not with real libraries. Remaining: 10–20 h here, plus shared libraries (10–20 h after +multiplayer). + +## Components and variants + +| Feature | Status | Notes | +|---|---|---| +| Create component, instances, detach, reset, go to main, restore main, push changes | done | | +| Per-layer overrides with reset; kept across main edits, nested swaps, copy/paste | done | main edits match a full rebuild exactly at 2,000 instances | +| Component sets / variants, add variant, switch | done | | +| Properties: boolean, text, instance swap (preferred values), variant | done | | +| Slots (preferred components, fill menu, kept across updates) | done | Figma 2025 feature | +| Exposed nested instances | done | | +| Descriptions | done | | +| Instance swap: panel, Alt-drop from Assets | done | | +| Assets panel: thumbnails, search, drag into frames and auto layout slots | done | virtualized | +| Instances pasted into other files follow their mains | done | missing main restorable | +| Component playground (try properties without placing) | missing | 1–2 h | +| Real-world libraries QA | **not checked** | [gaps](gaps.md) #3 | + +## Libraries + +| Feature | Status | Notes | +|---|---|---| +| Publish a file's components, sets, styles and variables (per-asset versions) | done | as local library files | +| Enable a library in a file; read-only linked copies | done | | +| Library updates available; overrides kept | done | | +| Shared team/organization libraries, library analytics, swap library | missing | [gaps](gaps.md) #10 | + +## Styles and variables + +| Feature | Status | Notes | +|---|---|---| +| Paint, text, effect, grid styles; style picker; text styles on character ranges | done | | +| Variables: colour, number, string, boolean; collections, modes, aliases, scopes, groups | done | | +| Bindings: fills, strokes, effects, opacity, padding, gaps, sizes, radius, font size, line height, letter spacing, text, visibility, layout grids, instance properties | done | | +| Explicit modes per frame, library collections' modes | done | | +| Gradient stops and variant properties bound to variables | missing | | +| Extended collections | missing | [gaps](gaps.md) #14 | +| Variables import/export (JSON) | missing | REST variables JSON is read on import | +| Expressions in prototype set-variable actions | done | see [prototyping-parity](prototyping-parity.md) | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/dev-mode-parity.md b/docs/dev-mode-parity.md new file mode 100644 index 0000000..00888dc --- /dev/null +++ b/docs/dev-mode-parity.md @@ -0,0 +1,27 @@ +# Dev Mode parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created from the ROADMAP's Dev Mode items) · **Target:** Figma Design Dev Mode (desktop app 126.10.7) + +**Breadth ~80%, ready ~62% (estimated).** The inspect surface is broad; what's missing connects +designs to real codebases. Remaining: 4–8 h. + +| Feature | Status | Notes | +|---|---|---| +| Dev Mode toggle (Shift+D), Inspect panel | done | | +| Properties with their styles and variables; redlines on hover | done | | +| Code: CSS, iOS (SwiftUI), Android (Compose) | done | plus HTML and React (ours); components take properties as parameters, instances are calls | +| Assets list with export | done | | +| Annotations: pinned properties, categories, coloured callouts, filter | done | | +| Ready for dev list, statuses, "Changed" after edits | done | | +| Focus view (one frame, previous / next) | done | | +| Compare changes (before/after side by side or overlaid, property diffs) | done | only against the snapshot taken when a frame was marked ready; not against any named version | +| Code Connect (map components to repository code) | missing | | +| Plugins in Dev Mode (Jira, GitHub, etc.) | missing | needs plugins | +| VS Code extension | missing | FigCraft's MCP server and control channel already serve design data to agents and editors | +| Dev resources links on layers | missing | 1 h | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/file-format-parity.md b/docs/file-format-parity.md new file mode 100644 index 0000000..e6d33d5 --- /dev/null +++ b/docs/file-format-parity.md @@ -0,0 +1,64 @@ +# File format parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; formats from the installed Figma's Info.plist and help center, ours from source) · **Target:** Figma Design (desktop app 126.10.7) + +Every format Figma reads or writes, with FigCraft's support. Sources: `Info.plist` of +`/Applications/Figma.app` (document types only; nothing inside the bundle's code was read), Figma's +help center (image and video types, export formats), and FigCraft's source. + +**Summary (estimated):** ~40% ready. The core interchange formats (SVG, PNG, JPG, PDF) are solid +and tested; Figma's own document, `.fig`, can't be read or written, which alone keeps FigCraft at +alpha. + +## Documents + +| Format | Figma | FigCraft read | FigCraft write | Fidelity / testing | Hours | +|---|---|---|---|---|---| +| `.fig` (Figma Design, `com.figma.document`, `application/x-figma`) | native (cloud; "Save local copy") | **no** | **no** | none | read 30–60, write 15–30 | +| `.jam` (FigJam), `.deck` (Slides) | native to other Figma products | no | no | out of scope | — | +| REST API file JSON (`GET /v1/files/:key`) + local variables JSON + `images/` folder | the API's output | **yes** (`file.open`, `file.import`, CLI) | no | pages, layer tree, geometry, paints, strokes, effects, text runs, vectors, auto layout, constraints, grids, components, sets, instances with overrides, component properties, styles, prototyping (incl. conditionals and variable modes), variables with modes, aliases, scopes and bindings; warnings for what's skipped (video triggers and actions, modifier keys). Unit tests in `crates/format/src/rest/*_tests.rs` | — | +| `.figcraft` (ours: zip of `document.json` + images, versions inside) | — | yes | yes | streamed JSON, 50k layers save ~0.09 s / load ~0.16 s (`cargo xtask bench`); old files keep opening (`large_tests.rs`) | — | +| Local library files | team libraries in the cloud | yes (enable a `.figcraft` as a library) | yes (publish) | per-asset versions, updates with overrides kept | see [collaboration-parity](collaboration-parity.md) | + +## Import (place / paste / drop) + +| Format | Figma | FigCraft | Notes | Hours | +|---|---|---|---|---| +| SVG | editable vectors | **yes**, editable | corpus of 21 synthetic files with hand-computed expected pixels, structure and round-trip checks; gradients, patterns as image fills, clip paths, masks, shadow/blur filters, blend modes, text as text layers; other filters dropped with a warning; text on a path as outlines; fuzzed | 2–4 (filters) | +| PNG, JPG | yes | yes | | — | +| GIF | yes (animated) | first frame only | | 2–4 | +| WebP | yes | yes | | — | +| HEIC | yes | **no** | needs a decoder with an acceptable licence | 2–3 | +| TIFF | Safari only | **no** | | 1 | +| BMP | — | yes | | — | +| MP4, MOV, WebM (video fills, paid plans) | yes | **no** | presenter playback is most of the work | 4–8 | +| Images over 4096 px | downscaled to 4096 | kept | | — | +| Pasted content from other apps | images, SVG, text, Figma clipboard | images, SVG, text (newest clipboard content wins) | no Figma clipboard (it carries Figma's own binary) | with `.fig` | + +## Export + +| Format | Figma | FigCraft | Notes | Hours | +|---|---|---|---|---| +| PNG | yes, scales/suffixes | yes | export settings per layer, presets (`2x`, `512w`, `512h`), preview, "Export N layers" | — | +| JPG | yes | yes | | — | +| SVG | yes (outline text option, ids) | yes | alpha/luminance masks kept; noise, texture, progressive and background blur, glass embedded as images | 1–2 | +| PDF | yes | yes | one page per frame, real selectable text in subset fonts, links, vectors and gradients as vectors, effects as images; bleed, crop/bleed marks, page boxes, naive CMYK; checked by rendering the PDF back against PNG exports | CMYK output intent 2–4 | +| WebP | — | yes (ours) | | — | +| Copy as CSS / SVG / PNG / text / link | yes | yes | | — | +| Dev Mode code (CSS, iOS SwiftUI, Android Compose) | yes | yes, plus HTML and React | see [dev-mode-parity](dev-mode-parity.md) | — | +| `.fig` ("Save local copy") | yes | no | | 15–30 | + +## Fonts + +| | Figma | FigCraft | +|---|---|---| +| Local fonts | yes (font helper / desktop app) | yes (system scan) | +| Bundled/shared fonts | Google Fonts in the cloud | optional `CRAFT_FONTS_DIR` build input (storytold/craft-fonts) | +| Variable fonts | yes | yes (axes, named instances, per-range axis values) | +| Missing-font replacement on open | yes | warnings only (REST import) | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/gaps.md b/docs/gaps.md new file mode 100644 index 0000000..4b8e540 --- /dev/null +++ b/docs/gaps.md @@ -0,0 +1,219 @@ +# Where FigCraft falls short of Figma + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (merged #101–#103: plugins and the multiplayer core) · **Target:** Figma Design (desktop app 126.10.7) + +Every known shortfall against Figma, one entry each, ranked by how much it stops a Figma user from +doing real work in FigCraft. Agents: pick work from the top unless the owner says otherwise. The +numbers behind the ranking are in [`target-app-parity.md`](target-app-parity.md). Hours are one +Opus 5.5 agent working sequentially, tests included, calibrated as described there. "Estimated" +everywhere unless marked measured. + +## Ranked + +No alpha blockers: the alpha gate in [`roadmap.md`](roadmap.md#alpha-gate) passes. Beta blockers are marked. + +| # | Gap | Kind | Hours | Doc | +|---|---|---|---|---| +| 1 | `.fig` files can't be opened (**beta blocker**) | File format | 30–60 | [file-format-parity](file-format-parity.md) | +| 2 | No real-time multiplayer or sharing (**beta blocker**) | Feature | 45–90 | [collaboration-parity](collaboration-parity.md) | +| 3 | Nothing checked against real Figma files | Fidelity | 15–30 | [target-app-parity](target-app-parity.md) | +| 4 | Interaction fidelity not compared tool by tool | UI/UX | 40–60 | [ui-parity](ui-parity.md) | +| 5 | No localization layer; English only | Localization | 60–100 | [localization-parity](localization-parity.md) | +| 6 | Plugins: no run-time UI, distribution or widgets; Figma's plugins don't run | Ecosystem | 25–55 | [target-app-parity](target-app-parity.md) | +| 7 | CPU canvas where Figma uses the GPU | Hardware/performance | 30–60 | [hardware-parity](hardware-parity.md) | +| 8 | Platform QA is mostly macOS | Stability/platforms | 10–20 | [hardware-parity](hardware-parity.md) | +| 9 | Figma Draw: brushes, pressure, text on a path, pattern fills | Feature | 10–18 | [target-app-parity](target-app-parity.md) | +| 10 | Shared (team) libraries | Feature | 10–20 | [components-parity](components-parity.md) | +| 11 | Spell check | Feature | 4–8 | [target-app-parity](target-app-parity.md) | +| 12 | Video and animated GIF fills; HEIC/TIFF images | File format | 6–12 | [file-format-parity](file-format-parity.md) | +| 13 | Live boolean editing and the vector tail | Feature | 6–10 | [target-app-parity](target-app-parity.md) | +| 14 | Variables: extended collections, import/export | Feature | 4–8 | [components-parity](components-parity.md) | +| 15 | Prototyping: media triggers and actions, gamepad | Feature | 3–6 | [prototyping-parity](prototyping-parity.md) | +| 16 | Dev Mode: Code Connect, editor integrations | Feature | 4–8 | [dev-mode-parity](dev-mode-parity.md) | +| 17 | Branching and merging | Feature | 8–15 | [collaboration-parity](collaboration-parity.md) | +| 18 | Display P3 on screen; one window only | Hardware | 6–12 | [hardware-parity](hardware-parity.md) | +| 19 | AI features | AI | 30–60 | [target-app-parity](target-app-parity.md) | +| 20 | Mobile apps (view, mirror, comment) | Platforms | 20–40 | [hardware-parity](hardware-parity.md) | +| 21 | Three menu items without a command | Feature | 2–4 | [parity-checklist](parity-checklist.md) | +| 22 | Screen readers never run; browser has no accessibility tree | UI/UX | 4–8 | [ui-parity](ui-parity.md) | +| 23 | CMYK output intent for print PDFs | File format | 2–4 | [file-format-parity](file-format-parity.md) | + +## Entries + +### 1. `.fig` files can't be opened +- **Missing:** a reader for Figma's native document (`com.figma.document`, extensions `fig`, `jam`, + `deck` in the installed app's `Info.plist`). Figma's files live in the cloud; "Save local copy" + writes a `.fig`. Today the only way in is the REST API file JSON (`file.open` / `file.import`), + which needs an access token and a separate download of images and variables. +- **Evidence:** no `.fig` code anywhere in `crates/format` (searched 2026-10-10); ROADMAP listed + ".fig import (best effort)" as left. +- **Impact:** blocks beta by definition: a designer can't bring existing work across. The single + biggest gap. +- **Estimate:** 30–60 h for a best-effort reader written from public format knowledge (a + compressed binary schema plus a message per node; mapping onto the existing REST importer's + model), with a corpus of synthetic `.fig` files saved from the installed Figma. Export to `.fig` + is a further 15–30 h and lower priority. + +### 2. No real-time multiplayer or sharing +- **Missing:** co-editing, live cursors and selections, observation mode, cursor chat, spotlight, + audio, share links and permissions. Comments and versions are local to the file. +- **Evidence:** the core landed in #103 (`crates/collab`: client-scoped ids, change sets, server + ordering and validation, client reconciliation, binary messages, randomized convergence tests over + real commands), but there is no networking yet, so nobody can co-edit (`docs/collab-protocol.md`). +- **Impact:** Figma's defining feature; most teams use it every day. Solo designers can work + without it. +- **Estimate:** 45–90 h: WebSocket transport and a session server hosted from the app (per the + protocol), presence, then sharing and permissions; the browser build needs the + same client. + +### 3. Nothing checked against real Figma files +- **Missing:** a corpus of real documents (design systems, app screens, prototypes) imported and + compared with Figma's own PNG/SVG/PDF exports. +- **Evidence:** every corpus in the repo is synthetic (`crates/svg/tests/corpus`, the synthetic + design system in `crates/engine/src/synthetic_ds.rs`). Scores were self-graded by the agents that + built the features. +- **Impact:** unknown fidelity in auto layout sizing, text metrics, effects and component + resolution on real files; the numbers in this repo can't be trusted beyond "estimated" until it + exists. +- **Estimate:** 15–30 h once `.fig` or REST import of real files is available; needs files whose + licence allows use (owner to supply or approve; never committed if not redistributable, see + craftrules `standards/test-corpora.md`). + +### 4. Interaction fidelity not compared tool by tool +- **Missing:** a side-by-side pass of every tool and panel: cursors, modifier keys while dragging + (e.g. Ctrl to ignore snapping on macOS), hover states, popovers, menus, snapping thresholds. +- **Evidence:** ROADMAP item 7 ("Left: tool by tool, panel by panel against the incumbent"). +- **Impact:** Figma users notice the feel within minutes; it decides whether they stay. +- **Estimate:** 40–60 h. Detail in [`ui-parity.md`](ui-parity.md). + +### 5. No localization layer; English only +- **Missing:** externalized strings and catalogs. Figma ships English, Japanese, Korean, French, + German, Spanish (Spain and Latin America) and Portuguese (Brazil). +- **Evidence (measured from source):** ~800 distinct capitalised UI string literals in + `crates/ui-egui/src` and 435 command labels, all inline; no catalog files. +- **Impact:** keeps out non-English designers, including Figma's large Japanese and Korean user + bases. +- **Estimate:** 15–25 h for the layer and string extraction, then 3–5 h per language plus native + review; 60–100 h for the 11 key languages. Detail in [`localization-parity.md`](localization-parity.md). + +### 6. Plugins: no run-time UI, distribution or widgets; Figma's plugins don't run +- **Landed (#101):** sandboxed WebAssembly plugins (wasmi, metered, memory cap, no WASI, also in + the browser) acting through the command registry, one undo step per run, manifest permissions, + Plugins menu, Run last plugin, Manage plugins, `plugin.*` commands, a Rust SDK and two examples + ([`plugins.md`](plugins.md)). +- **Missing:** plugin-defined UI at run time (forms or panels a plugin returns), settings storage, + distribution (a plugin directory), widgets, Community files. Figma's own plugins are JavaScript + against Figma's plugin API and don't run. +- **Impact:** teams that depend on specific Figma plugins (icons, content, accessibility checks) + can't bring them. FigCraft's CLI, control channel and MCP server cover agent automation better + than Figma does. +- **Estimate:** 25–55 h for the missing pieces of FigCraft's own API. Running Figma's plugins + needs a JS engine and an API shim: **owner decision needed**. + +### 7. CPU canvas where Figma uses the GPU +- **Missing:** GPU rendering of the canvas. FigCraft renders with tiny-skia on the CPU (banded, + parallel, retained) and shows the image through wgpu. +- **Evidence (measured, `cargo xtask bench`):** a 50k-layer page ~8 ms zoomed out with levels of + detail, single-layer edits at 10k layers ~0.2 ms; full 1440×900 renders 7–15 ms at 10k layers. + Heavy effects (glass, background blur, noise) and 4K/5K canvases at 2x are where CPU time grows. +- **Impact:** large files and effect-heavy designs; battery on laptops. +- **Estimate:** 30–60 h for a GPU path (vello or wgpu shaders) held to the CPU renderer as the + oracle. + +### 8. Platform QA is mostly macOS +- **Missing:** regular runs on Windows, Linux and the browser; real screen readers. +- **Evidence:** CI tests on Linux only (`.github/workflows/ci.yml`); release builds exist for every + platform (v0.2.0) but no issue has been filed yet and the builders checked on macOS. +- **Impact:** unknown bugs on the platforms where FigCraft is most attractive (Linux has no Figma + desktop app). +- **Estimate:** 10–20 h, partly human (hardware). + +### 9. Figma Draw: brushes, pressure, text on a path, pattern fills +- **Missing:** stretch and scatter brushes, pen pressure for the pencil and brushes, text on a + path, pattern fills, multi-edit. +- **Evidence:** `PaintKind` has solid, gradient and image only (`crates/color/src/lib.rs`); no + pressure input anywhere; SVG text on a path imports as outlines. +- **Impact:** illustration-flavoured work moved into Figma Draw in 2025. +- **Estimate:** 10–18 h. + +### 10. Shared (team) libraries +- **Missing:** libraries shared across people and files without copying them around; library + analytics; swapping a whole library. +- **Evidence:** local library files work (publish, enable, updates with overrides kept), see + [`components-parity.md`](components-parity.md). +- **Impact:** design-system teams. Builds on multiplayer's server. +- **Estimate:** 10–20 h after gap 2. + +### 11. Spell check +- **Missing:** spelling underline and suggestions while editing text. +- **Evidence:** no spell-check code in the repo. +- **Estimate:** 4–8 h with a permissively licensed dictionary and checker (provenance per + `ATTRIBUTION.md`). + +### 12. Video and animated GIF fills; HEIC/TIFF images +- **Missing:** Figma takes JPG, PNG, HEIC, WebP, GIF and TIFF images and MP4, MOV and WebM video + (help center, checked 2026-10-10). FigCraft decodes PNG, JPEG, WebP, GIF (first frame) and BMP. +- **Estimate:** 6–12 h (video playback in the presenter is most of it). + +### 13. Live boolean editing and the vector tail +- **Missing:** editing a boolean group's operands in place with live results, Design panel arc + fields, shape builder on strokes and open paths, one-sided variable widths. +- **Estimate:** 6–10 h. + +### 14. Variables: extended collections, import/export +- **Missing:** extended collections (a library collection extended with overrides), variables + import/export, variant properties and gradient stops bound to variables. +- **Estimate:** 4–8 h. + +### 15. Prototyping: media triggers and actions, gamepad +- **Missing:** video triggers (on media hit/end) and play/pause/mute/seek actions; gamepad input. + The REST importer warns and skips them (`crates/format/src/rest/proto.rs`). +- **Estimate:** 3–6 h after video fills (gap 12). + +### 16. Dev Mode: Code Connect, editor integrations +- **Missing:** mapping components to real code (Code Connect), plugins in Dev Mode, VS Code + extension. FigCraft's MCP server already serves design data to agents. +- **Estimate:** 4–8 h. + +### 17. Branching and merging +- **Missing:** branches of a file, review and merge. +- **Estimate:** 8–15 h (versions and Compare changes are a base). + +### 18. Display P3 on screen; one window only +- **Missing:** wide-gamut colour on the canvas (egui draws sRGB, so P3 colours outside sRGB clip on + screen; exports keep them); several windows (Figma's desktop app opens files in separate + windows). +- **Estimate:** 6–12 h. + +### 19. AI features +- **Missing:** Figma AI (first draft, rename layers, remove background, image generation and + editing, visual search, Make). +- **Estimate:** 30–60 h with openly licensed local models. **Owner decision needed.** + +### 20. Mobile apps +- **Missing:** Figma's iOS and Android apps view and comment on files and mirror prototypes. + FigCraft's web build runs in mobile browsers but is not designed for touch. +- **Estimate:** 20–40 h for a touch-first viewer and mirror. + +### 21. Three menu items without a command (measured) +- `file.openRecent`, `view.outlinesSelection`, `view.maskOutlines` + ([`parity-checklist.md`](parity-checklist.md)); the plugin pair landed in #101. +- **Estimate:** 2–4 h for the first three. + +### 22. Screen readers never run; browser has no accessibility tree +- **Evidence:** AccessKit names and keyboard navigation landed (#96), checked by tests only; + eframe's web backend doesn't send the tree yet. +- **Estimate:** 4–8 h plus human QA with VoiceOver, NVDA, Narrator and Orca. + +### 23. CMYK output intent for print PDFs +- **Evidence:** CMYK conversion is a documented naive formula; no CMYK ICC profile can ship in the + repository (licensing). +- **Estimate:** 2–4 h once an openly licensed profile is found. + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | minor | Marked beta blockers; no alpha blockers (the alpha gate passes) | +| 2026-10-10 | major | Created from the 2026-10-10 re-measure against Figma desktop 126.10.7 (replaces the gap list that lived in ROADMAP.md) | diff --git a/docs/hardware-parity.md b/docs/hardware-parity.md new file mode 100644 index 0000000..c99ef13 --- /dev/null +++ b/docs/hardware-parity.md @@ -0,0 +1,53 @@ +# Hardware and platform parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created) · **Target:** Figma Design (desktop app 126.10.7) + +How FigCraft uses hardware and which platforms it runs on, against Figma. Figma's desktop app is +Electron with a GPU helper process; its canvas renders on the GPU (WebGL, with WebGPU rolling out +since 2025). FigCraft renders the canvas on the CPU and presents it through wgpu. + +**Summary (estimated):** hardware ~50%, performance ~60%, platforms ~75%. + +## Hardware + +| Feature | Figma | FigCraft (macOS / Windows / Linux / web) | Hours | +|---|---|---|---| +| Canvas rendering | GPU | CPU (tiny-skia), banded across cores, retained (re-renders only what an edit or pan touches), levels of detail below 50% zoom; shown through wgpu (WebGPU or WebGL2 in the browser) | 30–60 for a GPU path | +| Effects (blurs, glass, noise) | GPU | CPU | in the above | +| HiDPI / Retina | yes | yes (all) | — | +| Wide-gamut display (Display P3) | yes, on capable displays | colours stored and exported in P3; the screen shows sRGB (egui) | 3–6 | +| Trackpad pinch zoom and two-finger pan | yes | yes (egui zoom delta, smooth scroll) | — | +| Pen tablet pressure (pencil, Figma Draw brushes) | yes (forum reports of regressions in 2025) | no | 3–6 | +| Several windows / multi-monitor | yes (a window per file; presenter in its own window) | one window with file tabs; presenter inside it | 4–8 | +| Screen readers | partial | AccessKit tree on desktop (names, roles, states), never tested with a real screen reader; none in the browser | 4–8 + human QA | +| Keyboard layouts (non-US) | yes | keymap uses logical keys; not checked on AZERTY/QWERTZ/JIS | 1–2 | + +## Performance (measured by `cargo xtask bench`, synthetic files, owner's Mac) + +| Case | FigCraft | Figma | +|---|---|---| +| 50k-layer page, zoomed out, full render | ~8 ms (levels of detail) | not timed side by side | +| 10k layers: full 1440×900 render | 7–15 ms | not timed | +| 10k layers: move one layer, re-render | ~0.2 ms | not timed | +| Design system of ~300 components × 2,000 instances: recolour a main used ~900 times | 4–18 ms | not timed | +| `.figcraft` at 50k layers: save / load | ~0.09 s / ~0.16 s | n/a | +| Idle window | 0 frames, ~0% CPU | — | + +Nothing has been timed against Figma on the same document (needs `.fig` import). + +## Platforms + +| Platform | Figma | FigCraft | Notes | +|---|---|---|---| +| macOS | desktop app (Intel and Apple silicon) | universal `.dmg`, signed and notarized (v0.2.0) | where nearly all QA happens | +| Windows x64 / arm64 | desktop app | `.msi` and portable zip for x64, x86 and arm64 | built in CI; little hands-on QA | +| Linux | none (browser only) | AppImage, `.deb`, `.rpm`, Flatpak, tarball, x86_64 and aarch64 | CI tests run here | +| FreeBSD | none | tarball | | +| Web | primary (figma.com) | `figcraft-web` (WASM, WebGPU/WebGL2), web zip | no accessibility tree; file access through the browser | +| iOS / Android | apps: view, comment, mirror prototypes | none (the web build is not touch-first) | 20–40 h for a viewer | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/localization-parity.md b/docs/localization-parity.md new file mode 100644 index 0000000..3af10fe --- /dev/null +++ b/docs/localization-parity.md @@ -0,0 +1,62 @@ +# Localization parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; measured from source) · **Target:** Figma Design (desktop app 126.10.7) + +FigCraft's user interface is English only: there is no localization layer yet. This page lists the +twelve key languages of the craftrules standard, then the other languages Figma ships. + +## What Figma ships + +Figma's help center lists its web, desktop and mobile apps in **English, Japanese, Korean, French, +German, Spanish (Spain and Latin America) and Portuguese (Brazil)** (checked 2026-10-10). Simplified +Chinese, Hindi, Arabic, Indonesian and Vietnamese are not offered; Figma points users to the +browser's page translation. The `.lproj` folders in `/Applications/Figma.app` (60+) are the +Electron/Chromium locale packs, not Figma's own UI languages. Text *content* in any script is +supported by both apps (CJK, Arabic and Devanagari shaping, IME); Figma has no vertical text. + +## What FigCraft has (measured 2026-10-10, from source) + +- **Strings:** ~800 distinct capitalised string literals in `crates/ui-egui/src` (labels, tooltips, + section titles, dialogs) and 435 command labels in `crates/engine/src` (menus, the Actions + palette), all inline in the code. ~1,200–1,500 user-visible strings in all. No catalog, no + translation function, no language preference. +- **Script support in documents:** Unicode bidi with Arabic shaping and mirrored brackets in text + layers; right-to-left list markers and indents; right-to-left names in the layers panel, tabs + and canvas labels (visual order, joined Arabic); inline IME composition with the candidate window + at the caret; system-font fallback for scripts the UI fonts lack. Devanagari shapes through + harfrust. No vertical text (Figma has none either). +- **Script support in the UI:** no mirrored (right-to-left) layout of panels. + +## Languages + +| Language | Code | UI strings translated | Dialogs / tooltips / help | Script support | Native review | Status | Hours to full | +|---|---|---|---|---|---|---|---| +| English | en | ~1,300 / ~1,300 (100%, source) | yes | Latin | yes (source) | full | 0 | +| Simplified Chinese (Mandarin) | zh-Hans | 0 (0%) | no | CJK text, IME and font fallback work in documents; UI font needs CJK coverage | no | none | 5–8 | +| Spanish | es (es-ES, es-419) | 0 (0%) | no | Latin | no | none | 4–6 (both variants, as Figma ships) | +| Hindi | hi | 0 (0%) | no | Devanagari shaping works in documents; UI font fallback to check | no | none | 5–8 | +| Arabic | ar | 0 (0%) | no | Bidi, shaping and RTL names work; the UI does not mirror | no | none | 10–16 | +| French | fr | 0 (0%) | no | Latin | no | none | 3–5 | +| Portuguese | pt (pt-BR) | 0 (0%) | no | Latin | no | none | 3–5 | +| Indonesian | id | 0 (0%) | no | Latin | no | none | 3–5 | +| Japanese | ja | 0 (0%) | no | CJK text and IME work in documents; UI font needs CJK coverage | no | none | 5–8 | +| German | de | 0 (0%) | no | Latin; long words need wider panels | no | none | 3–5 | +| Korean | ko | 0 (0%) | no | Hangul text and IME work in documents; UI font needs coverage | no | none | 4–6 | +| Vietnamese | vi | 0 (0%) | no | Latin with stacked diacritics | no | none | 3–5 | + +Other languages: none shipped (Figma ships none beyond the eight above). + +Before any language: **15–25 h** to add the localization layer (string catalog format, a lookup +used by `ui-egui` and the command registry, plural and argument handling, a language preference, +a test that every string has a key, pseudo-localization to find truncation). Per-language hours +above assume that layer exists and are agent hours; every language also needs a native speaker's +review (human). Total for the eleven: **60–100 h** including the layer (48–77 h of languages). + +Priority: Japanese, Korean, Spanish, Portuguese (Brazil), French and German first: those are +Figma's own languages, so their users expect them. + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created: English only, string counts measured from source, Figma's eight UI languages from its help center | diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md new file mode 100644 index 0000000..3f44670 --- /dev/null +++ b/docs/parity-checklist.md @@ -0,0 +1,15 @@ +# Parity checklist + +> **Generated:** 2026-10-11 by `cargo xtask parity`. Do not edit by hand. + +FigCraft commands registered for the incumbent's main menu and toolbar (455 commands in the engine). + +**200 / 203 menu items (98.5%)** + +## Missing + +- `file.openRecent` +- `view.outlinesSelection` +- `view.maskOutlines` + +Menu coverage measures breadth only; see docs/target-app-parity.md for depth and fidelity. diff --git a/docs/parity.md b/docs/parity.md deleted file mode 100644 index 143924b..0000000 --- a/docs/parity.md +++ /dev/null @@ -1,13 +0,0 @@ -# Parity report - -Generated by `cargo xtask parity`: FigCraft commands registered for the incumbent's main menu and toolbar (455 commands in the engine). - -**200 / 203 menu items (98.5%)** - -## Missing - -- `file.openRecent` -- `view.outlinesSelection` -- `view.maskOutlines` - -Menu coverage measures breadth only; see ROADMAP.md for depth and fidelity. diff --git a/docs/prototyping-parity.md b/docs/prototyping-parity.md new file mode 100644 index 0000000..9232892 --- /dev/null +++ b/docs/prototyping-parity.md @@ -0,0 +1,36 @@ +# Prototyping parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; triggers, actions, transitions and easings counted from `crates/doc/src/proto.rs`) · **Target:** Figma Design (desktop app 126.10.7) + +**Breadth ~88%, ready ~70% (estimated).** Every Figma trigger except media and gamepad, every +action except media control, every transition and easing exist (measured from the model enums on +2026-10-10). Not yet checked against larger real prototypes. Remaining: 5–9 h. + +| Group | Figma | FigCraft | Missing | +|---|---|---|---| +| Triggers | On click, on drag, while hovering, while pressing, key/gamepad, mouse enter, mouse leave, mouse down, mouse up, after delay, on media hit, on media end | 10: OnClick, OnHover, OnPress, OnDrag, MouseEnter, MouseLeave, MouseDown, MouseUp, AfterDelay, KeyPress | gamepad, media triggers | +| Actions | Navigate to, change to, back, scroll to, open link, open / swap / close overlay, set variable, set variable mode, conditional, play/pause/mute/seek media | 11: Navigate, Back, ScrollTo, OpenOverlay, SwapOverlay, CloseOverlay, OpenUrl, ChangeTo, SetVariable, SetVariableMode, Conditional | media actions | +| Transitions | Instant, dissolve, smart animate, move in/out, push, slide in/out | all 8 | — | +| Easing | Linear, ease in/out/in-and-out, back variants, gentle, quick, bouncy, slow, custom bezier, custom spring | all 13 | — | + +| Feature | Status | Notes | +|---|---|---| +| Connections drawn and dragged on the canvas; interaction editor | done | | +| Several actions per interaction; drag to reorder; conditional blocks with else-if/else | done | one undo step per edit | +| Expressions (`count + 1`, `mode(Theme) == "Dark"`, `accent[Dark]`) | done | checked when entered | +| Flows, starting points, descriptions | done | | +| Overlays: position, close on click outside, background, animate out | done | | +| Scroll behaviour: overflow directions, fixed, sticky, preserve scroll position, momentum and overscroll | done | | +| Presenter: device frames and colours, rotation, custom sizes, fit/fill/100%, responsive frames | done | device bodies drawn in code | +| Hotspot hints, inspect panel in the presenter, comments in the presenter | done | | +| Preview pane following edits live | done | | +| Edit interactions on several layers at once | done | | +| Prototype in a separate window; mirror to a phone | missing | see [hardware-parity](hardware-parity.md) | +| Video in prototypes | missing | needs video fills ([gaps](gaps.md) #12, #15) | +| Share a prototype link | missing | needs multiplayer/sharing | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the 2026-10-10 re-measure | diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 0000000..a0a677a --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,76 @@ +# FigCraft roadmap: milestones and what's next + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (merged #101–#103: plugins and the multiplayer core) · **Target:** Figma Design (desktop app 126.10.7) + +Forward-looking plan. Where FigCraft stands today: [`ROADMAP.md`](../ROADMAP.md) and +[`target-app-parity.md`](target-app-parity.md); the full ranked list: [`gaps.md`](gaps.md). Hours +are one Opus 5.5 agent; most milestones split across 4–6 agents on disjoint crates. There is no +`cargo xtask scorecard` in this repo; the measured number is `cargo xtask parity`. + +## Current focus + +1. **`.fig` import** (best effort) with a synthetic `.fig` corpus saved from the installed Figma: + 30–60 h. Unblocks beta and every real-file measurement. +2. **Real-file corpus and fidelity measurement**: import real files, compare against Figma's own + exports, turn estimated percentages into measured ones: 15–30 h. +3. **Tool-by-tool interaction pass** against the running Figma ([`ui-parity.md`](ui-parity.md)): + 40–60 h, parallel by tool. +4. **Localization layer**, then Figma's own languages first (ja, ko, es, pt-BR, fr, de): 15–25 h + for the layer, 3–5 h per language plus native review. +5. **Multiplayer M9** networking on the landed core, per [`collab-protocol.md`](collab-protocol.md): 45–90 h. + +## Alpha gate + +The core workflows a Figma Design user runs every day, checked end to end on macOS (the main +platform) with work saved to `.figcraft` and reopened. Evidence is the repo's tests and the +builders' side-by-side checks with synthetic files; nothing has been run on real Figma files yet. + +| Workflow | Works end to end? | Evidence | Hours to pass | +|---|---|---|---| +| Design screens: frames, shapes, vectors, text, auto layout, styles; save, reopen, export assets | yes | tools and panels in `crates/engine` and `crates/ui-egui`; `.figcraft` round trips (`crates/format/src/large_tests.rs`); PNG/JPG/SVG/PDF export tests | — | +| Build and use a design system: components, variants, properties, variables and modes, libraries | yes | `components_scale_tests.rs` (300 components, 2,000 instances), `library_tests.rs`, `library_variables_tests.rs`; libraries are local files, not shared | — | +| Prototype and present: interactions, flows, overlays, smart animate, variables | yes | `proto_*_tests.rs`, `present_*_tests.rs` | — | +| Hand off to developers: Dev Mode inspect, code, measurements, asset export, ready for dev | yes | `devinspect_tests.rs`, `component_codegen_tests.rs`, `devcompare_tests.rs`, `annotations_tests.rs` | — | +| Review with others: comments, versions, sharing the work | partial (not blocking) | comments with threads, mentions and resolve plus version history work inside a file (`comments_tests.rs`, `version_tests.rs`); the file is shared by passing it along; no real-time co-editing or share links yet; the sync core landed without networking ([collaboration-parity](collaboration-parity.md)) | beta gap: 45–90 | +| Continue existing Figma work (open `.fig`) | no (beta gap) | no `.fig` reader; REST JSON import works for files fetched through Figma's API ([file-format-parity](file-format-parity.md)) | beta gap: 30–60 | + +**Passes, so FigCraft stays alpha:** every daily design workflow works end to end on FigCraft's +own files, which save and reopen, and ready for real work (~47%) is above the ~40% bar. The two +gaps are real but don't break a workflow done in FigCraft: review works asynchronously through +comments in a shared file, and opening `.fig` is the step that moves work across from Figma, which +the standard requires for beta, not alpha. Both stay at the top of [`gaps.md`](gaps.md) as beta +blockers. + +## Milestones + +| Milestone | Status | Left | Hours | +|---|---|---|---| +| M0 Foundation: workspace, model, renderer, engine, UI shell, app, control channel | done (2026-10-09) | — | — | +| M0.9 CLI + MCP, web build, release packaging, PDF export | done (v0.2.0 released 2026-10-10 for every platform) | — | — | +| M1 Core editing completeness (tools, panels, menus, clipboard, files) | ~75% | Open recent, outline mode variants, keyboard box selection, interaction pass | 8–14 + pass | +| M2 Layout depth | ~80% | grid `fr` rows, real-file QA | 6–12 | +| M3 Components & styles depth | ~75% | extended collections, variables import/export, real libraries | 10–20 | +| M4 Vector & text depth | ~70% | live booleans, spell check, Figma Draw (brushes, pressure, text on a path, patterns) | 24–40 | +| M5 Prototype & present | ~85% | media, gamepad, separate window | 5–9 | +| M6 Interop & Dev Mode | ~55% | `.fig` import, video/HEIC/TIFF, CMYK intent, Code Connect | 40–80 | +| M7 Release & fidelity (signed builds, look & feel, shortcuts) | builds done; fidelity pass started | tool-by-tool pass | 40–60 | +| M8 Hardening & performance (bench, retained canvas, accessibility, idle) | ~60% | real-file corpus, platform QA, GPU canvas, screen readers | 60–110 | +| M9 Real-time collaboration | core done (#103: ids, change sets, server ordering, convergence) | WebSocket transport, hosting and joining, cursors, per-user undo, reconnect, browser client, standalone server, sharing | 45–90 | +| M10 Localization (new) | not started | layer + 11 languages | 60–100 | +| M11 Plugins | runtime, API, menu, manager and SDK done (#101) | run-time plugin UI, settings storage, distribution, widgets; Figma plugin compatibility is an owner decision | 25–55 | +| M12 AI features (new, owner decision) | not started | local models | 30–60 | + +## Next, after the current focus + +- Shared libraries on top of the multiplayer server (10–20 h), branching (8–15 h). +- GPU canvas held to the CPU renderer (30–60 h). +- Figma Draw tools (10–18 h). +- Mobile viewer and prototype mirror (20–40 h). + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | minor | Added the alpha gate (core-workflow table): passes, stage stays alpha | +| 2026-10-10 | major | Created: milestone table moved from ROADMAP.md with statuses re-checked; added M10–M12; current focus re-planned | diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md new file mode 100644 index 0000000..ae49f01 --- /dev/null +++ b/docs/target-app-parity.md @@ -0,0 +1,574 @@ +# FigCraft parity with Figma + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** minor (merged #101–#103: plugins and the multiplayer core; ready ~47%; last major: full re-measure against Figma desktop 126.10.7) · **Target:** Figma Design (desktop app 126.10.7, macOS) + +The authoritative assessment of how close FigCraft is to Figma Design. [`ROADMAP.md`](../ROADMAP.md) +summarizes it; [`gaps.md`](gaps.md) is the ranked work list; the measured menu checklist is +[`parity-checklist.md`](parity-checklist.md). Deeper checklists: +[`ui-parity.md`](ui-parity.md), [`file-format-parity.md`](file-format-parity.md), +[`hardware-parity.md`](hardware-parity.md), [`localization-parity.md`](localization-parity.md), +[`auto-layout-parity.md`](auto-layout-parity.md), [`components-parity.md`](components-parity.md), +[`prototyping-parity.md`](prototyping-parity.md), [`dev-mode-parity.md`](dev-mode-parity.md), +[`collaboration-parity.md`](collaboration-parity.md). + +## Headline + +| Number | Value | Kind | +|---|---|---| +| Menu/command breadth | **98.5%** (200 / 203 catalogued menu items have a live command) | **measured** (`cargo xtask parity`, re-checked from source on 2026-10-10) | +| Feature breadth (does each Figma Design feature exist, weighted) | **~78%** (core editor areas 1–16: ~90%) | estimated from the area table below | +| Ready for real work | **~47%** | estimated (dimension table below: written weights × written per-dimension scores) | +| Essentials user | **~53%** | estimated ([below](#essentials-user): core features 77.8% × discounts 0.92 × 0.92 × 0.8) | +| Mainstream practitioner | **~43%** | estimated ([below](#mainstream-practitioner): weekly areas 66.5% × discounts 0.9 × 0.9 × 0.8) | +| Remaining to beta | **~200–365 h** one Opus 5.5 agent (~40–80 h wall-clock with 5 parallel agents) | estimated | +| Remaining to full parity | **~390–745 h** one agent (~95–170 h wall-clock with 5 parallel agents) | estimated | +| Stage | **alpha**: the alpha gate passes ([roadmap](roadmap.md#alpha-gate)); `.fig` import and multiplayer are beta gaps (see [ROADMAP](../ROADMAP.md#stage)) | | + +The previous figures (ROADMAP of 2026-10-10, "feature depth ~79%", "full parity 115–195 h") were +self-graded against a 16-area rubric that left out, by design, multiplayer, plugins, cloud +libraries and AI features, and that counted no file-format blocker. Figma users rely on all of +those every day, so this re-measure weights them in. The core-editor depth figure drops from ~79% +to ~67% because nothing has yet been checked against real Figma files or side by side tool by +tool; presence was being graded as behaviour in places. + +## Readiness by audience + +| Audience | Ready % | Opus 5.5 agent wall-clock hours to ~95% | Work that dominates | +|---|---|---|---| +| Full target (ready for real work) | ~47% | ~375–705 h | multiplayer (45–90), localization (60–100), plugins (25–55), the interaction pass (40–60), `.fig` import (30–60), GPU canvas (30–60), AI (30–60) | +| Mainstream practitioner | ~43% | ~180–330 h | core editor depth incl. `.fig` import (98–188), the interaction pass (40–60), real-file corpus and platform QA (25–50), `.fig` export for handing work back (15–30) | +| Essentials user | ~53% | ~85–160 h | `.fig` import so files people send open (30–60), core tool polish (25–45), interaction pass on the core tools (15–25), stability QA (10–20), onboarding and starter templates (5–10) | + +Hours are one agent working sequentially, calibrated from this repo's history (about 1 agent-hour +per 1,000 added lines, 1–2.5 h per feature PR, ~7 h per honest depth point in the polish tail; see +[how the hours are calibrated](#how-the-hours-are-calibrated)). Each audience's work is a subset of +the next. About 70–80% parallelizes across 4–6 agents on disjoint crates (roughly ÷4 in +wall-clock); the `.fig` reader, the multiplayer core and a plugin runtime each need one owner, and +native-speaker review, real-file licensing and screen-reader QA need people. + +The full number is an additive weighted sum over the dimension table; mainstream and essentials use +multiplicative discounts, as the standard says. + +## What was measured, and how + +- **Target and version.** Figma desktop for macOS, `CFBundleShortVersionString` 126.10.7, + installed at `/Applications/Figma.app`. FigCraft is measured as of `origin/main` d452da3 + (2026-10-10, PR #99). +- **The installed app, names and public listings only.** FigCraft is clean-room + ([`AGENTS.md`](../AGENTS.md)): nothing inside the bundle's code or web assets was read. From + `Info.plist`: one document type, `com.figma.document`, extensions `fig`, `jam`, `deck` + (MIME `application/x-figma`), and the `figma://` URL scheme. The `.lproj` folders are + Electron/Chromium locale packs (60+), not Figma's UI languages; the UI languages come from + Figma's help center (see [`localization-parity.md`](localization-parity.md)). The bundle ships + GPU, Plugin and Renderer helper processes (GPU rendering; a sandboxed plugin runtime). +- **The menu catalog.** `crates/engine/src/catalog.rs` holds Figma's main menu tree (202 items in + File, Edit, View, Object, Text, Arrange, Vector, Plugins, Preferences, Libraries, Help), written + from public documentation and black-box observation (local notes in the gitignored + `plan/figma/03-menu-tree.md`). It leaves out the Widgets menu and dynamic plugin lists, so the + 98.5% overstates breadth against the full menu a little. +- **From source** (no build; 2026-10-10): 449 command ids registered with `spec!`, 963 `#[test]` + functions in 177 files, ~108,800 lines of Rust in 13 crates + 3 apps + xtask (before #101–#103, which added the `plugin` and `collab` crates and ~7k lines), 140 key bindings + and 13 gesture rows in `figcraft_engine::keymap`, 21 files in the SVG import corpus, 0 + translated UI strings (no localization layer exists). +- **Figma's feature set**: help center, release notes and Config 2025 announcements (Figma Draw, + grid auto layout, slots, glass/noise/texture effects, progressive blur), known to the assessor up + to mid-2026, plus web checks on 2026-10-10 (supported image/video types, UI languages, pen + pressure in Figma Draw). +- **Side by side.** Look & feel was compared with Figma UI3 on the owner's Mac (screenshots kept + local, never committed). No real Figma file has been opened in FigCraft (no `.fig` reader), and + no rendered frame has been compared pixel for pixel against Figma's own export. + +## Weights + +Weights are the share of a typical product designer's working time in Figma Design, written down +so they can be argued with. Areas 1–16 keep the original rubric's weights (they sum to 94, not the 100 the rubric claimed); +areas 17–21 are added (sum 19) because Figma users depend on them. Percentages below divide by the +total, 113. +Out of scope as separate products: FigJam, Figma Slides, Sites, Make, Buzz, Weave (the `.jam` and +`.deck` document kinds belong to them). + +## By feature area + +Breadth: does it exist. Ready: depth, correctness and fidelity for real projects. Hours: one Opus +5.5 agent, sequential, tests included. + +| # | Area | Weight | Breadth | Ready | Remaining | Hours | +|---|---|---|---|---|---|---| +| 1 | Canvas & navigation | 6 | 95% | 72% | Outline mode variants (`view.outlinesSelection`, `view.maskOutlines`), Display P3 on screen, QA at extreme zooms | 3–6 | +| 2 | Selection & transform | 8 | 95% | 68% | Handles, measuring and snapping checked tool by tool against Figma; rotated groups and mixed selections | 6–10 | +| 3 | Layers panel | 5 | 95% | 78% | Keyboard box selection, keyboard rename/context menu, long-list QA | 2–4 | +| 4 | Shapes & vector | 8 | 92% | 66% | Live boolean editing, Design panel arc fields, shape builder on strokes and open paths, one-sided widths | 8–14 | +| 5 | Paint | 7 | 85% | 66% | Video and animated GIF fills, wide-gamut canvas, embedded image profiles, HEIC/TIFF images | 5–9 | +| 6 | Strokes | 3 | 90% | 72% | Stroke styles, brush strokes (see 20) | 2–4 | +| 7 | Effects | 4 | 100% | 72% | Glass and progressive blur tuned side by side | 3–6 | +| 8 | Frames, groups, sections, masks | 5 | 95% | 75% | Visual QA with real files | 2–4 | +| 9 | Auto layout & constraints | 9 | 95% | 68% | Grid `fr` rows around fixed children; behaviour against real Figma files ([auto-layout-parity](auto-layout-parity.md)) | 6–12 | +| 10 | Text | 8 | 85% | 64% | Spell check, text on a path, CJK text QA, real-file text metrics | 8–14 | +| 11 | Components & variants | 9 | 95% | 68% | Real (not synthetic) libraries, `.fig` libraries, component playground ([components-parity](components-parity.md)) | 6–12 | +| 12 | Styles & variables | 5 | 85% | 70% | Extended collections, variables import/export, gradient stops and variant properties bound | 4–8 | +| 13 | Prototyping | 6 | 88% | 70% | Video triggers and media actions, gamepad triggers, real prototype QA ([prototyping-parity](prototyping-parity.md)) | 5–9 | +| 14 | Import/export | 6 | 65% | 35% | **`.fig` import** (the blocking gap), `.fig` export, HEIC/TIFF/video import, CMYK output intent ([file-format-parity](file-format-parity.md)) | 30–60 | +| 15 | Dev Mode / inspect | 2 | 80% | 62% | Code Connect, plugins in Dev Mode, editor integrations ([dev-mode-parity](dev-mode-parity.md)) | 4–8 | +| 16 | Comments, versions, find, misc | 3 | 80% | 58% | Comments are local only; branching; Open recent | 4–8 | +| 17 | Multiplayer & sharing | 8 | 15% | 5% | Core landed (`crates/collab`: ids, change sets, server ordering, convergence tested), no networking: WebSocket transport, hosting/joining, cursors, observation, cursor chat, share links and permissions ([collaboration-parity](collaboration-parity.md)) | 45–90 | +| 18 | Plugins & widgets | 4 | 35% | 20% | Own sandboxed WASM plugins landed (#101: manifest, permissions, menu, Run last, Manage, SDK, 2 examples). Left: plugin UI at run time, settings storage, distribution, widgets; Figma's plugins are JavaScript and don't run (a JS engine would be an owner decision) ([plugins.md](plugins.md)) | 25–55 | +| 19 | Team libraries & organization | 2 | 40% | 25% | Local library files exist; no shared/cloud library, no library analytics | 10–20 | +| 20 | Figma Draw extras | 2 | 45% | 30% | Have: variable width, lasso, shape builder, noise/texture. Missing: brushes (stretch/scatter), pressure, text on a path, pattern fills, multi-edit | 10–18 | +| 21 | AI features | 3 | 0% | 0% | First draft, rename layers, image edit/remove background, visual search, Make: needs local models (owner decision) | 30–60 | +| | **Weighted (÷113)** | 113 | **~78%** | **~57%** | | **218–431** | +| | Core editor only (1–16, ÷94) | 94 | ~90% | ~67% | | 98–188 | + +## By dimension (ready for real work) + +| Dimension | Weight | Ready | Hours | Evidence | Doc | +|---|---|---|---|---|---| +| Features (depth) | 35 | 57% | 78–146 (areas 1–13, 15, 16, 20) | The table above; core editor ~67% | this file | +| UI/UX fidelity | 15 | 58% | 40–60 | Look & feel compared side by side with UI3 (~65% by the builders); tool-by-tool interaction (cursors, modifiers while dragging, hover states, popovers) not yet compared; accessibility names and keyboard navigation landed | [ui-parity](ui-parity.md) | +| File formats | 12 | 40% | 30–60 | No `.fig` read or write; REST JSON import, SVG in/out, PNG/JPG/WebP/PDF export solid | [file-format-parity](file-format-parity.md) | +| Collaboration | 10 | 12% | 55–110 | Local comments and version history; the multiplayer core (sync model, server ordering, client reconciliation, convergence tests) landed in #103 without networking, so nobody can co-edit yet (`docs/collab-protocol.md`) | [collaboration-parity](collaboration-parity.md) | +| Stability | 8 | 55% | 20–40 | Never-crash lints, command guard with rollback, recovery copies, 963 tests incl. junk-parameter sweeps and a seeded retained-render walk; but two days old, one release (v0.2.0), no field reports, QA mostly on macOS | [gaps](gaps.md) | +| Performance | 6 | 60% | 30–60 | `cargo xtask bench`: 50k-layer page ~8 ms zoomed out, 10k-layer edits ~0.2 ms, 2,000-instance design system edits 4–64 ms; CPU (tiny-skia) canvas where Figma renders on the GPU; nothing timed against Figma on the same file | [hardware-parity](hardware-parity.md) | +| Hardware | 3 | 50% | 15–30 | Trackpad pinch and HiDPI yes; no pen pressure, no GPU canvas, no P3 on screen, one window | [hardware-parity](hardware-parity.md) | +| Localization | 3 | 10% | 60–100 | English only; Figma ships 7 more UI languages | [localization-parity](localization-parity.md) | +| Platforms | 3 | 75% | 10–20 | macOS, Windows (x64/x86/arm64), Linux, FreeBSD, web all packaged (v0.2.0); Figma also has iOS/Android apps; non-macOS QA thin | [hardware-parity](hardware-parity.md) | +| Ecosystem/plugins | 3 | 20% | 25–55 | Own WASM plugins with a Rust SDK and two examples (#101); no Figma plugin compatibility, no widgets, no distribution or community files; the CLI, control channel and MCP server are ahead of Figma for agents | [gaps](gaps.md) | +| AI features | 2 | 0% | 30–60 | None | [gaps](gaps.md) | +| **Ready for real work** | 100 | **~47%** | **~390–745** | | | + +Dimension hours add up to the full-parity total without double counting: the feature-area rows +for import/export (14), multiplayer and team libraries (17, 19), plugins (18) and AI (21) are +counted under their dimensions. + +## Essentials user + +Someone who uses only the core of Figma: a casual or beginner user making a few screens, a social +graphic or a simple mockup. Same method, with the core features a casual user touches. + +**1. Core features, weights and depth** (depth from the area table and checklists above): + +| Feature | Weight | Depth | Notes | +|---|---|---|---| +| Create, open, save and reopen a file; pages | 10 | 85% | home screen, `.figcraft` round trips; Open recent missing | +| Pan and zoom | 10 | 80% | wheel, pinch, Space-drag, zoom shortcuts | +| Select, move, resize, rotate, align, group, duplicate | 15 | 75% | not yet compared tool by tool | +| Frames with device presets | 8 | 80% | | +| Rectangle, ellipse, line, arrow, corner radius | 8 | 80% | | +| Text: type, font, size, weight, colour, alignment | 12 | 70% | no spell check | +| Colour picker, fills and strokes; place and crop images | 10 | 72% | no HEIC images | +| Layers panel: rename, hide, lock, reorder | 7 | 80% | | +| Basic auto layout (add, gap, padding) | 6 | 70% | | +| Undo / redo | 5 | 90% | unlimited, one step per gesture | +| Export PNG, JPG, SVG, PDF | 6 | 85% | | +| Copy and paste, incl. images from other apps | 3 | 75% | | +| **Weighted** | 100 | **77.8%** | | + +Left out: components and variables beyond using one, prototyping, Dev Mode, advanced vector and +type, and everything the mainstream number leaves out. + +**2. Discounts a casual user actually hits:** + +| Discount | Factor | Evidence | +|---|---|---| +| Launch and stability | ×0.92 | signed and notarized macOS build, installers for every platform (v0.2.0), never-crash rules and recovery copies; no field record yet | +| Discoverability and UI clarity | ×0.92 | the UI3 layout Figma users know, Actions palette, keyboard shortcuts panel; no onboarding, templates or Community files to start from | +| Opening files people send them | ×0.80 | what people send a Figma user is a Figma link or a `.fig`; neither opens. Images and SVG do | + +77.8% × 0.92 × 0.92 × 0.80 = **~53%** (estimated). User evidence: none yet (see above). + +## Mainstream practitioner + +The same question for the typical professional Figma Design user: a product designer who designs +screens, maintains or uses a design system, prototypes and hands off to developers every week. +Computed per craftrules `standards/progress-docs.md`. + +**1. Areas used weekly, with weights.** Feature areas 1–16 of the table above, with their weights +(sum 94). Left out as the standard says: plugins and widgets (18), AI (21), team and organization +libraries (19, cloud/team admin), Figma Draw extras (20, not weekly for a product designer), +localization beyond English, specialist hardware. Real-time multiplayer (17) is cloud collaboration +and is left out as an area, but its effect on working with Figma users is counted in discount 3. + +**2. Average depth** ("Ready" column, weighted): **66.5%**. + +**3. Discounts for what still stops real work:** + +| Discount | Factor | Evidence | +|---|---|---| +| Interaction fidelity | ×0.90 | UI3 look compared side by side (~65% by the builders); no tool-by-tool comparison of cursors, modifier keys while dragging, snapping thresholds or popovers yet; Ctrl to suspend snapping on macOS missing ([ui-parity](ui-parity.md)) | +| Stability on real machines | ×0.90 | Never-crash lints, command guard with rollback, recovery copies and 963 tests, but no field record at all: the repository is private, v0.2.0 has had no outside users or issue reports, CI tests run on Linux only and hands-on QA is on macOS. Harsher than VectorCraft's ×0.92 because there is no outside evidence either way | +| File exchange with Figma users | ×0.80 | A Figma designer's work lives in shared Figma files. FigCraft can't open `.fig` or write anything Figma opens as a document; incoming work can come through the REST API JSON (one way, needs an access token), outgoing only as SVG, PDF, PNG or code. Teammates, reviewers and developers would all need FigCraft ([file-format-parity](file-format-parity.md), [collaboration-parity](collaboration-parity.md)) | + +66.5% × 0.90 × 0.90 × 0.80 = **~43%** (estimated). + +**4. User evidence (2026-10-10):** 0 issues, 0 praise or "switched from Figma" reports, 0 comments +from anyone but the maintainers (`gh issue list`, `gh api .../issues/comments`; the repository is +private, 1 star, PRs only from maintainers). No outside evidence either way; nothing raises the +number. + +**Why it is lower than ready for real work (~47%), unusually.** The full number averages +dimensions additively, so the missing `.fig` exchange costs only the file-format dimension's 12% +weight, and FigCraft earns points the mainstream number doesn't count (platforms 75%: Linux, +FreeBSD and the web, where Figma has no desktop app). The mainstream number applies file exchange +as a multiplier on everything, because a Figma practitioner's whole working week is shared through +Figma files. Both are computed from written weights; neither was moved to match the other. The +mainstream number rises fastest with `.fig` import (the ×0.80 toward ×0.95: ~51%) and the +interaction pass. + +## How the hours are calibrated + +From this repository's own history (`git log`, `gh pr list`): + +- The whole app was built in ~25 wall-clock hours: first commit 2026-10-09 15:38 UTC, PR #99 + merged 2026-10-10 16:53 UTC; ~49k lines on day 1 before PRs, then 99 PRs adding ~81k lines. The + ROADMAP of that period records 4–6 agents in parallel, so ~110–150 agent-hours in all: about + **1 agent-hour per ~1,000 added lines**, and a typical feature PR (1,000–2,500 lines, e.g. + #84 arc handles, #92 PDF print options, #96 accessibility) took **1–2.5 agent-hours**. +- Between the ROADMAP revisions of 2026-10-09 22:19 UTC and 2026-10-10 16:53 UTC (~18.5 h wall, + 78 PRs, ~75–110 agent-hours) the self-graded depth went 58% → 79%: **~4–5 agent-hours per + self-graded point**. This re-measure grades about 0.6 points for each of those, which puts an + honest point nearer 7 agent-hours in the polish tail; new subsystems (a `.fig` reader, + multiplayer, a plugin runtime) are estimated bottom-up instead, since nothing comparable has been + built here yet. +- Parallelism: most of the work splits across 4–6 agents on disjoint crates (the history shows it + working); multiplayer, `.fig` import and the plugin runtime each need one owner for their core. + Needs a human: native-speaker review for every language, the plugin-runtime and AI-model + decisions, real-world Figma files to test with (licensing), Windows/Linux/screen-reader QA. + +## Area detail: what has landed and what is left + +Carried over from the ROADMAP's "Where we're lacking" list (2026-10-10, before this re-measure). +Hours in this narrative are the builders' estimates; the tables above supersede them. + +1. **Vector edit mode**: *landed:* edit-mode toolbar (move, pen, bend, paint bucket, lasso, cut), + pen that extends, branches and closes paths (vector networks), paint bucket fill/unfill of any + closed area (faces with holes), point/segment selection, handle mirroring (none/angle/angle and + length) with a Point panel (position, corner radius, mirroring), smooth/sharp points, join and + merge, delete vs delete-and-heal, nudging, one undo step per gesture, eraser (⇧E), shape builder + (⇧M: the regions of overlapping shapes, click or drag to merge, Alt to remove, curves kept), + variable width strokes (width profile presets with previews in the stroke settings, the Variable + width tool ⇧W: drag the path to add a width point, slide points, drag their handles, Delete; + smooth interpolation per subpath, dashes, caps and joins, canvas/PNG/SVG/PDF and outline stroke), + a transform box around several selected points (corners and edges scale them, Shift keeps + proportions, Alt from the centre; just outside a corner rotates, Shift in 15° steps; drag inside + to move; the Design panel's X/Y/W/H and flip/rotate act on the points), point snapping while + dragging points or handles and with both pens (to the points and segment midpoints of this and + other vectors, the usual layer targets and the pixel grid, with guides and a marker on the point + landed on; Ctrl/Cmd turns it off), arc handles on the canvas (sweep, start and ratio with a + live readout, Shift snapping, closing at the start, the other part from the gap; rotated and + flipped ellipses, any zoom). *Left:* live boolean editing, one-sided widths, Design panel arc + fields. 4–8 h. +2. **Text editing depth**: *landed:* OpenType features panel, small caps, lists, title case, + truncation/max lines, font picker with previews and recents, word/line selection, IME commit, + inline IME composition (underlined at the caret, reflowing, candidate window at the caret; the + document only gets the committed text), variable fonts (axes and named instances read from the + font, named instances as styles, Type settings ▸ Variable sliders, per-range axis values applied + to shaping, outlines and PDF), range-aware Typography panel with "Mixed". Range fills in the Fill + section. Right-to-left and mixed-direction text (Unicode bidi: Arabic shaping, mirrored brackets, + caret, clicks and selection follow the runs; arrow keys move visually). Right-to-left and + mixed-direction names in the panels (layers, pages, Assets, tabs, the file header, canvas frame + titles: visual order, joined Arabic, the ellipsis at a right-to-left name's left end; rename fields + whose caret, clicks, drags and arrow keys follow the shown text; system fonts for scripts the UI + fonts lack). The text style browser in the Typography section (list and grid views in each + style's own font, search, folders, this file's and enabled libraries' styles, apply, detach, edit + the typography, create from the selected chars, hover to preview on the canvas, "Mixed" when the + chars use several styles); text styles link chars, not just layers (editing what a style sets + unlinks the chars edited). Live previews of a hovered named instance or font style and of a + dragged axis slider (one undo step on release, Escape cancels). Visual QA: list markers keep the + paragraph's font, renames start with the name selected and centred, Max lines shows while + truncating. Right-to-left paragraphs mirror lists and indents: bullets and numbers (".1") on + the right, wrapped lines hanging from the right, the paragraph indent on the right, trailing + spaces hanging outside the line (canvas, PNG, PDF and SVG). *Left:* visual QA. 0.5 h. +3. **Auto layout and sections depth**: *landed:* on-canvas padding/gap handles (also wrapped-row + and grid column/row gaps, grid tracks outlined), min/max width/height (UI, Hug/Fill/Fixed, + hugging text wraps at its max), ignore auto layout (absolute position) with constraints, text + baseline alignment, grid tracks (fixed/hug/`fr`), grid cells and spans, wrap row gap UI, + wrap-aware drag-reorder (by row) and dragging into a grid cell, nested hug/fill settling in one + pass (wrapping fill text, three levels deep, grid rows), min/max redistribution, coherent + Fill/Hug rules, drag across nested auto layout frames (deepest one wins, insertion line, out to + the canvas or a plain frame). Arrow keys move auto layout children one place (along the flow + past hidden and absolute siblings, Up/Down between wrapped rows, to the neighbouring grid cell + (automatically placed children swap, anchored ones take or swap cells), and at the end of a + flow or across a row's axis into the neighbouring nested auto layout frame when the frame + around flows that way; one undo step, none when nothing can move). Visual QA of nested + hug/fill/fixed/min/max/wrap/grid samples against the documented rules (Fill turns a hugging + parent Fixed, min/max redistribution, wrap inside fill, absolute children following + constraints as hug frames grow). Sections: hide contents (name, outline and "Contents hidden" + on the canvas; contents skipped by rendering, hit testing and labels; dimmed in the layers + panel; Design panel checkbox and context menu), Wrap in new section, frames in sections get + canvas labels and are top-level frames (flows start there, navigation, Export frames to PDF), + "Navigate to" a section shows its frame shown last, else its first; ready for dev turns + "Changed" when the contents are edited, resolved with a reason; Compare changes shows what a + changed frame or section looked like when it was marked next to how it is now, with the + changed layers and their property changes. *Left:* whether `fr` rows of a fixed-height grid + should make room for fixed-size children (now `minmax(0, 1fr)`-like). 1–2 h. +4. **Components depth**: *landed:* component properties (edit/delete/bind) with the properties + panel, add variant, instance swap UI, per-layer overrides with reset, restore main, instance + structure protection; Assets panel with live thumbnails, search and drag-to-canvas (drops into + the frame or auto layout slot under the pointer); exposed nested instances (their properties + show on the main's instances); component descriptions (edited on the main, shown on + instances); local libraries (publish a file's components, sets and styles with per-asset + versions, enable library files, place library components and apply library styles as + read-only linked copies, "Library updates available" with overrides kept on update); slots + (a frame of a main made a slot property with preferred components; instances fill it with any + content of their own, kept across main updates, variant switches, copy/paste and detach, with + the main's default content until edited; reset slot; slot badges in the layers panel and on the + canvas; fill menu in the properties panel; drops from the Assets panel and the canvas land in + slots); nested overrides kept when the main moves or swaps a nested instance, and on nested + instances copied out of an instance (re-linked to their own main); canvas drags can no longer + pull layers out of an instance; library variables (publishing includes the file's variable + collections with their modes, aliases and scopes, versioned per variable and collection, without + variables hidden from publishing; files using the library see its collections read-only under + the library's name in the Variables editor and the variable pickers; binding, aliasing or setting + a library collection's mode on a frame copies the variables in as read-only linked copies, so the + file renders without the library; library components keep their variable bindings and modes; + "Library updates available" covers changed variables and bound layers follow). Explicit variable + modes in the Design panel: a frame's mode per collection, Auto (inherited) or its own, with + enabled libraries' collections listed under the library's name (picking a mode copies the + collection in). Instance boolean and text properties bound to boolean and string variables + (following modes, renames, reset and detach); layout grid settings in the Design panel whose + count, size, margin/offset and gutter bind to number variables; fills, strokes, effects and + layout grids reordered by dragging their rows, their variable bindings following. Components at + scale, QA'd with a synthetic design system (about 300 components: buttons, inputs, cards, navs + and badges as sets of size × state × type × theme variants, boolean/text/instance swap/slot + properties, instances nested four deep, text and paint styles, light/dark variables bound across + it) used 2,000 times with overrides at every level: main edits keep every override and match a + full rebuild exactly; values from variables (a theme switch, a bound corner radius) are no longer + recorded as overrides; detaching a variable on an instance layer is an override that survives main + edits; exposed nested instances stay exposed and swapped nested instances keep their layer names + through main edits; layers a swapped nested instance's main adds keep their ids and overrides. + Instance swap properties have preferred values (offered first). Alt-drop from the Assets panel + onto an instance swaps it (same-set instance preferred, highlighted while dragging); instances + pasted into other files follow their mains (library copies shared, published components used + from their library, other mains left behind as a restorable missing main). The Assets panel lays + out only the tiles in view and renders thumbnails as they show (cached, re-rendered only for + changed components). *Left:* QA with real-world (not synthetic) libraries. 1 h. +5. **Prototyping depth**: *landed:* on-canvas connections with drag-to-connect, interaction editor, + flows, smart animate, overlays, scroll/fixed/sticky, change-to and set-variable in the presenter. + Custom bezier and custom spring easings with editor fields; device frames (phone, tablet, + laptop, desktop bodies drawn in code) around the presented frame; overlays animate out with + their opening transition reversed; several selected layers edit their interactions together + (or replace mixed ones); scrolling inside device frames (the frame sized to the device's screen, + clipped or scrolling by wheel and drag, fixed layers pinned to the screen by their constraints, + nested "Scroll to", preserve scroll position); a resizable preview pane over the canvas that + plays the selected frame and follows edits live; device rotation (phones and tablets turn to + landscape: saved in the file, imported from REST files, drawn turned in the presenter and the + pane); presentation options (fit, fit width, fill, 100%, with Z to cycle them and R to + restart, the device frame shown or hidden, kept between presentations; what overflows the + window pans); scroll momentum (drags fling and slow down the same at any frame rate, the wheel + coasts, a drag past the ends stretches and springs back); responsive presentation (the presented + frame resized to the device's screen, or the window without a device, its constraints and auto + layout responding live; in the Options menu and the Prototype panel, saved in the file); device + colours (each model's colour variants, bodies drawn in code) and custom device sizes (a bare + screen with width and height fields, imported from REST files); flow descriptions in the + presenter's flow picker and under each flow; conditional actions (if / else if / else over + variable expressions) and set-variable-mode actions run in the presenter (from REST files or + commands). Conditionals are built in the interaction editor: an interaction's actions are a list + (add, reorder by dragging a row's grip, also inside conditional blocks, or from its menu, remove, + open one to edit it; one undo step per move), "Add action ▸ Conditional" adds an if whose + condition comes from a builder (a variable from the variable picker, an operator, a value or + another variable) or is typed as an expression (`count >= 3 and not done`, checked when entered, + what's wrong shown under the field), each block with its own actions (the same editors, + nested), plus "Else if" and "Else"; set variable values can be expressions (`count + 1`, + `"Hi " + name`); expressions read a variable's value in a given mode of its collection + (`accent[Dark]`, also from REST files' variable mode lookups) and the mode a collection is in + where the interaction runs (`mode(Theme) == "Dark"`, following set variable mode actions); every + edit is an undo step (`proto.action.*`, `proto.conditional.*`). Hotspot hints: a click where + nothing reacts flashes the screen's hotspots (an Options menu toggle, on by default); the + presenter's Inspect panel shows the hovered layer's properties. Overlays opened through commands + close on a click outside unless told not to, as in the editor. *Left:* QA against larger + real-world prototypes. 1–2 h. +6. **Interop**: *landed:* image crop handles; REST API file JSON import (`file.open` / `file.import` + / CLI: pages, layer tree, geometry, paints, strokes, effects, text runs, vectors from geometry + paths, auto layout, constraints, grids, components, sets, instances with overrides, component + properties, styles; image fills from an `images` folder or placeholders; warnings for the rest), + now with prototyping (interactions with their triggers, actions, transitions and easing, flows, + scrolling, the prototype device; conditional actions (if / else if / else over expressions), + set variable with variable references and expressions, set variable mode, all run by the + presenter) and variables (the local variables JSON passed along, next to the file or embedded: + collections, modes, aliases, scopes, layer bindings and explicit modes). + Export panel: a row per export setting (typed or preset sizes like `2x` / `512w` / `512h`, PNG, + JPG, WebP, SVG and PDF, suffix), a preview, and "Export N layers" (`file.exportLayers`) in the + panel and the Export dialog. Paste from other apps: images, SVG and text (the newest clipboard + content wins over our own copy; pasted SVG lands centred in the view). SVG import is editable and + checked against a corpus of synthetic files (expected pixels worked out by hand, layer structure, + export and re-import): groups named from their ids with transforms baked into the layers; + rectangles (corner radius), ellipses and lines kept as those shapes; gradients with exact + handles, `reflect`/`repeat` and focal points; patterns as image fills; clip paths and masks as + vector, luminance and alpha masks; shadow and blur filter chains as drop shadows, inner shadows + and layer blurs; blend modes; text as text layers with runs, anchors and stacked lines; images + and nested SVG images; import warnings for what's left out; linked files never read; hostile + input fuzzed. SVG export keeps alpha and luminance masks. PDF export: one page per frame in points (Export frames to + PDF, the Export panel, `figcraft-cli export -o x.pdf`), vectors, gradients and strokes as + vectors, real selectable text in subset fonts with clickable hyperlinks, images embedded once, + opacity and blend modes, clip content, alpha/luminance/vector masks, shadows and layer and + background blurs as images; checked by rendering the PDFs back against PNG exports. PDF print + options in the Export panel (per PDF export setting), the Export dialog, `file.export`, + `file.exportLayers`, `file.exportFramesPdf` and `figcraft-cli export`: a bleed showing what lies + past the frame (its fills reach out, its children are clipped at the bleed), crop and bleed + marks outside it, MediaBox / BleedBox / TrimBox, and CMYK colour (a documented, deterministic + naive conversion; images and rasterised effects too). + *Left:* .fig import (best effort), a CMYK output intent (no CMYK ICC profile can ship in the + repository), SVG filters other than shadows and blurs (left out with a warning). 8–16 h. +7. **Look & feel and interaction-fidelity pass**: *landed:* keyboard shortcuts audited against the + public shortcut reference: one keymap (`figcraft_engine::keymap`) drives the menus, the canvas, + the control channel and MCP, with macOS and Windows/Linux keys where they differ (mask, bring to + front/back, distribute, tidy up, layout grids, pixel preview), Text-only and canvas-only bindings + (Cmd/Ctrl+K: link while typing, Actions on the canvas), Cmd/Ctrl+/ for Actions, `+`/`-` zoom, + Shift+0/1/2 from any layout, Cmd/Ctrl+0, hold Z for the zoom tool (Alt zooms out, drag an area), + two quick digits for an exact opacity, boolean keys (Alt+Shift+U/S/I/E), remove fill/stroke + (Alt+/, Shift+/), outlines on Shift+Cmd+O, pixel grid on Cmd+', Shift+E / Shift+D and the other panel keys, Ctrl+Tab between files, B for the paint bucket in vector edit mode; the Keyboard + shortcuts panel docks at the bottom with a tab per group and search, keycaps per platform. + *Left:* tool by tool, panel by panel against the incumbent (cursors, modifier keys while + dragging such as Ctrl to ignore snapping on macOS, hover states, menus, popovers); multiplayer + cursor keys wait for multiplayer. 40–60 h. +8. **Collaboration (local):** comments landed: pins pinned to frames and layers that move with them + (to other pages too) and stay where they were when the layer is deleted, your pins dragged onto + another frame, crowded pins clustered when zoomed out (a click zooms them apart), Shift+C to show + or hide them; threads where you edit and delete your own messages, emoji reactions, @mentions + with a picker of the names used in the file (your name from Preferences), read and unread state, + resolve, and "Copy link" (`figcraft://comment/`: pasting or `comment.open` goes to the page, + zooms to the frame and opens the thread); the Comments panel with search (text, names, frame), + filters (open, resolved, yours, unread), sorting by date or page, each thread's frame and page, + and Up/Down to step through threads; comments on the presented frame (Comments button or + Shift+C: read and reply). All of it through `comment.*` commands. Version history + landed (named versions saved in the `.figcraft` file; restore, rename, duplicate, delete; panel; + view a version on the canvas read-only before restoring it; autosave checkpoints every 30 + minutes, folded in the panel). Real-time collaboration is designed (`docs/collab-protocol.md`: + WebSocket sessions the app can host itself, server-ordered per-property changes, live cursors) + and its core landed (`crates/collab`, no networking yet): client-scoped node ids, every saved + layer field and the document-level data (styles, variables, comments, images…) as synced + properties, diffs after a command that cost the size of the edit, fractional sibling positions, + a session server that orders and validates batches (cycles, deleted layers, id spaces, sizes) + and a client that shows its own edits at once and replays them over others'; derived data + (auto layout, instances, bindings) is repaired by the author after concurrent edits; binary + messages (a moved layer is 43 bytes, a cursor 23) with a JSON form; a randomized multi-client + test over real commands converges. + Plugins landed: sandboxed WebAssembly plugins (a metered wasmi + interpreter with a memory cap and no WASI, also in the browser) whose API is the command + registry; each run is one undo step and is rolled back when it fails (error, trap, endless loop, + memory); a `figcraft-plugin.json` manifest declares menu commands with parameters and read or + write access with an optional command allowlist, and files, other documents, the undo history, + dialogs and other plugins are always off limits. Plugins ▸ Development ▸ Import plugin from + manifest… (kept in the preferences, the module re-read on every run), the installed plugins in + the Plugins menu with a parameters form drawn from the manifest, Run last plugin (⌥⌘P), Manage + plugins, and `plugin.*` commands for scripts, the CLI and MCP; a Rust SDK and two example + plugins (Tidy names, Swatch grid) in `plugins/`, built by `cargo xtask plugins`. *Left:* + plugin-defined UI at run time (forms or panels a plugin returns), plugin settings storage, + distribution; for collaboration, the WebSocket transport, hosting and joining from the app, + live cursors, per-user undo, reconnect, the browser client and a standalone server. 18–45 h. +9. **Hardening and performance**: *landed:* `cargo xtask bench` (synthetic 1k/10k/50k-layer + pages: engine, render and headless UI-frame timings). The canvas keeps its last image and + re-renders only what a pan uncovers or an edit touches: moving one layer at 10k layers re-renders + in ~0.2 ms instead of ~8 ms (0.8 vs 24 ms at 50k zoomed out), a 40 px pan in ~0.7 ms instead of + ~7.5 ms. The layers panel lays out only the rows in view (every screen expanded at 50k: 39 → + 0.6 ms a frame); text layouts are shared instead of re-formatted per lookup; overflowing text is + culled by its glyphs. At 10k: full 1440×900 renders 7–15 ms, single-layer edits ~10 µs, hit + tests ~26 µs. Zoomed out (50% and below) the canvas draws levels of detail: layers under 2 px + land as their averaged colour, text under 4 px is greeked into bars, small rectangles and clip + layers skip the path pipeline (exports and closer zooms stay exact): a whole 50k-layer page + renders in ~8 ms instead of ~50 ms. `.figcraft` at 50k layers saves in ~0.09 s instead of ~1 s + and loads in ~0.16 s instead of ~0.86 s (JSON streamed to and from the document without a + value tree, layer fields at their defaults left out: 63 → 22 MB of JSON, old files still + open). The retained canvas is held to a full render: a seeded random walk (edits, undo/redo, + pans and zooms over nested, rotated and clipping frames, groups, masks, booleans, auto layout, + effects, text, instances, variables and styles) checks every step, and found clip edges on a + pixel boundary letting a column through in some renders. Drags show live on the canvas (every + finished render is shown, not only the newest one asked for), and a button held still no + longer rebuilds the preview and re-renders every frame. + Components at scale (`cargo xtask bench`, synthetic design system of about 300 + components used by 2,000 instances): edits of mains reach their copies directly instead of + rebuilding every instance (value, size and layer added/removed edits; other edits rebuild each + affected instance once, inner mains first), bound variables no longer touch unchanged layers on + every edit, auto layout re-flows only where sizes or places changed: recolouring or resizing a + main's layer used ~900 times 188/226 → 4/18 ms, adding a layer to it 430 → 21 ms, a label style + in all 72 button variants (1,800 copies) 450 → 57 ms, switching a variant, reset, detach, push + and paste ~450 → under 3 ms, accepting a library update 460 → 64 ms; the Assets panel with 2,000 + assets 3.4 → 1.3 ms a frame. Accessibility: the custom-painted + controls name themselves for screen readers (AccessKit on desktop: role, name, value and state + for tools, layer rows with their type, level, selection and hidden/locked state, fields, + dropdowns, tabs, menu items, and the canvas, which describes the selection); keyboard navigation: + F6 / Shift+F6 move between the toolbar, layers, canvas and properties, Tab / Shift+Tab move + within a region with a focus ring, Enter or Space activate, the arrows go along the toolbar and + through the layer rows, menus and tool flyouts opened from the keyboard take it and give it back, + Escape returns to the canvas (where Tab selects the next layer again instead of wandering into + the tab strip); reduced motion follows the system's setting or a preference; secondary and + accent text meet WCAG AA in both themes. + An idle window draws no frames: it redrew ~240 times a second + (the window title was re-sent every frame, and each viewport command asks for another), ~33% of + a core in a debug build, and now sits at 0 frames and ~0% CPU; the toast, the autosave + checkpoint and the presenter's "after delay" timers wake it at their deadline, the interaction + editor's curve preview plays when it shows, changes or is hovered, and a screenshot keeps frames + coming only until it arrives (`ui.inspect` `framesDrawn` and `repaintCauses` show what asked for + frames; headless tests hold it). *Left:* a real-world file corpus, Windows/Linux/browser + QA, runs with real screen readers (NVDA, Narrator, VoiceOver, Orca), the AccessKit tree in the + browser (eframe's web backend doesn't send it yet), keyboard box selection, keyboard rename and + context menus in the layers panel. 28–46 h. + +## Inventory: what exists today + +Carried over from the ROADMAP's "Shipped so far" (2026-10-10). The test count there was stale: 963 `#[test]` functions as of this re-measure. + +- **Architecture:** 15 crates with enforced layering (`cargo xtask layers`): geom, color, doc, + layout, text, pathops, plugin, collab, render, format, svg, engine, ui-egui (+ mcp, pdf). Every action + is a command (449 command ids); undo is unlimited via structural sharing (`Arc` node snapshots); gestures are + one undo step; `command.batch` runs several commands as one step. +- **Document model:** pages, frames, groups, sections, rectangles, ellipses (arcs/rings), polygons, + stars, lines/arrows, vector networks, text with styled runs, boolean groups, components, component + sets (variants), instances with per-layer overrides, slices; fills (solid, linear/radial/angular/ + diamond gradients, images with fill/fit/crop/tile + adjustments), multiple strokes with + inside/center/outside alignment, per-side weights, dashes, caps/arrowheads, joins; effects (drop + and inner shadow with spread that offsets the outline exactly: ellipses, stars, vectors, text; + inner shadows over the fills and under the children and strokes; layer blur; background blur + that sees the whole backdrop, inside clipping frames, faded groups and masks too; both blurs + uniform or progressive (the radius ramps between two points, dragged on the canvas); noise in + mono, duo and multi colour with grain size, density and blend mode; texture with clip to shape; + glass with light angle and intensity, refraction, depth, dispersion, frost and splay; the same in + PNG, PDF and SVG exports, SVG embedding renders of noise grains, texture, progressive and + background blur and glass); corner radii with + smoothing; constraints; auto layout (horizontal, vertical, wrap, grid; hug/fill/fixed; min/max; + absolute children); layout grids; export settings; prototype interactions, flows and transitions; + paint/text/effect/grid styles; variables with collections, modes and aliases. +- **Renderer:** CPU (tiny-skia) scene renderer used for canvas, export and the web: isolated layers + for opacity/blend/effects, clip content, masks, booleans (linesweeper), text (harfrust shaping, + skrifa outlines, font fallback), aligned strokes with caching. +- **Engine:** pointer tools (move/marquee/deep select/resize/rotate/Alt-duplicate with smart-guide + snapping, frame/section/slice/shapes/line/arrow with Shift/Alt, text, pen, pencil, hand, + eyedropper), Cmd/Ctrl-click and Cmd/Ctrl-marquee into nested layers, Shift-marquee toggling, + Select layer (every layer under the click), measuring (Alt-hover distances from the selection to + layers, parents and ruler guides, Cmd+Alt for nested layers, extension lines, one box inside the + other, overlaps, live distances to the neighbours while Alt-dragging, Shift+Alt for auto layout + padding and gaps; labels that never overlap at any zoom), text editing (caret, selection, words, + lines), auto layout reorder by dragging, drop into frames, align/distribute/tidy, z-order, + flip/rotate, the scale tool (panel, and canvas handles that scale everything about its anchor + point or from the centre with Alt, with a live factor, one undo step per drag), booleans, flatten, + outline stroke, components (create, instances, sync with overrides, reset, detach, push changes, + variants, properties, slots), styles and variables, prototype commands, find/replace, batch rename, + copy/paste (internal + SVG/text), file new/open/save/import/export (native `.figcraft`, SVG + in/out, PNG/JPG/WebP), version snapshots. +- **UI (egui, swappable):** the incumbent's 2026 layout: tab strip that is also the window's title + bar (frameless on Windows/Linux with drawn window buttons, drag, double-click maximise and edge + resizing; macOS window buttons inset into it), icon rail, file header, pages and + layers tree (rename, visibility/lock, drag to reorder/reparent), Assets panel, floating bottom + toolbar with flyouts and mode switcher, Design / Prototype / Inspect panels (Dev Mode: properties with their styles and variables, annotations + with pinned properties and categories drawn as coloured callouts on the canvas (filtered by category), + a ready-for-dev list, a focus view on one frame with previous / next, Compare changes since a frame + was marked ready (before / after side by side or overlaid, property-level diffs), CSS/HTML/React/SwiftUI/Compose + code where components take their properties as parameters and instances are calls), colour picker + (HSB square, hue/alpha, hex, gradient stops, image fills), main menu generated from the catalog, + context menu, Actions palette (⌘K), keyboard shortcuts from one keymap per platform (a tabbed, + searchable Keyboard shortcuts panel), keyboard navigation (F6 between regions, Tab within them, a + focus ring) and screen-reader names for the custom controls (AccessKit), presentation player with + transitions, light and dark themes, home screen, About/Preferences/shortcuts/variables dialogs. +- **Automation:** desktop control channel (`--control `: execute commands, inspect document/UI, + synthetic pointer/keys/typing, menu invocation, screenshots, renders). +- **Tests:** 963 `#[test]` functions (2026-10-10) including junk-parameter sweeps over every command (and every vector-edit command while editing), importer fuzzing and render regressions. + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | minor | Merged main after #101–#103: WASM plugins (plugins area 0% → 35% breadth, 20% ready; ecosystem 5% → 20%) and the multiplayer core without networking (multiplayer 5% → 15% breadth, 5% ready; collaboration 8% → 12%); menu breadth 97.5% → 98.5% (200/203); ready for real work ~46% → ~47%; full parity 420–790 h → 390–745 h; beta 210–380 h → 200–365 h. Fixed the stated weight sums (areas 1–16 sum to 94, total 113; percentages were already computed with those) | +| 2026-10-10 | minor | Readiness-by-audience table: hours to ~95% for full (~400–750 h), mainstream (~180–330 h) and essentials (~85–160 h). Full number confirmed as an additive weighted sum; unchanged | +| 2026-10-10 | minor | Added the essentials user number (~53%: core features 77.8% × 0.92 launch/stability × 0.92 discoverability × 0.8 opening files people send) | +| 2026-10-10 | minor | Added the mainstream practitioner number (~43%: weekly areas 66.5% × 0.9 interaction × 0.9 stability × 0.8 file exchange) and user-evidence count (none). Checked that ready for real work (~46%) is built from the written dimension weights and scores; unchanged | +| 2026-10-10 | minor | Stage checked against the alpha gate: stays alpha | +| 2026-10-10 | major | Created from the ROADMAP's parity rubric, honest assessment and area narrative. Full re-measure against Figma desktop 126.10.7: added multiplayer, plugins, team libraries, Figma Draw extras and AI as weighted areas; split breadth from ready-for-real-work; core depth re-graded ~79% → ~67%; hours calibrated from git history; full parity 115–195 h → 420–790 h | diff --git a/docs/ui-parity.md b/docs/ui-parity.md new file mode 100644 index 0000000..a4d03cf --- /dev/null +++ b/docs/ui-parity.md @@ -0,0 +1,93 @@ +# UI and interaction parity + +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-10 · **Change:** major (created; collected from the ROADMAP, the keymap and the canvas code) · **Target:** Figma Design UI3 (desktop app 126.10.7) + +Fine canvas control is what Figma users feel first: handles, snapping, nudging, modifier keys, +drag behaviour, numeric precision. This checklist covers the tools, gestures and panels. Status: +**done** (built and checked against Figma's documented behaviour or by eye), **partial**, **missing**. +Nothing here has been compared tool by tool against the running Figma yet; that pass is the main +remaining work (40–60 h, [gaps](gaps.md) #4). + +**Summary (estimated):** UI/UX fidelity ~58%. Layout and look of UI3 compared side by side (~65%); +interaction feel not yet compared. + +## Window and panels + +| Item | Status | Notes | +|---|---|---| +| UI3 layout: tab strip as title bar, icon rail, file header, pages + layers, floating bottom toolbar with flyouts, Design / Prototype / Inspect panels | done | frameless window on Windows/Linux with drawn buttons | +| Light and dark themes | done | colours from `theme::Tokens` | +| Minimize UI (Cmd+\\) | done | | +| Resizable panels | partial | check widths and snap points against Figma | +| Actions palette (Cmd+K, Cmd+/) | done | commands; no assets search parity | +| Context menus | done | canvas and layers; keyboard access to the layers context menu missing | +| Main menu from the logo | done | generated from `catalog.rs`; popups sized to content | +| Keyboard shortcuts panel | done | docked, tabbed by group, searchable, per-platform keycaps | +| Multiplayer avatars, Share button | missing | waits for multiplayer | + +## Selection and transform + +| Item | Status | Notes | +|---|---|---| +| Click, Shift-click, marquee, Shift-marquee toggle | done | | +| Deep select (Cmd/Ctrl-click, Cmd/Ctrl-marquee) | done | | +| Select layer menu (every layer under the click) | done | | +| Enter / Shift+Enter (children / parent), Tab / Shift+Tab (siblings) | done | Tab renames the next layer while renaming | +| Resize handles: Shift keeps proportions, Alt from centre, constraints-aware | done | | +| Rotate just outside a corner; Shift in 15° steps | done | rotated handle box when layers share a rotation | +| Flip, rotate 90° | done | | +| Alt-drag duplicate | done | | +| Scale tool (K): handles about an anchor, live factor, panel | done | | +| Nudge 1 / Shift 10 (preference), Cmd+arrows resize | done | arrows reorder auto layout children | +| Smart guides: edges, centres, spacing labels, parent, layout grid, ruler guides | done | red, `snap.rs`; thresholds not yet compared with Figma's | +| Ctrl to suspend snapping while dragging (macOS) | missing | | +| Measure (Alt hover, Cmd+Alt nested, Shift+Alt padding/gaps) | done | labels never overlap | +| Pixel grid snapping, pixel preview, 2x preview | done | | +| Numeric fields: arithmetic, scrubbing by dragging the label, mixed values | partial | check scrub speed and Shift/Alt steps | +| Keyboard box selection | missing | | + +## Tools + +| Tool | Status | Notes | +|---|---|---| +| Move, hand (Space), zoom (hold Z, Alt out, drag area) | done | | +| Frame (presets panel, swap orientation), section, slice | done | | +| Rectangle, ellipse (arc handles), polygon, star, line, arrow; Shift/Alt | done | Design panel arc fields missing | +| Pen: vector networks, branch, close, bend; pencil | done | no pen pressure | +| Vector edit mode: bend, paint bucket, lasso, cut, eraser, transform box, point snapping, mirroring | done | live boolean editing missing | +| Shape builder (Shift+M), variable width (Shift+W) | done | | +| Text: point, auto height, fixed; caret, words, lines, IME | done | no spell check | +| Eyedropper (I) | done | | +| Comment (C), Shift+C to show/hide | done | local only | +| Brushes, text on a path (Figma Draw) | missing | | +| Image crop handles | done | | + +## Canvas + +| Item | Status | Notes | +|---|---|---| +| Pan/zoom: wheel, pinch, Space-drag, Shift+0/1/2, Cmd+0, `+`/`-` | done | | +| Rulers and guides (drag out, move, remove; rotated frames; frame guides) | done | | +| Frame labels (rotated, right-to-left), size badge | done | | +| Outline mode | partial | "Outlines" done; outline selection and mask outlines missing | +| Layout grids (Ctrl+G) | done | | +| Gradient and padding/gap handles on the canvas | done | | +| Hover outline, selection colours, handle sizes | done | measured from UI3 screenshots | +| Cursors per tool and modifier | partial | not compared | +| Multiplayer cursors, cursor chat, spotlight | missing | | + +## Accessibility (ours vs Figma's) + +| Item | Status | Notes | +|---|---|---| +| Screen-reader names, roles, values, states (AccessKit) | done on desktop | browser: eframe doesn't send the tree yet | +| Keyboard navigation: F6 regions, Tab within, focus ring | done | | +| Reduced motion | done | system setting or preference | +| WCAG AA contrast of secondary and accent text | done | | +| Tested with VoiceOver, NVDA, Narrator, Orca | missing | human QA | + +## Revision history + +| Date | Change | Summary | +|---|---|---| +| 2026-10-10 | major | Created from the ROADMAP's look-and-feel and interaction items, the keymap and the canvas code | diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 9ddaa21..ba23a17 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -3,7 +3,7 @@ //! - `ci` fmt check, clippy -D warnings, tests, layers, assets, wasm check //! - `layers` crate dependency layering check //! - `assets` every file under assets/ and docs/ has a row in ATTRIBUTION.md -//! - `parity` menu-catalog coverage → docs/parity.md +//! - `parity` menu-catalog coverage → docs/parity-checklist.md //! - `version` print the version, or `version set X.Y.Z` //! - `icon` regenerate the app icon PNGs/ICO from code (original artwork) //! - `wasm` check the core crates and web app for wasm32, and build the plugin SDK and examples @@ -198,8 +198,17 @@ fn parity() -> bool { ]; let (done, total, missing) = figcraft_engine::catalog::parity(&extra); let pct = done as f64 * 100.0 / total.max(1) as f64; + // The generation date: the date of the last commit (no clock dependency in xtask). + let date = Command::new("git") + .args(["log", "-1", "--format=%cs"]) + .current_dir(root()) + .output() + .ok() + .and_then(|o| String::from_utf8(o.stdout).ok()) + .map(|d| d.trim().to_string()) + .unwrap_or_default(); let mut md = format!( - "# Parity report\n\nGenerated by `cargo xtask parity`: FigCraft commands registered for the incumbent's main menu and toolbar ({} commands in the engine).\n\n**{done} / {total} menu items ({pct:.1}%)**\n\n", + "# Parity checklist\n\n> **Generated:** {date} by `cargo xtask parity`. Do not edit by hand.\n\nFigCraft commands registered for the incumbent's main menu and toolbar ({} commands in the engine).\n\n**{done} / {total} menu items ({pct:.1}%)**\n\n", figcraft_engine::all_commands().len() ); if missing.is_empty() { @@ -210,13 +219,13 @@ fn parity() -> bool { md.push_str(&format!("- `{m}`\n")); } } - md.push_str("\nMenu coverage measures breadth only; see ROADMAP.md for depth and fidelity.\n"); - let path = root().join("docs/parity.md"); + md.push_str("\nMenu coverage measures breadth only; see docs/target-app-parity.md for depth and fidelity.\n"); + let path = root().join("docs/parity-checklist.md"); if let Err(e) = std::fs::write(&path, md) { eprintln!("{}: {e}", path.display()); return false; } - eprintln!("parity: {done}/{total} ({pct:.1}%) → docs/parity.md"); + eprintln!("parity: {done}/{total} ({pct:.1}%) → docs/parity-checklist.md"); true }