Commit graph

746 commits

Author SHA1 Message Date
Danila Poyarkov fcbd938b80 fix(fig): consolidate instance override propagation 2026-09-01 01:07:19 +03:00
Danila Poyarkov 01353e7ca7 fix(scene-graph): preserve text instance overrides 2026-09-01 01:04:22 +03:00
Danila Poyarkov 07e4cb2438 Merge remote-tracking branch 'origin/master' into consolidate-pr551-next 2026-09-01 01:02:35 +03:00
Danila Poyarkov be942783dc
refactor(i18n): migrate app copy to domain namespaces
* refactor(i18n): migrate app copy to domain namespaces

- Replace the monolithic dialogs catalog with 16 flat product-domain catalogs
- Preserve every translated locale value while moving all 356 messages
- Expose narrow domain composables and retain useI18n as a compatibility aggregate
- Document namespace ownership and admission rules

* fix(i18n): complete migrated locale coverage

- Translate exposed MCP automation, code editor, credential, and media placeholders
- Restore missing German, Spanish, French, Italian, Polish, and Russian diacritics
- Preserve technical product terms and interpolation placeholders

* fix(i18n): polish remaining locale wording

- Correct the mixed-language German code source label
- Preserve stock_photo and Pexels semantics in German and Polish
- Improve Italian MCP and code-editor grammar
- Use the standard Russian term for MCP endpoint

* fix(i18n): migrate diagnostics copy after rebase

- Add a diagnostics domain for newly merged usage and telemetry settings
- Keep settings navigation labels in the settings domain
- Preserve translated diagnostics catalogs from current master

* style(app): format rebased settings components

* refactor(i18n): simplify domain message keys

- Remove redundant domain prefixes from settings, diagnostics, automation, and integration catalogs
- Move feature-specific actions out of the common namespace
- Preserve current-master language picker and diagnostics copy across every locale
- Update consumers to concise semantic keys

* fix(app): preserve font and updater contracts

- Restore browser and abort-aware font loading from current master
- Remove the unused parameter helper from common messages
- Update updater tests for semantic domain keys

* fix(i18n): finish semantic diagnostics access

* refactor(i18n): derive active MCP status message

* fix(i18n): preserve rendering settings after rebase

- Add a rendering domain for tiled canvas preferences
- Preserve the current-master language and rendering settings UI
- Move every translated renderer preference out of the retired dialogs catalog

* fix(i18n): polish reviewed locale semantics

* test(i18n): enforce translation completeness baseline

- Fail on interpolation placeholder drift and suspicious mixed-script values
- Reject new source-identical translations while tracking existing debt explicitly
- Report translated-message coverage for every supported locale
- Require baseline cleanup when existing placeholders are translated

* refactor(i18n): baseline reviewed mixed-script messages

- Replace brittle product-vocabulary exceptions with Unicode script detection
- Track reviewed mixed-script messages by stable locale and message identity
- Reject new entries and stale baseline debt without hardcoded terminology

* fix(fig): resolve relocated stroke test helper
2026-08-31 23:54:14 +03:00
Danila Poyarkov 61e9951b12 test(fig): place stroke import coverage with current imports 2026-08-31 23:12:17 +03:00
Danila Poyarkov 2e98ab04a8 fix(canvas): normalize imported dash patterns 2026-08-31 22:25:48 +03:00
Danila Poyarkov 3702f9c93a fix(canvas): include arrow caps in bounds and controls 2026-08-31 21:25:38 +03:00
Ed-Key 9b48e47329 feat(canvas): render arrow stroke caps on lines and open vectors
ARROW_LINES and ARROW_EQUILATERAL stroke caps were accepted by the schema
and round-tripped from .fig files, but the renderer mapped every cap to
Butt, so imported arrows lost their heads and arrows could not be drawn
locally.

Add a pure arrow-cap geometry module to scene-graph (open-endpoint
collection with per-vertex cap overrides, weight-scaled head geometry)
and draw heads in the stroke color for LINE nodes and open VECTOR
centerline strokes, including the dashed-centerline path. Fold the head
reach into strokeOverflow and the node picture margin so heads are not
cropped by visual bounds, caches, or culling. Round-trip per-vertex
stroke caps through the .fig vector style override table so one-ended
Figma arrows import correctly. Expose both caps in the stroke inspector
cap picker with localized labels, and cover the renderer with an
arrow-stroke-caps Playwright canvas snapshot.

