Commit graph

99 commits

Author SHA1 Message Date
Danila Poyarkov 47fe43c3ec feat(text): harden font resolution lifecycle
- Gate ingest rendering until required faces and script fallbacks resolve
- Key CanvasKit artifacts by font registration generation and invalidate affected nodes
- Load character-aware remote subsets with cumulative coverage and exact render aliases
- Use BCP-47 language hints for shaping and CJK fallback order
- Keep baked .fig glyphs as an exhaustion-only fallback
2026-07-17 14:52:35 +03:00
Danila Poyarkov 1750199b9c chore: tidy ignore rules 2026-07-05 13:15:57 +03:00
Danila Poyarkov b5665afab5 fix(tauri): restore desktop clipboard access 2026-07-01 10:40:29 +03:00
Danila Poyarkov 8cefbedd50 feat(app): add desktop HTTP bridge for online services 2026-06-30 16:52:26 +03:00
Danila Poyarkov ec5ef4474e
i18n: add Japanese and complete menu localization (#367)
* i18n: more menu translations

* chore: code formatting

* chore: code formatting

* chore: code formatting

* i18n: more menu translations

* chore: code formatting

* i18n: added new menu translations and japanese language

* i18n: added theme-auto string

* i18n: translated rest of the menu text

* fix(i18n): polish PR 273 locale updates

- Fix obvious translation regressions in existing locales
- Preserve update size interpolation across localized update messages
- Use standard UI terms for theme and boolean operation labels

* fix(i18n): tune localized toggle labels

- Use paired action wording for toggle commands
- Clarify Japanese frame-selection command label

---------

Co-authored-by: Santos Alarcón <santosalarcon86@gmail.com>
2026-06-30 10:25:52 +03:00
rcoenen b8076adfbb
fix(desktop): enable image drag-and-drop in the Tauri window
Tauri's dragDropEnabled defaults to true, which makes the native OS file
drop intercept and swallow the event so the webview's HTML5 drop handler
(useCanvasDrop) never fires — drag-and-drop of images worked in the browser
but failed in the desktop app. Set dragDropEnabled: false so the webview
receives HTML5 drag/drop natively and the existing web handler works on
desktop too. No web-side code changes.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-06-30 09:50:15 +03:00
Danila Poyarkov 2dc51375ad Release v0.13.2 2026-05-30 19:14:12 +03:00
Danila Poyarkov 2d4e2a7b10 Release v0.13.1 2026-05-30 01:12:58 +03:00
Danila Poyarkov 6de7cd3871 Release v0.13.0 2026-05-30 00:16:35 +03:00
Danila Poyarkov 7a433584cc Release v0.12.2 2026-05-19 18:10:25 +03:00
Danila Poyarkov 8fa34fb0b8 Release v0.12.1 2026-05-19 13:27:24 +03:00
Danila Poyarkov 79583056a5 fix(tauri): refresh updater signing key 2026-05-18 23:23:20 +03:00
Danila Poyarkov 3012d0d36b fix(tauri): compile release builds 2026-05-18 22:30:58 +03:00
Danila Poyarkov 682160b75b Release v0.12.0 2026-05-18 21:06:06 +03:00
Danila Poyarkov 1c8fe1ee8b feat(editor): add outline stroke command 2026-05-17 20:18:14 +03:00
Danila Poyarkov d927a2b443 feat(text): share outline conversion for paths 2026-05-17 19:45:39 +03:00
Danila Poyarkov dc93ec54c5 feat(editor): add flatten selection command 2026-05-17 18:27:54 +03:00
Danila Poyarkov 83c24925e8 feat(editor): add boolean operation commands 2026-05-17 17:33:26 +03:00
Danila Poyarkov 2154bb09a2 fix(app): align paste to replace menu label 2026-05-17 16:13:25 +03:00
Danila Poyarkov bdbb37b092 feat(editor): add paste to replace 2026-05-17 16:05:28 +03:00
Danila Poyarkov 4a37a5e534 feat(editor): add frame selection command 2026-05-17 15:52:20 +03:00
Danila Poyarkov 0da23d5526 refactor(app): derive command menu shortcuts 2026-05-17 15:07:14 +03:00
Danila Poyarkov 75d1726640 test(app): cover menu shortcut conversion 2026-05-17 15:02:42 +03:00
Danila Poyarkov 38d30e25e0 refactor(app): derive menu shortcut formats 2026-05-17 14:50:43 +03:00
Danila Poyarkov 4bf161b983 fix(components): sync instances when switching variants
- Swap instance contents when changing variants instead of only updating componentId
- Recreate instance redo state without stale child IDs
- Insert assets into entered containers using local coordinates
- Fall back to Windows paths when URL parsing fails
2026-05-12 18:43:11 +03:00
Danila Poyarkov ddf415ec30 feat(tauri): support desktop file associations
- Register .fig and .pen files with desktop bundles
- Open associated files on startup and via single-instance handoff
- Reuse the existing Tauri file open flow without broad filesystem scopes
2026-05-12 16:12:16 +03:00
Danila Poyarkov dac6f171e3 feat(app): add font cache management hooks 2026-05-05 21:50:31 +03:00
Danila Poyarkov b248e0c53a feat(tauri): add signed updater 2026-05-01 13:00:50 +03:00
Danila Poyarkov f7b3f2de75 build(tauri): generate native menu before builds 2026-04-30 16:07:14 +03:00
Danila Poyarkov 28d67818e2 refactor(app): share browser and tauri menu model 2026-04-30 16:01:47 +03:00
Danila Poyarkov 0d16354c89 feat(app): add light theme setting 2026-04-30 15:52:59 +03:00
Danila Poyarkov 6545f20c53
Refactor architecture boundaries across core, app, and packages (#234)
* refactor(core): decompose editor factory and action modules

Split the monolithic editor factory and large action modules into focused
domain helpers:

- create.ts assembles context through bridge modules (clipboard,
  components, structure, undo) and delegates to graph-reads, graph-events,
  layout-runner, component-sync, and state factory
- structure.ts delegates to group, container-wrap, auto-layout-wrap,
  reorder, and state-toggle helpers
- selection.ts delegates to hit-test, overlays, container navigation,
  and read helpers
- clipboard.ts delegates to subtree-history, images, export, copy,
  fonts, and placement helpers
- shapes.ts delegates to pen actions and section-adopt
- components.ts delegates to focus and instances helpers
- alignment.ts delegates to flip-rotate helper
- text.ts uses explicit TextEditSession for snapshot comparison

New focused modules: nudge, variable-bindings, layout-mode,
page-viewports, tool-registry, color-space

Undo: history/position and history/snapshot helpers, hardened
batch/rollback with nested batch support and configurable limit

* refactor(core): split tool definitions by domain

Split the monolithic tool registry into domain-specific modules:

- read/ — selection, find, pages, fonts, components, nodes, query, jsx
- create/ — basic shapes, components, vector, JSX render
- modify/ — paint, effects, geometry, layout, state, text, update
- structure/ — basic, arrange, batch, hierarchy, replace, tree
- variables/ — bindings, collections, read, values
- vector/ — boolean, path, export, viewport
- analyze/ — colors, typography, spacing, clusters, diff, eval
- describe/ — summaries, tree, roles, layout-issues
- stock-photo/ — providers, requests, apply
- codegen/ — component-map, tokens

Split registry into core/extended tiers; refine schema and AI adapter

* refactor(core): restructure kiwi codec and instance overrides

Reorganize the Kiwi .fig codec into domain subdirectories:

- binary/ — codec, schema, protocol
- fig/ — file, import, parse (core, worker, transfer)
- node-change/ — convert, export-node, serialize, plugin-data
- instance-overrides/ — constraints, dsd, populate, props, resolve,
  symbol-overrides, symbol-props, sync, types

Vendored kiwi-schema/ left isolated

* refactor(core): split profiler, icons, IO, and add subpath exports

Profiler: speedscope-export, capture-session, hud-controller
Icons: api, svg, types, render, create-icons tool
IO: format registry and subpath exports
Canvas/color/text/vector: targeted cleanup

Add deliberate subpath exports: random, xpath, vector, color, canvas,
scene-graph, kiwi, design-jsx, io, tools, editor, layout, canvaskit,
profiler, text, lint, rpc, figma-api, constants

* refactor(vue): decompose canvas input, surface lifecycle, and controls

Canvas surface: gl-surface, kit-loader, render-loop, resize-observer

Canvas input handlers:
- move: drop-target, move-snap, duplicate-drag
- select: select-move, select-hover, select-hit
- resize: resize-rect, resize-vector, resize-start
- transform: rotation, marquee, pan, text-selection
- text-edit: navigation, clipboard, textarea lifecycle
- Shared: click-count, space-key, pan, pan-zoom, draw, raf-scheduler

Editor composition:
- commands split: actions, context, metadata, edit, selection, view
- menu-model split: command-groups, builders, types
- Gradient stop composable reuse in primitive root

Controls: fill, layout, typography, appearance, effects, stroke,
okhcl, prop-scrub, node-props, undo-batch, color-variable-binding
Variables/i18n/document/export helpers

Organize canvas, primitives, controls, editor, and variables into
cohesive module directories with package-local import aliases

Expose MenuActionNode/MenuSeparatorNode from public API

* refactor(app): split document IO, editor session, and automation bridge

Document IO: source-state, naming, writer, reload-source, reload-state,
imported-document, watch-targets, save-targets

Editor session: create, modules, types, accessors, computed, refs
Editor canvas: loader-overlay, collaboration-awareness,
context-selection, menu-actions, menu-model

Automation bridge: eval, tools, exports, files, selection, RPC fallback

AI/ACP: transport, map-update, permission, debug, chat effects/storage
Collab: awareness, graph-bindings, yjs-sync, follow, session, types
Shell keyboard: actions, bindings, clipboard, focus, nudging,
raw-events, registry, reserved, shortcuts, space-tool
Shell menu: app-menu, document-name, entry, files

Demo: colors, effects, helpers, section builders (components,
app-preview, effects, standalone, variables) — document.ts reduced
from 981 to 32 lines as pure orchestrator

Move app modules under src/app/ with organized domain structure:
editor, document, ai, collab, shell, automation, demo, tabs

* refactor(app): decompose UI components with provide/inject context

Split monolithic components using Reka UI-inspired namespace folders
with scoped provide/inject context — no prop drilling:

- CollabPanel/ — context, avatars, share, connected, join
- ColorPickerPanel/ — context, area, format, field groups, sliders
- MobileHud/ — context, action toast, tool badge, file menu, presence
- ProviderSettings/ — context, API key/type, endpoint, tokens, photos
- Toolbar/ — actions, types, desktop, mobile, tool button, flyout
- LayoutSection/ — types, auto-layout, flex, grid, padding, size, clip

Properties helpers: fill-okhcl adapter, fill-label, color-style-row
Menu: entry helpers, document-name rename, stale type removal

* refactor(mcp): split server into focused modules

- browser-rpc — WebSocket client management
- mcp-sessions — session lifecycle
- tool-output — response formatting
- tool-schema — Zod schema generation from ToolDefs
- jsx-preprocess — JSX source transformation
- result — result helpers
- tool-registration — MCP tool wiring
- auth — API key validation
- http-options — CORS/request handling
- stdio-bridge — stdio transport adapter

* refactor(cli): split analyze subcommands and shared helpers

- Analyze subcommands: clusters, colors, spacing, typography
- RPC data loading helper
- Migrate imports to targeted core subpath exports

* refactor(docs): split VitePress config and shared table component

Config helpers: sdk-sidebar, seo, labels, sidebars, locale-theme,
root-theme, locales

Shared SdkDataTable component replaces duplicated table markup in
SdkPropsTable, SdkEventsTable, and SdkSlotsTable

Update contributing and testing docs

* refactor(tauri): decompose desktop entrypoint

Split lib.rs into focused service modules:

- fig_container.rs — .fig archive/compression commands
- fonts.rs — font cache and system font enumeration
- menu.rs — native menu construction
- menu_events.rs — menu event dispatch and devtools toggle
- window.rs — main window show/focus lifecycle

* test: share domain test factories and migrate fixtures

New shared helpers:
- tests/helpers/scene.ts — makeSceneGraph factory
- tests/helpers/vector-network.ts — vertex/segment/network builders
- tests/helpers/fig-traversal.ts — all-node collection, type counts
- tests/helpers/undo.ts — undo test utilities
- tests/helpers/editor-history.ts — editor history test helpers

Migrate render, vector, fig-roundtrip, and undo tests to use shared
factories instead of inline fixture construction

* build: add structural lint rules, split vite config, update docs

Structural lint (oxlint.structure.json + lint/plugin.js):
- 20+ custom rules enforcing package boundaries, lifecycle patterns,
  naming conventions, and import discipline

Vite config split: raw-markdown, canvaskit-assets, pwa, server,
aliases, automation plugins

Remove legacy shims and utils superseded by SDK/core modules
Update AGENTS.md, CONTRIBUTING.md, eval-command docs, tsconfig

* fix(vue): normalize canvas directory casing and remove duplicate export

- Rename Canvas/ to canvas/ in git index to match #vue/canvas/* imports
  (PascalCase was correct for component primitives but canvas/ is a
  non-component domain directory)
- Remove duplicate ./random subpath export in core package.json

* fix: add #vue and #core Vite resolve aliases for dev server

* refactor(core): reduce remaining large modules

Split the remaining large core hotspots into cohesive domain modules while preserving public facades and behavior.

- Extract scene graph types, variables, node defaults, and vector-network helpers
- Decompose canvas renderer orchestration, state, paints, colors, lifecycle, labels, and delegated domain methods into renderer/ and labels/ subfolders
- Split Kiwi node-change, binary variable binding, layout, RPC, vector, JSX export, clipboard, design JSX, and Figma proxy helpers
- Replace collision-driven *Fn import aliases with namespace imports and enforce the pattern in lint

Validation:
- bun run check
- bun --filter @open-pencil/vue build
- bun run test:dupes

* fix(app): forward color input attrs

* fix(app): cover section drawing errors

* fix(editor): undo option-drag duplicates

* docs: document domain subfolder convention

* fix(app): handle undo redo on keydown

* refactor(app): dispatch shortcuts from keydown

* refactor: group prefixed domain modules

* refactor(app): use tinykeys for shortcuts

* refactor(core): group symbol override modules

* refactor(core): group fig kiwi container helper

* refactor(canvas): split overlay rendering modules

* refactor(vue): remove unused internal barrels

* fix(app): lay out demo components before instancing

* fix(app): restore demo badge spacing

* perf(canvas): split scene and overlay rendering

* refactor(vue): wrap wheel gesture lifecycle

* fix(canvas): wait for fonts before hiding loader

* docs: update unreleased changelog
2026-04-30 15:14:19 +03:00
Danila Poyarkov d5b63682c4 chore: commit Cargo.lock with fix-path-env dependency 2026-04-23 20:07:12 +03:00
Danila Poyarkov ba414e1af7 Release v0.11.8 2026-04-23 16:15:37 +03:00
Danila Poyarkov 8c643298f3 Revert "debug: add MCP spawn logging, revert cmd approach"
This reverts commit 663e1018e7.
2026-04-23 14:05:19 +03:00
Danila Poyarkov 663e1018e7 debug: add MCP spawn logging, revert cmd approach 2026-04-23 13:58:53 +03:00
Danila Poyarkov fbf582a493 fix(tauri): fix MCP server spawn on Windows and PATH on macOS
- Windows: npm installs .cmd wrappers, not direct executables. Spawn
  via 'cmd /c openpencil-mcp-http' on Windows to resolve .cmd files.
- macOS/Linux: add fix-path-env-rs to inherit shell PATH in GUI apps.
- Add 'cmd' to shell spawn capabilities for Windows.

Fixes #226
2026-04-23 13:20:58 +03:00
Danila Poyarkov 1f073859c9 fix(tauri): fix PATH not inherited by GUI app on macOS/Linux
macOS GUI apps don't inherit shell PATH from .bashrc/.zshrc, so
openpencil-mcp-http installed via bun/npm/nvm couldn't be found.
Added fix-path-env-rs which reads /etc/paths and shell config
to populate PATH before spawning child processes.

Fixes #226
2026-04-23 11:57:38 +03:00
Danila Poyarkov f3dbf2c271 Release v0.11.7 2026-04-22 20:31:33 +03:00
Danila Poyarkov b502b43c4d feat(mcp): add open_file, new_document tools and disk export via path param
- open_file: opens a .fig/.pen from disk into a new tab via MCP
- new_document: creates an empty doc with optional save path
- export_image, export_svg, get_jsx: optional path param writes output
  to disk instead of returning base64/string (avoids flooding AI context)
- OPENPENCIL_MCP_ROOT env var scopes all file paths (defaults to cwd)
- setPlannedFilePath + startWatchingCurrentFile on editor store
- Extract openFileFromPath helper in use-menu.ts
- Add fs:allow-mkdir and scoped fs:allow-watch Tauri capabilities
- Better 'app not connected' error in stdio — instructs agent to stop

Co-authored-by: Jais Pedersen <jais@pedersens.net>
2026-04-22 17:05:54 +03:00
Joseph Cumines c38223a700
fix(tauri): correctly configure NSAllowsLocalNetworking
Fixes #213
2026-04-22 13:01:38 +03:00
Danila Poyarkov 837c09bd78 fix(tauri): ATS exception for localhost WebSocket on macOS
Allow insecure localhost connections via NSAllowsLocalNetworking so the
WebSocket bridge works in release builds on macOS.

Also add debug logging for WebSocket and MCP health check failures.

Closes #190
Co-authored-by: Anton Soldatov <sld0Ant@users.noreply.github.com>
2026-04-15 13:16:29 +03:00
Danila Poyarkov cd4e1a2271 feat(mcp): add stdio transport for Claude Code / Cursor
- Add packages/mcp/src/stdio.ts — proper stdio MCP server that
  connects to the running app via WebSocket
- openpencil-mcp bin now points to stdio entry (was HTTP)
- openpencil-mcp-http bin added for the HTTP server
- Extract registerTools() from server.ts to share between transports
- Move index.ts banner output to stderr (prevents stdout corruption)
- Update Tauri shell spawn to use openpencil-mcp-http
- Update all docs (EN + 6 translations): correct binary names, source
  paths, port number

Fixes #194
2026-04-13 11:51:01 +03:00
Danila Poyarkov f8f4af5937 Release v0.11.6 2026-04-08 22:04:22 +03:00
Danila Poyarkov 2c3191cf96 Release v0.11.5 2026-04-08 21:38:44 +03:00
Danila Poyarkov 26a7d2d454 Release v0.11.4 2026-04-08 20:52:09 +03:00
Danila Poyarkov a20d170956 Release v0.11.3 2026-04-08 16:06:37 +03:00
Danila Poyarkov 33d293b221 Release v0.11.2 2026-03-30 18:38:36 +03:00
Danila Poyarkov 9be3514f2b Release v0.11.1 2026-03-30 17:24:00 +03:00
Danila Poyarkov 911bed3ede Release v0.11.0 2026-03-30 16:48:27 +03:00