- Serialize writable-document autosaves and retain only the newest trailing version
- Preserve saves requested while export or persistence is in flight
- Cover file, storage, retry, and recovery scheduling invariants
* refactor(editor): separate canvas view state
- Classify shared and view-local editor state explicitly
- Let canvas surfaces render supplied view state and report their viewport
- Preserve the existing one-canvas behavior by default
* fix(canvas): preserve loading render state
* feat(editor): model split canvas panes
- Add pure recursive split-tree operations with validated sizes
- Add explicit pane registry and independent view-state cloning
- Cap visible panes and cover close and split behavior
* refactor(editor): group state ownership modules
- Move shared and view state into the editor state namespace
- Model the partition with explicit interfaces and default factories
- Derive runtime view keys from the default view object
* feat(editor): model split canvas panes
- Add pure recursive split-tree operations with validated sizes
- Add explicit pane registry and independent view-state cloning
- Cap visible panes and cover close and split behavior
* feat(editor): add split canvas views
- Render recursive pane layouts with Reka UI splitters and pane-local headers
- Route canvas input, selection, viewport state, and close actions to the active pane
- Repaint every canvas during shared document previews and cover split lifecycle in tests
* fix(editor): clean up inactive pane interactions
- Cancel drag, padding preview, and text editing state when pane focus changes
- Remove duplicate changelog entries introduced while updating master
* feat(code): isolate Design JSX execution
- Transform JSX with the existing Sucrase dependency and execute it in a disposable opaque-origin iframe worker
- Block ambient network capabilities and enforce source, timeout, output, depth, and element limits
- Validate that only bounded plain structured data returns to the application
* feat(code): add editable Design JSX
- Add a lazy CodeMirror editor with JSX syntax support, completion, diagnostics, and bounded scrolling
- Convert validated sandbox output into trusted Design JSX helpers before rendering
- Apply or insert JSX as one undoable graph transaction while preserving dirty drafts
* feat(code): localize JSX editor actions
- Add translated-message fallbacks for editing, applying, inserting, and draft state
- Document the editable JSX workflow in the unreleased changelog
* fix(code): satisfy typed sandbox validation
- Keep the sandbox document terminator literal and preserve optional selection handling under type-aware lint
* test(code): resolve sandbox probes through app aliases
* fix(code): bound sandbox results before cloning
- Enforce string, array, object, depth, element, and byte limits inside the disposable worker
- Retain host-side validation as a second structured-data boundary
* fix(code): keep JSX and HTML editing modes separate
- Switch generated Tailwind output back to OpenPencil JSX before editing
- Close the JSX editor when opening HTML/CSS import and avoid stacking both editors
* feat(code): support authored Design JSX programs
- Allow local constants, function components, arrays, conditionals, fragments, and multiple roots
- Preserve replacement positions for multiple selected roots and reject mixed-parent or locked selections
- Cover multi-root undo, redo, and all-or-nothing rollback
* feat(code): add explicit JSX view mode
- Let authors leave CodeMirror without applying a draft
- Keep the editable surface and HTML/CSS importer mutually exclusive
* feat(code): diagnose unknown JSX vocabulary
- Warn on OpenPencil elements and properties that are absent from the canonical schema
- Surface diagnostics inline through CodeMirror lint markers
* test(code): accept WebKit isolation diagnostics
- Cover the sandbox architecture against Playwright WebKit
- Accept engine-specific wording while preserving the same unavailable-window assertion
* refactor(code): consolidate Design JSX vocabulary
- Drive renderer warnings, completion, and diagnostics from one supported-property schema
- Recognize locally declared components and add focused schema and transform tests
- Replace CodeMirror basicSetup with an explicit feature set and remove the umbrella package
* fix(code): support Design JSX variable helpers
* refactor(code): unify JSX sandbox validation
* fix(code): account for complete sandbox output
* fix(code): preserve locked JSX descendants
* fix(code): preserve JSX sibling order
* fix(code): recompute JSX parent layouts
* feat(code): add live code previews
* test(code): centralize graph assertions
* fix(code): harden live preview sessions
* docs: describe live code editing
* fix(code): update editor accessibility labels
* fix(code): use theme-aware error colors
* fix(dev): stop Vite disconnect error loops
* fix(code): clarify live preview status
* fix(ui): avoid tooltip attribute warnings
* test(code): assert semantic preview status
* refactor(code): remove obsolete editor messages
* fix(code): harden preview concurrency and isolation
* fix(code): cancel stale reset previews
- Derive default instance placement from transformed component bounds
- Convert the target point into the destination parent coordinate space
- Preserve explicit drag-and-drop coordinates and undo snapshots
* refactor(editor): separate canvas view state
- Classify shared and view-local editor state explicitly
- Let canvas surfaces render supplied view state and report their viewport
- Preserve the existing one-canvas behavior by default
* fix(canvas): preserve loading render state
* refactor(editor): group state ownership modules
- Move shared and view state into the editor state namespace
- Model the partition with explicit interfaces and default factories
- Derive runtime view keys from the default view object
- Convert primarily vertical Shift+wheel input to horizontal panning
- Preserve native horizontal trackpad deltas instead of swapping both axes
- Keep Ctrl and Meta wheel gestures on the existing zoom path
* feat(acp): add reusable MCP connections
- Store named Streamable HTTP connections separately from model providers
- Keep bearer tokens in the credential manager and resolve them per ACP session
- Add localized settings, validation, documentation, and focused coverage
* test(acp): harden MCP connection workflow
- Label credential inputs and confirm destructive connection removal
- Exercise MCP server delivery through an in-memory ACP session
- Extend the browser smoke test to cover accessible input and confirmation flows
* fix(acp): validate MCP connection lifecycle
- Keep non-browser storage initialization in memory and restore the German model copy
- Reject persisted name collisions and invalid draft IDs
- Preserve connections on credential failures and require credentials before enablement
* feat(canvas): measure distances between layers
- Show temporary Figma-style guides while Option or Alt is held
- Support deep nested targets with Command or Control plus Alt
- Measure transformed world bounds and container padding
* fix(canvas): anchor diagonal measurement guides
- Join diagonal distances at the nearest object corners
- Separate horizontal and vertical value badges
- Crop visual coverage tightly around the measurement overlay
* fix(canvas): cover measurement edge cases
- Draw transformed target outlines and center value pills on guides
- Suppress conflicting hover overlays during measurement mode
- Cover containment, overlap, multi-selection, rotation, and fractional gaps
* fix(canvas): suppress conflicting measurement overlays
- Hide auto-layout hover visuals while distance measurements render
- Assert fractional measurement geometry with numeric tolerance
- Show complete user messages with every image immediately after sending
- Analyze up to four bounded images without adding pixels to Design context
- Organize image handling under the extensible attachment domain
- Resolve clipPath geometry referenced through use elements
- Import clipped paint runs as editable mask groups
- Cover clipped multicolor SVG imports with a regression test
- Route bounded selection renders through the optional Vision model
- Return compact text findings without retaining image data in Design chat history
- Bound MCP and AI image exports by their longest pixel edge
- Preserve uppercase acronym casing in package tooling and CSS helpers
- Keep selector escaping without restoring removed test ID prop APIs
Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
- Decode zstd FIG data and reject invalid compressed payloads
- Compose caller CSS with Tailwind defaults during DOM import
- Slice pooled fixture buffers to their exact byte range
Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
- Track loaded font provenance and aggregate page-level face fidelity, including synthesized styles and active Inter substitutions
- Add a localized warning banner with retry and affected-layer actions
- Expose get_font_status through the Figma API and MCP tool registry
- Serialize recovery cleanup with active snapshot writes
- Preserve version ordering across autosave, restore, and cleanup
- Fall back to memory when IndexedDB operations fail
- Persist debounced FIG snapshots for source-less documents in IndexedDB
- Restore or discard orphaned snapshots from the editor startup dialog
- Clear recovery data after successful saves and explicit tab closure
- Redact and bound provider error details in copied logs
- Avoid repeat toasts after locale changes
- Show reasoning effort only for supported providers
- Report credit and output-limit failures through localized toasts and debug logs
- Persist optional provider-specific reasoning effort on model profiles
- Classify insufficient-credit connection tests and cover failure diagnostics
* fix(tauri): prevent Windows font loading crashes
- Return native font files over binary Tauri IPC instead of JSON byte arrays
- Resolve desktop script fallbacks without parsing large system fonts in JavaScript
* fix(core): restore quality checks
- Use the shared Vector primitive for render-bound offsets
- Remove unsupported SLICE handling from SceneGraph rescaling
- Drop an unused generated-text test binding
* chore: address font fix review
- Place the release note under the Fixed heading
- Name fallback resolution options and use the shared Tauri constant
- Render segments not referenced by any region loop alongside filled paths\n- Add focused path construction coverage and a canvas visual snapshot\n- Resolve Plugin API type-aware lint findings exposed by the full quality gate
- Match Figma rescale behavior across geometry, typography, effects, and descendants\n- Expose page backgrounds through preserved FIG metadata\n- Return nullable visual render bounds with stroke, effect, and clipping support\n- Cover the Plugin API behavior against live Figma probes
* fix(mcp): close orphaned servers that no app ever claims
- Add ServerOptions.appAttachTimeoutMs: if no app registers within this
window after startup, the server closes itself and removes its
discovery file, instead of squatting the port indefinitely.
- Wire it through the openpencil-mcp-http CLI as
OPENPENCIL_MCP_APP_TIMEOUT_MS (opt-in, unset/0 disables it — a bare
CLI invocation for manual testing should not self-terminate).
- The desktop app opts in with a 30s timeout when it spawns the server.
Without this, a server that outlives its spawning app (renderer crash,
forced reload) keeps holding its port with a stale discovery file. The
app's liveness check only asks whether something answers /health, not
whether an app has ever registered (see /health's no_app status) — so
every later launch finds the orphan already listening and defers to
it, and MCP tool calls fail with "app is not connected" until someone
manually kills the orphaned process. Closing self-caused orphans at
the source means the next launch finds no discovery file and takes
the normal fresh-spawn path.
Fixes#488
* fix(mcp): clean up servers after app disconnects
- Re-arm the orphan watchdog when the registered app disconnects
- Cancel pending shutdown when the app reconnects within the grace period
- Reject timeout values that overflow the runtime timer range
* test(mcp): make watchdog reconnect coverage deterministic
- Wait for the disconnected health state before reconnecting
- Report distinct safe-integer and timer-range validation errors
---------
Co-authored-by: swe-sanad <sanad.arousi@export119.com>
* fix(storage): polish workspace and connection feedback
- Move Refresh into the Storage Workspace header and keep shell theme actions available outside the editor route
- Split native shell and editor menu listeners behind the app shell
- Replace permanent CORS controls and inline connection results with standard toasts and clearer browser guidance
* fix(app): harden native menu routing
- Dispose menu listeners that finish registering after their Vue scope closes
- Mark shell-owned actions in the shared menu schema instead of duplicating IDs
- Cover route-neutral shell action classification
* fix(core): preserve inline SVG primitives
- Convert parsed circle, ellipse, rect, line, polyline, and polygon children through the shared SVG path pipeline
- Preserve nested presentation attributes, transforms, and JSX-style SVG attribute names
- Cover mixed and primitive-only inline SVG renders
* chore: format merged mobile navigation
* fix(core): disambiguate xmldom document types
- Alias the xmldom Document type so clean CI does not resolve it as the browser DOM type
- Guard the generated SVG document root before collecting paths
* fix(core): preserve inline SVG root styles
- Carry root presentation properties into parsed SVG child conversion
- Apply nested SVG transforms before creating vector networks
- Cover inherited root fills and transformed primitive geometry
* fix(core): scale transformed SVG strokes
- Remap component IDs through SceneGraph updates so the instance index stays consistent
- Cover imported instances resolving through the remapped source ID
- Restore source component synchronization for the reporter's .fig file
- Load Prism JSX only after exposing the Prism runtime
- Treat unavailable MCP automation as optional during startup
- Connect the desktop automation bridge only after MCP is ready
- Discard stale provider refreshes and queued previews
- Guard malformed deflate data and listener failures
- Start periodic refresh without an immediate callback
- Validate ranged thumbnail payloads and S3 bounds
- Invalidate stale previews and expose loading errors
- Document the public document workspace composable
- Load embedded Figma thumbnails through bounded S3 byte-range requests
- Add a headless Vue workspace composable with lazy previews and refresh lifecycle
- Cache local previews and refresh the workspace after saves and synchronization