Commit graph

660 commits

Author SHA1 Message Date
Danila Poyarkov b6c922e335 Fix all code review issues in RPC bridge
Bugs fixed:
- Export response now wrapped in {ok, result} like all other commands
- btoa(String.fromCharCode(...data)) replaced with loop to avoid
  RangeError on large images
- JSX export uses dedicated export_jsx RPC command instead of eval
  with undefined selectionToJSX reference

Issues fixed:
- connectAutomation cleanup on component unmount via onUnmounted
- Bridge state encapsulated in startAutomationBridge closure instead
  of module-level lets
- Previous browser WS closed on new connection to prevent leaks
- walkNodes returns boolean for early termination, find stops at limit
- Unused imports removed from node.ts (fmtList, nodeToData)
- Hand-rolled hex in node.ts replaced with colorToHex from core
- makeFigmaFromStore extracted to shared figma-factory.ts, used by
  both ai/tools.ts and automation/server.ts
- Unused limit param removed from AnalyzeColorsArgs
- Unused groupBy param removed from AnalyzeTypographyArgs
2026-03-07 20:42:37 +03:00
Danila Poyarkov c9e755a181 Fix RPC bridge response unwrapping and export
- Bridge was double-wrapping responses ({ok, result: {ok, base64}}) — now
  forwards the server's payload directly, stripping only type/id fields
- Compute layouts after mutations so auto-layout frames position correctly
- Export createElement and resolveToTree from core for bridge JSX transform
- Fix package.json exports: remove node condition that pointed to non-existent
  dist/, use publishConfig.exports for npm consumers
2026-03-07 20:27:57 +03:00
Danila Poyarkov 1f04926166 Compute layouts after mutating automation commands
renderTreeNode and mutating tools create auto-layout frames but didn't
trigger Yoga layout computation, leaving children stacked at (0,0).
Call computeAllLayouts after mutations so frames size and position correctly.
2026-03-07 20:18:59 +03:00
Danila Poyarkov 70c25cddf5 Fix render tool in automation: use ssrLoadModule for JSX transform
The render tool needs esbuild to transform JSX → createElement calls, but
esbuild only runs in Node, not in the browser where the automation server
executes commands. The bridge now:

1. Intercepts render tool calls with JSX
2. Uses Vite's ssrLoadModule to import @open-pencil/core (handles TS source)
3. Transforms JSX → tree on the Node side via buildComponent + resolveToTree
4. Sends the tree to the browser which calls renderTreeNode directly

Also fixes @open-pencil/core exports: remove "node" condition that pointed
to non-existent dist/ during development. Published consumers get dist/ via
publishConfig.exports override.
2026-03-07 20:16:52 +03:00
Danila Poyarkov 39af21ff06 Pre-process render JSX in bridge where esbuild is available
The render tool needs esbuild to transform JSX, but esbuild only runs in
Node — not in the browser where the automation server executes. The bridge
now intercepts render tool calls, converts JSX to a tree on the Node side
using buildComponent + resolveToTree from core, and sends the tree to the
browser which calls renderTreeNode directly.

Also exports createElement and resolveToTree from core for bridge use.
2026-03-07 20:10:48 +03:00
Anton A S 513e0b6f4a Add SEO: OG tags, Twitter Card, hreflang, JSON-LD, sitemap
- config.ts: og:site_name, og:image (+w/h/alt), twitter:card/site/image
- config.ts: transformPageData — per-page canonical, og:url, og:locale,
  og:locale:alternate, hreflang for all 6 locales + x-default,
  og:title/description and twitter:title/description from frontmatter
- config.ts: sitemap with xhtml:link alternates for all 174 pages × 6 locales
- SchemaOrg.vue: SoftwareApplication JSON-LD on EN homepage only
- HomeLayout.vue: render SchemaOrg in home-features-after slot
- index.md + de/fr/es/it/pl index.md: add translated title to frontmatter
2026-03-07 19:49:24 +03:00
Danila Poyarkov 2a9d47a761 Fix Vite build: import constants via relative path for esbuild compat
bridge.ts is bundled by esbuild as a Vite plugin — it can't resolve
workspace package entries (@open-pencil/core) at config time because
dist/ is not built yet. Use relative import to the source file instead.
2026-03-07 19:49:09 +03:00
Anton A S 940d0de5b6 Sync docs with v0.7.0 and unreleased features
- Update comparison tables: 78 tools (was 75), SVG export no longer a Penpot advantage,
  renderer LOC updated to ~3,200 after split into 10 files
