Commit graph

2329 commits

Author SHA1 Message Date
Danila Poyarkov 103e4ac151 test(canvas): fix nested guide renderer coverage 2026-08-19 20:28:10 +03:00
Danila Poyarkov c141663291 fix(editor): address guide authoring review
- Dispose CanvasKit dash effects and render nested frame guides
- Validate imported guide GUIDs and invalidate stale raw guide metadata
- Resolve frame owners through nested hit ancestry and require primary-button ruler drags
- Share guide preview types through a neutral editor module
2026-08-19 20:13:57 +03:00
Danila Poyarkov adaf6dacb9 fix(canvas): keep guide renderer fixtures complete 2026-08-19 18:10:36 +03:00
Danila Poyarkov f9c0f56ec3 chore(vue): keep guide input dispatch lint-clean 2026-08-19 18:09:46 +03:00
Danila Poyarkov f892cb583c feat(editor): add ruler guide authoring foundation
- Preserve page and frame guide GUIDs through .fig conversion
- Add undoable guide add, move, transfer, and remove actions
- Start page/frame guide previews from CanvasKit rulers
- Render warm guide previews with frame-scoped solid lines and dotted continuation
2026-08-19 18:08:48 +03:00
Danila Poyarkov 83a5ea1b42
feat(ai): add HarnessAgent sidecar foundation (#560)
* feat(ai): add HarnessAgent sidecar foundation

* feat(ai): integrate Pi as a Harness provider

* fix(ai): harden Harness provider integration

* fix(ai): address Harness integration review

* fix(ai): align Harness code with project conventions

* fix(ai): preserve Harness sessions on cancellation

* test(ai): cover Harness JSONL framing

* refactor(ai): generalize Harness sidecar adapters

* fix(ci): build Harness sidecar for native checks
2026-08-19 17:41:10 +03:00
Danila Poyarkov 44d9ba477a
Merge pull request #546 from 0xemc/fix/fs-plugin-permissions
fix(desktop): grant missing fs-plugin permissions for exists/read_text_file/create/open
2026-08-19 17:13:57 +03:00
Danila Poyarkov a2161aef63 fix(desktop): narrow MCP discovery permissions
- Limit text reads and existence checks to platform discovery files
- Drop unused create and open capabilities
- Document restored desktop automation reconnection
2026-08-19 16:49:21 +03:00
Danila Poyarkov 733b179e16 Merge remote-tracking branch 'origin/master' into review-pr-546-fix 2026-08-19 16:14:20 +03:00
Danila Poyarkov 0d6f50b445
Merge pull request #559 from open-pencil/feat/configurable-snapping-guides
feat(editor): add configurable snapping and guides
2026-08-19 13:22:24 +03:00
Danila Poyarkov 73f0883521 Merge remote-tracking branch 'origin/master' into feat/configurable-snapping-guides 2026-08-19 13:20:21 +03:00
Danila Poyarkov 8e3f904ed4 fix(io): normalize legacy guide arrays safely
- Restore missing or malformed guides as empty arrays during graph hydration
- Keep library revision clones independent while preserving valid guides
2026-08-19 12:53:00 +03:00
Danila Poyarkov 9ef2f63d57 fix(editor): harden snapping edge cases
- Preserve rounded auto-layout preview displacement through drop commits
- Bound imported layout-guide counts and tiny grid steps
- Normalize missing guide arrays in direct graph hydration paths
- Add regression coverage for auto-layout movement and guide limits
2026-08-19 12:33:32 +03:00
Danila Poyarkov 94d3b28be6 fix(canvas): release vector drags on global mouseup
- Observe window mouseup in capture phase so overlays cannot swallow drag completion
- Assert vector points stop following the pointer after release
2026-08-19 11:05:03 +03:00
Danila Poyarkov 17f791ffe4 fix(vue): guard optional resize test state without lint noise 2026-08-19 10:23:45 +03:00
Danila Poyarkov f4ef46a249 test(vue): keep resize helpers compatible with partial editors 2026-08-19 00:15:34 +03:00
Danila Poyarkov f2228f45ef fix(editor): apply CodeRabbit snapping fixes
- Preserve transformed Control bypass and native preference dispatch
- Clarify snapping settings and keep fractional positions visible
- Filter hidden targets and harden guide and resize handling
- Update native menu schema coverage
2026-08-19 00:07:29 +03:00
Danila Poyarkov b48fe1623b fix(editor): address snapping review feedback after merge
- Preserve transformed Control-bypass movement and hide invalid snap targets
- Route native snapping toggles through persisted preference actions
- Harden axis tolerance, resize behavior, and guide repaint lifecycle
- Keep fractional coordinates visible and clarify localized setting descriptions
2026-08-18 23:12:02 +03:00
Danila Poyarkov 0332b062c5
refactor(canvas): adopt immutable CanvasKit paths (#554)
* refactor(canvas): adopt immutable CanvasKit paths

- Upgrade CanvasKit to 0.41.1 across app, Core, CLI, and Vue peers

- Build mutable geometry with PathBuilder and detach immutable paths for drawing

- Replace in-place strokes, transforms, and boolean operations with immutable results

- Update renderer mocks and path construction tests for the new API

* test(canvas): model immutable path ownership

- Return detached path instances from CanvasKit builder mocks

- Assert shadow ring and combined path disposal

- Preserve recorded vector operations across ownership transfer

* fix(build): align CanvasKit workspace versions
2026-08-18 23:09:45 +03:00
Danila Poyarkov e0491ed0ae Merge remote-tracking branch 'origin/master' into feat/configurable-snapping-guides 2026-08-18 22:57:27 +03:00
Danila Poyarkov d44c1f9d82
ci: parallelize quality and trim shard builds (#558)
* ci: parallelize quality and trim shard builds

- Split source, package, repository, and Storybook checks into independent jobs

- Build only Core before quick unit shards instead of all public packages

- Keep full package and dist validation in the dedicated package-quality job

- Disable duplicate Storybook component metadata extraction

* fix(ci): build declarations before source checks

* fix(ci): apply review security and docgen settings

- Pin checkout and disable credential persistence

- Declare read-only workflow permissions

- Explicitly disable Storybook Vue docgen

* ci: clarify check and step names

* fix(ci): cap workflow job runtimes

- Limit the WebView dependency install to three minutes

- Limit native contracts to eight minutes

- Limit all other CI jobs to ten minutes

* ci: retry native contracts on a fresh runner

* ci: move native contracts to Ubuntu 24

- Leave the deprecated Ubuntu 22 hosted image

- Retry WebKit dependency provisioning on the current runner image

* ci: prebuild native contract dependencies

* ci: pin native contracts image digest

* fix(ci): authenticate native image pulls

* fix(ci): include Bun archive tooling

* ci: pin updated native contracts image

* fix(tools): register CI image tooling
2026-08-18 22:52:18 +03:00
Danila Poyarkov 42b1fa07f0 Merge origin/master into feat/configurable-snapping-guides 2026-08-18 22:05:51 +03:00
Danila Poyarkov 921cd702f8 fix(editor): address snapping review feedback
- Preserve parent-local movement during Control bypass
- Route native snapping menu actions through persisted preferences
- Harden guide alignment, lifecycle rendering, and transformed resize behavior
- Update preference descriptions and fractional position display
2026-08-18 22:03:53 +03:00
Danila Poyarkov bd4f6f0a22
build(ai): upgrade to AI SDK 7 (#555)
- Upgrade direct model chat providers and transports to AI SDK 7.\n- Keep the local ACP execution path unchanged.\n- Preserve chat, tool, vision, and provider behavior across the adapter boundary.
2026-08-18 19:31:02 +03:00
Danila Poyarkov 91e759d7fd feat(editor): add configurable snapping and guides
- Snap vector points, moved layers, and resized edges to geometry, objects, guides, and pixels
- Add persistent snapping preferences with browser and native menu controls
- Normalize canvas and layout guides across Scene Graph and .fig conversion
- Clear transient snapping feedback across interrupted interactions
2026-08-18 19:11:48 +03:00
Danila Poyarkov 211a4ea99c
fix(i18n): localize app notifications (#557)
- Add app-owned notification translations for every supported locale.\n- Localize common file, clipboard, collaboration, chat, vectorization, storage, recovery, and library toasts.\n- Preserve actionable runtime details inside localized messages.
2026-08-18 18:52:19 +03:00
Danila Poyarkov 3e8171ffda docs: clean up Unreleased changelog
- Keep one section per public changelog category

- Remove duplicate and validation-only entries

- Restore missing user-visible clipboard and MCP fixes
2026-08-18 17:54:18 +03:00
Danila Poyarkov f3973202eb
chore: refresh compatible dependencies (#545)
- Refresh compatible workspace dependencies and lockfiles.\n- Preserve package exports and documentation compatibility.\n- Update affected compatibility tests.
2026-08-18 17:44:40 +03:00
Danila Poyarkov 4342fd3262
perf(chat): release completed streaming parser history (#553)
- Keep only the active assistant response in streaming Markdown mode.\n- Remount completed responses in static mode to release incremental AST caches.\n- Preserve final Markdown, code rendering, and theme behavior.
2026-08-18 17:43:49 +03:00
Victor Wads 4e48420ac1
feat(app): open multiple files from the Open dialog (#552)
- Open multiple selected design files in separate tabs.\n- Support desktop, File System Access, and fallback pickers.\n- Continue opening later selections when one file fails.
2026-08-18 11:30:36 +03:00
xemc 3f6cb88b5e fix(desktop): grant missing fs-plugin permissions for exists/read_text_file/create/open
The default capability only granted read_file/write_file/mkdir/remove/watch,
but the app also calls exists(), readTextFile(), create(), and open() from
@tauri-apps/plugin-fs. Each fs-plugin command requires its own explicit
permission identifier in Tauri v2 — these were never added.

The most visible symptom: EditorView's automation startup calls
discoveryFileExists()/readDiscoveryToken() (spawn.ts) to reuse an already-
running MCP server. With allow-exists and allow-read-text-file missing, both
calls silently fail (the fs-plugin IPC rejection is caught and treated as
"file not found"), so the app always falls through to spawning a redundant
MCP server process and registers with a freshly generated auth token instead
of the real one — which the already-running server then rejects, leaving
automation permanently disconnected from any already-running MCP server.
2026-08-18 06:15:12 +10:00
Danila Poyarkov 15bd0ba19f
fix(text): align editing overlays with vertical text (#543)
- Offset selection and caret geometry with the rendered paragraph.\n- Translate text-editing hit testing into paragraph coordinates.\n- Cover every aligned coordinate-mapping path.
2026-08-17 19:32:40 +03:00
Danila Poyarkov 97e42e8102
test(collab): add deterministic browser sessions (#541)
* test(collab): add deterministic browser sessions

- Extract a typed room transport boundary around Trystero
- Add a development-only WebSocket relay transport for browser tests
- Cover two-peer edits, awareness, departure cleanup, and reconnect convergence without public network services

* fix(collab): harden browser test transport

- Scope collaboration controls to explicit development test hooks
- Validate bounded relay messages and reject duplicate action receivers
- Remove only awareness clients owned by a departing peer
- Guarantee relay and browser cleanup after setup failures

* fix(collab): strengthen browser session coverage

- Prevent remote awareness rebroadcast and track ownership by transport peer
- Guard and validate the development relay lifecycle
- Simulate a network partition with retained peers and concurrent offline edits
- Make browser and relay setup and teardown failure-safe

* test(collab): prove partitioned peer convergence

- Queue and assert traffic during a deterministic network partition
- Converge non-conflicting edits from retained host and guest sessions
- Reject relay startup failures and guard test-only browser APIs
2026-08-17 12:57:03 +03:00
Danila Poyarkov d29fe37fd5
fix(chat): match code blocks to the app theme (#542)
- Update vue-stream-markdown to 1.0.4.\n- Pass OpenPencil's resolved theme to Shiki rendering.\n- Keep code backgrounds and syntax colors readable in light and dark modes.
2026-08-17 12:18:58 +03:00
rcoenen be272dc4dc
feat(fig): support text on path 2026-08-17 12:00:01 +03:00
Danila Poyarkov d112bc9044
fix(chat): preserve native copying of selected text (#540)
- Allow native text selection in AI chat messages.\n- Leave active DOM text ranges to the platform clipboard.\n- Preserve canvas clipboard routing when no document text is selected.
2026-08-17 11:54:24 +03:00
Danila Poyarkov 54c1373d3e
ci: derive GitHub Release metadata from changelog (#536)
- Extract the release body from the changelog section matching the pushed tag.\n- Keep the GitHub Release title identical to the tag.\n- Document signing, updater, publication, deployment, and Homebrew handoff.
2026-08-17 11:07:13 +03:00
Danila Poyarkov d7613f34ec
perf(scene-graph): accelerate axis-aligned hit tests (#534)
* perf(scene-graph): accelerate axis-aligned hit tests

- Reuse cached world positions for untransformed node chains
- Preserve exact matrix hit testing beneath rotated and flipped ancestors
- Profile pointer, hit-test, cached, overlay, and volatile rendering at 500 and 2,000 nodes

* fix(vue): restore layer drop indicators

- Forward reactive drag instructions through virtualized layer item slots
- Render above, below, and child feedback before the drop completes
- Add browser regressions for reorder lines and container highlights

* fix(scene-graph): harden hit-test performance coverage

- Cache transformed ancestry within each hit-test traversal
- Invalidate absolute positions after preview flips and reparenting
- Attach scale-relative browser profiles and correct auto-layout fixture geometry

* fix(scene-graph): reject cyclic layer reorder

- Prevent reorderChild from parenting a node beneath its descendant
- Cover graph preservation after a rejected cyclic reorder
2026-08-16 15:43:25 +03:00
Danila Poyarkov 97bc86fa70
fix(app): use callable fetch adapter type (#535) 2026-08-16 13:40:44 +03:00
Danila Poyarkov 780221b006
test(tauri): add native WebView interaction harness (#532) 2026-08-15 14:17:05 +03:00
Danila Poyarkov e7c408a28f
perf(app): coalesce overlapping autosaves (#531)
- 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
2026-08-15 12:23:01 +03:00
Danila Poyarkov b0ebe91ed6
perf(collab): skip unchanged Yjs node fields (#529)
* perf(collab): skip unchanged Yjs node fields

- Compare encoded node fields before writing to Y.Map
- Cover unchanged sync, repeated drag-like updates, echo behavior, and concurrent convergence
- Reduce 100 unchanged syncs from 13,700 updates to zero

* test(collab): simulate queued Yjs convergence

- Use the official Yjs TestConnector for deterministic queued delivery
- Exercise offline concurrent edits, reconnect, random message flushing, and convergence
2026-08-15 11:40:27 +03:00
Danila Poyarkov 7a02ee2c62
feat(editor): model split canvas panes (#519)
* 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
2026-08-15 10:31:52 +03:00
Danila Poyarkov 6193b6da7e
feat(code): add live JSX and HTML/CSS editing (#525)
* 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
2026-08-15 09:48:42 +03:00
Danila Poyarkov d8c968c04a
fix(editor): place nested component instances in world space (#524)
- 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
2026-08-14 21:24:20 +03:00
Danila Poyarkov 29ed07bcc4
refactor(editor): separate canvas view state (#518)
* 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
2026-08-14 21:24:01 +03:00
Danila Poyarkov f781c48eaa
fix(canvas): pan horizontally with Shift+wheel (#523)
- 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
2026-08-14 20:58:28 +03:00
Danila Poyarkov d67415c793
docs: explain component library workflows (#520)
Documents component libraries and localized workflows added by #512.
2026-08-14 20:39:47 +03:00
Danila Poyarkov a29f609dd2
fix(settings): separate MCP connections from models (#522)
- Add a dedicated MCP connections destination to Settings navigation
- Keep ModelsPanel focused on model profiles and assignments
- Update documentation, changelog, and browser coverage for the new location
2026-08-14 20:39:29 +03:00
Danila Poyarkov 90f2498bcf
fix(collab): validate synchronized node data (#517)
* fix(collab): validate synchronized node data

- Exclude renderer-only text picture caches from Yjs payloads

- Normalize source metadata and geometry at the remote boundary

- Cover malformed payloads and typed geometry round trips

* fix(collab): reject malformed geometry fills

* fix(collab): validate nested fill metadata

* test(collab): preserve valid nested fill metadata
2026-08-14 20:38:46 +03:00