Commit graph

386 commits

Author SHA1 Message Date
Danila Poyarkov 2a3e848e3b Deduplicate AI tools: use FigmaAPI.toJSON() and core parseColor
- get_page_tree: replace hand-rolled nodeToJSON with FigmaAPI.wrapNode().toJSON()
- get_selection: same — use FigmaAPI proxy serialization
- resolveColor: delegate hex parsing to core parseColor() (culori) instead of manual parseInt
2026-03-01 13:20:01 +03:00
Danila Poyarkov b6e792846f Harden FigmaAPI: hide internals via symbols, freeze arrays, fix layoutSizing
- Replace _id/_graph/_api with Symbol-keyed properties so eval scripts
  can't access SceneGraph internals directly
- fills/strokes/effects return frozen structuredClone copies
- Fix currentPage getter to define selection only once per proxy
- Fix layoutSizingHorizontal/Vertical: respect parent layout direction
  even when the node itself is an auto-layout frame
- Add 6 new tests: layoutSizing, frozen arrays, internals not exposed
2026-03-01 13:12:26 +03:00
Danila Poyarkov 9a7d170887 Add 17 CLI integration tests for eval command
Tests cover: page name, primitives, findAll queries, node creation,
auto-layout, text, top-level await, stdin piping, JSON output,
syntax/runtime errors, no-code error, undefined output, --output write,
array serialization, getNodeById on real .fig files.
2026-03-01 13:07:06 +03:00
Anton A S de048b4d21 Add User Guide section with 11 articles derived from OpenSpec specs
New docs/user-guide/ section covering: canvas navigation, selection &
manipulation, drawing shapes, text editing, pen tool, layers & pages,
context menu, exporting, auto-layout, components, and variables.

Each article includes Mac+Win/Linux shortcuts tables, cross-platform
note, cross-links between related articles, and consistent structure.

VitePress sidebar updated with User Guide as first group (12 entries).
2026-03-01 13:02:47 +03:00
Danila Poyarkov b41424dd84 Add motivation to README: why OpenPencil exists 2026-03-01 12:58:13 +03:00
Anton A S 15abce330f Sync specs & docs: AI chat, Code panel, JSX export
- Merge from master: 19 commits (AI chat + Code tab)
- Update specs: editor-ui (Properties panel → Design|Code|AI tabs,
  AI chat panel, model selector, 10 AI tools, DirectChatTransport,
  Code panel with JSX export), scene-graph (sceneNodeToJsx),
  testing (AI chat Playwright, 14 JSX export tests)
- Update docs: features (AI Chat + Code Panel sections, Properties
  Panel tabs), figma-comparison (AI tools 🟡, Dev Mode 🟡,
  Code snippets 🟡, 83/150), roadmap (Phase 5 AI + Code),
  keyboard-shortcuts (⌘J , ⌘B/I/U )
- Archive sync-ai-chat-code-tab change
2026-03-01 12:33:57 +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 0cba4fb4b7 Add FigmaAPI + eval CLI command with 60 unit tests
FigmaAPI in @open-pencil/core provides a Figma Plugin API-compatible
interface backed by SceneGraph. Covers node creation, property access,
tree operations, auto-layout, text, traversal, grouping, components,
selection, and serialization.

CLI: bun open-pencil eval <file> --code 'figma.createFrame()'
2026-03-01 12:21:07 +03:00
Danila Poyarkov 63748ecee6 Plan: eval command with Figma-compatible plugin API 2026-03-01 12:13:31 +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 5fbad7b092 Sync specs & docs: style runs, JSX renderer, CLI expansion, tests
- Merge from master: 22 commits (rich text, JSX renderer, CLI, dedup, tests)
- Update specs: text-editing (style runs, ⌘B/I/U, .fig roundtrip,
  double/triple-click, selectLine), canvas-rendering (mixed-style
  ParagraphBuilder), editor-ui (B/I/U/S buttons), cli (analyze, node,
  pages, variables), tooling (jscpd, kiwi-serialize, test:coverage),
  testing (.fig roundtrip, import perf, JSX tests), scene-graph
  (StyleRun model, JSX renderer)
- Update docs: features (rich text formatting, JSX renderer, expanded
  CLI, code quality), figma-comparison (Text styles 🔲🟡, 80/150),
  roadmap (Phase 4+5 delivered items)
- Archive sync-style-runs-jsx-cli-tests change
2026-03-01 12:09:41 +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 91a6f599fa Remove chat avatars 2026-03-01 11:54:04 +03:00
Danila Poyarkov 921a9cd261 Fix tool name extraction from UIMessage parts, add tool call e2e test
Tool part type is 'tool-create_shape' (name embedded in type field),
not a separate toolName property. Extract via part.type.replace('tool-', '').

