Commit graph

182 commits

Author SHA1 Message Date
Danila Poyarkov 8c85d2b953 fix(canvas): improve Figma mask and text fidelity 2026-05-23 00:18:33 +03:00
Danila Poyarkov 3dc0904466 fix(canvas): support luminance masks and tile transforms 2026-05-22 23:44:10 +03:00
Danila Poyarkov 98616c8610 fix(canvas): render Figma-style corner smoothing 2026-05-22 23:05:24 +03:00
Danila Poyarkov 76ee122dee fix(canvas): render smoothed corners and effect blend modes 2026-05-22 22:50:58 +03:00
Danila Poyarkov 0ce57ea0fa fix(canvas): render Figma mask stacks 2026-05-22 21:05:35 +03:00
Danila Poyarkov 8e1d5d40e7 fix(canvas): render Figma blend modes 2026-05-22 21:00:34 +03:00
Danila Poyarkov 59f769e2ef docs: expand unreleased changelog 2026-05-21 15:01:33 +03:00
Danila Poyarkov dff56cff2f docs: update changelog 2026-05-21 14:57:58 +03:00
Danila Poyarkov 7a433584cc Release v0.12.2 2026-05-19 18:10:25 +03:00
Danila Poyarkov 8cb6d008fc fix(ai): allow custom OpenRouter models 2026-05-19 15:10:32 +03:00
Danila Poyarkov 8fa34fb0b8 Release v0.12.1 2026-05-19 13:27:24 +03:00
Danila Poyarkov 8fbc2939e3 fix(properties): keep effect controls visible 2026-05-19 13:20:47 +03:00
Danila Poyarkov 26fb9b6a0b fix(canvas): render background blur as backdrop 2026-05-19 13:07:46 +03:00
Danila Poyarkov 83af1453d8 fix(fonts): load Google font previews 2026-05-19 13:02:15 +03:00
Danila Poyarkov 682160b75b Release v0.12.0 2026-05-18 21:06:06 +03:00
Danila Poyarkov d442e9d6cb docs: update changelog 2026-05-18 20:30:10 +03:00
Danila Poyarkov a6050da061 docs: update unreleased changelog 2026-05-17 22:20:55 +03:00
Danila Poyarkov e7b610b228 docs: restore dropped user-facing changelog entries 2026-05-16 15:42:52 +03:00
Danila Poyarkov a33100b076 docs: tighten changelog for end users 2026-05-16 15:42:18 +03:00
Danila Poyarkov 9c5db24cf5 docs: update changelog for test and quality improvements 2026-05-16 15:40:06 +03:00
Danila Poyarkov ccc2b0a52c chore(release): polish asset labels and loaders 2026-05-13 03:44:11 +03:00
Danila Poyarkov 866cabd623 feat(kiwi): preserve component library metadata
- Import Figma component keys, library keys, publish/version IDs, descriptions, links, and variant specs
- Export verified component metadata back into NodeChange fields
- Use variantPropSpecs to derive component property values after component set imports
- Cover large fixture metadata import as heavy tests
2026-05-12 21:48:42 +03:00
Danila Poyarkov 24d3ea748f fix(components): respect default variants in assets
- Insert component set assets using explicit default variant values
- Report duplicate variant value combinations in the assets panel
- Cover default insertion and conflict warnings in Playwright
2026-05-12 18:16:51 +03:00
Danila Poyarkov 1ba9b3e697 docs: update changelog for fallback fonts 2026-05-12 17:47:26 +03:00
Danila Poyarkov 1ceabf7938 feat(components): add local assets panel
- Add a left-sidebar Assets tab for local components and component sets
- Insert component set assets as instances of the default variant
- Showcase local component set insertion in the demo
- Cover search, empty state, standalone insert, and variant switching with Playwright
2026-05-12 17:30:35 +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 98ce9a70ac docs: update changelog with variables and refactoring work 2026-05-07 11:41:52 +03:00
Danila Poyarkov 99d4cb8c3b docs: update changelog with variables and refactoring work 2026-05-07 10:38:37 +03:00
Danila Poyarkov 7dce333200 docs: document event bus and wire app consumers
- Update CHANGELOG.md with event bus, test restructuring, and lint hardening
- Document EditorEvents table and conventions in AGENTS.md
- Wire collab graph sync to editor event bus instead of SceneGraph.onNodeEvents
- Wire collab awareness zoom to viewport:changed instead of Vue watcher
- Wire collab selection broadcasting to selection:changed instead of Vue watcher
2026-05-06 15:38:45 +03:00
Danila Poyarkov 7f3eb532d8 fix(core): render gradient text fills
- Clip gradient paints through the shaped paragraph mask instead of reading only the paint color
- Cover the paragraph mask path and a headless red-to-blue text render

