# Changelog ## Unreleased ### Fixes - Fix `@open-pencil/vue` failing to import from npm — `getAbsolutePositionFull` was imported from `@open-pencil/core/canvas/coordinate`, an unexported subpath. Re-exported the function from `@open-pencil/core/canvas` and updated the vue import. ## 0.11.7 — 2026-04-22 ### Features - Add stdio transport for MCP server — `openpencil-mcp` now works as a proper stdio MCP server for Claude Code, Cursor, etc. HTTP server available as `openpencil-mcp-http`. - Default canvas background to dark when system prefers dark color scheme - Add `list_available_fonts` MCP tool for font discovery - Copy node ID / XPath from context menu; CLI selection command - Arrow key nudge for selected nodes (1px, Shift+arrow for 10px) - JSX renderer: `position="absolute"`, `top`, `left` props for absolute children inside auto-layout containers - MCP server sends `notifications/tools/list_changed` when the desktop app connects or disconnects - Headless text measurement via opentype.js per-glyph advance widths — no CanvasKit needed - Add `open_file` and `new_document` MCP tools with `OPENPENCIL_MCP_ROOT` path scoping - Optional `path` param on `export_image`, `export_svg`, `get_jsx` — write output to disk instead of returning base64/string - Multi-root JSX support — multiple top-level elements auto-wrapped in a fragment - `Component` and `Instance` tag aliases in JSX renderer - JSX prop reference doc — copy to clipboard via book icon in Code panel - Prompts (`CODEGEN_PROMPT`, `JSX_REFERENCE`) moved from embedded strings to markdown files ### Fixes - Fix Backspace not deleting selected nodes after clicking on canvas — canvas now receives focus on click so keyboard shortcuts aren't blocked by stale input focus - Support Cmd/Ctrl+click for additive multi-select in layers panel (previously only Shift+click worked) - Fix macOS Tauri build — move `NSAllowsLocalNetworking` ATS config from invalid `tauri.conf.json` property to a proper `Info.plist` file - Fix tab order and keyboard handling in inspector panel - Fix design token variables not resolved before passing to yoga-layout - Suppress keyboard shortcuts while editing property panel inputs - Fix tooltip competing with popover trigger on Windows - Fix hit area for nodes with rotated parents - Error toasts auto-dismiss, deduplicate, and cap stack at 5 - Bump yoga-layout to 3.3.0-grid.3 with `Node.free()` support - Bump PWA precache limit for canvaskit-webgpu - Fix color picker dragging flooding the undo stack — fill/stroke/effect color and opacity drags now collapse into a single undo entry per interaction via debounced batching in `PropertyListRoot` - Fix .fig import crash on alias variables without a GUID - Fix `save_file` crash on vectors with missing tangent control points — default to straight segments - Validate `create_vector` path JSON upfront with clear error messages for malformed input - Fix MCP/AI tools rejecting string-encoded numeric arguments from MCP clients (`"42"` → `42`) - Fix "Create Instance" context menu item always grayed out — inverted disabled flag - Show "Create Instance" instead of "Create Component" in context menu when a component is selected - Fix headless layout: use stored .fig dimensions instead of rough text size estimates (26K → 11K mismatches on material3.fig) - Fix `--help` output with huge vertical gaps between commands — remove inline examples from query description - Fix `openpencil-mcp` npm package missing `dist/stdio.js` — explicitly list entry points in tsconfig - Show toast when MCP server fails to start instead of silently swallowing the error - Fix provider settings popover not appearing — tooltip wrapper broke floating-ui positioning - Fix `set_font_range` producing invalid style runs that crash `.fig` export — use `applyStyleToRange`, apply color and fontWeight from style name - Fix MCP "app not connected" error — message now instructs the agent to stop and inform the user - Fix external links in AI panel blocked by Tauri ACL — use opener plugin instead of shell ## 0.11.6 — 2026-04-08 ### Fixes - Switch `@open-pencil/core` build from `tsgo` + `fix-esm-import-path` to `tsdown` — fixes bare directory imports that broke Node.js and Bun consumers ## 0.11.5 — 2026-04-08 ### Fixes - Fix published npm packages resolving to TypeScript source instead of compiled JavaScript — `publishConfig.exports` overrides are now applied during CI publish - Fix Windows CI build failures caused by backslash file paths in custom lint rules ## 0.11.4 — 2026-04-08 ### Fixes - Fix `@open-pencil/core` published package containing stale import paths from before the domain module restructuring — CLI and MCP installs from npm now resolve correctly - Add `save_file` MCP tool for saving the current document to disk - Clipboard text export now writes richer v4 `derivedTextData` payloads with glyph outlines for better paste fidelity ## 0.11.3 — 2026-04-08 ### Fixes - Show actionable install errors in the chat panel when a required local AI CLI is missing - Fix inline layer rename so clearing the name restores the default name, and Backspace/Delete inside rename inputs no longer delete the layer - Fix rotated frame hit testing, hover highlights, and selection overlays so interactive areas and overlay labels stay aligned during rotation - Fix text edit undo so it restores both the original text and `styleRuns` - Pressing Enter with a selected text node now starts text editing and selects all text - Fix `ScrubInput` Enter handling so committing a value no longer triggers a second blur-based commit that overwrites it - Show the auto-layout panel for `COMPONENT`, `COMPONENT_SET`, and `INSTANCE` nodes - Fix missing layout direction icons in the auto-layout controls - Fix nested text selection inside gradient cards - Unify the size control into a single inline sizing input/dropdown with shorter localized labels to prevent overflow ## 0.11.2 — 2026-03-30 ### Fixes - Stabilize npm publishing with isolated temp publish directories instead of mutating tracked package manifests in CI - Strip build-time scripts and dev dependencies from generated publish manifests so tarballs pack from verified artifacts only - Fix `@open-pencil/mcp` release packaging so the published npm tarball includes its built `dist/` CLI and server entrypoints deterministically - Fix `@open-pencil/core` release build configuration so CI publish jobs include Node and Bun ambient types when compiling package artifacts ## 0.11.1 — 2026-03-30 ### Fixes - Fix npm publishing pipeline to publish packed tarballs instead of raw package folders - Attempt to fix `@open-pencil/mcp` npm package contents so the published CLI includes its built `dist/` entrypoints - Fix `@open-pencil/vue` npm package metadata and build output so the published package resolves from `dist/` while local workspace development keeps using source aliases ## 0.11.0 — 2026-03-30 ### Features - Lock and visibility toggle buttons in layers panel (hover to reveal, always shown when active) - Figma-style selection scope — double-click to enter groups/frames/components, Escape to exit - Nested container navigation — each double-click goes one level deeper - Dashed border around entered container for visual feedback - Layer panel click syncs canvas scope automatically - Vue SDK internationalization primitives — `useI18n()`, locale detection, persisted locale selection, lazy-loaded locale JSON files, and exported locale metadata for custom editor shells - Vue SDK docs and public API audit — documented advanced exports (`useOkHCL()`, variables helpers, viewport and locale APIs), aligned docs with the actual `provideEditor()` injection model, and expanded release-ready SDK guidance - npm release pipeline now publishes `@open-pencil/core`, `@open-pencil/cli`, `@open-pencil/mcp`, and `@open-pencil/vue` together on version tags - App language picker in the menu bar — switch UI locale without reloading - Added a vector curve editor and improved drawing experience with the pen tool - Resume pen drawing from existing open path endpoints — click an endpoint to continue the curve - Close open paths by dragging one endpoint to the other - Align selected anchor points relative to each other in vector edit mode — the standard alignment buttons in the position panel now operate on selected vertices when 2 or more are selected - Unified core IO format registry — `.fig` is now modeled as the native document format alongside shared export adapters for PNG, JPG, WEBP, SVG, and JSX - Export selection or current page as `.fig` from the app export UI and app menu - New CLI commands: `open-pencil convert` for document conversion, `open-pencil formats` to inspect readable/writable/exportable formats, and `open-pencil lint` for design consistency, structure, and accessibility checks - CLI export now supports `.fig` output and routes PNG/JPG/WEBP/SVG/JSX/`.fig` through the shared IO layer - `Open…` now supports `.pen` Pencil documents through the shared document reader pipeline while keeping `.fig` as the native save format - Display‑P3 document color space pipeline — documents now default to Display‑P3, `.fig` import/export preserves document color profiles, the live canvas requests P3 surfaces with sRGB fallback, and raster/SVG export paths accept explicit color-space targets - Color picker overhaul — unified `RGB` / `HSL` / `HSB` / `OkHCL` field formats, slider-space-aware track/thumb previews, and better neutral-color editing behavior for fills, strokes, gradient stops, and component fills - OkHCL metadata now round-trips through `.fig` plugin data and integrates directly into the main fill/stroke color workflow with preview gamut diagnostics - Vue SDK now exposes reusable color-picker model helpers and solid fill/stroke commit helpers for custom editor shells - Update built-in Z.ai and MiniMax model lists — Z.ai now uses the Anthropic-compatible endpoint for GLM coding models, adds GLM-5.1, and MiniMax adds M2.7 / M2.7-highspeed - Arabic and RTL support across text rendering, editing, layout, export, and AI tooling — text nodes support `Auto`/`LTR`/`RTL`, auto-layout frames support `Auto`/`LTR`/`RTL` flow, and JSX/AI prompts/tools can now generate and edit both explicitly ### Fixes - Fix shortcuts, now work on non-English keyboard layouts. - Fix imported `.fig` file open and page-switch regressions — loaded documents now keep graph/store state in sync, remap imported canvas/page children correctly, and recompute imported auto-layout descendants when switching pages - Fix first canvas render happening before fonts load — wait for fonts before the initial draw to avoid Safari and text measurement glitches - Preserve `fig-kiwi` version on `.fig` roundtrip — imports keep the original header version instead of rewriting everything to a hardcoded value; new files default to version 101 - Normalize auto-layout text export for Figma — text children inside auto-layout frames now serialize with `NONE` auto-resize to match Figma behavior and avoid overflow on reimport - Fix keyboard editing regressions after the refactor — canvas shortcuts no longer fire while editing text, and Delete/Backspace no longer delete nodes during text entry - Fix MCP page switching persistence — `switch_page` now survives across tool calls in the same session - Improve CJK font fallback coverage — load multiple Google Fonts for broader Han/Japanese/Korean text support - Normalize more visible UI strings for localized app chrome — menus, panels, variables dialog, code panel, chat setup, and editor controls now respect the selected locale instead of falling back to English in common flows - Fix imported text rendering in browser and headless export — preserve stored bounds until fonts are ready, restore missing font-loaded guards, use natural width for `WIDTH_AND_HEIGHT` text, and clip text to node bounds - Fix browser/headless rendering mismatch for imported toolbar/instance content by correcting runtime imported layout recomputation instead of diverging browser rendering behavior - Fix `set_layout` tool not defaulting to HUG sizing when enabling auto-layout — frames now shrink/grow to fit children instead of keeping fixed dimensions - Normalize font family names on `.fig` export — strip optical size suffixes (e.g. "DM Sans 9pt" → "DM Sans") so Figma recognizes the font - TEXT nodes now default to a solid black fill — previously exported with no fill, making text invisible when opened in Figma - Fix save crash when COLOR variable is missing alpha channel - Fix console error spam on deployed web app from automation WebSocket reconnect loop - Fix headless CLI font fallback — bundled Inter font now ships with `@open-pencil/core` and loads without a web server - Locked nodes now block move, resize, rotate, and delete on canvas - Locked containers block double-click enter - Marquee selection skips locked and hidden nodes - COMPONENT/INSTANCE containers are now enterable via double-click - Replaced the alignment and reflection icons with the correct ones ## 0.10.0 — 2026-03-15 ### Performance - Offload .fig parsing (unzip + Kiwi decode) to a Web Worker — main thread stays responsive during file open - Offload .fig compression to a Web Worker during save (was blocking 450ms+) - Add instance index (`componentId → Set`) — `getInstances()` is O(1) instead of scanning all nodes - Defer graph event subscription until after layout computation during file open — eliminates redundant `syncInstances` calls - Cache label collection (sections/components) per scene mutation instead of walking the full tree every frame - Blocking font loading — fonts load before first render to ensure correct glyphs ### Features - ACP agent support — use Claude Code, Codex, or Gemini CLI as AI assistants in the desktop chat panel - Permission confirmation dialog — ACP agents request user approval for file/shell operations, MCP design tools auto-approved - Unified MCP server — single HTTP + WebSocket proxy replaces Vite SSR bridge - Stock photo integration — `stock_photo` tool fetches images from Pexels or Unsplash and applies to design nodes. Provider adapter supports custom providers. - Skeleton-first AI workflow — 4-phase design process (plan → skeleton → content fill via `replace_id` → polish) for more reliable AI-generated layouts - Batched AI tools — `calc` accepts arrays of expressions, `stock_photo` fetches all images in parallel, `batch_update` applies multiple property changes in one call, `describe` accepts `ids` array for multi-node inspection - AI visual feedback — blue pulsing border on nodes being modified, green flash on completion - Auto-depth `describe` — adapts inspection depth to subtree size (small block → deeper, large page → shallower) - `set_fill` gradient support — linear gradients with `color_end` and `gradient` direction params - `render` tool `replace_id` — atomically swap skeleton placeholders with real content - MCP `export_image_file` tool for headless PNG rendering - Grid layout in AI chat — JSX renderer supports `grid`, `columns`, `rows`, `gap` props - Configurable max output tokens in AI provider settings (default 16384) - Z.ai AI provider with GLM-5, GLM-4.7, GLM-4.6, GLM-4.5 model families - MiniMax AI provider with M2.5, M2.1, M2 models ### Improved .fig import fidelity - Resolve variable-bound fill colors through alias chains - Fix SCALE constraint resizing for auto-layout instances - Propagate SCALE constraints through instance clone chains - Skip self-referencing symbolOverrides on nodes with explicit kiwi properties - Fix DSD resolution for swapped instance children - Fix instance swap override propagation through clone chains - Fix component property override resolution through clone chains - Fix text/property overrides clobbered by second transitive sync ### Fixes - Fix text rendering with wrong fonts on file open — all font weights (including default family) are now loaded before the first render - Fix `weightToStyle` mapping: weight 400 now correctly maps to "Regular" instead of "Medium" - Fix detached ArrayBuffer crash when switching pages after saving — export worker now copies image buffers before transferring - Show warning toast when fonts fail to load, error toast when file open fails - Fix FillPicker crash when selecting image fills (missing `ref` import from #92) - Fix Google Fonts TLS/network errors not cached — failed families no longer retry on every render - Fix CJK text garbled when font is unavailable — fallback now renders through paragraph shaper instead of raw `drawText`, preserving CJK characters via the fallback font chain - Fix auto-layout overflow in AI-generated designs — text wrapping, min/max constraints, absolute positioning, and FILL sizing now work correctly - Fix `layoutAlignSelf` limited to STRETCH — full range supported (CENTER, MAX, MIN, BASELINE) - Fix hidden auto-layout children losing their dimensions on layout recompute - Fix ProviderSettings popover not visible in AI chat - Fix paste/copy/cut intercepted by canvas in AI chat input - Strip TypeScript casts from AI-generated JSX (`as any`, `as const`) - Fix parsing complex .fig files crashing on missing GUIDs in component overrides - Fix headless text layout using 100×100 default size instead of estimated dimensions — multi-line wrapping now estimated correctly - Fix clipboard roundtrip losing properties — clipsContent, constraints, arcData, strokeCap/Join, layoutAlignSelf, textAutoResize, autoRename now preserved in Figma Kiwi serialization - Fix MCP headless export crashing on `window.queryLocalFonts` in non-browser runtimes (Bun/Node) - Fix MCP `export_image` rendering blank text — fonts now loaded before rasterization - Fix text always using paragraph rendering with Inter fallback chain (no more missing-font garbling) - Clip children to rounded corners when `clipsContent` is true - Use child shape for drop shadows on transparent containers - Treat `FOREGROUND_BLUR` as layer blur wrapping children - Fix radial, angular, and diamond gradient rendering - Fix .fig export roundtrip: variable GUIDs colliding with document - Fix file open dialog not working on first click in Safari - Skip variable fonts from local font access, use Google Fonts instead - Disable autosave by default ## 0.9.0 — 2026-03-09 ### Features - XPath query command — `open-pencil query design.fig "//FRAME[@width < 300]"` to find nodes by type, attributes, and tree structure using XPath selectors - CSS Grid layout mode — select a frame, click the grid icon in the auto layout toolbar to switch from flex to grid. Configure column/row tracks (fr, fixed px, auto), column and row gaps, and per-side padding. Powered by a [Yoga fork](https://github.com/open-pencil/yoga/tree/grid) with cherry-picked CSS Grid PRs from upstream - JSX and Tailwind CSS export for grid layouts — `grid grid-cols-N`, `gap-x-*`/`gap-y-*`, child `col-start-*`/`row-start-*`/`col-span-*`/`row-span-*` - Multi-provider AI support — connect to Anthropic, OpenAI, Google AI, or any OpenAI-compatible endpoint directly, in addition to OpenRouter. Per-provider API key storage, provider settings popover, automatic migration from single OpenRouter key - Anthropic-compatible provider for custom API endpoints - New AI tools: `get_jsx` (JSX roundtrip view), `diff_jsx` (structural diff), `describe` (semantic role, visual style, layout, design issues) - AI visual verification — `export_image` returns image content to the model for vision-based review - API type toggle (Completions/Responses) for OpenAI-compatible providers - Figma zoom shortcuts — ⌘0 (100%), ⌘1 (zoom to fit), ⌘2 (zoom to selection), ⇧1/⇧2 alternatives - XPath query tool — `query_nodes` for AI/MCP with attribute selectors, tree traversal, and type filtering ### Fixes - Serialize variables, collections, and bindings to `.fig` files — previously lost on save (#65) - Text nodes created via MCP now render in Figma — emit `derivedTextData` with font metadata and layout size (#64) - Double-click on layer tree no longer toggles expand/collapse — use the chevron instead - Page rename input matches layer rename styling - Fix `w="fill"`/`h="fill"` in JSX renderer — now direction-aware based on parent flex axis - Fix text auto-resize defaulting to fixed 100×100 — text without explicit width uses `WIDTH_AND_HEIGHT` - Fix `clipsContent` not propagated to Yoga — frames with clip enabled now set `Overflow.Hidden` - Fix `COUNTER_ALIGN_MAP` mapping stretch to `MIN` instead of `STRETCH` - Fix JSX export omitting x/y for absolute-positioned children - Fix JSX export ignoring `textAutoResize` for text sizing - Fix drag terminating on mouseleave — drags now continue outside the canvas - Fix `export_image` stack overflow on large nodes — chunked base64 encoding - Undo support for auto-layout reorder, layer tree reorder, and drag reparent - Page snapshot undo for AI tool mutations - Fix collab sync for same-parent reorder — `node:reordered` events now propagated to Yjs peers - Fix orphaned instances on clipboard paste — detach to FRAME when component is missing - Fix text typography lost on Figma clipboard import — preserve fontFamily, fontWeight, fontSize, lineHeight - Fix `copyFill` missing `gradientTransform` and `imageTransform` — gradient fills now round-trip correctly ### Performance - Event-driven rendering and component sync — `SceneGraph` emits typed events on mutations; `requestRender()` calls reduced from 94 to 22, component instance sync uses microtask batching with deduplication - Replace `structuredClone` with typed copy helpers for fills, strokes, effects, and style runs (~24× faster in hot paths) - Filter .fig unzip to only decompress canvas and image entries, skipping metadata cruft ### Improvements - Padding on a frame auto-enables vertical auto-layout - AI tools run `computeAllLayouts` after execution — layout updates immediately - Enhanced AI system prompt with full JSX prop reference and verification workflow - Chat panel preserves messages when toggling UI visibility - SceneGraph event bus (nanoevents) — `node:created`, `node:updated`, `node:deleted`, `node:reparented`, `node:reordered` events replace monkey-patching in collab sync and manual render invalidation - Replace esbuild-wasm (14 MB) with sucrase (201 KB) for JSX transform — `buildComponent()` and `renderJSX()` now synchronous and browser-compatible - `useMagicKeys` keyboard shortcut system — replaces tinykeys with VueUse built-in, cross-platform Meta/Control handling, modifier exclusion for combo conflicts - Dev-only debug toolbar for copying chat logs - Auto-layout icons in layer tree — vertical (rows), horizontal (columns), and grid icons for auto-layout frames; components keep their purple diamond - Frame titles on canvas are now draggable — clicking a selected top-level frame's name label starts a drag - Compact layout controls — icon-based gap (↔/↕) and padding (T/R/B/L) inputs instead of text labels - Auto-detect horizontal vs vertical direction when wrapping in auto layout (Shift+A) - Fix alignment grid for vertical layouts — visual positions now match spatial axes - Fix grid switch from HUG-sized frames — frame expands to fit children - Remove unwanted white fill when wrapping in auto layout ## 0.8.0 — 2026-03-07 ### Features - Mobile layout & PWA — responsive editor with touch-optimized toolbar, swipeable bottom drawer (layers/properties/design/code), HUD overlay, and installable PWA with icons and service worker - Tailwind CSS v4 JSX export — export selections as HTML with Tailwind utility classes (`
`) from the Code panel, CLI (`bun open-pencil export --format jsx --style tailwind`), or programmatically via `sceneNodeToJSX(id, graph, 'tailwind')`. Supports layout, sizing, colors, border radius, opacity, rotation, overflow, shadows, blur, and typography. Uses v4 spacing semantics (px/4 multiplier) with automatic fallback to arbitrary values. - Code panel format toggle — switch between OpenPencil (custom components) and Tailwind (HTML + utility classes) output - Homebrew tap — `brew install open-pencil/tap/open-pencil` for macOS (arm64 + x64), auto-updated on each release - Double-click to rename layers — inline rename in layer panel, shared `useInlineRename` composable - New AI/MCP tools: `analyze_colors`, `analyze_typography`, `analyze_spacing`, `analyze_clusters`, `diff_create`, `diff_show`, `get_components`, `get_current_page`, `arrange`, `node_to_component` - CLI-to-app RPC bridge — all CLI commands work against the running app when no file is specified. Start the app, then run `bun open-pencil tree` to inspect the live document - VitePress docs site — user guide, reference, architecture, and development docs at openpencil.dev with 6 locales (en, de, fr, es, it, pl), SEO (OG tags, hreflang, JSON-LD, sitemap), and dark theme ### Improvements - Refactor mobile drawer tabs, layout sizing dropdowns, and inline rename to use Reka UI primitives - Add shared UI style helpers with tailwind-variants for menus, selects, buttons, and surfaces - Unified tool definitions — define once in `packages/core/src/tools/`, automatically available in AI chat, CLI, and MCP - Harden FigmaAPI — hide internals via Symbols, freeze arrays, fix `layoutSizing`, 30+ new properties and methods - Split tools into domain files (read, create, modify, structure, variables, vector, analyze) — easier to navigate and extend - Replace inline type definitions with named types (`Color`, `Vector`, `SceneNode`) across the codebase - Split 3200-line `renderer.ts` into `packages/core/src/renderer/` with 10 focused files (scene, overlays, fills, strokes, shapes, effects, rulers, labels) - Centralize all color utilities in `packages/core/src/color.ts` — `colorToHex8`, `colorToCSSCompact`, `normalizeColor`, `colorDistance`; remove 5 duplicate implementations across the codebase - Add `geometry.ts` with shared rotation math (`degToRad`, `radToDeg`, `rotatePoint`, `rotatedCorners`, `rotatedBBox`) - Extract `isArrayMixed()` helper for multi-selection property panels ### Fixes - Fix drawer animation jump on close — single spring transition instead of two-phase - Fix `ALL_TOOLS` registry missing newer tools (`analyzeColors`, `diffCreate`, `exportImage`, `arrangeNodes`) - Fix `renderJSX` typo in tool definitions (`renderJsx` → `renderJSX`) - Fix all oxlint warnings and tsgo errors — replace `!` non-null assertions in `use-collab.ts` with local const captures - Fix broken test imports — stale `../../src/engine/` paths updated to `@open-pencil/core` - Fix flaky E2E tests: layers panel navigates to `/demo`, zoom-to-fit test zooms in first, snapshot rendering stabilized with `workers: 1` and `colorScheme: dark` - Fix bogus .fig import mappings for `expanded` and `strokeMiterLimit` fields - Fix PWA manifest error in dev mode, handle invalid font data gracefully - Fix eval response unwrapping and `export_jsx` page selection in RPC bridge - Fix automation commands not recomputing layouts after mutations - Fix workspace dependency not resolved when installing from npm (switch CI to pnpm publish) ### Internal - Add `motion-v` for declarative animations — used in mobile drawer (spring-animated height with pan gestures) and toolbar (layout-animated category switching with directional slide transitions) - Mobile drawer: replace `useSwipe` + manual rAF animation with `motion.div` `:animate` + `@pan`/`@panEnd`; always-on tab state (no more null `activeRibbonTab`); content stays rendered when closed - Mobile toolbar: replace manual `scrollWidth` measuring + inline CSS transitions with `motion.div layout` + `AnimatePresence` directional slide variants - Mobile UI cleanup: extract shared `colorToCSS` util to core, `initials` to `src/utils/text`, `toolIcons` to `src/utils/tools`; replace hand-rolled dropdowns with reka-ui Popover/DropdownMenu; narrow `mobileDrawerSnap` type to string union; move magic numbers to constants; disable PWA service worker in dev mode - 83 new E2E tests (57 → 140): design panel, code panel, components, copy/paste, multi-page, text editing, keyboard shortcuts, context menu - 150 new unit tests (588 → 738): color, undo, snap, vector, style-runs, text-editor - 48 new E2E tests (9 spec files) + 26 mutation unit tests + store/canvas test helpers - Add `data-test-id` attributes to AppearanceSection, LayoutSection, TypographySection, VariablesDialog, EditorView ## 0.7.0 — 2026-03-05 ### Features - SVG export — export selections as SVG from the export panel, context menu, CLI (`bun open-pencil export --format svg`), or MCP/AI tools (`export_svg`). Supports rectangles, ellipses, lines, stars, polygons, vectors, text with style runs, gradients, image fills, effects, blend modes, clip paths, and nested groups (#46) - Copy/Paste as submenu in context menu — Copy as text, Copy as SVG, Copy as PNG (⇧⌘C), Copy as JSX - Stroke align (Inside/Center/Outside) with clip-based rendering matching Figma behavior - Individual stroke weights per side (Top/Right/Bottom/Left) with side selector dropdown - Google Fonts fallback — automatically loads fonts from Google Fonts API when not available locally - Auto-save toggle in File menu — disable to prevent automatic writes to the opened .fig file - Renderer profiler with in-canvas HUD overlay, GPU timing, and phase instrumentation ### Improvements - Replace custom color picker with Reka UI Color components (ColorArea, ColorSlider, ColorField) — adds keyboard navigation and accessibility to the color area, hue, and alpha controls ### Fixes - CJK text rendering — load a system CJK font (PingFang SC, Microsoft YaHei, Noto Sans CJK) as fallback; falls back to Noto Sans SC from Google Fonts when no system font is available (#48) - Font registration errors no longer cache invalid font data — `loadFont` only caches after successful CanvasKit registration - Fix `render` tool failing on Windows + Bun with "Cannot find module" error (#43) - Fix hover highlighting nodes from internal component pages — scope hit-test to current page - Fix hit-testing on transparent frames and groups — empty containers without fills or strokes are now click-through, clipping parents reject hits outside their bounds, matching Figma behavior - Fix instance overrides on .fig import and clipboard paste — resolve guidPaths by overrideKey, handle component swaps (`overriddenSymbolID`), propagate through nested clone chains. Import and paste now share a single override engine. - Apply Figma component property assignments on import — boolean visibility toggles and instance swaps via `componentPropRefs`/`componentPropAssignments` - Apply `derivedSymbolData` sizes on import — containers now shrink correctly when component properties hide children - Fix override resolution for nested instance targets — check the current node before searching descendants - Fix component property assignments for nested instances — resolve scoped `componentPropAssignments` inside `symbolOverrides` via guidPath, handle `guidValue` for instance swaps, reorder phases so transitive sync doesn't clobber visibility - Pixel-perfect vector rendering using pre-computed `fillGeometry`/`strokeGeometry` blobs from .fig files — eliminates white gaps between adjacent stroked shapes - Stroke outlines on clipboard paste — convert vectorNetwork paths to filled outlines via CanvasKit when geometry blobs are unavailable - Apply `derivedSymbolData` transforms and geometry during import — instance children render at correct scale and position - Fix internal pages becoming visible after .fig round-trip — preserve `internalOnly` flag on export - Scope layout recomputation to current page for paste/undo/font-load (major speedup on large multi-page files) - Show loading overlay until all document fonts are loaded (no more partially rendered text) - Load fonts when switching pages (previously only loaded for the first page) - Always show visibility toggle on fill, stroke, and effect rows (matches Figma) - Fix renderer crash on double destroy when closing files quickly - Fix .fig page ordering — use deterministic byte comparison for fractional index positions - Fix text truncation using `textTruncation` field instead of `textAutoResize` - Fix horizontal scrollbar on design and pages panels - Style scrollbars for Tauri (thin dark overlay instead of default OS chrome) - Enable file watcher in Tauri — `watch` feature was missing from `tauri-plugin-fs` ## 0.6.0 — 2026-03-04 ### Features - Multi-selection properties panel — edit position, size, appearance, fill, stroke, and effects across multiple selected nodes - Shared values display normally, differing values show "Mixed" - W/H inputs in multi-selection mode - Flip horizontal/vertical using scale transform instead of rotation - Single-node alignment aligns to parent frame bounds - ACP agent package — Agent Communication Protocol server for AI coding tools, reusing core ToolDefs ### Build - Apple code signing and notarization for macOS builds - Git LFS storage moved from GitHub to Cloudflare R2 ### Fixes - Fix Figma clipboard paste: extract shared kiwi→SceneNode conversion, fixing broken auto-layout, missing gradient/image fills, effects, style runs, and text properties - Fix vector rendering on paste — scale path coordinates from Figma's normalizedSize to actual node bounds - Fix pasted instances having no children — populate from component via symbolData when both are in clipboard - Detect component sets on import — promote FRAME nodes with VARIANT componentPropDefs to COMPONENT_SET - Skip internal canvas on paste — components on Figma's hidden internal page populate instances but are not pasted as visible nodes - Apply instance overrides on paste — text content, fills, visibility, layoutGrow, and textAutoResize from symbolOverrides - Fix auto-layout child ordering — sort by geometric position instead of z-order position strings - Load fonts on paste and .fig import — collect font families from text nodes and load into CanvasKit - Text measurement in auto-layout — use CanvasKit paragraph metrics for WIDTH_AND_HEIGHT text nodes - Recompute layouts after font loading completes - Fix PERCENT line height conversion — was stored as raw value instead of pixels - Fix InvalidCharacterError when copying nodes with non-ASCII text - Load all font weight/style variants needed by pasted text nodes - Fix font loading not registering in core cache - Fix halfLeading applied to text measurement — enable only for rendering - Clear hover on zoom/pinch to keep scene picture cache valid - Fix flip buttons using rotation math instead of actual mirroring - Fix flip transform encoding — scale first matrix column only (was incorrectly producing 180° rotation) - Decode flip state from .fig transform matrix on import ## 0.5.1 — 2026-03-03 ### Fixes - Fix File → Save crash when document has layer blur effects ## 0.5.0 — 2026-03-03 ### Features - Effects rendering: drop shadow, inner shadow, shadow spread, layer blur, background blur, foreground blur - Text shadows render on glyphs instead of bounding box - Multi-file tabs — open multiple documents in tabs within a single window - Tab bar with close buttons, middle-click to close, and new tab (+) button - Keyboard shortcuts: ⌘N/⌘T new tab, ⌘W close tab, ⌘O opens in new tab - Native Tauri menu: File → New and File → Close Tab wired to tab actions - Render text from SkPicture cache when fonts are missing — pixel-perfect display without the font installed - Missing font indicator (⚠) next to font picker in the sidebar - Right-click context menu on layers panel — same actions as the canvas context menu - 40+ new AI/MCP tools ported from figma-use: - Granular set tools: `set_rotation`, `set_opacity`, `set_radius`, `set_minmax`, `set_text`, `set_font`, `set_font_range`, `set_text_resize`, `set_visible`, `set_blend`, `set_locked`, `set_stroke_align` - Node operations: `node_bounds`, `node_move`, `node_resize`, `node_ancestors`, `node_children`, `node_tree`, `node_bindings`, `node_replace_with` - Variable CRUD: `get_variable`, `find_variables`, `create_variable`, `set_variable`, `delete_variable`, `bind_variable` - Collection CRUD: `get_collection`, `create_collection`, `delete_collection` - Boolean operations: `boolean_union`, `boolean_subtract`, `boolean_intersect`, `boolean_exclude` - Vector path tools: `path_get`, `path_set`, `path_scale`, `path_flip`, `path_move` - Create tools: `create_page`, `create_vector`, `create_slice` - Viewport: `viewport_get`, `viewport_set`, `viewport_zoom_to_fit`, `page_bounds` - Misc: `flatten_nodes`, `list_fonts` - `set_text_properties` tool: alignment, auto-resize, decoration - `set_layout_child` tool: sizing, grow, align_self, positioning - 13 MCP server integration tests via `InMemoryTransport` ### UI - Resizable pages/layers split in left panel with reka-ui Splitter - Layers tree auto-expands and scrolls to reveal selected node - Loading overlay on canvas while opening .fig files - Hide internal-only pages (e.g. "Internal Only Canvas" in design systems) - Render page dividers — pages named with only dashes/asterisks/spaces show as horizontal lines - Only show component labels for COMPONENT and COMPONENT_SET, not instances - Replace all native `