Mock transport now emits proper UI message stream protocol:
tool-input-start → tool-input-delta → tool-input-available → tool-output-available.
2026-03-01 11:51:38 +03:00
Danila Poyarkov 873671baeb Fix valibot transform incompatible with JSON Schema serialization
Move hex→RGBA conversion from v.transform() (which can't be serialized
to JSON Schema for the LLM) to a resolveColor() helper called in execute.
2026-03-01 11:46:52 +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 4032108be0 Move AI models to @open-pencil/core constants, add Kimi K2.5 (vision+code), benchmark-ranked tags 2026-03-01 11:38:40 +03:00
Danila Poyarkov 6268d8b119 Fix double/triple-click text selection
- Track click count with timing/proximity in onMouseDown
- Double-click in text: select word (was only handled in dblclick)
- Triple-click in text: select all
- Double-click to enter editing: select word at click position
- Add selectLine/selectLineAt to TextEditor
2026-03-01 11:36:49 +03:00
Danila Poyarkov 9b59d8e816 Update model list to current versions (Claude 4.6, Gemini 3.1, GPT-5.3, DeepSeek V3.2, Qwen 3.5) 2026-03-01 11:34:38 +03:00
Danila Poyarkov 299b668e7b Show selected model name in selector trigger 2026-03-01 11:33:12 +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 20827a27d3 Deduplicate fig-kiwi parsing, font weight mapping, layout, style runs, text editor
- Extract buildFigKiwi, parseFigKiwiChunks, decompressFigKiwiDataAsync to kiwi-serialize.ts
- Unify styleToWeight across fonts.ts, fig-import.ts, src/engine/fonts.ts
- Merge applyYogaLayout + applyYogaLayoutNested into single recursive fn
- Extract expandRuns helper in style-runs.ts
- Add prepareMove helper to TextEditor for selection extension boilerplate

jscpd: 18 → 9 clones, 1.7% → 0.62%
2026-03-01 11:29:26 +03:00
Danila Poyarkov c18ced5dcf Rename ApiKeySetup → APIKeySetup 2026-03-01 11:12:37 +03:00
Danila Poyarkov c08cbe5c0f Split ChatPanel into ChatMessage, ChatInput, ApiKeySetup 2026-03-01 11:11:46 +03:00
Danila Poyarkov e3ae61e99d Consolidate font weight mapping and FIG_KIWI_VERSION 2026-03-01 11:08:59 +03:00
Danila Poyarkov f0c482ac5c Add model selector with curated list (Claude, Gemini, GPT, DeepSeek, Llama) 2026-03-01 11:08:47 +03:00
Danila Poyarkov 61cd018353 Fix empty state vertical centering in chat panel 2026-03-01 11:05:09 +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 f92a8835f4 Deduplicate kiwi and serialization code
Replace src/kiwi/ copies with re-exports from @open-pencil/core.
Extract shared sceneNodeToKiwi into kiwi-serialize.ts, used by
both fig-export.ts and clipboard.ts.

jscpd: 15.6% → 1.7% duplication (35 → 18 clones, -4459 lines)
2026-03-01 10:59:35 +03:00
Danila Poyarkov 9235a75e6f Report app name to OpenRouter via X-OpenRouter-Title header 2026-03-01 10:58:22 +03:00
Danila Poyarkov b10785fdee Extract DesignPanel from PropertiesPanel 2026-03-01 10:55:52 +03:00
Danila Poyarkov bf5c905134 Move AI chat to Design/AI tab in properties panel 2026-03-01 10:54:51 +03:00
Danila Poyarkov 46bb9230d3 Add jscpd for copy-paste detection 2026-03-01 10:49:09 +03:00
Danila Poyarkov a32d80f448 Deduplicate render internals: shared resolveToTree, remove dead code 2026-03-01 10:45:39 +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 6bc3f7c50d Use git push --no-verify for LFS, drop custom alias 2026-03-01 10:41:16 +03:00
Danila Poyarkov dc602b0731 Document git qpush alias for fast LFS-skipping pushes 2026-03-01 10:39:57 +03:00
Danila Poyarkov cae260c178 Document LFS skipverify setting 2026-03-01 10:36:00 +03:00
Danila Poyarkov ca422147b4 Add .fig roundtrip tests: real file parsing, property invariants, encode/decode cycle 2026-03-01 10:33:58 +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 cc5dda29d9 AI chat: no backend, direct OpenRouter from browser, Stronghold for key storage 2026-03-01 10:23:53 +03:00
Danila Poyarkov 7dcc5822f8 Merge cli-commands: analyze, node, pages, variables commands 2026-03-01 10:19:46 +03:00
Danila Poyarkov 9873580a04 Reference plan.md from AGENTS.md 2026-03-01 10:19:38 +03:00
Danila Poyarkov f1806f6f33 Add test:coverage script 2026-03-01 10:19:38 +03:00
Danila Poyarkov 36e3f14ac4 CLI: add analyze, node, pages, and variables commands
- analyze colors: color palette usage with clustering
- analyze typography: font/size/weight distribution
- analyze spacing: gap/padding values with grid check
- analyze clusters: repeated patterns (potential components)
- node: detailed properties by ID
- pages: list pages with node counts
- variables: list design variables and collections
2026-03-01 10:19:38 +03:00
Danila Poyarkov 9b97346aa2 Remove .env from tracking, add to .gitignore 2026-03-01 10:14:48 +03:00
Danila Poyarkov 017b0aa3c1 Move AI chat design into plan.md Phase 5 2026-03-01 10:14:40 +03:00
Danila Poyarkov af6a98ca56 AI chat: JSX-first rendering, guardrail tools, workflow from figma-use 2026-03-01 10:12:01 +03:00
Danila Poyarkov 4fb929073a AI chat design document 2026-03-01 10:09:09 +03:00