Files

96 KiB
Raw Permalink Blame History

FigCraft Roadmap

Stage: alpha · next: beta, ~26 points and ~162–292 h away (one Opus 5.5 agent; ~33–67 h wall-clock with 5 agents)

Last reviewed: 2026-10-10 · Last updated: 2026-10-13 · Change: minor (core editor leftovers: component playground, auto gap handles, variables inside styles, inner shadows and background blur on groups, command-made text readable on dark pages, a one-step frame/group convert, delays on mouse triggers and manual overlay offsets, wrapped-line alignment; .fig export: instance sizes, variables with modes, shared styles, variable-width strokes; starter templates, a Templates tab and Getting started tips on the home screen; your online files; everyday editing partials: number fields, outline options, Hide when publishing, cursors, panel widths, dark pages; sharing with a join code; text box sizes measured against documents re-saved by other software; live sessions per document; .fig export checked by opening written files in other software; a public figcraft-server: open hosting, owner tokens, per-address limits, idle expiry, moderation, install.sh; experimental .fig export; keyboard shortcut parity suite and bindings; Simplified Chinese draft catalog; Latin American Spanish overlay; prototyping tail: gamepad triggers, widgets in prototypes, mode lookups; plugin directory on figcraft-server; Japanese and Korean draft catalogs and CJK UI fonts; plugin widgets and the plugin panel tail; French, German and Brazilian Portuguese draft catalogs; cursor chat and spotlight in live sessions; layers and assets panels behaviour suite and fixes; vector multi-edit and edit tail; dev resources links; extended collections tail; branch version history and finer list merges; headline percentages recomputed from the area table: feature breadth ~84%, core ~94%, mainstream ~50%; text lists, hanging punctuation and decoration styles; comments and version history behaviour suite and fixes; canvas navigation, guides and grids behaviour suite and fixes; export and inspect behaviour suite and fixes; .fig import: editable vector networks and more layer kinds; shapes and vector behaviour suite and fixes; paint and effects behaviour suite and fixes; frames, groups, sections and masks behaviour suite and fixes; styles and variables behaviour suite and fixes; prototyping behaviour suite and fixes; components behaviour suite and fixes; embedded image colour profiles; layers panel keyboard: F2 rename, Shift+F10 context menu, keyboard box selection, 10k-layer QA; per-side stroke weight variables; text behaviour suite: CJK line breaking, metrics, vertical trim; selection and transform behaviour suite and fixes; .fig import, best effort; Windows QA pass with eight fixes; auto layout behaviour suite and fixes; Display P3: gamut warning and soft-proof (true P3 blocked upstream); several windows; localization layer with a draft Spanish catalog; hosting figcraft-server: wss in the desktop app, server releases, deployment guide; plugin panels and settings; canvas fixes: boolean hit testing on the result, group drags, frame outlines and slices; code connect; stretch and scatter brushes, pen pressure; text on a path and pattern fills; team libraries on the server and swap library; branches: create, update from main, review and merge; animated GIF fills and TIFF images; Open recent, outlines for the selection and mask outlines: menu breadth 100%; extended collections, variables import/export, gradient stop and variant bindings; feature breadth ~80%; ready ~49%) · Target: Figma Design (desktop app 126.10.7)

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.

Headline numbers

Value Kind
Menu/command breadth 100% (211 / 211) measured, docs/parity-checklist.md (cargo xtask parity)
Feature breadth ~85% (core editor ~94%) estimated, docs/target-app-parity.md
Ready for real work ~53% estimated, same doc (written dimension weights and scores)
Essentials user ~59% estimated: core features 77.8% × 0.92 launch/stability × 0.94 discoverability × 0.88 opening files people send (method)
Mainstream practitioner ~50% estimated: weekly areas 72.7% × 0.9 interaction × 0.9 stability × 0.85 file exchange with Figma users (method)
Remaining to beta ~155–280 h one agent estimated
Remaining to full parity ~262–519 h one agent (~83–145 h wall-clock with 5 agents) estimated

Readiness by audience

Audience Ready % Opus 5.5 agent wall-clock hours to ~95% Work that dominates
Full target (ready for real work) ~53% ~268–522 h multiplayer (42–84), localization (29–51), plugins (8–26), the interaction pass (40–60), GPU canvas (30–60), AI (30–60), the .fig import's tail (5–10)
Mainstream practitioner ~50% ~120–229 h core editor depth incl. the .fig import's tail (49–98), the interaction pass (40–60), real-file corpus and platform QA (25–50), checking the rest of the experimental .fig export elsewhere: effects, images, prototypes, real files (5–15)
Essentials user ~59% ~55–100 h the .fig import's tail so the files people send open well (5–10), core tool polish (25–45), interaction pass on the core tools (15–25), stability QA (10–20)

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). 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.

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.

Stage

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 opens .fig files only best effort, has only a preview of multiplayer, and nothing has been checked against real Figma documents. Ready-for-real-work is ~53%, 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 unproven on real files, both beta gaps (alpha gate). Beta needs ~75% and reliable .fig import: the .fig import's tail (5–10 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); native speakers' reviews of the six language drafts need people.

By dimension

Dimension Ready Hours Doc
Features (depth) 63% (core editor 72%) 28–67 target-app-parity
UI/UX fidelity 58% 40–60 ui-parity
File formats 60% (.fig read best effort with editable vectors; experimental write, round trips through our own importer and written files opened in other software) 5–10 file-format-parity
Collaboration 13% (core in; live sessions with document sync, cursors and text carets, cursor chat and spotlight, the browser joins, invite links open the app; a self-hosted server with edit and view links and team libraries; preview) 46–92 collaboration-parity
Stability 55% 20–40 gaps
Performance 60% 30–60 hardware-parity
Hardware 60% 10–21 hardware-parity
Localization 39% (layer; English; Spanish with a Latin American overlay, French, German, Brazilian Portuguese, Japanese, Korean, Simplified Chinese drafts; CJK UI fonts) 29–51 localization-parity
Platforms 75% 10–20 hardware-parity
Ecosystem / plugins 38% (own WASM plugins with panels, settings and widgets; a self-hosted plugin directory) 8–26 gaps
AI features 0% 30–60 gaps

Features

Area Breadth Ready Hours Doc
Canvas & navigation 98% 74% 1–4 ui-parity
Selection & transform 97% 72% 3–5 ui-parity
Layers panel 99% 85% 1–2 ui-parity
Shapes & vector 99% 73% 1–3 target-app-parity
Paint 90% 71% 2–5 target-app-parity
Strokes 95% 75% 1–2 target-app-parity
Effects 100% 75% 2–5 target-app-parity
Frames, groups, sections, masks 97% 80% 1–3 target-app-parity
Auto layout & constraints 98% 74% 3–6 auto-layout-parity
Text 90% 70% 3–7 target-app-parity
Components & variants 96% 72% 4–9 components-parity
Styles & variables 95% 76% 2–4 components-parity
Prototyping 92% 74% 2–5 prototyping-parity
Import/export 86% 58% 5–10 file-format-parity
Dev Mode / inspect 96% 72% 0–1 dev-mode-parity
Comments, versions, misc 87% 63% 1–3 collaboration-parity
Multiplayer & sharing 17% 5% 42–84 collaboration-parity
Plugins & widgets 60% 35% 8–26 plugins
Team libraries 70% 40% 4–8 components-parity
Figma Draw extras 88% 60% 1–3 gaps
AI features 0% 0% 30–60 gaps

Languages

Language Code Strings Status
English en 100% full
Simplified Chinese zh-Hans 100% draft (needs native review)
Spanish es, es-419 100% (es-419: an overlay of 98 entries) draft (needs native review)
Hindi hi 0% none
Arabic ar 0% none
French fr 100% draft (needs native review)
Portuguese (Brazil) pt-BR 100% draft (needs native review)
Indonesian id 0% none
Japanese ja 100% draft (needs native review)
German de 100% draft (needs native review)
Korean ko 100% draft (needs native review)
Vietnamese vi 0% none

No other languages. Figma ships English, Japanese, Korean, French, German, Spanish and Portuguese (Brazil); FigCraft has the localization layer, English and Spanish (Spain and Latin America), French, German, Brazilian Portuguese, Japanese, Korean and Simplified Chinese drafts (Preferences ▸ Language; Traditional Chinese has no catalog; CJK UI text uses an installed CJK font, loaded only when needed; adding a language: docs/translating.md). Document text in any script (bidi, Arabic shaping, IME) already works. Detail: docs/localization-parity.md.

Upcoming

Ranked; detail and milestones in docs/roadmap.md.

  1. .fig import's tail: fixes from real files, connector labels, table cells, filled areas with their own fills (the best-effort import, editable vector networks, the other layer kinds and variable prototype actions landed 2026-10-11): 5–10 h; then checking the rest of the experimental .fig export (landed 2026-10-12; written files open and draw in other software) on effects, images, prototypes and real files: 5–15 h.
  2. Real-file corpus and measured fidelity: 15–30 h.
  3. Tool-by-tool interaction pass against Figma: 40–60 h.
  4. Languages: native reviews of the es, fr, de, pt-BR, ja and ko drafts (people), Latin American Spanish (1–2 h), then Simplified Chinese (3–5 h).
  5. Multiplayer (M9): accounts and teams on top of the live sessions and the standalone server (transport, hosting, invite links that open the app, document sync, presence with remote text carets, cursor chat and spotlight, per-user undo, reconnect with offline edits, collision-free ids for styles, variables and comments, the browser client, figcraft-server with persistence and share links to edit or view, team libraries on the server landed): 42–84 h.