- Update figma-comparison: Rename layers , SVG export , +Copy/Paste as, +Tailwind export,
  +Stroke align, +per-side stroke weights; coverage 88/152 → 94/158
- Add What's Next roadmap to architecture.md: AI providers, figma-use tool set,
  CI tooling, prototyping, CSS Grid, PDF export, .fig fidelity
- Update user-guide: SVG in export format table, Copy/Paste as submenu,
  stroke align + per-side weights, layer inline rename, mobile drawer, Code tab format toggle
- Fix keyboard shortcuts: ⌘N/⌘T/⌘W , ⌘\ , add ⇧⌘C 
- Expand MCP tools reference from ~25 to all 78 tools in full category tables
- Add Homebrew tap install to Getting Started
- Add new features.md sections: SVG export, Copy/Paste as, stroke align, mobile/PWA,
  Tailwind JSX export, Google Fonts fallback, auto-save toggle, Homebrew tap,
  layer rename, renderer profiler
- Full locale sync for DE, ES, FR, IT, PL: all 7 files updated in each locale
2026-03-07 19:25:41 +03:00
Anton A S e828185d9e Merge branch 'master' into add-vitepress-docs 2026-03-07 19:01:09 +03:00
Danila Poyarkov 2ec382fc9d Fix RPC bridge review issues: centralize colors, ports, remove non-null assertions
- Use colorToHex/colorDistance from color.ts instead of hand-rolled hex math
  in rpc/commands.ts (removes toHex, hexToRgb, colorDistance duplicates)
- Extract AUTOMATION_HTTP_PORT/AUTOMATION_WS_PORT to core constants, import
  in bridge.ts, server.ts, app-client.ts instead of duplicating magic numbers
- Add requireFile() helper in app-client.ts, replace all file! non-null
  assertions across 12 CLI command files