Claude-Session: https://claude.ai/code/session_012zjEbyLSBYyPpJP4fu1XNB
2026-08-31 21:25:38 +03:00
Danila Poyarkov 24647675ad fix(fig): preserve roundtrip options type 2026-08-31 20:31:25 +03:00
Danila Poyarkov e5f440d8be fix(fig): guard component property definitions 2026-08-31 19:20:03 +03:00
Danila Poyarkov e3fed2374f fix(fig): validate component property definitions 2026-08-31 18:56:23 +03:00
Danila Poyarkov 9da04f03ce fix(fig): use named assignment type guard 2026-08-31 16:51:08 +03:00
Danila Poyarkov 81454fe1f7 fix(fig): compare component properties structurally 2026-08-31 16:24:54 +03:00
Danila Poyarkov 160452448f Merge remote-tracking branch 'origin/master' into sync-pr605 2026-08-31 16:14:33 +03:00
Danila Poyarkov 716e40f0fa
Merge pull request #611 from open-pencil/figma-component-property-api
feat(figma-api): expose component property accessors
2026-08-31 15:05:51 +03:00
Danila Poyarkov 379ef8b62d
perf(canvas): rebuild navigation rendering (#591)
* perf(canvas): add traced navigation benchmarks

- Record and replay timestamped pan and zoom gestures through DOM and CDP input paths\n- Correlate input, viewport, render, long-task, and retained-backing events in Chromium traces\n- Report frame pacing, latency, jump, anchor drift, and crisp-settlement metrics

* perf(canvas): stabilize navigation comparisons

- Separate low-overhead metric runs from optional CPU-profile traces\n- Warm scenarios before recording and use a consistent SwiftShader browser configuration\n- Add a canonical momentum-pan reversal gesture alongside pinch reversal

* fix(canvas): require hardware GPU navigation benchmarks

- Run macOS performance captures through Metal-backed ANGLE and reject accidental SwiftShader fallback\n- Record the GL renderer and reserve software GPU mode for portable correctness smoke runs

* perf(canvas): cache shadow rasters for crisp backing

- Rasterize local drop and inner shadows only while constructing retained scene backing\n- Bound native image memory and invalidate cached entries with node and renderer lifecycle changes\n- Quantize zoom-aware raster resolution and reuse nearby scales without lowering normal scene quality

* test(canvas): verify retained shadow raster fidelity

- Compare settled retained-backing shadow output with direct CanvasKit rendering\n- Keep backdrop blur on the picture fallback and exercise graph-driven cache invalidation\n- Cover updates, deletion, and reparenting through actual SceneGraph events

* perf(canvas): benchmark real FIG fixtures

- Serve exact local fixture bytes through an isolated Playwright route for production preview runs\n- Wait for document loading and page population before zooming to fit and recording navigation\n- Record the resolved fixture path in benchmark environment artifacts

* fix(canvas): preserve nested effect subtree pictures

- Keep deeply nested shadow documents on one retained subtree picture instead of exploding them into per-node image draws\n- Restrict shadow raster acceleration to effect-bearing page children\n- Cover nested shadow fallback and restore gold-preview FIG pinch performance to master levels

* refactor(canvas): share recorded wheel sample type

* perf(canvas): defer backing settlement across zoom reversals

- Track explicit navigation phases and gesture generations instead of inferring idle from viewport timing\n- Cancel or defer retained backing construction while pan, zoom, momentum, or tentative settlement is active\n- Add a repeated short-pause pinch reversal fixture based on the user trace

* perf(canvas): index bounded render chunks

- Split oversized painter subtrees into self-paint and bounded descendant chunks without dropping container visuals\n- Bulk-load chunk visual bounds into RBush for selective world-space queries\n- Cover bounded updates and gold-preview build/query complexity before tile rendering consumes the index

* refactor(canvas): namespace render chunk coverage

* perf(canvas): model chunk paint context

- Preserve ancestor transform and clip dependencies for independently renderable chunks\n- Keep opacity, blend, blur, and mask isolation subtrees atomic until command-level splitting exists\n- Report oversized atomic chunks and lock gold-preview to bounded painter units

* perf(canvas): record pixel-correct render chunks

- Record interruptible chunks in world coordinates with ancestor transforms, clips, and chunk-local culling bounds\n- Draw opacity, blend, blur, and mask isolation chunks directly into destination surfaces in painter order\n- Compare composited chunk output with direct CanvasKit rendering instead of relaxing visual thresholds

* perf(canvas): render selective world tiles

- Map world regions to fixed 256-device-pixel tile targets and quantized sharpness levels\n- Query only intersecting render chunks and preserve atomic destination compositing\n- Match multi-tile CanvasKit output against direct rendering and measure gold-preview tile cost

* perf(canvas): cache chunk pictures across tiles

- Reuse world-space chunk command pictures for every intersecting tile\n- Pool 256-pixel tile surfaces and expose allocation, draw, flush, and snapshot timings\n- Keep expensive atomic foreground blur visible as an over-budget scheduler constraint

* perf(canvas): schedule cached tile rendering

- Bound tile images with an LRU cache and reuse pooled CanvasKit surfaces\n- Plan mandatory holes, stale visible refreshes, and overscan by navigation and content generation\n- Stop jobs at a strict deadline while reporting fallbacks, stale work, overruns, and over-budget effects

* perf(canvas): integrate progressive tiled rendering

- Keep retained scene output as the interaction fallback while exact tiles refine only after navigation becomes idle
- Centralize runtime URL flags and pass renderer selection through the typed Vue canvas API
- Replace benchmark sleeps with explicit mode-aware renderer settlement and report exact tiled coverage
- Preserve bounded scheduler metrics, generation cancellation, native resource cleanup, and shared visual-bounds logic

* refactor(app): centralize runtime query configuration

- Parse collaboration, recent-files, benchmark, presentation, and renderer flags in one typed app module
- Remove ad hoc URL parsing from workspace and collaboration runtime consumers
- Cover supported values and production-safe defaults without adding a repository lint rule

* fix(canvas): replace fallback pixels with exact tiles

- Render opaque page-background tile cells and install them with source replacement instead of double-compositing translucent scene content
- Exercise the live progressive controller against direct rendering across masks, effects, blend isolation, images, fallback text, transforms, and clipping
- Preserve the bounded reversal path with zero Long Tasks and exact settlement near 128 ms on gold-preview.fig

* perf(canvas): invalidate tiled content selectively

- Index chunk dependencies across contained nodes and transform or clipping ancestors
- Re-record affected chunk pictures and invalidate tiles intersecting old or new visual bounds
- Advance unaffected cached tiles to the new scene generation instead of rebuilding the full chunk index and tile cache
- Keep structural graph mutations on the safe full-rebuild path and cover selective refresh end to end

* perf(canvas): bound atomic blur tile refresh

- Render atomic blur chunks with tile-local isolation bounds and blur halos instead of replaying full-subtree layers
- Keep content refresh behind the retained fallback, cap GPU submissions to four tile jobs per frame, and adapt estimates from measured work
- Preserve large-radius CPU over-budget visibility while preventing Metal-backed refresh bursts and deferred GPU overload
- Add deterministic node-mutation benchmarks and summarize scheduler throughput, job duration, overruns, and exact content settlement

* perf(canvas): cancel obsolete tile refresh generations

- Count and report queued jobs removed by content or navigation generation changes
- Add deterministic mutation-then-reversal benchmark support without sleeps
- Assert exact tile work remains suspended during navigation and resumes for the final viewport
- Summarize cancellation alongside scheduler throughput, overruns, and settlement metrics

* test(canvas): cover live tiled blur settlement

- Load gold-preview.fig through the real tiled canvas surface and wait on explicit renderer settlement
- Commit the settled radius-210 large-blur browser snapshot
- Replay the canonical zoom reversal during refresh and require byte-identical final canvas convergence

* fix(canvas): harden renderer resource lifecycle

- Release tiled surfaces, images, pictures, and queued work across surface, font, graph, page, structure, and renderer lifecycle boundaries
- Restore pooled canvas, viewport, and backing state through exception-safe native recording and raster paths
- Rebuild tiled chunk topology only when isolation requirements actually change, preserving selective blur mutation performance
- Document deterministic active-renderer settlement and add lifecycle, graph replacement, cache failure, and surface replacement regressions

* test(canvas): remove source-matching renderer claims

- Delete the autopsy suite that inferred runtime correctness from source text, regexes, line placement, and symbol counts
- Keep renderer ordering, cache cleanup, effect behavior, and pixel fidelity covered by executable behavioral and lifecycle tests

* perf(canvas): present retained backing during tiled navigation

- Profile production reversal traces and attribute tiled p95 cost to GPU command-buffer flushes from full-scene fallback replay and tile presentation
- Use the retained backing as the moving fallback while tile scheduling and cached lookup remain allocation-free
- Defer tile image presentation until idle and expose visible versus presented tile counts in navigation telemetry
- Reduce tiled reversal render p95 from about 8ms to 0.3ms while preserving exact idle replacement and visual parity

* perf(canvas): prioritize visible tile settlement

- Profile per-tile allocation, draw, flush, snapshot, and chunk costs through scheduler telemetry
- Defer overscan until all visible exact tiles are covered
- Replace the four-job idle cap with a higher safety ceiling while the measured five-millisecond deadline controls cheap work
- Reduce mutation-plus-reversal exact settlement from about 272ms to 160ms without Long Tasks, overruns, or over-budget jobs

* refactor(canvas): clarify renderer lifecycle boundaries

- Extract retained backing state types and navigation preview timing\n- Isolate tiled scheduler telemetry from frame orchestration\n- Document settlement and CanvasKit ownership invariants\n- Preserve hot drawing loops, budgets, cache limits, and rendering decisions

* fix(canvas): preserve current label rendering

Retain the merged paragraph-label cache lifecycle and substituted-font readiness while reconstructing the renderer stack on current master.

* test(canvas): keep tile benchmark assertions deterministic

Keep performance timing in benchmark telemetry while asserting structural tile selectivity and cache behavior in CI.

* feat(canvas): expose experimental tiled rendering

- Persist retained or tiled canvas mode in General settings\n- Keep retained rendering as the default and apply changes after reload\n- Preserve URL overrides for deterministic benchmarks and support reproduction

* refactor(app): centralize renderer preference state

Expose renderer override provenance from runtime configuration and keep the settings control's derived state separate from its explicit persistence action.

* refactor(app): share settings layout anatomy

Reuse slot-based section headers and bordered groups while keeping each settings control row explicit.

* fix(canvas): harden tiled renderer boundaries

- Bound low-zoom tile planning and handle failed tile surface allocation\n- Preserve effect raster dependencies, runtime-safe clocks, and navigation timing contracts\n- Keep benchmarks deterministic, backward compatible, and accurately localized

* fix(canvas): invalidate dependent node pictures

Track first-child shadow dependencies for retained node pictures so child geometry updates cannot leave stale parent shadows.
2026-08-31 13:39:40 +03:00
Danila Poyarkov 2e29787c5e feat(figma-api): complete component property compatibility 2026-08-31 09:47:46 +03:00
Danila Poyarkov 82191b75f7 feat(figma-api): expose component property accessors 2026-08-31 09:32:13 +03:00
Danila Poyarkov 7c5033f444 Merge remote-tracking branch 'origin/master' into component-property-compatibility 2026-08-30 23:47:44 +03:00
Danila Poyarkov 55305b4f02 fix(scene-graph): scope component property cleanup 2026-08-30 22:45:21 +03:00
Danila Poyarkov 35667d84b5
fix(canvas): edit section labels inline (#608)
* fix(canvas): edit section labels inline

- Vertically center shaped section titles using cached paragraph metrics\n- Add generalized canvas-label edit state and a reusable inline label control\n- Match dark and light label presentation while editing and commit renames with undo

* fix(canvas): align label contrast handling

Use shared WCAG contrast selection for rendered and edited canvas labels while retaining exact node-fill presentation in the editing overlay.

* fix(canvas): composite translucent label colors

Choose label foreground contrast after compositing translucent section fills against the active canvas background.
2026-08-30 22:24:08 +03:00
Danila Poyarkov db9049dac9 refactor(scene-graph): align component property modules 2026-08-30 22:22:24 +03:00
Danila Poyarkov a2d0d6552d
fix(fig): harden document worker sessions (#594)
* fix(app): cancel large FIG opens before tab cleanup

- Abort tab-local preparation before awaiting recovery persistence so closing a decoding tab terminates its FIG worker immediately
- Add explicit graph-event unsubscription and lazy FIG resource release for disposed editor stores
- Keep staging-editor disposal separate from live graph resource ownership
- Let same-origin document fetches bypass all cross-origin font response limits

* refactor(fig): isolate worker sessions per document

- Give each lazy FIG document a dedicated MessageChannel and retained worker session
- Route manifest and page population traffic through the session port instead of global worker handlers
- Close the port and worker explicitly on cancellation or tab disposal
- Preserve current lazy source transfer and export fidelity until raw NodeChange patch export is implemented

* perf(fig): preserve unchanged archives in worker sessions

- Keep a second transferable copy of the original FIG archive inside the document worker session instead of main-thread memory
- Track whether user graph mutations invalidate exact archive reuse
- Return unchanged documents byte-for-byte through the session without full-page materialization or recompression
- Release archive request ownership with the page population worker and editor graph resources

* fix(fig): choose the first visible imported page

- Ignore internal-only canvases when selecting the initial active page\n- Keep internal component pages available for lazy instance population

* fix(fig): retain original archives across fallbacks

- Keep session-owned workers alive when population is oversized\n- Register the input archive when worker graph transfer falls back to the main thread\n- Preserve byte-identical unchanged saves without restoring lossy materialization

* fix(fig): harden worker session ownership

- Route concurrent archive replies through persistent request resolvers and reject stale in-flight archives after edits\n- Retain disposal-only handles for oversized sessions and guard Worker construction\n- Reuse the shared FIG import options contract and cover session disposal and invalidation

* test(fig): isolate Worker availability mutation
2026-08-30 21:40:13 +03:00
Danila Poyarkov 61e0e5fbe4 fix(scene-graph): tighten component property helpers 2026-08-30 21:31:31 +03:00
Danila Poyarkov 7bda8cc17a refactor(scene-graph): share component property operations 2026-08-30 20:24:16 +03:00
Danila Poyarkov 0f64cecc49
fix(text): finalize font readiness and label shaping (#593)
* fix(text): prepare browser fonts atomically

- Fetch approved Fontsource resources directly in browsers with bounded responses and retryable provider failures
- Limit page font resolution concurrency and retain live Inter substitution paragraphs after baked glyph invalidation
- Shape frame, section, and component labels through a bounded native Paragraph cache
- Cover real Geist, Geist Mono, and Roboto Mono browser loading plus substitution and cache lifecycle behavior

* test(canvas): cover substitution and label shaping

- Capture baked missing-font text before editing, live Inter substitution on first input, and visible undo output
- Assert text-picture and derived-glyph invalidation with finalized substituted readiness
- Cover shaped frame, rotated frame, section, component, component-set, ellipsis, kerning, and zoom label presentation

* fix(text): preserve same-origin fetches during font resolution

- Route same-origin application and fixture requests through native fetch while Unifont temporarily proxies global HTTP requests
- Keep the external provider HTTPS allowlist enforced for cross-origin font resources
- Cover the production race discovered while loading gold-preview.fig during provider initialization

* fix(text): preserve substituted path glyphs

- Keep imported derived curved glyphs for text-on-path layers when exact fonts finalize as substituted
- Cover substituted path rendering through the runtime renderer and refresh the corrected visual oracle
- Update shaped Inter measurement badges and merged typography panel snapshots after visual inspection
- Search virtualized font catalogs explicitly and restore the canvas screenshot helper used by broad E2E coverage

* fix(text): use browser font transport without desktop warning

- Keep the browser provider implementation aligned with current settings behavior after splitting from preparation

* test(text): inject same-origin browser font context

- Keep the transport test deterministic outside a Window global

* fix(text): preserve final browser font transport hardening

- Carry the same-origin large-document bypass and bounded cross-origin provider checks from the preserved integration snapshot

* fix(text): initialize font transport outside Window contexts

- Keep unit and headless module imports safe while browsers use their current origin

* test(text): satisfy async visual fixture contract

- Return from the resolver setup continuation after requesting render

* test(canvas): include paragraph cache lifecycle

* fix(text): cancel queued browser font loads

- Race serialized provider work against preparation cancellation\n- Release queue slots after cancelled waiters without disturbing active requests\n- Reuse one section-title paragraph cache entry for measurement and drawing

* fix(text): close font queue cancellation races

- Release reserved proxy queue slots when cancellation lands after queue acquisition\n- Skip paragraph work for zero-width section labels

* fix(text): abort active provider resolution

- Race active provider resolution against its preparation signal and restore the temporary fetch proxy promptly\n- Forward cancellation through proxied provider requests\n- Align the renderer font-readiness facade with substituted text
2026-08-30 14:33:32 +03:00
Danila Poyarkov 6f5638380a
feat(app): prepare documents atomically per tab (#592)
* feat(app): show atomic document loading progress

- Preserve the existing full-canvas pencil loader while adding phase, detail, accessible status, and honest determinate progress
- Keep one generation-safe load owner across FIG decoding, graph preparation, page population, fonts, fallbacks, layout, viewport fitting, and first-render fade
- Prevent nested page setup and viewport cleanup from revealing partially prepared documents
- Cover obsolete sessions, font-resolution ownership, and staged loader UI

* refactor(app): scope editor preparation per tab

- Replace the shared loading boolean with one reactive preparation snapshot and one imperative controller per editor store
- Keep Core page work progress-only and inject canvas suspension from the app boundary
- Route FIG, storage, recovery, DOM import, and page switching through reusable tab-local preparation handles
- Abort only the closing tab's operation and cover generation safety, multi-tab isolation, progress UI, and disposal

* fix(editor): commit prepared pages atomically

- Prepare population, fonts, fallbacks, and layout without changing the visible page
- Reject cancelled and stale prepared pages before committing viewport, selection, and page events
- Keep the preparation overlay until the committed scene version is presented
- Cover call order, cancellation, stale generations, and presentation acknowledgement

* fix(app): stage imported documents before commit

- Prepare imported graphs in an isolated Core editor before replacing the live document
- Share font loading while keeping live selection, graph, renderers, and history untouched during staging
- Preserve the previous graph when staging is cancelled or fails and remove the duplicate pre-font layout pass

* refactor(app): namespace preparation UI

- Move canvas and tab preparation presentations into focused subfolders with concise component names
- Share progress and phase presentation helpers across preparation surfaces
- Show tab-local preparation status without covering the active canvas for background work

* fix(app): cancel preparation work at source

- Publish typed per-store preparation lifecycle events with explicit completion, cancellation, and failure outcomes
- Propagate tab-local AbortSignals through FIG parsing, population workers, and browser font downloads
- Keep cancellable font requests outside shared in-flight caches while retaining globally completed font registrations
- Stop FIG manifest previews from replacing the live graph before atomic document commit

* fix(app): cancel storage and DOM preparation

- Propagate preparation signals through S3 downloads, byte progress, local-cache boundaries, and DOM/CSS conversion checkpoints
- Reuse merged diagnostics and localized toasts for document, storage, and presentation failures
- Replace manual font concurrency and presentation timers with es-toolkit limitAsync and withTimeout
- Guard stalled first presentation and fix the merged recovery dialog title bindings

* fix(app): stage reload and font retry

- Prepare reload graphs in isolation and preserve the current document on read, decode, font, or layout failure
- Restore page and viewport state only after atomic graph commit with cancellable reload reads
- Run font Retry as a tab-local preparation with cache reset, final layout, picture invalidation, and presentation acknowledgement
- Keep completed document pixels visible while Retry reports activity in the tab

* fix(app): enforce exclusive preparation outcomes

- Complete document, storage, recovery, and DOM preparations only after successful commit
- Keep failed and cancelled handles terminal so lifecycle events cannot report contradictory outcomes
- Preserve external AbortError identity across storage timeouts and cancel streamed readers without returning partial bytes
- Cover credential-free pre-abort, mid-stream cancellation, progress cutoff, and terminal outcome exclusivity

* feat(diagnostics): record preparation outcomes

- Persist completed, cancelled, and failed preparation lifecycles through the validated diagnostics recorder
- Store only operation kind, outcome, cancellation or failure category, terminal phase, and coarse duration bucket
- Exclude document subjects, font families, storage identities, URLs, raw durations, messages, and stack traces

* chore(app): keep browser font tests with typography split

- Remove the browser font transport test inherited from a mixed cancellation commit; the source and coverage remain on the typography branch and safety snapshot

* test(vue): assert injected render suspension

- Exercise shouldSuspendRender instead of removed Core loading state\n- Preserve the contract that rendering resumes without a version change

* test(app): complete atomic preparation contracts

- Acknowledge first presentation in headless file-open tests\n- Assert the cancellable font-loading signature at the Tauri fallback boundary

* fix(app): preserve preparation cancellation

- Stage imported graphs before mutating live tabs and propagate aborts through page, DOM, font, and storage work\n- Use the accessible progress primitive and clamp determinate values\n- Cover fallback-font cancellation and yield pending-open test polling to the task queue

* test(text): await fallback font request cancellation

Start the mocked remote font request before aborting so the test proves that the active request receives the preparation signal.
2026-08-30 12:21:49 +03:00
PAVEL TKACHEV b1c34a5054 test(fig): compare instance swap targets by path 2026-08-30 00:36:51 +03:00
xemc 7dc46bb993 feat(figma-api): add exposeInstanceSwap for real instance-swap component properties
Adds figma.exposeInstanceSwap(slots, candidates, propertyName), which
exposes one or more nested instances as an instance-swap slot — the
enclosing component (or component set, walking up past intermediate
variant members) gets an INSTANCE_SWAP property offering the given
candidates, and each slot instance is tagged to respond to it. Mirrors
Figma's "Create component property > Instance swap", letting a designer
pick which component fills a slot (e.g. an icon on a button) instead of
the slot being baked-in static content.

Exposed as the expose_instance_swap MCP/CLI/chat tool.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-29 16:30:42 +03:00
Danila Poyarkov 33baf1eb7f style(figma-api): format component conversion test 2026-08-29 15:47:43 +03:00
Danila Poyarkov 7fdf3952a2 merge: sync component sizing fix with master 2026-08-29 15:42:24 +03:00
Danila Poyarkov cbfc93f9bc test(figma-api): cover padding after component conversion 2026-08-29 15:40:25 +03:00
Danila Poyarkov 8408b56721
refactor(app): modernize browser clipboard adapter (#601)
* refactor(app): isolate system clipboard adapters

- Split browser and Tauri clipboard behavior into focused adapters\n- Inject browser clipboard capabilities into unit-testable operations\n- Remove navigator and document mutation from headless clipboard tests

* refactor(app): delegate browser clipboard fallbacks

- Use copy-to-clipboard for modern rich MIME writes and execCommand fallback\n- Keep OpenPencil-specific HTML and plain-text payload construction at the adapter boundary\n- Remove hand-rolled browser capability and selection handling

* test(clipboard): verify rich browser menu round-trip

- Exercise copy from the browser Edit menu under a user gesture\n- Verify text/html and text/plain ClipboardItem formats\n- Paste the system clipboard payload back into the canvas

* refactor(clipboard): reduce adapter surface

- Expose only command dispatch and the injectable system clipboard contract\n- Keep browser and Tauri copy/paste operations private to their adapters\n- Rename the in-memory DataTransfer fallback and share design HTML recognition

* fix(clipboard): harden format and fallback handling

- Require complete OpenPencil or Figma clipboard markers\n- Await browser writes so adapter failures resolve false\n- Write plain-only Tauri payloads as text and reject unrelated clipboard text

* fix(clipboard): reject unrelated current browser data

* fix(clipboard): bind fallbacks to copied selection

- Match cached rich HTML to the current Tauri plain-text fallback\n- Preserve nodes when selection changes during an asynchronous cut\n- Reject unrelated current browser HTML before consulting memory

* fix(clipboard): reuse the shared memory payload type

* fix(clipboard): scan design markers linearly

* fix(clipboard): distinguish unavailable and empty reads

* style(clipboard): use includes for marker closure

* test(clipboard): avoid wall-clock marker assertions
2026-08-28 14:37:42 +03:00
xemc 1fd7990cd9 fix(figma-api): preserve auto-layout sizing mode when converting a node to a component
createComponentFromNode copied only a hand-picked list of fields onto the
new COMPONENT node, omitting primaryAxisSizing/counterAxisSizing. A HUG-sized
auto-layout frame silently reverted to FIXED sizing on conversion, so later
padding changes no longer resized the frame (itemSpacing still worked since
it doesn't affect the frame's own size).
2026-08-26 10:17:07 +10:00
Mikel Cabezas 7a311677cc
fix(editor): harden clipboard fallbacks
Merges the contributor clipboard fallback fix with maintainer follow-ups for browser cut safety and isolated fallback tests. Selections are preserved when clipboard serialization fails, and clipboard fallback tests no longer depend on host APIs.
2026-08-24 19:16:16 +03:00
Sergio Bernal b65b1bd481
fix(chat): treat MCP results with optional isError correctly
Merges the contributor fix with maintainer follow-up coverage. MCP results now treat omitted isError as success, scope detection to mcp__ tools, and preserve generic tool error handling.
2026-08-24 18:18:02 +03:00
Danila Poyarkov 5f8a373b2b
feat(diagnostics): add local usage and diagnostics foundation
Supersedes #572. Adds local structured AI usage and diagnostics history, typed diagnostic events, localized Usage/Diagnostics settings, shared IndexedDB lifecycle, and consolidated button/dialog primitives.
2026-08-24 16:56:40 +03:00
Danila Poyarkov bb8c5c18d9
fix(editor): commit vector drags on pointer release (#586)
* fix(editor): commit vector drags on pointer release

- Commit vertex and Bézier handle edits immediately on release\n- Rebase active vector-edit state after graph commits\n- Use vector-specific input paths and cover Pen-created Bézier drags

* test: reduce visual snapshot scope

- Replace behavior screenshots with scene assertions\n- Capture renderer fixtures from bounded canvas regions\n- Remove obsolete full-viewport snapshots

* fix(vector): harden edit cancellation and endpoint remapping

- Restore temporary vector geometry on cancelled pointer drags\n- Commit Bézier handle releases consistently and guard stale handle state\n- Preserve valid endpoint indices when connecting vector vertices

* fix(vector): cancel bend drags and satisfy formatting

* fix(vector): guard stale handle references

* fix(vector): guard stale overlay handle indices

* fix(vector): validate overlay handle keys

* refactor(vector): use typed handle selection ids

* test(vector): align typed handle selection coverage
2026-08-24 16:02:27 +03:00
Danila Poyarkov f75d67ad4d
feat(app): make crash recovery configurable
* feat(app): make crash recovery configurable

- Add an enabled-by-default persisted recovery preference and General settings control
- Stop recovery writes and remove the active document snapshot when disabled
- Suppress startup recovery discovery while the preference is disabled
- Cover disabled persistence and re-enable behavior

* fix(i18n): translate recovery preferences

* fix(app): serialize recovery disable cleanup

- Block re-enabled persistence until pending snapshot removal completes
- Preserve disable generations so stale cleanup cannot reset newer recovery state
- Display runtime-overridden recovery state in Settings
- Deep-clone nested preferences before updating recovery
2026-08-21 18:58:27 +03:00
Danila Poyarkov 0f981ff2af fix(mcp): isolate Portless development routes
- Register the Vite-owned MCP child as a worktree-prefixed Portless sibling service\n- Inject HTTPS and WebSocket automation URLs into the browser instead of assuming port 7600\n- Isolate development socket and discovery files while preserving fixed-port non-Portless flows
2026-08-21 08:14:04 +03:00
Danila Poyarkov 22c98e28c8 Merge origin/master into agent/mcp-automation-settings
# Conflicts:
#	src/views/EditorView.vue
2026-08-20 18:48:44 +03:00
Danila Poyarkov 9c4d188ea4 refactor(mcp): keep disabled tools typed across boundaries
- Carry normalized tool-name arrays through app and development JSON configuration

- Serialize the legacy CSV format only at child-process environment boundaries

- Bound, validate, trim, and deduplicate development tool policy input
2026-08-20 18:44:44 +03:00
Danila Poyarkov bb5960cd62 refactor(app): polish files workspace and New tabs
- Keep New tabs provisional so opening or creating a design reuses the active tab
- Separate recent document, storage, menu, worker, and workspace responsibilities
- Add source-aware recents, responsive files UI, loading states, and localized copy
- Preserve native local Open Recent behavior while supporting remote storage history
2026-08-20 17:20:33 +03:00
Danila Poyarkov 376447a5dd Merge remote-tracking branch 'origin/master' into pr-550-push-integration
# Conflicts:
#	CHANGELOG.md
2026-08-20 17:20:25 +03:00
Danila Poyarkov fad731b3e7 fix(mcp): align runtime metadata and restart errors
- Publish explicit effective tool state while retaining disabled tools for Settings

- Classify filesystem writes as side effects and localize category labels

- Stop failed restarts and return precise development control status codes
2026-08-20 16:27:11 +03:00
Danila Poyarkov 7955207146 Merge origin/master into agent/mcp-automation-settings 2026-08-20 16:02:26 +03:00
Danila Poyarkov b9bdc043f7 fix(app): harden MCP configuration controls
- Parse bounded UTF-8 development configuration and await forced child exits

- Keep native folder selection behind the Tauri boundary

- Align Settings controls with read and write effects
2026-08-20 15:55:48 +03:00
Danila Poyarkov 25d7889ab2 refactor(app): make MCP runtime lifecycle explicit
- Encapsulate app-global runtime state in a testable service

- Serialize health refresh, start, stop, and restart operations

- Validate health metadata and clean state after failures
2026-08-20 15:55:48 +03:00
Danila Poyarkov 4a8714377e refactor(mcp): model tool effects and capabilities
- Remove duplicated document-access declarations from core tools

- Replace the MCP catalog with typed descriptors, capabilities, and policy

- Emit standard MCP annotations through type-safe registration
2026-08-20 15:55:48 +03:00
Danila Poyarkov dc8367921b test(canvas): cover selected frame guide scope 2026-08-20 15:17:46 +03:00