Danila Poyarkov
96d8ab5789
Move docs to packages/docs, add Cloudflare Pages deploy
...
- Move docs/ → packages/docs/ as @open-pencil/docs workspace package
- Add screenshot.png as hero image on landing page
- Add GitHub Actions workflow for Cloudflare Pages deploy (openpencil.dev)
- Remove vitepress from root devDependencies
- Root docs:* scripts delegate via bun --filter
2026-03-01 15:16:16 +03:00
Anton A S
fbb397ad45
Merge remote-tracking branch 'origin/master' into add-vitepress-docs
2026-03-01 12:26:10 +03:00
Danila Poyarkov
c59d5fc397
Add Code tab with JSX export and syntax highlighting
...
- sceneNodeToJsx() in @open-pencil/core: converts SceneNode subtree to JSX
- CodePanel.vue with Prism.js highlighting, line numbers, copy button
- Third tab in properties panel: Design | Code | AI
- 14 new tests covering shapes, text, layout, effects, multi-selection
2026-03-01 12:12:45 +03:00
Anton A S
37e1ba1caa
Merge remote-tracking branch 'origin/master' into add-vitepress-docs
2026-03-01 11:56:06 +03:00
Danila Poyarkov
bf8636c677
Merge chat-panel: AI chat with OpenRouter, tool execution, model selector
2026-03-01 11:55:57 +03:00
Danila Poyarkov
f06631489f
Wire AI tools to editor store with valibot schemas
...
10 tools: create_shape, set_fill, set_stroke, update_node, set_layout,
delete_node, select_nodes, get_page_tree, get_selection, rename_node.
Uses @ai-sdk/valibot for schema integration with ToolLoopAgent.
2026-03-01 11:45:27 +03:00
Danila Poyarkov
f6434bc4f9
Fix chat reactivity (markRaw), add Playwright tests with mock transport
...
Use markRaw to prevent Vue from deep-proxying the Chat class
instance, which broke its internal Vue refs. Add dedent for
multiline prompts.
Tests use mock transport by default. Set TEST_REAL_LLM=1 and
OPENROUTER_API_KEY to run against real OpenRouter.
2026-03-01 11:30:30 +03:00
Danila Poyarkov
2145af5280
Use reka-ui Tabs/ScrollArea/Collapsible/Tooltip, tw-animate-css, vue-stream-markdown
2026-03-01 11:03:51 +03:00
Danila Poyarkov
46bb9230d3
Add jscpd for copy-paste detection
2026-03-01 10:49:09 +03:00
Danila Poyarkov
13f562adc6
JSX renderer in @open-pencil/core
...
TreeNode builder functions (Frame, Text, Rectangle, etc.) produce a
lightweight tree structure. Two rendering paths:
- renderTreeNode(): tree → scene graph (browser, no deps)
- renderJsx(): JSX string → esbuild → tree → scene graph (CLI/headless)
Tailwind-like shorthand props: w/h, bg, rounded, flex, gap, p/px/py,
justify, items, shadow, blur, etc.
27 tests covering all node types, layout props, effects, and nesting.
2026-03-01 10:42:06 +03:00
Danila Poyarkov
5d23c3e834
AI chat panel with ⌘J toggle, DirectChatTransport, OpenRouter
...
- ChatPanel.vue: message list, tool timeline, typing indicator, API key setup
- use-chat.ts: Chat + DirectChatTransport + ToolLoopAgent (no backend)
- App.vue: toggle between PropertiesPanel and ChatPanel in same splitter slot
- ⌘J keyboard shortcut to open/close chat
2026-03-01 10:31:57 +03:00
Danila Poyarkov
f1806f6f33
Add test:coverage script
2026-03-01 10:19:38 +03:00
Anton A S
384c66f5b2
Merge remote-tracking branch 'origin/master' into add-vitepress-docs
2026-03-01 09:35:02 +03:00
Anton A S
adea7eb645
Sync specs & docs: variables, image export, CLI, core extraction
...
- Update specs: scene-graph (variables/collections/modes/bindings/.fig import),
editor-ui (VariablesPanel, ExportSection, splash), canvas-rendering
(variable resolution, image export, sceneVersion/renderVersion),
desktop-app (monorepo), tooling (Bun workspace), testing (variable tests)
- Create cli spec: info, tree, find, export commands
- Update docs: features, figma-comparison (79/150), roadmap (Phase 4 ✅ ,
Phase 5 🟡 ), keyboard-shortcuts (⇧⌘E), contributing (monorepo structure)
- Restore vitepress devDependency lost during merge
- Archive sync-variables-export-cli change
2026-03-01 02:17:48 +03:00
Danila Poyarkov
52a31cff2f
Use TanStack Table for variables dialog with resizable columns
...
Replace hand-rolled flex layout with @tanstack/vue-table:
- Proper <table> with column resizing (drag header borders)
- Sticky header row
- FlexRender for cell content (reka-ui Editable inline editing)
- Use culori via parseColor instead of manual hex parsing
2026-03-01 02:12:19 +03:00
Danila Poyarkov
33435cc1d1
Make CLI available as bun open-pencil in workspace
2026-03-01 01:21:29 +03:00
Danila Poyarkov
6d1cec1606
Extract @open-pencil/core package
...
Move engine (scene-graph, renderer, layout, codec, kiwi) into
packages/core/ as a Bun workspace package. The app's src/engine/
files become thin re-export shims so all existing imports still work.
- Bun workspace with packages/core
- Zero DOM dependencies in core
- Headless-friendly CanvasKit init (locateFile option)
- Constants split: engine constants in core, UI constants in app
- All 76 unit tests pass, lint + typecheck clean, vite build works
2026-03-01 01:03:07 +03:00
Danila Poyarkov
495e419e79
Zstd compression via Tauri Rust command, deflate fallback for browser
...
- Added zstd crate to Rust deps and zstd_compress Tauri command
- Export uses native Zstd in Tauri, deflate in browser (our reader
handles both)
- Removed zstd-wasm dependency (decompress-only, didn't work)
2026-02-28 14:56:06 +03:00
Danila Poyarkov
197323162f
Fix .fig export: Zstd compression, IS_TAURI constant, fs permissions
...
- Replace deflate with Zstd compression via zstd-wasm for .fig export
(Figma expects Zstd, not zlib deflate)
- Extract IS_TAURI constant from repeated window check
- Fix Tauri fs permissions: use allow-write-file / allow-read-file
with glob scope instead of bare allow-write / allow-read
2026-02-28 14:48:22 +03:00
Danila Poyarkov
8d3d3444ad
Tauri native dialog for Save/Open with fs plugin
2026-02-28 13:54:21 +03:00
Danila Poyarkov
159ee6b7c9
Fix production build type errors
2026-02-28 11:37:02 +03:00
Danila Poyarkov
bcd8bf6bca
Add IconsResolver for auto-import, explicit imports only for dynamic maps
2026-02-28 08:29:39 +03:00
Danila Poyarkov
3ddc671bc5
Replace emoji icons with Lucide via Iconify (unplugin-icons)
...
- unplugin-icons + @iconify-json/lucide for compile-time icon bundling
- Toolbar: proper cursor, frame, square, pen, type, hand icons
- Layers panel: per-type node icons + chevron-right for expand/collapse
- Remove icon field from ToolDef (icons mapped in components)
2026-02-28 08:24:42 +03:00
Danila Poyarkov
f0d817c747
Refactor: vendor kiwi-schema, extract types/constants, culori colors
...
- Fork kiwi-schema from source TypeScript (evanw/kiwi), drop npm dep + patch
- Deduplicate GUID/Color types into src/types.ts
- Extract UI colors and default fills into src/constants.ts
- Replace hand-rolled hex parsing with culori library
- Extract demo shapes from App.vue into src/demo.ts
- useUrlSearchParams from VueUse for test mode detection
- Move fig-file/fig-import into kiwi/ (format layer)
- Delete PoC files (poc-yoga.ts, poc-test.ts)
2026-02-28 08:08:04 +03:00
Danila Poyarkov
e03a01dbe3
Add bun:test unit tests for SceneGraph (15ms)
2026-02-28 07:45:50 +03:00
Danila Poyarkov
40f7b3a648
Playwright visual regression testing with Figma CDP reference
...
- Playwright E2E tests for OpenPencil: draw, move, delete, undo shapes
- Visual screenshot baselines with toHaveScreenshot()
- SwiftShader for headless WebGL/CanvasKit rendering
- Figma CDP helper for reference tests (connect to Figma Desktop)
- ?test URL param for clean canvas without demo shapes
- Scripts: test, test:update, test:figma, figma:debug
2026-02-28 07:32:15 +03:00
Danila Poyarkov
509dd4fab4
Migrate to Tailwind CSS 4.2
...
- @tailwindcss/vite plugin for zero-config build
- @theme tokens: panel, canvas, border, hover, accent, surface, muted, input
- All scoped CSS replaced with Tailwind utility classes
- Only remaining scoped CSS: ColorPicker range slider thumbs
- Removed conflicting * { padding: 0 } reset (Tailwind preflight handles it)
2026-02-28 00:54:38 +03:00
Danila Poyarkov
859afdce45
Add .fig file import (Kiwi codec → scene graph)
...
File parser:
- .fig files are ZIP archives with Kiwi-encoded canvas data
- Detects canvas blob by name (canvas.fig) or largest binary entry
- Decodes Kiwi Message → NodeChange[] → SceneGraph
Node conversion:
- Maps Figma types to OpenPencil types (COMPONENT → FRAME, etc.)
- Extracts position from transform matrix (m02, m12)
- Extracts rotation from transform matrix (atan2)
- Converts fillPaints/strokePaints to Fill[]/Stroke[]
- Converts effects (shadows, blurs)
- Handles independent corner radii
- Preserves text properties (font, size, alignment, spacing)
- Builds parent-child tree from parentIndex GUIDs
- Sorts children by parentIndex.position
Browser compatibility:
- fzstd for Zstd decompression (replaces Bun.zstd*)
- fflate for ZIP extraction
- Cmd+O opens file dialog for .fig files
- UndoManager.clear() for resetting on file open
2026-02-27 23:01:35 +03:00
Danila Poyarkov
323a1f90c4
Migrate React → Vue 3 + VueUse + Reka UI
...
- Vue 3 SFC components with <script setup>
- Reactive store (Vue reactivity) replacing React refs/state
- Composables: useCanvas, useCanvasInput, useKeyboard
- Components: EditorCanvas, LayersPanel, PropertiesPanel, Toolbar
- Floating toolbar (Figma UI3 style) with pill shape + shadow
- Properties panel with Design/Prototype tabs + zoom display
- Sections: Position, Rotation, Layout, Appearance, Fill, Stroke, Effects, Export
- CSS custom properties for theming (--panel-bg, --border, --accent, etc.)
- Add Figma UI3 CDP inspection findings (toolbar, panels, sections)
2026-02-27 21:25:31 +03:00
Danila Poyarkov
ec90f35df8
PoC 2 & 3: Yoga WASM layout + Kiwi codec
...
Yoga WASM (yoga-layout v3.2.1):
- Vertical/horizontal auto-layout with gap, padding, alignment ✅
- Nested frames with flex-grow ✅
- Space-between distribution ✅
- 1000-node layout in 3ms ✅
Kiwi binary codec (from figma-use multiplayer module):
- 194-definition Figma schema (2178 lines) compiles in 6ms
- Encode 4 nodes → 237 bytes Zstd-compressed
- Full round-trip: encode → Zstd compress → decompress → decode ✅
- Patch kiwi-schema to allow sparse field IDs (Figma uses IDs > 312)
Extracted files: schema.ts, codec.ts, protocol.ts, client.ts, index.ts
2026-02-27 17:16:21 +03:00
Danila Poyarkov
c123dad50c
Add oxlint, oxfmt, typescript-go
...
- oxlint with react, react-hooks, typescript, import, unicorn plugins
- oxfmt (no trailing commas, single quotes, sorted imports)
- tsgo (typescript-go native preview) for fast typechecking
- Fix all lint warnings: non-null assertions, unused expressions, stale closures
- Scripts: lint, format, typecheck, check
2026-02-27 15:52:55 +03:00
Danila Poyarkov
68b54ad6b7
Initial commit: Tauri + CanvasKit + React editor scaffold
...
- Tauri v2 desktop shell with 1280x800 window
- CanvasKit WASM (Skia) rendering via WebGL2
- Scene graph with typed nodes (Frame, Rectangle, Ellipse, Line, etc.)
- Skia renderer with fills, strokes, rounded corners, opacity, rotation
- Selection system with resize handles
- Undo/redo manager (inverse command pattern with batching)
- Bottom toolbar (Select, Frame, Rect, Ellipse, Line) matching Figma UI3
- Left layers panel, right properties panel
- Pan (scroll), zoom (Ctrl+scroll toward cursor)
- Keyboard shortcuts: V/F/R/O/L for tools, Cmd+Z undo, Backspace delete
- 5 demo shapes rendered on canvas
2026-02-27 15:48:29 +03:00