- Document same-machine trust security model in bridge.ts header comment
- Replace (globalThis as any).Bun with typed isBunRuntime() helper
- Add changelog entry for CLI-to-app RPC bridge feature
2026-03-07 15:11:31 +03:00
Danila Poyarkov 99365384df Merge remote-tracking branch 'origin/master' into fix-cli-rpc
# Conflicts:
#	packages/core/src/index.ts
2026-03-07 15:03:40 +03:00
Danila Poyarkov 72cbd195ac Trim internal refactor details from changelog 2026-03-07 14:56:35 +03:00
Danila Poyarkov 898932d5d7 Update changelog with reka-vueuse refactor 2026-03-07 14:55:24 +03:00
Danila Poyarkov 97baef474d Merge branch 'reka-vueuse-refactor' 2026-03-07 14:46:40 +03:00
Danila Poyarkov 7cdb1d1eaa Replace Bun.serve with Hono + ws for Node.js compatibility
Bridge now uses Hono for the HTTP server and ws for WebSocket —
works on both Bun and Node.js. Uses @hono/node-server as fallback
when Bun runtime is not available.
2026-03-07 14:30:12 +03:00
Danila Poyarkov 3684caea87 Fix duplicate :class, rename race, useFileDialog leak, restore clip/wrap 2026-03-07 14:27:17 +03:00
Danila Poyarkov 19fb22c267 Update changelog with refactor batch 1 2026-03-07 13:48:25 +03:00
Danila Poyarkov 14b796a40d Add 8 E2E test suites for release sanity coverage
83 new tests across 8 files:
- design-panel: selection → properties panel, fill/stroke/effect add, visibility toggle, multi-select
- code-panel: JSX output, OpenPencil/Tailwind toggle, copy button, empty state
- components: create component (⌘⌥K), create instance, propagation, detach
- copy-paste: store copy/paste, ⌘D duplicate, cut, multi-select duplicate
- multi-page: add/switch/delete pages, rename, last-page protection
- text-editing: text tool, text node creation, typography section, frame tool
- keyboard-shortcuts: all 9 tool keys, ⌘A/Escape/Backspace, ]/[, ⌘G/⌘⇧G, ⌘\, ⌘Z/⌘⇧Z
- context-menu: right-click items, duplicate/visibility/lock/delete/group/component, Copy as submenu
2026-03-07 13:23:32 +03:00
Danila Poyarkov 7fbe21c8e1 Fix flaky E2E tests: layers panel, zoom-to-fit, snapshot stability
- layers-panel: navigate to /demo so demo layers exist
- app-menu zoom-to-fit: zoom in first so zoom-to-fit has something to change
- playwright.config: force workers=1 and colorScheme=dark for consistent
  WebGL/SwiftShader snapshot rendering across runs
- Update empty-canvas snapshot for current dark-mode canvas appearance
2026-03-07 11:08:22 +03:00
Danila Poyarkov bd5cdc8eee Centralize all color utilities in color.ts
- Add colorToHex8 (hex with alpha via culori formatHex8)
- Add colorToCSSCompact (no-space rgba for Tailwind shadow classes)
- Add normalizeColor (partial Color → full Color with defaults)
- Add colorDistance (Euclidean RGB via culori differenceEuclidean)
- Replace colorToCSS body with culori formatRgb
- Change rgba255ToColor to positional args (r, g, b, a)
- Remove duplicate formatColor from svg-export.ts and export-jsx.ts
- Remove duplicate colorDistance from tools/analyze.ts
- Remove duplicate convertColor from kiwi/kiwi-convert.ts
- Replace hand-rolled hex+alpha in HsvColorArea.vue with colorToHex8
- Replace hand-rolled rgba255→Color in HsvColorArea.vue with rgba255ToColor
- Expand color.test.ts from 16 to 34 tests
2026-03-07 10:02:11 +03:00
Danila Poyarkov 9784544f1f Clean up tools/schema, add geometry.ts, isMixed helper, fix imports, add tests
- Strip tools/schema.ts from 1831 to 65 lines (remove duplicate tool defs)
- Fix tools/index.ts to export ALL_TOOLS from registry instead of schema
- Fix renderJsx → renderJSX typo in tools/create.ts and structure.ts
- Add geometry.ts with shared rotation/coordinate math utilities
- Add isArrayMixed() helper to use-multi-props.ts, deduplicate FillSection/StrokeSection/EffectsSection
- Fix broken test imports: use @open-pencil/core instead of relative paths into packages/core/src/
- Merge duplicate import statements across all test files
- Export profiler internals and style-run helpers from core index.ts
- Add 6 new test files: color, undo, snap, vector, style-runs, text-editor (98 new tests)
- Update renderer-effects test for renderer/ directory split
2026-03-06 22:33:10 +03:00
Danila Poyarkov e7e5f53b57 Add CLI-to-app RPC bridge for live document access
- Extract shared RPC command handlers into packages/core/src/rpc/
  (info, pages, tree, find, node, variables, analyze colors/typography/spacing/clusters)
- Add automation bridge (src/automation/bridge.ts) that runs in Vite/Bun process,
  listens on localhost:7600 (HTTP) and :7601 (WebSocket)
- Add browser-side handler (src/automation/server.ts) that connects via WebSocket,
  executes commands against live EditorStore with requestRender()/flashNodes()
- Supports eval, tool execution, and image export via RPC
- Refactor all CLI commands: file arg is now optional — omit it to connect
  to the running app instead of loading a .fig file
- Bearer token auth generated per session, exposed via /health endpoint
- Vite plugin starts the bridge automatically during dev
2026-03-06 22:29:49 +03:00
Danila Poyarkov 859143149e Split renderer.ts into renderer/ directory 2026-03-06 22:25:59 +03:00
Danila Poyarkov 31326e8e5e Eliminate as Record<string, unknown> casts
- Add index signature to NodeChange for Kiwi codec fields
- Add blobs field to FigmaMessage
- Use 'in' type guards instead of Record casts in ai-adapter
- Use Object.fromEntries for Partial<SceneNode> property copying
- Use satisfies instead of as for handle position map
- Type node() to accept { children?: unknown; [key: string]: unknown }
- Remove ext() helper in kiwi-convert (direct property access)

37 occurrences → 1 (Kiwi codec boundary only).
2026-03-06 21:43:32 +03:00
Danila Poyarkov 4dc127f2d2 Configure oxfmt import sorting with proper groups
Replace experimentalSortImports with sortImports.
Groups: builtin → external → internal (@open-pencil/, @/).
Newlines between groups, alphabetical within.
2026-03-06 21:43:23 +03:00
Danila Poyarkov c33e4152df Fix PWA manifest error in dev, handle invalid font data
Remove hardcoded manifest link from index.html (VitePWA injects
it in production builds). Catch FontFace.load() rejections from
invalid font data with a warning.
2026-03-06 21:43:16 +03:00
Danila Poyarkov 07e9182b4c Move collab routing logic into CollabPanel
CollabPanel now uses injected collab + useRouter() directly.
No more emit relay through EditorView.
2026-03-06 21:43:10 +03:00
Danila Poyarkov b4698d7a63 Use colorToCSS() instead of hand-rolled rgba conversions
Fix colorToCSS to include alpha channel. Replace all manual
Math.round(c.r * 255) patterns with colorToCSS() from core.
2026-03-06 21:43:03 +03:00
Danila Poyarkov 9d73297040 Delete re-export shims, import from @open-pencil/core directly
Remove 14 src/engine/ shims and entire src/kiwi/ directory.
Only src/engine/fonts.ts remains (has real Tauri font logic).
Replace isTauri() with IS_TAURI constant.
2026-03-06 21:42:56 +03:00
Danila Poyarkov 6ec8fc518b Move demo to /demo route, add @unhead/vue for title management
- / shows empty canvas
- /demo loads demo content (for app.openpencil.dev landing link)
- Title template: '{page} — OpenPencil' via useHead
- 'Try it online' links in README and docs point to /demo
2026-03-06 20:54:48 +03:00
Danila Poyarkov 3ed9ccbe3f Merge master into reka-vueuse-refactor 2026-03-06 19:40:20 +03:00
Danila Poyarkov 30cbba22aa Extract shared surface, button, and select styles 2026-03-06 19:36:36 +03:00
Danila Poyarkov bdb95a9d31 Refine breakpoint and rename patterns 2026-03-06 19:32:14 +03:00
Danila Poyarkov 35dc5bd2a5 Extract menu styling with tailwind-variants 2026-03-06 19:01:14 +03:00
Danila Poyarkov 2d58168ce0 Update changelog: add mobile/PWA, layer rename, drawer fix 2026-03-06 18:33:02 +03:00
Danila Poyarkov 23be8e3950 Fix missing parseColor and DEFAULT_SHADOW_COLOR imports in schema.ts 2026-03-06 18:29:53 +03:00
Danila Poyarkov a334a7f63c Refactor UI to use Reka & VueUse primitives 2026-03-06 18:28:40 +03:00
Danila Poyarkov df8e303498
Add Homebrew tap with auto-update workflow (#61) 2026-03-06 18:08:47 +03:00
Danila Poyarkov 5ae6234e40
Tailwind CSS v4 JSX export (#54)
* Add Tailwind CSS v4 JSX export format

- Add JSXFormat type ('openpencil' | 'tailwind') to sceneNodeToJSX/selectionToJSX
- Tailwind resolver (tailwind.ts): px→spacing (v4 multiplier), hex→color class,
  fontSize/fontWeight/borderRadius named lookups with arbitrary value fallback
- Export: FRAME→div, TEXT→p, SECTION→section, className with TW utility classes
- CLI: export --format jsx --style tailwind
- CodePanel: format toggle button (OpenPencil / Tailwind)
- Rename Jsx→JSX in all public APIs (sceneNodeToJSX, selectionToJSX, renderJSX, etc.)
- 29 new Tailwind export tests, all 43 export tests pass

* Extract escapeJSXText — replace nested ternary with entity map lookup

* Deduplicate export-jsx: extract shared padding, corner radius, and node context helpers

* Update changelog

* Tighten Tailwind JSX export fidelity
2026-03-06 18:04:11 +03:00
Danila Poyarkov 324e1460d6
Merge pull request #58 from open-pencil/rename-dblclick
Double-click to rename layers, shared useInlineRename composable
2026-03-06 15:18:05 +03:00
Danila Poyarkov bc52095138 Add double-click to rename layers, extract useInlineRename composable
- New useInlineRename composable: shared editing state, commit logic,
  and keyboard handling for inline rename across panels
- LayerTree: double-click a layer name to rename inline
- PagesPanel: refactored to use useInlineRename, removing duplicate code

Closes #57
2026-03-06 09:50:35 +03:00
Danila Poyarkov 6f31af44e9 Fix drawer animation: single spring transition, no jump on close
Use one constant spring (stiffness 800, damping 50) for both drag
tracking and snap animation. Eliminates the transition switch that
caused motion-v to reinitialize mid-animation. Extract spring
constants to constants.ts. Fix selectTab not updating targetHeight.
2026-03-06 09:22:03 +03:00
Danila Poyarkov a2d7b89709 Adopt motion-v for mobile drawer and toolbar animations
- MobileDrawer: spring-animated height via motion.div :animate + @pan,
  replaces useSwipe + manual rAF. Tab state always set (never null),
  content stays rendered when drawer is closed.
- Toolbar: AnimatePresence with directional slide variants and
  layout-animated width via motion.div layout, replaces manual
  scrollWidth measuring + inline CSS transitions.
- Add SWIPE_VELOCITY_THRESHOLD constant.
- activeRibbonTab type narrowed from union | null to union.
2026-03-06 08:50:38 +03:00
Danila Poyarkov 724e632251 Fix mobile drawer jump on swipe down
Reset dragOffset after snap change and a rAF so the height
transition starts before the translate snaps back to 0.
2026-03-06 00:14:28 +03:00
Danila Poyarkov 49b891d3f9 Refactor mobile drawer: use VueUse composables, unify panels
- Replace hand-rolled touch handlers with useSwipe
- Replace manual offsetHeight measurement with useElementSize
- Replace window.innerHeight with useWindowSize
- Merge MobileRibbon into MobileDrawer (unified bottom sheet)
- Match desktop layout: PagesPanel + Layers in same panel
- Add viewport-fit=cover for safe area insets
- Glassy HUD buttons with backdrop-blur
- Fix toolbar overflow on narrow viewports
- Remove MobileRibbon.vue, SWIPE_MAX_DURATION constant
2026-03-05 22:13:24 +03:00
Anton Soldatov 168c25c189
feat: mobile layout, PWA support (#27) (#27)
- Mobile-responsive editor with bottom drawer, ribbon nav, HUD overlay
- Touch support: single-finger tools, two-finger pinch-zoom
- PWA: manifest, service worker, installability
- Extract LayerTree from LayersPanel, shared utils (colorToCSS, initials, toolIcons)
- Constants moved to src/constants.ts, clipboard state to editor store
- reka-ui Popover/DropdownMenu in MobileHud

Co-authored-by: Danila Poyarkov <dev@dannote.net>
2026-03-05 19:51:51 +03:00
Danila Poyarkov 661b83e749 Port analyze/diff tools from figma-use, split tools into domain files
Analyze: colors, typography, spacing, clusters
Diff: diff_create (tree diff), diff_show (preview changes)
Utility: get_components, get_current_page, arrange, node_to_component

Split schema.ts (2600 lines) into read, create, modify, structure,
variables, vector, analyze, registry — each under 600 lines.

Clean up inline types (use Color, Vector, SceneNode from existing defs).
Update AGENTS.md and CONTRIBUTING.md with code quality guidelines.
2026-03-05 19:16:23 +03:00
Danila Poyarkov e7f827c0e3 Fix npm publish: remove manual .npmrc that overwrote setup-node auth 2026-03-05 10:58:55 +03:00
Danila Poyarkov c67c60a42c Fix Windows build: add shell: bash to contributor step 2026-03-05 10:44:32 +03:00
Danila Poyarkov be44b4d404 Release v0.7.0 2026-03-05 10:32:35 +03:00