Progress log

  • 2026-10-13 · Component playground (M3): with an instance, a component or a component set selected, the Inspect tab shows a Playground: a preview of the component and a control for each variant, boolean and text property. What is tried there changes the preview and the code in the Code section, never the file (no undo step, the canvas instance stays as it is); Reset goes back to the component's or the instance's own values. component.playground {id?, properties?, language?, path?} gives the same to scripts: the properties with their values, the code, and a PNG on request (playground_tests). Left: instance-swap and slot properties in the playground (the command takes an instance swap; the panel has no control for it), a code connect template's snippet with the tried values. Numbers unchanged.
  • 2026-10-13 · Auto layout, on-canvas handles of automatic gaps (M2): the handle between spread rows or columns (and between items with an auto gap) shows the distance the layout gives the gap instead of the stored value, and dragging it makes the gap a fixed one from there, as typing a gap in the panel does; one undo step (gap_handle_tests). Before, the drag changed a value that had no effect. The documentation is silent on dragging an automatic gap. Numbers unchanged.
  • 2026-10-13 · Variables inside styles (M3): a shared style can bind variables to fields of its value (style.bind {style, field, variable?}: a paint style's colours and gradient stops, an effect style's colour, radius, spread and offsets, a grid style's size, count, gutter and offset, a text style's font size, line height, letter spacing, family and style). Every layer using the style shows those fields resolved in its own modes and stays linked when a variable or a mode changes; the style keeps them resolved in the default modes. A style made from a layer keeps that layer's bindings; a new value drops bindings to what is gone. The style editor binds from its property rows (paint colour, shadow colour, blur radius, grid size) and detaches from the variable's chip; the style picker marks styles that use variables. .fig export and import carry the bindings on the style, REST layers hand theirs to the style they use. Left: binding text style fields and the other effect and grid fields from the editor (commands only), library variables in the picker, a style's library copy. Numbers unchanged.
  • 2026-10-13 · Effects on groups, inner shadows and background blur (M3): a group is no outline of its own, so its inner shadows are cast inwards from around what its layers draw together (their pixels, over them: no shade at a seam between two layers) and its background blur and glass show the backdrop through the outlines of its layers (under them). Canvas and PNG; SVG embeds a group with an inner shadow as a render and its background blur as an image under the layers; PDF places both as images, the blur matching the PNG. Where the group holds one shape the pixels match that shape, or a frame filled like it, carrying the effect (group_effects_tests in render, svg and pdf). Offsets and spreads of a group's inner shadow go by whole pixels. Numbers unchanged.
  • 2026-10-13 · Text made by commands on a dark page (M1): in the app, text.create and node.create {type: text} that name no fill give white text on a dark page, by the same rule as the Text tool (the page's colour decides, also inside a frame); a named fill, fills or fillStyle is kept. Sessions without an interface (CLI, MCP, exports) still make black text everywhere. Numbers unchanged.
  • 2026-10-13 · Frames and groups, a one-step convert (M1): object.convertToGroup and object.convertToFrame (the Design panel's type menu on a frame or a group) change the layer in place, its layers staying where they are on the page. A frame turned into a group loses what only a frame has (auto layout, with the positions it gave kept and fill children fixed; fills, strokes, corner radius, clipping, layout grids, guides, scrolling) and takes its layers' box; a group turned into a frame keeps its box, with no fill and no clipping. Instances, main components, layers inside instances and empty frames are refused with the reason, all or nothing; one undo step. Numbers unchanged.
  • 2026-10-13 · Prototyping, delays on mouse triggers and manual overlay offsets (M5): mouse enter, leave, down and up wait delayMs before their actions run (once while waiting; dropped when the screen or overlay they were on goes away; a pointer that leaves early doesn't cancel, the documentation is silent), and a manual overlay sits at offset: [x, y] from the top-left of the layer that opens it (without one, right below it, as before). Delay and X/Y fields in the interaction editor, the player on its own clock, REST import (delay, overlayRelativePosition), .fig import and export (the export's field for mouse delays is unchecked against other software). Numbers unchanged.
  • 2026-10-13 · Auto layout, wrapped-line alignment (M2): a wrapping layout's lines (rows of a horizontal one, columns of a vertical one) are packed where the cross alignment says (start, centre, end; before, they always sat at the start), stretch when every child fills across the flow, or take the free space between them (contentAlign: spaceBetween, the Design panel's Row/Column gap mode, the alignment pad lighting the whole cross axis). Read from REST JSON and .fig, written to .fig, align-content in CSS, an instance override with the other alignment settings. 13 hand-computed layout cases and command tests. Numbers unchanged.
  • 2026-10-13 · .fig export: instance sizes, variables, styles (gap 1): instances write what they change from their main (size, name, paints) as an override addressed by the main's id, what follows for their layers as derived data and a scale factor when scaled as a whole; variable collections, modes, variables and bindings, the modes frames and pages set, shared styles with their links and variable-width strokes are written, and the import reads all of it back. Checked by opening written files in other software: resized and scaled instances keep their size and lay their layers out for it, variables with their modes and colour bindings resolve there (a frame set to another mode shows that mode's colours, also inside instances), colour, text, effect and grid styles are listed, and variable-width strokes that are the same on both sides of the path draw with their width; number, string and boolean bindings and bindings on effects, layout guides and gradient stops come across as the values they give but did not show as bound there (their entries now also name the layer field they set, not yet checked there), and strokes wider on one side of the path are written as filled outlines, no longer editable strokes there (the stroke itself is kept as plugin data and our own import puts it back; not yet checked there). Numbers unchanged. text, effect and grid styles, number, string and boolean bindings, bindings on effects, layout guides and gradient stops, and variable-width strokes are not yet checked there. Numbers unchanged.
  • 2026-10-13 · Starter templates and first-run help: eight templates built in code (mobile app, landing page, dashboard, design system starter, wireframe kit, social post sizes, presentation slides, icon set starter), a Templates tab on the home screen, template.list and file.newFromTemplate for scripts and agents, and a Getting started card that can be closed and comes back from the Help menu
  • 2026-10-12 · Your online files: a file shared or published online stays yours after its tab closes or the app quits. The app remembers it (with its owner token, kept with the preferences and never shown) and Home ▸ Online lists what you own: open a file again as its owner, start or stop sharing, copy its code, rename it, remove it from the server or forget it here. Servers are asked once, when the list opens; tabs mark files in a live session; a crash reopens such a file from its server and puts back the changes that hadn't reached it. collab.files, collab.openFile, collab.forgetFile; servers need an upgrade only to tell which files are still there. The six draft catalogs translate every string again
  • 2026-10-12 · Everyday editing partials: number fields (scrub rates with Shift and Alt, arrow keys by the nudge preferences, arithmetic with brackets, relative edits of Mixed values per layer), outline mode's hidden layers and object bounds, Hide when publishing in the Assets panel, a cursor for every tool and modifier, panel widths that are kept, and dark pages (white text on them) for files made in the dark theme
  • 2026-10-12 · Sharing with a join code: Share ▸ Online (through the server in Preferences, built in) or Local network, one Start sharing button and a short code to read out (K7M-2QX-9TD; a longer one locally that carries the host's address); others type it under Join with a code (the popover, the home screen), where a link works too. The server names links with codes, keeps them hashed and limits wrong ones; collab.share, collab.join {code}; servers must be upgraded to hand codes out (older ones keep working with links)
  • 2026-10-12 · Text metrics measured: our example documents, re-saved by other software, were read back and compared layer by layer. Line heights are now whole pixels, advances sit on a 1024-per-em grid and letter spacing goes between glyphs only; all 230 self-sizing text boxes in the 7 documents match to the pixel (24 of 131 before in the design-system example). One font family; real files still unchecked (gap 3). No number moves
  • 2026-10-12 · Live sessions are per document: every open file has its own session or none, several run at once (host one, join another, publish a third) and keep syncing behind the tab in front, the Share popover, people, cursors, chat, spotlight and follow are the file in front's, collab.peers lists them all (sessions), and closing a file ends its session only (before, one session followed every tab and starting another replaced it)
  • 2026-10-12 · A public figcraft-server: open_publish = true lets anyone publish without the server key (Share ▸ Publish to server asks the server first and shows who hosts it, its terms and how long unopened files are kept), with an owner token shown once that manages the file later (collab.manageFile); limits per address, idle expiry, reports (Share ▸ Report this file…), block-ip and files list --sort, GET /healthz, and packaging/server/install.sh that sets up a Debian/Ubuntu machine with Caddy, ufw and backups (server.md). Numbers unchanged (hosting, not a Figma feature).
  • 2026-10-12 · .fig export opens elsewhere (gap 1): written files were checked by opening them in other software: layers, fills, gradients, strokes, shadows, vectors, components and text draw as in FigCraft. The export now says that the document and its pages are visible and opaque, numbers its schema as the format does, and writes outlines, text settings, standard font style names and line height units; effects such as glass and noise, images and prototype interactions are still unchecked there, and variables are not written. Numbers unchanged.
  • 2026-10-12 · Experimental .fig export (gap 1): file.export {format: "fig"}, File ▸ Export… ▸ .fig (experimental), figcraft-cli export --format fig and MCP's export write the whole document: layers, geometry, paints with their images, strokes, effects, styled text, vector networks, auto layout, components and instances with their overrides, and prototype interactions; what's left out (style links, variables, comments, Dev Mode data…) comes back as warnings. Checked only by reading the files back with our own importer. File formats 60%.
  • 2026-10-12 · Keyboard shortcut parity (gap 4): a table test with a row for each of the 129 shortcuts in the public documentation, macOS and Windows/Linux keys each, and the 48 bindings it is silent on pinned; 126 bound (110 before), Run last plugin moved off a documented conflict on Windows, 2 missing. New: others' cursors toggle, list levels on Cmd/Ctrl+] and [ while editing, keyboard box selection on Alt+Space / Ctrl+Space, arrows that pan with nothing selected, Control suspending snapping on macOS, Space/N/C/F while presenting, the Frame tool on A, pixel grid on Shift+', link on Shift+Cmd+U, ungroup on Cmd/Ctrl+Backspace, suggest auto layout and go to main component keys; shifted symbols on other keyboard layouts.
  • 2026-10-12 · Plugin directory on figcraft-server (gap 6): publish a plugin folder with the server key (figcraft-cli plugin publish), browse a server's plugins in Plugins ▸ Manage plugins ▸ Browse, install after a confirmation that shows the permissions it asks for, update when a newer version appears, remove; bundles are checked in full on the server and again in the app, downloads must match their SHA-256, installed plugins live per user in the same sandbox; plugin.directory.* for scripts and MCP; the operator moderates with figcraft-server plugins. Plugins & widgets 60%.
  • 2026-10-12 · Plugin widgets and the panel tail (gap 6, plugin API 3; older plugins run unchanged): a widget plugin puts a layer of its own on the canvas (Plugins ▸ Widgets, widget.insert), described by the plugin, validated and built with locked layers inside; clicking a part it named calls it back with the widget's state (kept in the layer, so it saves, copies, undoes, exports and syncs) as one undo step, and it redraws; widget.click and widget.list for agents; a Counter example. Panels of several plugins open side by side and plugin colour fields open the colour picker. Plugins & widgets 55%.
  • 2026-10-12 · Layers and Assets panels behaviour suite (gap 4): several layers dropped together land together, Collapse layers keeps the selection's rows open, dragging across eyes or padlocks sets several layers at once, a Rename layers dialog for several layers (number codes as documented, regular expressions, a start value), pages dragged to reorder, dividers, "Copy of" duplicates, Assets folders by page, frame and slash names, and hidden-from-publishing names that decide both ways.
  • 2026-10-12 · Vector multi-edit and the vector edit tail (gap 9): several vector layers in edit mode at once (select, marquee, drag, nudge, delete, mirroring and radius across them), several Bezier handles dragged together, rounded points beside curved segments, a stroke cap and join per point, and the Pen connecting to its own points or continuing a selected open path.
  • 2026-10-11 · Canvas navigation, guides and grids behaviour suite (gap 4): zoom, panning, the pixel grid (now from 400%), rulers, guides (top-level frames only; select, Delete, nudge, Remove guide, Alt-drag copies, Alt measures while dragging), layout grids (Auto counts; hidden on rotated frames), outline mode (clicks reach layers behind) and measuring, each rule from the documentation.
  • 2026-10-11 · Export and inspect behaviour suite (gap 4): exports cover what a layer paints (shadows only where they fall, true stroke widths, no room for hidden layers, a mask group's mask), slices export what's under them, layer names with slashes export into folders; export settings gained contents only, include bounding box and the SVG options (outline text, ids, simplified strokes); Inspect shows colours in hex, RGB, CSS, HSL or HSB, CSS in rem, blend modes and positions from the frame, and lists icons and images as assets. Dev Mode 70%.
  • 2026-10-11 · .fig import's tail (gap 1): vectors open as editable vector networks with their corner radii, handle mirroring and end caps (outlines when the network is missing or damaged); sticky notes, shapes with text, connectors, tables and similar layers import as frames, text and vectors instead of being dropped; set-variable and conditional prototype actions come across. File formats 58%, ready ~49%.
  • 2026-10-11 · Paint and effects behaviour suite: every documented rule for fills, blend modes, gradients, images, colour models, shadows, blurs and effect exports is a table-driven case. Fixes: Normal groups isolate and clipping frames don't, plus darker is drawn, drop shadows hide behind translucent layers in every export, Fill images reach the box's edges, "Normal" no longer means pass-through. Paint 70%, effects 75%.
  • 2026-10-11 · .fig import, best effort (gap 1): file.open, file.import, drag and drop, the CLI and MCP open .fig files. A generic kiwi decoder reads each file's own schema, and the decoded nodes map by field name onto the REST importer: layers, paints and styles, text runs, vectors as outlines, auto layout, components and instances (expanded with their overrides and property values), variables, prototyping and images from the archive; the rest is a warning. File formats 55%, ready ~49%.
  • 2026-10-11 · Gamut warnings (gap 18): the colour picker of a Display P3 file flags colours outside sRGB and View ▸ Soft-proof sRGB stripes them on the canvas. Showing P3 itself waits on eframe/egui-wgpu exposing the surface colour space wgpu 30 already supports.
  • 2026-10-11 · Several windows (gap 18): File ▸ New window, Open in new window on a tab or a tab dragged off the strip; each window has its own tabs, panels and canvas, draws only when it needs to and asks about unsaved changes when it closes (the main window too); the control channel and MCP open, list, focus and capture windows. Hardware 60%.
  • 2026-10-11 · Hosting figcraft-server: the desktop app and figcraft-cli open wss:// links (rustls, certificates always verified; FIGCRAFT_CA_FILE for a private authority), releases ship the server for Linux x86_64 and aarch64, it stops gracefully on SIGTERM or Ctrl+C, and docs/server.md walks through deploying it on a rented Linux server (systemd unit, Caddy or nginx, firewall, Docker, upgrades, backups).
  • 2026-10-11 · Plugin panels and settings (gap 6, ABI v2; v1 plugins run unchanged): a plugin shows a panel of fields and buttons drawn with FigCraft's widgets and is called back for each button or changed value (one undo step per callback, same sandbox limits), plugin.ui / plugin.event / plugin.close drive panels from scripts and MCP, and per-plugin settings are kept with the preferences; Swatch grid gained a palette panel. Plugins & widgets 45%.
  • 2026-10-11 · Canvas fixes: clicks hit boolean groups where their result is (a click in a subtracted hole reaches what's behind), a layer dragged inside a group stays in it, View ▸ Frame outlines and View ▸ Slices draw, and a flaky idle test now waits for the render thread (gap 13).
  • 2026-10-11 · Team libraries on figcraft-server (gap 10): Assets ▸ Libraries ▸ Publish to server keeps the file's library on the server under the file (per-asset versions; the server's version is followed); other files enable it by pasting a share link (a view link is enough), get "Library updates available" from a background check and accept with overrides kept; the server counts which files use which components (Show usage, library.usage); library.swap re-points instances, styles and variables to another library by names. Team libraries 70%.
  • 2026-10-11 · Animated GIF fills (first frame on the canvas and in exports, played in the presenter and the preview, waking the window only for the next frame) and TIFF images (gap 12).
  • 2026-10-11 · The last three menu items got commands: File ▸ Open recent (kept in the preferences, missing files greyed, Clear recent), outlines for the selection and mask outlines (gap 21). Menu breadth 203/203.
  • 2026-10-11 · Extended variable collections (a library collection's modes and variables in a collection of the file, overridden per mode with reset, following library updates), variables import/export (the REST local variables JSON, merged by name; CSS custom properties), gradient stops and variant properties bound to variables (gap 14).
  • 2026-10-11 · Live boolean editing: operands stay editable layers (double-click or Cmd/Ctrl-click selects one, moving, resizing or editing its points redraws the result during the drag with every operand outlined, per-operand operations from the boolean controls, prefix-cached recompute); Design panel arc fields; the shape builder on strokes and open paths; one-sided variable widths (gap 13). Feature breadth ~79%.
  • 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-13 minor Component playground (M3): with an instance, a component or a component set selected, the Inspect tab shows a Playground: a preview of the component and a control for each variant, boolean and text property. What is tried there changes the preview and the code in the Code section, never the file (no undo step, the canvas instance stays as it is); Reset goes back to the component's or the instance's own values. component.playground {id?, properties?, language?, path?} gives the same to scripts: the properties with their values, the code, and a PNG on request (playground_tests). Left: instance-swap and slot properties in the playground (the command takes an instance swap; the panel has no control for it), a code connect template's snippet with the tried values. Numbers unchanged.
2026-10-13 minor Auto layout, on-canvas handles of automatic gaps (M2): the handle between spread rows or columns (and between items with an auto gap) shows the distance the layout gives the gap instead of the stored value, and dragging it makes the gap a fixed one from there, as typing a gap in the panel does; one undo step (gap_handle_tests). Before, the drag changed a value that had no effect. The documentation is silent on dragging an automatic gap. Numbers unchanged.
2026-10-13 minor Variables inside styles (M3): a shared style can bind variables to fields of its value (style.bind {style, field, variable?}: a paint style's colours and gradient stops, an effect style's colour, radius, spread and offsets, a grid style's size, count, gutter and offset, a text style's font size, line height, letter spacing, family and style). Every layer using the style shows those fields resolved in its own modes and stays linked when a variable or a mode changes; the style keeps them resolved in the default modes. A style made from a layer keeps that layer's bindings; a new value drops bindings to what is gone. The style editor binds from its property rows (paint colour, shadow colour, blur radius, grid size) and detaches from the variable's chip; the style picker marks styles that use variables. .fig export and import carry the bindings on the style, REST layers hand theirs to the style they use. Left: binding text style fields and the other effect and grid fields from the editor (commands only), library variables in the picker, a style's library copy. Numbers unchanged.
2026-10-13 minor Effects on groups, inner shadows and background blur (M3): a group is no outline of its own, so its inner shadows are cast inwards from around what its layers draw together (their pixels, over them: no shade at a seam between two layers) and its background blur and glass show the backdrop through the outlines of its layers (under them). Canvas and PNG; SVG embeds a group with an inner shadow as a render and its background blur as an image under the layers; PDF places both as images, the blur matching the PNG. Where the group holds one shape the pixels match that shape, or a frame filled like it, carrying the effect (group_effects_tests in render, svg and pdf). Offsets and spreads of a group's inner shadow go by whole pixels. Numbers unchanged.
2026-10-13 minor Text made by commands on a dark page (M1): in the app, text.create and node.create {type: text} that name no fill give white text on a dark page, by the same rule as the Text tool (the page's colour decides, also inside a frame); a named fill, fills or fillStyle is kept. Sessions without an interface (CLI, MCP, exports) still make black text everywhere. Numbers unchanged.
2026-10-13 minor Frames and groups, a one-step convert (M1): object.convertToGroup and object.convertToFrame (the Design panel's type menu on a frame or a group) change the layer in place, its layers staying where they are on the page. A frame turned into a group loses what only a frame has (auto layout, with the positions it gave kept and fill children fixed; fills, strokes, corner radius, clipping, layout grids, guides, scrolling) and takes its layers' box; a group turned into a frame keeps its box, with no fill and no clipping. Instances, main components, layers inside instances and empty frames are refused with the reason, all or nothing; one undo step. Numbers unchanged.
2026-10-13 minor Prototyping, delays on mouse triggers and manual overlay offsets (M5): mouse enter, leave, down and up wait delayMs before their actions run (once while waiting; dropped when the screen or overlay they were on goes away; a pointer that leaves early doesn't cancel, the documentation is silent), and a manual overlay sits at offset: [x, y] from the top-left of the layer that opens it (without one, right below it, as before). Delay and X/Y fields in the interaction editor, the player on its own clock, REST import (delay, overlayRelativePosition), .fig import and export (the export's field for mouse delays is unchecked against other software). Numbers unchanged.
2026-10-13 minor Auto layout, wrapped-line alignment (M2): a wrapping layout's lines (rows of a horizontal one, columns of a vertical one) are packed where the cross alignment says (start, centre, end; before, they always sat at the start), stretch when every child fills across the flow, or take the free space between them (contentAlign: spaceBetween, the Design panel's Row/Column gap mode, the alignment pad lighting the whole cross axis). Read from REST JSON and .fig, written to .fig, align-content in CSS, an instance override with the other alignment settings. 13 hand-computed layout cases and command tests. Numbers unchanged.
2026-10-13 minor .fig export (gap 1): instance sizes (resized, filling an auto layout, scaled), variables with modes and bindings, shared styles and variable-width strokes are written and read back. Checked by opening written files in other software: resized and scaled instances keep their size and lay their layers out for it, variables with their modes and colour bindings resolve there (a frame set to another mode shows that mode's colours, also inside instances), colour, text, effect and grid styles are listed, and variable-width strokes that are the same on both sides of the path draw with their width; number, string and boolean bindings and bindings on effects, layout guides and gradient stops come across as the values they give but did not show as bound there (their entries now also name the layer field they set, not yet checked there), and strokes wider on one side of the path are written as filled outlines, no longer editable strokes there (the stroke itself is kept as plugin data and our own import puts it back; not yet checked there). Numbers unchanged
2026-10-13 minor Starter templates and a first run that explains itself: eight templates built in code through the command layer (mobile app, landing page, dashboard, design system starter, wireframe kit, social post sizes, presentation slides, icon set starter; original and synthetic, deterministic, about 10–190 ms each to build), template.list and file.newFromTemplate for the app, CLI and MCP, File ▸ New from template…, a Templates tab on the home screen (cards with thumbnails rendered from the documents, search, kind filter, keyboard and screen-reader names) in place of the Community placeholder, a row of templates on Recents while there are no recent files, a Getting started card that can be closed and comes back from Help ▸ Getting started (help.gettingStarted), and a first run that opens on the home screen. The Drafts placeholder is gone (the app has no drafts folder). Essentials ~57% → ~59% (discoverability ×0.92 → ×0.94), its hours ~60–110 h → ~55–100 h; other numbers unchanged
2026-10-12 minor Your online files (M9): a file put on a server without its key stays its owner's after its tab closes or the app quits. The app records each one with the preferences (server, id, name, owner token, the owner's links, the codes others join with; at most 200; the token never in a command result, ui.inspect, a log or debug output) and Home ▸ Online lists them: open one as its owner (a new tab, or its tab comes to the front), Start / Stop sharing, Copy code / Copy link, Rename on the server, Remove from server (confirmed), Forget (the file stays on the server). Nothing is asked of a server until the section opens; then one request per server (Admin owned, a compatible addition within protocol version 2) says which files are still there, and a server that is offline or older leaves the list as recorded. Tabs of files in a live session carry a mark (shared, or open only to you), toasts about a file that isn't in front name it, and after a crash a recorded file reopens from its server as its owner, its recovery copy kept until its unsent changes are back on the server (or it is opened beside the file). collab.files, collab.openFile, collab.forgetFile; collab.manageFile takes its server and token from the record and gains share / unshare. The draft catalogs (French, German, Brazilian Portuguese, Japanese, Korean, Simplified Chinese) translate the 71 strings and 5 command labels they lacked and the new ones. Numbers unchanged
2026-10-12 minor Everyday editing partials closed (gap 4): number fields scrub a step a point (×10 with Shift, ×0.1 with Alt, on past the screen edge where the platform reports it), step with the arrow keys by the nudge preferences, take brackets, units and relative edits (+10, *2, 50%), commit on Tab and nothing when left untouched, and on Mixed apply relative edits to each layer in one undo step; outline mode's Include hidden layers and Include object bounds (view.outlinesHiddenLayers, view.outlinesObjectBounds), drawn and clickable; Hide when publishing from the Assets panel (component.hideWhenPublishing); a cursor for every tool, modifier and hover target (rotate turned to its corner, pen states, eyedropper, comment, copy, not-allowed), with guides and handles keeping theirs; panel widths with limits, double-click reset and the preferences (view.panelWidths); a file or page made in the dark theme has a #1E1E1E page (sessions without an interface keep #F5F5F5) and text drawn on a dark page is white. Menu breadth 211/211. UI/UX fidelity 58% and the interaction pass 40–60 h unchanged at this rounding: the side-by-side comparison is what remains
2026-10-12 minor Sharing with a join code (M9, from the owner's use: sharing wasn't intuitive): the Share popover is one flow, Online (the file is published to the server in Preferences, built in wss://collab.craftapps.dev/, and the server names its edit and view links with nine-symbol codes like K7M-2QX-9TD) or Local network (the app hosts; a 20-symbol code carries its IPv4 address, port and a 44-bit secret, with check bits), one Start sharing button, the code large with Copy code and Copy link, who is here, can edit / can view online, and Stop sharing (online: the others' links and codes are revoked and they are disconnected, while the file stays on the server with its owner in it and can be shared again with new codes; removing it is a separate, confirmed step); Join with a code is one field (popover, home screen, Join dialog) for a code of either kind or a link; addresses, keys and ports moved under Advanced and Preferences ▸ Server for online sharing (reset, or empty to turn online sharing off). Protocol additions within version 2 (Resolve / Resolved, Admin code): the server keeps a stretched hash and the wrapped token, never the code, and limits wrong codes (10 a minute per address, a 15-minute lockout after 10 wrong, 1,000 wrong an hour for everyone); codes go with their link and file. Older servers leave the links in place of a code; older apps join by link. collab.share, collab.join {code}, code and share in collab.peers; the browser joins by code. Numbers unchanged
2026-10-12 minor Live sessions per document (M9, a fix from real use): the engine keeps one session per open document instead of one for the app, the link carries several under their own ids (desktop, browser, tests), the window and the collab.* commands follow the active document, collab.peers gains session and sessions, ui.inspect's live gains session and sessions; joining opens the session's file in its own tab without touching other sessions and closing a file ends its session only. Numbers unchanged
2026-10-12 minor .fig export checked by opening written files in other software (gap 1): layers, fills, gradients, strokes, shadows, vectors, components and text draw as in FigCraft, after fixes to what the export writes (visible document and pages, the format's schema numbering, outlines, text settings, font style names, line height units); effects such as glass and noise, images and prototype interactions still unchecked there. Numbers unchanged
2026-10-12 minor Public figcraft-server hardened against resource exhaustion after a security review: messages capped by what a connection is for (a file's size when open), byte-bounded send queues and a bound on bytes waiting for the hub, files checked as they grow (refused batches roll back with the reason; per-address and total caps count growth), the core's recent-batch memory bounded in bytes, no confirmation for changes that couldn't be written, team libraries only in key-published files on public servers with unpacking bounded by the file cap, usage reports kept in memory, layered IPv6 limits (/64, /56, /48), a global publish rate, connections reserved for sessions, per-address download shares, library connections cut on revoke and removal, a private data directory and key, and safer install.sh, systemd and backups. Percentages and hours unchanged
2026-10-12 minor A public figcraft-server (open hosting): with open_publish = true anyone publishes a file without the server key and gets its edit and view links plus an owner token (128 bits, shown once, stored hashed) that lists, makes and revokes its links, renames it or removes it (collab.manageFile); limits per address (connections at once and a minute, messages a second, publishes an hour, files and MiB kept; IPv6 by /64; X-Forwarded-For believed only from trusted_proxy; tables capped at 10,000 addresses) and for everyone (max_total_mb), each refusal saying why; files published without the key expire after idle_days unopened (the date shown to everyone in the file); moderation (`files list --sort size
2026-10-12 minor Experimental .fig export (gap 1): file.export {format: "fig"}, File ▸ Export… ▸ .fig (experimental), the CLI and MCP write the whole document (layer tree, geometry, paints with image bytes, strokes, effects, text with styled runs, vector networks, auto layout, constraints, components, sets, instances with their overrides and property values, prototype interactions) with a kiwi encoder mirroring the decoder and the schema of the fields written; what's left out is a warning; verified only by round trips through our own importer. File formats 59% → 60%; import/export 84%/57% → 86%/58%; file exchange stays ×0.85; mainstream hours ~130–244 h → ~120–229 h; feature breadth (~84%), ready for real work (~53%), essentials (~57%), mainstream (~49%), beta (~155–280 h) and full parity (~265–523 h) unchanged at this rounding
2026-10-12 minor Keyboard shortcut parity suite and bindings (gap 4): a table test with one row per shortcut in the public documentation, macOS and Windows/Linux keys each (129 rows: 126 bound, 110 before; 1 moved off a documented conflict; 2 missing; 2 kept by a platform), plus 48 pinned undocumented bindings so every default binding is in the table; newly bound: A (Frame), Shift+' (pixel grid), Alt+Cmd+\ (others' cursors, new view.multiplayerCursors), Ctrl+F6, Shift+Cmd+U (link), Cmd/Ctrl+] and [ (list levels while editing, new text.listIndent / text.listOutdent), Cmd/Ctrl+Backspace (ungroup), Alt+Space / Ctrl+Space (keyboard box selection, Cmd/Ctrl+arrows draw it out), suggest auto layout, go to main component, arrows that pan with nothing selected (new view.pan), Control suspending snapping on macOS, Space/N/C/F while presenting; symbols another layout types with Shift count without it; no default binding uses a system-reserved chord (tested). Menu breadth 207/207 (View ▸ Multiplayer cursors). UI/UX fidelity 58% and the interaction pass 40–60 h unchanged at this rounding
2026-10-12 minor Simplified Chinese draft catalog (gap 5): zh-Hans.toml translates every UI string (1,371 keys; plurals give only other, and plural_one never picks "one"), command label (524) and menu wording (29), machine-drafted in a concise UI style with full-width punctuation and marked as a draft awaiting native review; Preferences ▸ Language lists 简体中文, System maps zh, zh-CN, zh-SG and zh-Hans to it, and Traditional Chinese (zh-Hant, zh-TW, zh-HK, zh-MO) has no catalog and stays English (or the next OS language), never Simplified. A Chinese UI draws Han in a Chinese face first (Microsoft YaHei, PingFang SC, Noto Sans CJK SC), ahead of the craft-fonts build's Japanese BIZ UDPGothic, and changing the UI language lays the CJK faces out again (switching from Japanese to Chinese no longer keeps the Japanese face in front). String counts re-measured: 1,371 UI keys, 524 command labels and 29 menu wordings (1,924 entries); the French, German, Brazilian Portuguese, Japanese and Korean drafts have 1,899 of them (the 25 newer strings read English). Localization 36% → 39%, 31–54 h → 29–51 h; ready for real work unchanged (~53%); full parity ~267–527 h → ~265–524 h
2026-10-12 minor Latin American Spanish overlay (gap 5): es-419.toml lists only the 87 entries (61 UI strings, 26 command labels) whose wording differs in Latin American usage (agregar for añadir, presionar for pulsar, configuración for settings, Enter for the Intro key, control for a gamepad, resorte for a spring) and reads es.toml, then English, for the rest (a regional catalog overlays its language's); same tú register as Spanish; a draft awaiting native review. Preferences ▸ Language lists Español (Latinoamérica); System maps es-419, es-MX, es-AR, es-CO and the other Latin American and US Spanish tags to it, es-ES and es to Spanish. Localization 35% → 36%, 32–55 h → 31–54 h; ready for real work unchanged (~53%); full parity ~268–528 h → ~267–527 h
2026-10-12 minor Prototyping tail (gap 15, the part that doesn't need video): key/gamepad triggers take controller buttons (Gamepad A … Gamepad Home, the standard layout's 17 buttons, from a Controller menu beside the key field; the REST import maps controller triggers instead of skipping them); the player reads controllers on Windows (Windows.Gaming.Input through the windows crate the app already used; no new dependency) and in the browser (the Gamepad API), polling only while the prototype has such a trigger and the window has the focus, and the control channel presses buttons (ui.input {gamepad}); macOS, Linux and FreeBSD read no controllers yet. Widgets react to clicks in a presented prototype (the canvas's callback and sandbox limits, on the prototype's copy: the file and its history don't change, restarting starts over). proto.evaluate computes an expression where a layer's interaction would run (MCP); the mode lookup and set-variable-mode rules are cases in a behaviour suite (they already held). Prototyping breadth 90% → 92%, ready unchanged at 74%, 3–6 h → 2–5 h; area hours 120–260 → 119–259 (core 33–75 → 32–74), Features (depth) 29–68 h → 28–67 h; percentages unchanged at this rounding; full parity ~276–538 h → ~275–537 h
2026-10-12 minor Plugin directory on figcraft-server (gap 6): the server keeps plugin bundles (manifest, module, up to 32 assets; an uncompressed length-prefixed format named by its SHA-256) published with the server key (figcraft-cli plugin publish, plugin.directory.publish), checked in full before they are kept (size cap, manifest and plugin API version, a version newer than the one kept, the module compiled but never run, plain asset names) and capped (max_plugins, max_plugin_mb, max_plugins_mb); anyone who reaches the server lists, searches and fetches them (hash-checked again on read, a shared download budget); the operator moderates with figcraft-server plugins [remove]. The app's Plugins ▸ Manage plugins gains a Browse tab: a server's plugins with Install / Update / Remove, an install confirmation that shows the permissions asked for, the source and the SHA-256, the download checked against the listed hash before anything is read, plugins kept per user in hash-named folders; plugin.directory.list / install (needs confirm: true) / publish / unpublish for scripts and MCP. Not in the browser build yet; no public catalogue, publisher accounts, signatures, ratings or background update checks. Plugins & widgets 55%/32% → 60%/35%, 10–30 h → 8–26 h; Ecosystem dimension 34% → 38%; weighted totals unchanged at this rounding; full parity ~281–548 h → ~279–544 h
2026-10-12 minor Japanese and Korean draft catalogs and CJK UI fonts (gap 5): ja.toml and ko.toml translate every UI string (1,351 keys; plurals give only other, and plural_one never picks "one" in either), command label (519) and menu wording (29), machine-drafted and marked as drafts awaiting native review; Preferences ▸ Language lists 日本語 and 한국어, System picks ja* and ko*. CJK UI text renders: once the UI language, the open file's names or comments, typed text or the language picker needs Japanese kana, Hangul or Han, the desktop app appends one installed face per script to egui's fallbacks (Windows Yu Gothic UI / Meiryo / Malgun Gothic / Microsoft YaHei, macOS Hiragino Sans / Apple SD Gothic Neo / PingFang SC, Linux Noto Sans CJK; the craft-fonts build's BIZ UDPGothic first), reading only that face's file and sharing its bytes with egui (English users load none: startup and memory unchanged); the web shows Japanese and Korean only when built with craft-fonts' Noto Sans CJK (FIGCRAFT_EMBED_CJK), else it keeps them out of the picker and System. Localization 30% → 35%, 40–65 h → 32–55 h; ready for real work ~52% → ~53% (52.9 → 53.1); full parity ~284–554 h → ~276–544 h; beta ~162–292 h → ~155–280 h
2026-10-12 minor Plugin widgets and the panel tail (gap 6, plugin API 3; v1 and v2 plugins unchanged): a plugin marked as a widget puts a layer of its own on the canvas from Plugins ▸ Widgets or widget.insert: it describes the layer (frames with auto layout, text, rectangles, ellipses, images it carries) and FigCraft validates the description (size, layer count, depth, numbers, colours, text and image sizes) and builds it as a frame with locked layers inside; a click on a part the plugin named (on the canvas with the Move tool, a pointing hand over it, or widget.click) calls the plugin back in a fresh, metered sandbox with the widget's state, as one undo step, and the widget is redrawn; the state lives in the widget's own layer data, so widgets survive save and reload, copying, undo, export and live sessions; no plugin can write that data or call widget.*. widget.list lists them. A Counter example widget. Plugin panels of different plugins open side by side, and a colour field's swatch opens the colour picker (the plugin hears of the colour when a drag ends). Plugins & widgets 45%/28% → 55%/32%, 15–40 h → 10–30 h; Ecosystem dimension 28% → 34%; weighted totals unchanged at this rounding; full parity ~286–558 h → ~281–548 h
2026-10-12 minor French, German and Brazilian Portuguese draft catalogs (gap 5): every UI string, command label and menu wording (1,899 entries) machine-drafted in each and marked as drafts awaiting native review, falling back to English per key (new strings need only English and Spanish); 0 counts as singular in French and Brazilian Portuguese; System picks the first OS language with a catalog (pt-PT and pt read pt-BR); long translations elide with a tooltip in dropdowns, two-column labels and the home cards. Localization 20% → 30%, 45–75 h → 40–65 h; ready for real work unchanged (~52%); full parity ~289–564 h → ~284–554 h; beta ~170–305 h → ~162–292 h
2026-10-12 minor Cursor chat and spotlight in live sessions: / opens a chat bubble at your pointer that everyone sees as you type and that fades a few seconds after the last change; a spotlight (your avatar's menu, collab.spotlight) makes everyone follow your view and page until they move their own. Ephemeral presence the host validates and rate-limits, passed only to clients that read it (older clients keep working). Multiplayer & sharing breadth 15% → 17%, ready unchanged (5%), 45–90 h → 42–84 h; collaboration 13% unchanged, 49–98 h → 46–92 h; feature breadth (~84%) and ready for real work (~51%) unchanged at this rounding; full parity ~301–587 h → ~298–581 h
2026-10-12 minor Layers and Assets panels behaviour suite written from the public documentation (6 engine tests with about 50 table rows and 5 panel tests driven through the UI; about 30 rows that the code before the fixes contradicts) and its fixes (several layers dropped together, Collapse layers, eye and padlock sweeps, Rename layers dialog with the documented number codes, page dragging, dividers, "Copy of" duplicates, Assets folders, hidden-from-publishing names both ways). Layers panel 98%/82% → 99%/85%; percentages and full parity hours unchanged at this rounding
2026-10-12 minor Vector multi-edit and the vector edit tail, with a behaviour suite written from the public documentation (5 tests, about 30 table rows and steps, and a junk-parameter sweep of every vector command in multi-edit mode): several vector layers are edited at once (Enter, double-click or vector.edit.begin {ids}; a press on another layer's point, handle or segment makes it the active layer; Shift-click, marquee and lasso select across layers; dragging, the arrows, Delete, delete and heal, mirroring, smoothing, corner radius and point caps and joins reach every layer's selected points in one undo step; the pen, bend, paint bucket, cut and eraser work in the active layer); several Bezier handles are selected with Shift-click and dragged together (vector.edit.moveHandles); a sharp point next to a curved segment rounds (the curve is cut where the arc meets it and keeps its shape); a point can have its own stroke cap and join (vector.edit.strokeCap, vector.edit.strokeJoin, the Point section of the Design panel; canvas, PNG, SVG and PDF, outline stroke); the Pen outside edit mode connects to one of its own points and ends the path, and continues a selected open path from an end point. Left: corner smoothing beyond rectangles, the transform box around points of several layers, per-point caps and joins on dashed, variable-width and brush strokes. Shapes & vector 98%/72% → 99%/73%, 2–4 h → 1–3 h; Figma Draw extras 80%/55% → 88%/60%, 2–5 h → 1–3 h (gap 9: pen pressure on macOS and Linux tablets left). Totals recomputed by the doc's method, which rows since the last recompute had left stale: the area table's weighted breadth is 83.7% (~83%; core 94.1%, ~94%) and ready 63.1% (~63%; core 72.1%, ~72%), hours 133–284 (core 38–83); Features (depth) 61% → 63%, 46–94 h → 34–76 h; ready for real work 52.6% (~52%); mainstream weekly areas 71.0% → 72.1% (× 0.9 × 0.9 × 0.85 = 49.7%, ~49%, rounded down); essentials unchanged (~57%); full parity ~306–595 h → ~294–572 h (on top of the rows merged since: ~301–587 h → ~289–564 h; area-table totals recomputed on the merged table and rounded down: breadth ~84%, ready ~63%, core ~94%/~72%, mainstream weekly areas 72.4%, ~49%)
2026-10-12 minor Dev resources (gap 16): links for developers (a URL and a name) on any layer: devResource.add / edit / remove / list, undoable, saved and synced; an instance also lists its main component's (and that component's set's) links read-only with where they come from, and layers inside an instance show their main layer's; URLs are checked as web links (http or https, a host, no spaces, at most 2,048 characters) and never fetched (a link added without a name is named after its URL), opened only when clicked; the Inspect tab lists, adds, edits and removes them; get_node and inspect_document return them as devResources. The editor extension stays out of scope (the MCP server serves agents and editors). Dev Mode breadth 93% → 96%, ready 70% → 72%, 1–3 h → 0–1 h; feature breadth (~82%) and ready for real work (~51%) unchanged at this rounding; full parity ~304–593 h → ~303–591 h
2026-10-12 minor Extended collections' tail (gap 14): variables a library adds to a collection this file extends now count as a library update of their own (listed by name without a copy yet) and arrive inheriting when accepted, instead of waiting for the library's next other update; a library collection that is itself an extended collection can be extended again, values flowing down the chain as each file accepts updates with every level's overrides kept (checked end to end). Styles & variables breadth 94% → 95%, ready unchanged (76%), 3–5 h → 2–4 h; gap 14 1–2 h → 0–1 h (real-library checks left); feature breadth (~82%) and ready for real work (~51%) unchanged at this rounding; full parity ~305–594 h → ~304–593 h
2026-10-12 minor A branch's own version history and finer list merges (gap 17): versions saved or autosaved on a branch tab go into the branch (viewed, restored, renamed, deleted and duplicated there, saved in the file with it); merging adds a version to the main file's history and the merged or archived branch keeps its own; fills, strokes and effects merge item by item, conflicting only when the same item changed both ways, an item was removed on one side or both sides added different items. Comments, versions, find, misc breadth 85% → 87%, ready 60% → 61%, 2–5 h → 1–4 h; gap 17 1–3 h → 1–2 h; feature breadth (~82%) and ready for real work (~51%) unchanged at this rounding; full parity ~306–595 h → ~305–594 h (the Features table here still showed 80%/58%/4–8 h from before branches landed)
2026-10-12 minor Headline percentages recomputed from the area table by its own method (weights × written scores): feature breadth ~82% → ~84% (core editor ~93% → ~94%), weighted ready ~61% → ~63%, core ready ~70% → ~72%, mainstream weekly areas 71.3% → 72.3% and mainstream ~49% → ~50%; several earlier rows had moved the area scores without carrying them into the totals. Hours are unchanged (left for the next full re-measure)
2026-10-12 minor Text lists, hanging punctuation and decoration styles, with a behaviour suite written from the public documentation (7 layout tests and 7 command tests, about 60 table rows): lists are set per paragraph (the list buttons, shortcuts and Type settings act on the paragraphs the selection touches, the whole layer when it isn't being edited), nest up to 8 levels (Tab and Shift+Tab; numbers go 1. a. i., bullets • ◦ ▪, counted per level), Enter on an empty item and Backspace at an item's start step out a level and then out of the list, typing - , * or 1. at a paragraph's start starts one; list spacing (between items, in place of paragraph spacing), hanging lists (markers outside the box) and hanging punctuation (opening punctuation outside a start-aligned edge, closing punctuation outside an end-aligned one, taking no room when lines wrap); underline and strikethrough style (solid, dotted, wavy), thickness, underline offset, skip ink and colour. Canvas, PNG, SVG and PDF; node.set keys (indentation, listSpacing, hangingPunctuation, hangingList, textDecorationStyle/Thickness/Offset/SkipInk/Color), inspect (lineTypes, lineIndentations), CSS (text-decoration-style/-thickness/-color, text-underline-offset, text-decoration-skip-ink) and the REST import (lineTypes with lineIndentations per paragraph, which collapsed to one list style before). Text 87%/68% → 90%/70%, 5–10 h → 3–7 h; mainstream weekly areas 71.0% → 71.2%; other percentages unchanged at this rounding; full parity ~306–595 h → ~304–592 h
2026-10-12 minor Comments and version history behaviour suite written from the public documentation (15 tests, about 80 table rows plus stepwise checks; 4 tests failed before the fixes) and its fixes: in a live session, threads made in the session couldn't be replied to, edited, reacted to, resolved, moved, deleted or opened (their ids, from their creator's id space, were refused as out of range); restoring a version brought back that version's comments, losing newer threads and replies (comments now stay, those on layers the version lacks staying where they were); restoring now keeps the replaced design in the history as an autosave first, unless a version of it was just saved or restored; giving an autosave a title makes it a named version (it could be dropped to make room); merging a branch adds the main file as it was and then a Merged “<branch>” version to its history. Pinned where the documentation is silent: pins go to the innermost frame under them, copies, duplicates and duplicated pages come without comments, replying reopens a resolved thread, versions stay with whoever saved them in a live session (a shared history needs accounts). Left: a branch's own version history, comparing two versions. Comments, versions, misc 85%/60% → 85%/62%, 2–5 h → 2–4 h (this table still showed 80%/58%/4–8 h from before branches landed); percentages unchanged at this rounding; full parity ~306–595 h → ~306–594 h
2026-10-11 minor Canvas navigation, rulers, guides, layout grids, outline mode and measuring behaviour suite written from the public documentation (18 tests, about 120 table rows and checks) and its fixes: the pixel grid shows from 400% (it waited for 800%); guides belong to the page or a top-level frame (a guide dropped over a nested frame goes to the frame holding it, and a frame moved into another keeps its guides but they stop showing, snapping and measuring); a guide can be selected, deleted with Delete, nudged with the arrows and removed from the context menu (guide.select, guide.remove without an index); Alt-dragging a guide drops a copy and holding Alt while dragging one measures to the nearest edges in the frame it crosses; columns and rows count Auto (as many fixed-size ones as fit); layout grids don't show or snap on a rotated frame; in outline mode shapes are clicked on their outlines, reaching layers behind. Left: outline mode's Include hidden layers and Include object bounds. Canvas & navigation 97%/72% → 98%/74%, 2–5 h → 1–4 h (this table still showed 95%/72%/3–6 h from before the outlines landed); percentages unchanged at this rounding; full parity ~320–615 h → ~319–614 h
2026-10-11 minor Export and inspect behaviour suite written from the public documentation (139 cases in 19 tests; 47 failed before the fixes) and its fixes: an export covers what the layer paints, so a drop shadow adds room only where it falls, strokes on boxes and ellipses reach their real width (they added up to four times as much), hidden layers take no room and a mask group exports the mask's area; a slice exports everything under it; slashes in layer names export into folders; Copy as PNG copies the whole selection. Added: the export settings' contents only and include bounding box, and for SVG outline text (off writes <text>), unique id attributes and simplified strokes (stroke attributes where exact); Inspect colour formats (hex, RGB, CSS, HSL, HSB), CSS in rem, a Blend row, positions measured from the frame around a layer (groups aren't frames), CSS for rotation, blend modes, gradient directions and kinds, text alignment, case and decoration; icons and images in the asset list (file.exportLayers {assets}). Import/export 80%/50% → 82%/53% (the row still showed the figures from before .fig import); Dev Mode 90%/64% → 93%/70%; mainstream weekly areas 68.1% → 68.4%; percentages and full parity hours unchanged at this rounding
2026-10-11 minor .fig import's tail (gap 1): vectors open as editable vector networks (points, curved segments, filled areas with their winding, per-point corner radius and handle mirroring, end caps from the end points), falling back to outlines when the network is missing or damaged; sticky notes, shapes with text, connectors, tables, code blocks, slides and similar layers import as the closest frames, text layers and vectors with a warning instead of being dropped; set-variable, set-variable-mode and conditional prototype actions come across. New parsers fuzzed on fixtures generated in code. File formats 55% → 58%, 8–15 h → 5–10 h; import/export breadth 80% → 82%, ready 50% → 54%; feature and area totals and ready for real work (~49%) unchanged; beta ~173–310 h → ~170–305 h; full parity ~321–618 h → ~318–613 h
2026-10-11 minor Shapes and vector behaviour suite written from the public documentation and its fixes: rounded vector points are drawn and exported, a boolean group looks like its top layer (a subtraction like the bottom one), Alt draws lines from the centre, stars keep to 3–60 points, delete and heal follows the curve, Shift-click on a point at a corner of the points' box deselects it, outline stroke keeps the stroke's colour style, opacity and effects, the miter field shows degrees, individual corners only for rectangles and frames, Option/Alt+Shift+F flattens, MCP key reaches the edit tools. Added: corner radius and star ratio handles, Count and Ratio fields, cut drags that divide shapes into layers, paint bucket drags. Shapes & vector 97%/68% → 98%/72%, 1–3 h → 2–4 h. Totals recomputed from the area table, which earlier rows had left stale: feature breadth ~80% → ~82% (core ~91% → ~93%), Features (depth) 57% → 61% (core 68% → 69%), 60–115 h → 56–109 h, ready for real work ~49% → ~51%, mainstream ~46% → ~48%; full parity ~321–618 h → ~319–615 h (the selection suite's −3/−5 h hadn't reached the totals)
2026-10-11 minor Paint and effects behaviour suite written from the public documentation and its fixes: Normal groups and frames isolate their children and clipping frames don't (canvas, SVG, PDF); plus darker drawn on the canvas and in PNG exports; drop shadows hidden behind what the layer covers unless shown behind transparent areas, SVG included, with filter regions that reach as far as the effects; Fill images cover the box to its edges; "Normal" names Normal in commands and the blend menu. Paint 85%/66% → 87%/70% (breadth from the GIF/TIFF row), 5–9 h → 3–6 h; effects 72% → 75%, 3–6 h → 2–5 h; percentages unchanged at this rounding; full parity ~321–618 h → ~319–616 h
2026-10-11 minor Frames, groups, sections and masks behaviour suite written from the public documentation (15 frame, group and section tests, 6 mask tests) and its fixes: a layer a mask hides can't be clicked there (clicks reach what's behind; Select layer agrees), a mask group's box and exports are the mask's (plus any layers under it), sections stay on the page or in sections (moves, drags, pastes, grouping and new sections in frames refused or kept on the page), drawing a frame or section around layers puts those fully inside it in it, resizing a section leaves its contents where they are (and a frame resized with Cmd/Ctrl held keeps its layers' sizes too), and X/Y of layers in groups are measured in the frame (groups have no coordinate space). Frames, groups, sections, masks 95%/75% → 97%/80%, 2–4 h → 1–3 h; percentages unchanged at this rounding; full parity ~323–621 h → ~322–620 h
2026-10-11 minor Styles and variables behaviour suite written from the public documentation (18 command-level tests) and its fixes: editing a styled fill, stroke, effect or layout grid list (directly, a paint row, an added fill or a bound variable) unlinks that style instead of being overwritten by the next style edit; applying a style replaces variables bound to what it sets; text styles go on text layers only; deleting a variable (or its collection) unbinds the layers using it, which keep their last value, and aliases to it take its values; bindings are type-checked (a colour variable can't drive a width) and number variables fill text content; aliases are checked when a variable is created. Added: duplicate, move (reorder, into a folder) and rename folder for styles, with a Local styles list grouped by type and folder (click to edit, right-click, drag to reorder); duplicate mode, set as default and move column for modes; per-platform code syntax (Web, iOS, Android) used by generated CSS and the variables JSON; font weight, paragraph spacing/indent and text content scopes for number variables. Found missing: variables inside styles. Styles & variables 92%/72% → 94%/76%, 1–2 h → 3–5 h; percentages unchanged at this rounding; full parity ~323–621 h → ~325–624 h
2026-10-11 minor Prototyping behaviour suite written from the public documentation (7 model tests, 12 player tests with 21 gestures) and its fixes: on drag starts only for a drag its animation's way and the animation follows the pointer, key combinations (Shift+K) fire (and are recorded and imported), an overlay's after-delay timer starts when it opens, instances of interactive components play their variant's interactions and "Change to" changes the right instance, spring presets are physical springs that play until they settle, smart animate overshoots with spring and back easings, fixed layers draw above scrolling content; added scroll to offsets. Prototyping 88%/70% → 90%/74%, 5–9 h → 3–6 h; mainstream weekly areas 68.1% → 68.4%, mainstream ~46% → ~47%; other percentages unchanged at this rounding; full parity ~320–615 h → ~318–612 h
2026-10-11 minor Components behaviour suite written from the public documentation (10 tests, 45 table cases) and its fixes: instances now keep overrides of auto layout padding, gap and alignment, layout grids, export settings, prototype interactions and every text property (resizing, paragraph spacing, lists…; these were lost when the main changed); moving, rotating, resizing or re-constraining layers inside an instance, and its auto layout direction, are refused (the instance itself resizes); switching variants keeps an override only where both variants had the same value (text layers keep theirs); swapping from the Assets panel keeps only text overrides; the default variant is the top-left one (instances, Assets thumbnails, code); hidden exposed instances hide their properties; pushing changes from a nested layer goes to the outer main. Added: variant property reordering and duplicate combination warnings. Components 95%/68% → 96%/72%, 6–12 h → 4–9 h; with #133's selection and transform change, core editor ready ~68% → ~69% and mainstream ~46% → ~47% (weekly areas 68.1% → 68.8%); full parity ~320–615 h → ~315–607 h (the totals now also carry #133's area 2 hours)
2026-10-11 minor Embedded image colour profiles (ICC in PNG/JPG/WebP/TIFF, PNG sRGB/gAMA/cHRM) converted into the file's colour space when decoded. Paint 85%/66% → 90%/67% (the row had lagged the parity doc), 5–9 h → 3–6 h; totals unchanged at this rounding
2026-10-11 minor Layers panel keyboard and stroke variables: F2 renames the selected layer (also from a layer row with the keyboard, which gets it back; Escape there cancels), Shift+F10 (view.contextMenu) opens the context menu at the focused row or below the canvas selection and the menu takes the keyboard, F8 (select.area) draws a selection box for keyboard-only users (arrows move it, Shift+arrows size it, Enter selects like a marquee; agents pass a box), long lists checked at 10k layers (revealing a layer, expanding or collapsing everything and arrow keys take at most 1.3 ms a frame in the release UI bench; the revealed row takes the keyboard); colour styles on strokes were already complete, and each side's stroke weight now binds to a number variable (strokeTopWeight…, bindable fields in the Design panel and REST import). Layers panel 95%/78% → 98%/82%, 2–4 h → 1–2 h; Strokes 90%/72% → 95%/75%, 1–3 h → 1–2 h; mainstream depth 67.8% → 68.1%; feature breadth (~80%), ready for real work (~49%), essentials (~57%) and mainstream (~46%) unchanged at this rounding; full parity ~321–618 h → ~320–615 h
2026-10-11 minor Text behaviour suite written from the public documentation (13 text cases, 5 command tests) and its fixes: CJK lines break between ideographs, kana and Hangul and before and after Latin words without breaking inside them, with the line-start and line-end rules (closing punctuation, small kana and the prolonged sound mark never start a line, opening brackets never end one); a style's line height, baseline and decoration come from its own font, so lines with CJK or emoji drawn by fallback fonts keep the spacing of the others; paragraph indent applies to start-aligned text only; carets, Delete and Backspace step over whole grapheme clusters (emoji sequences, flags, combining marks), which also shape with one font; double-click and word moves take one script's run in text without spaces. Added: vertical trim (cap height to baseline; leadingTrim, Type settings, REST import, inspect, CSS text-box). Text 85%/64% → 87%/68%, 7–13 h → 5–10 h; percentages unchanged at this rounding; full parity ~323–621 h → ~321–618 h
2026-10-11 minor Selection and transform behaviour suite written from the public documentation (5 selection tests with 38 table rows, 11 transform tests) and its fixes: Alt-resizing shrinks about the centre too (it could only grow); groups, frames with Scale or stretch constraints and several layers with different rotations scale each layer along its own axes, keeping its rotation and flip (children turned 90° grew along the wrong axis, nested turned groups too); several layers dragged past an edge mirror and flip; a flipped layer reads back the rotation typed; resizes land on whole pixels with the pixel grid on; a press inside a layer smaller than its handles moves it and the nearest handle wins (the first in reach did), with its handles hidden under 16 px; locked layers selected in the layers panel get no handles and aren't dragged with the rest; the background of a top-level frame with layers starts a marquee inside it (it moved the frame); Select inverse skips hidden layers like Select all. Added: equal spacing snapping with labelled gaps, Cmd/Ctrl while resizing a frame ignores its constraints. Selection & transform 95%/68% → 97%/72%, 6–10 h → 3–5 h; core editor ready ~67% → ~68%; feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~345–666 h → ~342–661 h
2026-10-11 minor Windows QA pass (gap 8): everyday workflows on Windows 11 in the desktop app and through MCP; eight fixes: recovery copies of unsaved documents reopen after a crash or a forced quit (file.recover), Ctrl moves and deletes by word in text on Windows and Linux, scrubbed fields keep their value, typing on a field Tab reached edits it, Escape closes dialogs, linear gradients keep square bands, panel hints wrap, the window-close question and "Open in new window" are translated. Percentages and hours unchanged
2026-10-11 minor Auto layout behaviour suite written from the public documentation (64 layout cases, 8 command tests) and its fixes: a frame is never smaller than its padding, only the frame's inside stroke counts when strokes are included (and new auto layout includes them), auto gaps stop at 0, grid fr tracks behave like the CSS fr unit (a track never gets less than its content), canvas stacking is drawn, exported and hit (it was stored only). Added: auto gaps evenly and around, vertical wrap, grid cell alignment, strokes and canvas stacking controls. Auto layout 95%/68% → 98%/74%, 6–12 h → 3–6 h; percentages unchanged at this rounding; full parity ~348–672 h → ~345–666 h
2026-10-11 minor Display P3 honest minimum (gap 18): the colour picker of a Display P3 file warns when a colour is outside sRGB (Outside sRGB, with what the canvas and exports do), and View ▸ Soft-proof sRGB (view.proofSrgb) stripes the canvas pixels sRGB can't show. Why the canvas still shows sRGB: wgpu 30 can present Display P3 or extended-range sRGB surfaces (Metal, DX12, Vulkan, WebGPU canvases), but eframe/egui-wgpu 0.36 configure an 8-bit sRGB surface with no option for the format or colour space, and egui's renderer writes sRGB-encoded UI colours; showing P3 needs those two upstream (or a patched egui-wgpu). Hardware 13–27 h → 12–26 h; gap 18 6–12 h → 5–11 h; percentages, feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~363–697 h → ~362–696 h
2026-10-11 minor Several windows (gap 18): File ▸ New window, a tab's Open in new window or a tab dragged off the tab strip opens files in another window with its own tabs, panels and canvas, sharing the files, preferences, libraries and clipboard; each window draws only when it needs to (idle: ~0% CPU), closing one closes its files after asking about unsaved changes (the main window too, which takes over another window instead of quitting; the last window quits), and the control channel and MCP open, list, focus and capture windows (window.new, window.list, window.focus, window on any request); the screen-reader tree covers the main window only (eframe 0.36), so with a screen reader running files stay tabs; one window in the browser. Hardware 55% → 60%, 13–27 h → 10–21 h; gap 18 6–12 h → 4–8 h (P3 on screen left); feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~363–697 h → ~360–691 h
2026-10-11 minor Localization layer landed (gap 5): per-language catalogs baked in at build time with English text as keys and fallback, placeholders and plurals, command labels by id, Preferences ▸ Language (System follows the OS or the browser) applied live and pref.language; English catalog and a complete Spanish draft awaiting native review. Localization 10% → 20%, 60–100 h → 45–75 h; ready for real work unchanged (~47%); full parity ~363–697 h → ~348–672 h; beta ~200–365 h → ~195–355 h
2026-10-11 minor Hosting figcraft-server: the desktop app and figcraft-cli open wss:// links (rustls with Mozilla's root certificates, always verified; FIGCRAFT_CA_FILE adds a private authority), releases ship the server for Linux x86_64 and aarch64, it stops gracefully on SIGTERM or Ctrl+C, and docs/server.md has a deployment guide (systemd unit, Caddy, nginx, Docker); percentages and hours unchanged until the next re-measure
2026-10-11 minor Plugin panels and settings landed (gap 6, ABI v2; v1 plugins unchanged): a plugin shows a panel of notes, fields (text, number, checkbox, menu, list, colour) and buttons drawn with FigCraft's widgets; a button or a changed value calls it back with every value (same limits per callback, one undo step per callback that edits, rolled back on failure), its module staying loaded while the panel is open; plugin.ui / plugin.event / plugin.close drive panels headless; per-plugin settings (64 KB) kept with the preferences; the Swatch grid example gained a palette panel that remembers the last palette. Plugins & widgets breadth 35% → 45%, ready 20% → 28%, 25–55 h → 15–40 h; ecosystem 20% → 28%; feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~373–712 h → ~363–697 h
2026-10-11 minor Canvas fixes (gap 13 closed): boolean groups are clicked where their result is (a click in a subtracted hole reaches what's behind; with the group or an operand selected its operands are hit, so each can still be picked), a layer dragged inside a group stays in the group (frames and auto layout still take other drops), View ▸ Frame outlines and View ▸ Slices draw on the canvas, and the idle tests wait for the render thread instead of counting frames. Shapes & vector 1–3 h → 1–2 h (vector QA with real files left); percentages, feature breadth (~79%), ready for real work (~47%) and full parity hours unchanged at this rounding
2026-10-11 minor Code connect and Dev Mode plugins (gap 16): a component or set links to its code component per language (import path, name, a template with {property} and {property ? "a" : "b"} placeholders); inspect.code, inspect.componentCode and the Inspect panel show that snippet with the instance's values (also inside generated layer trees), edited in Connect to code with a live preview; links are saved, synced and undoable, and travel as figcraft.connect.json (codeConnect.export / codeConnect.import). Plugins that only read run from the Inspect tab. Dev Mode breadth 80% → 90%, ready 62% → 64%, 4–8 h → 1–3 h; feature breadth (~79%) and ready for real work (~47%) unchanged; full parity ~378–722 h → ~375–717 h
2026-10-11 minor Stretch and scatter brushes and pen pressure landed (gap 9): eight brushes drawn in code (four stretched along the path, four scattered with spacing, size, rotation and scatter jitter from a seed) in the stroke settings, drawn everywhere strokes are and flattened by outline stroke; the Pencil records pen pressure as the stroke's width profile (Windows pens, browser styluses; macOS and Linux tablets report none) and can draw with a brush; Figma Draw extras breadth 45% → 65%, ready 30% → 45%, 10–18 h → 5–9 h; Strokes 2–4 h → 1–3 h; Hardware 50% → 55%, 15–30 h → 13–27 h; feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~378–722 h → ~358–687 h
2026-10-11 minor Text on a path and pattern fills landed (gap 9): text follows a path or shape (start, side, alignment; edited in place; canvas, PNG, SVG and PDF; SVG <textPath> imports as text on a path) and pattern fills tile a layer (grid or half-shifted rows or columns, scale, spacing, alignment; live as the source changes; SVG <pattern>, PDF tiling patterns); Figma Draw extras breadth 45% → 65%, ready 30% → 45%, 10–18 h → 5–10 h; Text 8–14 h → 7–13 h; feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~380–725 h → ~375–715 h
2026-10-11 minor Team libraries on figcraft-server landed (gap 10): a file's library is published to the server under the file and enabled in other files by a share link (per-asset versions; updates noticed in the background and accepted with overrides kept), the server counts which files use which components, and a whole library can be swapped for another by names; Team libraries breadth 40% → 70%, ready 25% → 40%, 10–20 h → 4–8 h; collaboration 12% → 13%, 55–110 h → 49–98 h; feature breadth (~79%) and ready for real work (~47%) unchanged; full parity ~380–725 h → ~375–715 h
2026-10-11 minor Branches landed (gap 17): File ▸ Create branch… copies the file into a branch tab that remembers its base; Review and merge shows both sides' changes (layers with Inspect-style property changes, styles, variables, comments) and the conflicts (the same property changed on both sides, or a layer deleted on one side and edited on the other), each resolved for the branch or main; merging is one undo step and archives the branch; Update from main; branches are saved in the .figcraft file. Comments, versions, find, misc breadth 80% → 85%, ready 58% → 60%, 4–8 h → 2–5 h; collaboration 12% → 13%; menu breadth 204/204 (the catalog gained File ▸ Create branch…); feature breadth (~79%) and ready for real work (~47%) unchanged at this rounding; full parity ~380–725 h → ~378–722 h
2026-10-11 minor Animated GIF fills and TIFF images (gap 12, without video and HEIC): GIF fills keep the original file, show the first frame on the canvas and in exports and play in the presenter and the preview (frames decoded on first play, at most 500 frames and 128 MB; always looping; the window wakes only for a GIF's next frame); TIFF images open, import, place and paste. Paint breadth 85% → 87%, 5–9 h → 4–7 h; gap 12 6–12 h → 5–10 h (video playback and HEIC left, both needing non-Rust decoders); feature breadth (~79%), ready for real work (~47%) and full parity hours unchanged at this rounding
2026-10-11 minor The last three catalogued menu items got commands (gap 21): File ▸ Open recent (recent files kept in the preferences, at most 20, a file that's gone greyed in the menu and dropped when picked, Clear recent), View ▸ Outlines ▸ Show outlines for selection and View ▸ Mask outlines: menu breadth 98.5% → 100% (203/203); Canvas & navigation breadth 95% → 97%, 3–6 h → 2–5 h; feature breadth (~79%), ready for real work (~47%) and full parity hours unchanged at this rounding
2026-10-11 minor Extended collections, variables import/export and gradient stop and variant property bindings landed (gap 14): Styles & variables breadth 85% → 92%, ready 70% → 72%, 4–8 h → 1–2 h; feature breadth unchanged (~79%); ready for real work unchanged (~47%); full parity ~385–730 h → ~380–725 h
2026-10-11 minor Collaboration wording after the standalone server: figcraft-server keeps many files, persisted as a snapshot plus a log of what changed (compacted, checksummed, damaged files skipped and reported), restarts lose nothing confirmed and apps resume where they were; the app publishes its file to it; share links per file let people edit or only view (the server refuses a viewer's edits), are revocable and stored as hashes; TLS comes from a reverse proxy (the desktop app has none of its own yet); percentages and hours unchanged until the next re-measure
2026-10-11 minor Live boolean editing, Design panel arc fields, the shape builder on strokes and open paths and one-sided variable widths landed (gap 13): Shapes & vector breadth 92% → 97%, ready 66% → 68%, 8–14 h → 1–3 h; feature breadth ~78% → ~79%; ready for real work unchanged (~47%); full parity ~390–745 h → ~385–730 h
2026-10-11 minor Collaboration wording after the collaboration polish: styles, variables, collections, modes and comments created in a live session take ids from their creator's id space (concurrent creations no longer overwrite each other; the server checks it), others' text carets and selections show on the canvas, and typing in a layer someone else is typing in says so; percentages unchanged
2026-10-11 minor Wording only: live sessions (#104), then the browser joining them and figcraft:// invite links opening the desktop app; percentages and hours unchanged until the next re-measure
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