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
Danila Poyarkov
0df5492542
Document kiwi decoder benchmark: JS vs Rust findings
2026-03-01 10:08:14 +03:00
Danila Poyarkov
f24f6e0dc6
Add .fig test fixtures (LFS) and fix O(n²) import bottleneck
...
- Add Material 3 Design Kit and Nuxt UI v4 community files as test fixtures
- Track tests/fixtures/*.fig with Git LFS
- Fix O(n²) getChildren() in fig-import: build children index upfront
- material3.fig (87K nodes): 37s → 535ms (69x faster)
- nuxtui.fig (314K nodes): minutes → 2.3s
- Optimize kiwi ByteBuffer: inline readVarUint, use TextDecoder for strings
2026-03-01 09:55:07 +03:00
Anton A S
824193ab7a
Sync specs & docs: canvas-native text editing, font-kit, variables dialog
...
- Merge from master: 19 commits (text editing, system fonts, variables UI)
- Update specs: text-editing (canvas-native, TextEditor, phantom textarea,
font picker, keyboard nav, mouse selection), canvas-rendering (selection
rects, blinking caret), editor-ui (Variables dialog with TanStack Table,
ColorInput, alpha checkerboard, demo collections), desktop-app (font-kit
commands, CSS font faces, app identity), undo-redo (variable operations)
- Update docs: features (text editing, font picker, variables, undo),
figma-comparison (notes for text/fonts/variables rows),
roadmap (Phase 4 delivered items)
- Archive sync-text-editing-fonts-variables-ui change
2026-03-01 09:47:46 +03:00
Anton A S
384c66f5b2
Merge remote-tracking branch 'origin/master' into add-vitepress-docs
2026-03-01 09:35:02 +03:00
Danila Poyarkov
88bfacdc9e
Rich text style runs with per-selection bold/italic/underline
...
StyleRun model: array of {start, length, style} with
CharacterStyleOverride (fontWeight, italic, textDecoration, etc.).
Renderer uses ParagraphBuilder.pushStyle/pop for mixed-style text.
TextEditor delegates paragraph building to renderer.buildParagraph().
⌘B/I/U apply to selection range when text is selected, or toggle
whole-node style when no selection. Style runs adjust on
insert/delete to preserve formatting across edits.
Fig roundtrip: import characterStyleIDs + styleOverrideTable from
TextData, export back with deduped style table.
B/I/U/S toggle buttons in TypographySection.
2026-03-01 09:03:38 +03:00
Danila Poyarkov
33d3defcef
Canvas-native text editing with phantom textarea
...
TextEditor class in core — cursor positioning, selection, word
boundaries, line navigation via CanvasKit Paragraph API
(getGlyphPositionAtCoordinate, getRectsForRange).
Renderer draws selection highlights and blinking caret directly
on the canvas. Blue outline around text node during editing.
Phantom textarea captures input, IME composition, clipboard,
arrow keys, Home/End, word/line movement (⌥/⌘ modifiers).
Replaces the old visible <textarea> overlay.
2026-03-01 03:46:43 +03:00
Danila Poyarkov
4e03d262c0
Register system font faces for CSS preview, fix picker highlight width
2026-03-01 03:25:50 +03:00
Danila Poyarkov
621e38e178
Font picker: start with empty search, scroll to current font
2026-03-01 02:59:17 +03:00
Danila Poyarkov
326f5d194d
Preload system fonts on app startup
...
Cache font list in Rust via OnceLock, fire preload request from
main.ts so the font list is ready before user opens the picker.
2026-03-01 02:57:58 +03:00
Danila Poyarkov
5ccae709a0
Add system font enumeration via font-kit
...
Rust: list_system_fonts and load_system_font Tauri commands using
font-kit crate for cross-platform system font access.
TS: font shim detects Tauri runtime and uses invoke() for font
listing/loading instead of queryLocalFonts (unavailable in WKWebView).
2026-03-01 02:56:12 +03:00