Fixes #246
2026-05-06 00:22:17 +03:00
Danila Poyarkov 0f9b69d051 test(app): expand Tauri helper coverage 2026-05-05 22:07:02 +03:00
Danila Poyarkov 768b527155 feat(core): add font fallback manifest 2026-05-05 21:35:12 +03:00
Danila Poyarkov 25ea361fd7
feat(app): cache downloaded fonts
- Add a downloaded font cache hook to FontManager
- Store Tauri font downloads under AppLocalData with manifest validation
- Prefer cached downloads before system font lookup on desktop
- Skip opt-in heavy .fig parsing tests in PR CI
2026-05-05 21:14:38 +03:00
Joseph Cumines c69e3884cf
fix(core): critical codec and canvas fixes
- Deduplicate plugin data and relaunch data during .fig parsing/export
- Unify shared plugin data into the pluginData storage path
- Refactor shadow rendering and harden CanvasKit font provider teardown
- Expand engine and renderer coverage
2026-05-05 14:58:02 +03:00
Danila Poyarkov ac15fb143b feat(io): add PDF export
Vector PDF output via jsPDF + svg2pdf.js (lazy-loaded, 124KB gzipped).
Reuses existing SVG export pipeline — text stays selectable, paths
stay sharp at any zoom.

- packages/core/src/io/formats/pdf/ — SVG→PDF conversion module
- export_pdf tool for MCP/AI
- PDF format in IO registry and app export panel
- CLI: bun open-pencil export file.fig --format pdf
2026-05-04 00:18:54 +03:00
Danila Poyarkov b9f3fc418e docs: update unreleased changelog 2026-05-03 23:22:04 +03:00
Danila Poyarkov 7199774177 feat(app): bind size fields to variables 2026-05-01 17:20:45 +03:00
Danila Poyarkov c7db8c6004 feat(app): add color variable binding picker 2026-05-01 17:11:50 +03:00
Danila Poyarkov b248e0c53a feat(tauri): add signed updater 2026-05-01 13:00:50 +03:00
Danila Poyarkov 2b3898aace docs: update unreleased changelog 2026-05-01 11:41:53 +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 121128038a docs: update changelog for fig fidelity fixes 2026-04-25 22:52:25 +03:00
Danila Poyarkov ba414e1af7 Release v0.11.8 2026-04-23 16:15:37 +03:00
Danila Poyarkov d25d80083b fix(vue): resolve unexported subpath import breaking npm consumers
- Export getAbsolutePositionFull from @open-pencil/core/canvas subpath
- Update vue import from @open-pencil/core/canvas/coordinate to @open-pencil/core/canvas
- Formatting fixes from oxfmt in pen/convert.ts, pen/read.ts, figma-factory.ts
2026-04-22 21:11:53 +03:00
Danila Poyarkov f3dbf2c271 Release v0.11.7 2026-04-22 20:31:33 +03:00
Danila Poyarkov 84c5e0dded docs: update changelog 2026-04-22 17:53:32 +03:00
Danila Poyarkov 5c0262fa80 docs: update changelog 2026-04-22 15:53:07 +03:00
Danila Poyarkov 125240aa1b docs: update changelog with unreleased changes 2026-04-22 13:48:39 +03:00
Anton Soldatov 7b5a5bdeef
fix(tauri): use opener plugin for external links instead of shell (#197)
External links (<a target="_blank">) in the AI panel triggered
"Command plugin:shell|open not allowed by ACL" on Tauri desktop.

Root cause: Tauri v2 intercepts <a target="_blank"> via the shell plugin,
but only the opener plugin had ACL permissions. Replace all external links
with programmatic openUrl() from @tauri-apps/plugin-opener, which is already
whitelisted via "opener:default" in capabilities.

- Extract openExternalLink() composable for Tauri/browser switch
- Replace <a target="_blank"> with <button @click> in ProviderSetup/Settings
- Add E2E test verifying window.open is called in browser context

Fixes #193

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-04-15 11:02:00 +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