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
This commit is contained in:
parent
fbb397ad45
commit
15abce330f
|
|
@ -107,6 +107,9 @@ Core extraction, CLI, MCP server, design guidelines, screenshot verification loo
|
|||
- .fig roundtrip tests with LFS fixtures (material3.fig 87K nodes, nuxtui.fig 314K nodes)
|
||||
- .fig import O(n²) → O(n) fix (37s → 535ms on 87K nodes), ByteBuffer optimization
|
||||
- test:coverage script
|
||||
- AI chat: OpenRouter direct (no backend), Stronghold key storage, 10 tools (create_shape, set_fill, etc.), model selector, ⌘J toggle, streaming markdown, Playwright tests with mock transport
|
||||
- Code panel: sceneNodeToJsx() export, Prism.js highlighting, line numbers, copy button, 14 tests
|
||||
- Properties panel restructured: Design | Code | AI tabs
|
||||
- npm publishing preparation for core and cli packages
|
||||
|
||||
**Planned:**
|
||||
|
|
|
|||
|
|
@ -69,18 +69,22 @@ Both the layers panel and properties panel are resizable — drag the edge betwe
|
|||
|
||||
## Properties Panel
|
||||
|
||||
Context-sensitive panel with sections:
|
||||
Tabbed interface with **Design** | **Code** | **AI** tabs (reka-ui Tabs).
|
||||
|
||||
The **Design** tab is context-sensitive with sections:
|
||||
|
||||
- **Appearance** — opacity, corner radius (uniform or per-corner with independent toggle), visibility
|
||||
- **Fill** — solid/gradient/image type picker, gradient stop editor, hex input, opacity
|
||||
- **Stroke** — color, weight, opacity, cap, join, dash pattern
|
||||
- **Effects** — add/remove effects, type picker (drop shadow, inner shadow, layer blur, background blur, foreground blur), inline expanded controls (offset, blur, spread, color for shadows; blur radius for blurs), per-effect visibility toggle
|
||||
- **Typography** — font family (FontPicker with virtual scroll and search), weight, size, alignment
|
||||
- **Typography** — font family (FontPicker with virtual scroll and search), weight, size, alignment, B/I/U/S buttons
|
||||
- **Layout** — auto-layout controls when enabled
|
||||
- **Position** — alignment buttons, rotation, flip
|
||||
- **Export** — scale, format (PNG/JPG/WEBP), live preview, multi-export
|
||||
- **Page** — canvas background color (shown when no nodes selected)
|
||||
|
||||
The **Code** tab shows JSX export of the selection (see [Code Panel](#code-panel)). The **AI** tab provides an AI chat interface (see [AI Chat](#ai-chat)).
|
||||
|
||||
## Group/Ungroup
|
||||
|
||||
⌘G groups selected nodes. ⇧⌘G ungroups. Nodes are sorted by visual position when grouping to preserve reading order.
|
||||
|
|
@ -189,7 +193,23 @@ Two rendering paths:
|
|||
- `renderTreeNode()` — tree → scene graph (any runtime, no external deps)
|
||||
- `renderJsx()` — JSX string → esbuild → tree → scene graph (CLI/headless)
|
||||
|
||||
Covered by 27 tests for all node types, layout props, effects, and nesting.
|
||||
|
||||
|
||||
## AI Chat
|
||||
|
||||
Built-in AI assistant accessible via the AI tab in the properties panel or <kbd>⌘</kbd><kbd>J</kbd>. Communicates directly with OpenRouter from the browser — no backend server required. API key stored securely in Tauri Stronghold (localStorage fallback in browser).
|
||||
|
||||
**Model selector** with curated models: Claude, Gemini, GPT, DeepSeek, Qwen, Kimi, Llama — stored in `@open-pencil/core` constants with benchmark-ranked tags. Responses stream as markdown (vue-stream-markdown).
|
||||
|
||||
**10 AI tools** wired to the editor store with valibot schemas: `create_shape`, `set_fill`, `set_stroke`, `update_node`, `set_layout`, `delete_node`, `select_nodes`, `get_page_tree`, `get_selection`, `rename_node`. The ToolLoopAgent executes tools automatically in a loop. Tool calls display as collapsible timeline entries in the chat (reka-ui Collapsible).
|
||||
|
||||
Tested with Playwright using mock transport for CI.
|
||||
|
||||
## Code Panel
|
||||
|
||||
The Code tab in the properties panel shows the JSX representation of the current selection. Uses `sceneNodeToJsx()` from `@open-pencil/core` to convert the SceneNode subtree into JSX with Tailwind-like shorthand props. Prism.js syntax highlighting with line numbers and a copy-to-clipboard button. Multi-selection shows each node's JSX. The exported JSX is compatible with `renderJsx()` for round-trip creation.
|
||||
|
||||
|
||||
|
||||
## Code Quality
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ Feature-by-feature comparison of Figma Design capabilities with Open Pencil's cu
|
|||
✅ Supported — feature works end-to-end · 🟡 Partial — core behavior exists, some sub-features missing · 🔲 Not yet implemented
|
||||
:::
|
||||
|
||||
**Coverage:** 80 of 150 Figma feature items addressed — 64 ✅ fully supported, 16 🟡 partial, 70 🔲 not yet. Last updated: 2026-03-01.
|
||||
**Coverage:** 83 of 150 Figma feature items addressed — 64 ✅ fully supported, 19 🟡 partial, 67 🔲 not yet. Last updated: 2026-03-01.
|
||||
|
||||
## Interface & Navigation
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ Feature-by-feature comparison of Figma Design capabilities with Open Pencil's cu
|
|||
| Layer outlines view | 🔲 | Wireframe view of all layers |
|
||||
| Custom file thumbnails | 🔲 | Thumbnail generated on export, but no custom thumbnail picker |
|
||||
| Nudge value settings | 🔲 | Default 1px/10px; Figma allows custom small/big nudge values |
|
||||
| AI tools | 🔲 | Figma AI features (rename, search, generate); Open Pencil plans MCP-based AI in Phase 5 |
|
||||
| AI tools | 🟡 | 10 AI tools via OpenRouter (create/modify/delete shapes, fills/strokes, layout); no AI-generated images or AI-powered search yet |
|
||||
|
||||
## Layers & Shapes
|
||||
|
||||
|
|
@ -204,9 +204,9 @@ Feature-by-feature comparison of Figma Design capabilities with Open Pencil's cu
|
|||
| Real-time multiplayer | 🔲 | Planned (Yjs-based) |
|
||||
| Cursor chat | 🔲 | Inline chat bubbles at cursor |
|
||||
| Branching & merging | 🔲 | Version branches for design files |
|
||||
| Dev Mode (inspect) | 🔲 | CSS/code generation from designs |
|
||||
| Dev Mode (inspect) | 🟡 | Code tab shows JSX representation of selection; no CSS properties or handoff specs |
|
||||
| Code Connect | 🔲 | Link design components to code |
|
||||
| Code snippets | 🔲 | Auto-generated code from layers |
|
||||
| Code snippets | 🟡 | JSX export with syntax highlighting and copy; no CSS/Swift/Kotlin snippets |
|
||||
| Figma for VS Code | 🔲 | Editor plugin integration |
|
||||
| MCP server | 🔲 | Planned for Phase 5; 117-tool MCP server from figma-use |
|
||||
| CLI tools | 🟡 | Headless CLI: info, tree, find, export, analyze (colors/typography/spacing/clusters), node, pages, variables; MCP server not yet |
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ Full Figma-compatible shortcut map. ✅ = implemented.
|
|||
| <kbd>⌘</kbd><kbd>0</kbd> | Zoom to 100% | ✅ |
|
||||
| <kbd>⌘</kbd><kbd>1</kbd> | Zoom to Fit | 🔲 |
|
||||
| <kbd>⌘</kbd><kbd>2</kbd> | Zoom to Selection | 🔲 |
|
||||
| <kbd>⌘</kbd><kbd>J</kbd> | Toggle AI Chat | ✅ |
|
||||
|
||||
## Object
|
||||
|
||||
|
|
@ -96,9 +97,9 @@ Full Figma-compatible shortcut map. ✅ = implemented.
|
|||
|
||||
| Shortcut | Action | Status |
|
||||
|----------|--------|--------|
|
||||
| <kbd>⌘</kbd><kbd>B</kbd> | Bold | 🔲 |
|
||||
| <kbd>⌘</kbd><kbd>I</kbd> | Italic | 🔲 |
|
||||
| <kbd>⌘</kbd><kbd>U</kbd> | Underline | 🔲 |
|
||||
| <kbd>⌘</kbd><kbd>B</kbd> | Bold | ✅ |
|
||||
| <kbd>⌘</kbd><kbd>I</kbd> | Italic | ✅ |
|
||||
| <kbd>⌘</kbd><kbd>U</kbd> | Underline | ✅ |
|
||||
| <kbd>⇧</kbd><kbd>⌘</kbd><kbd>X</kbd> | Strikethrough | 🔲 |
|
||||
|
||||
## Canvas Interaction
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
schema: spec-driven
|
||||
created: 2026-03-01
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# Design: Sync AI chat, Code tab
|
||||
|
||||
## Approach
|
||||
Documentation-only. Update/create specs for AI chat and Code panel, propagate to VitePress docs and comparison matrix.
|
||||
|
||||
## Affected spec domains
|
||||
|
||||
1. **editor-ui** — Properties panel restructured to Design | Code | AI tabs, DesignPanel extraction, ChatPanel + sub-components, CodePanel, ⌘J shortcut
|
||||
2. **scene-graph** (new requirement) — sceneNodeToJsx() export function
|
||||
3. **testing** — Playwright chat tests with mock transport, 14 JSX export tests
|
||||
|
||||
## New spec domain consideration
|
||||
AI chat could warrant its own spec domain, but it's tightly integrated into editor-ui (tab in properties panel, tools call editor store). Keep in editor-ui for now.
|
||||
|
||||
## VitePress docs updates
|
||||
- features.md: add "AI Chat" section, add "Code Panel" section, update Properties Panel description
|
||||
- figma-comparison.md: AI tools 🔲→🟡, Code snippets 🔲→🟡, Dev Mode 🔲→🟡
|
||||
- roadmap.md: Phase 5 delivered items (AI chat, Code tab)
|
||||
- keyboard-shortcuts.md: ⌘J (toggle AI chat)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Proposal: Sync AI chat, Code tab
|
||||
|
||||
## Why
|
||||
19 commits from master (6268d8b..c59d5fc) introduce AI chat integration and a Code panel for JSX export.
|
||||
|
||||
## What changed
|
||||
|
||||
### AI chat (5d23c3e → bf8636c, 15 commits)
|
||||
- ChatPanel with message list, tool timeline, typing indicator, API key setup via Tauri Stronghold
|
||||
- DirectChatTransport: no backend server, calls OpenRouter directly from browser
|
||||
- ToolLoopAgent with 10 AI tools (valibot schemas): create_shape, set_fill, set_stroke, update_node, set_layout, delete_node, select_nodes, get_page_tree, get_selection, rename_node
|
||||
- Model selector with curated list: Claude 4.6, Gemini 3.1, GPT-5.3, DeepSeek V3.2, Qwen 3.5, Kimi K2.5, Llama
|
||||
- ⌘J keyboard shortcut to toggle chat
|
||||
- Properties panel restructured: Design | Code | AI tabs (reka-ui Tabs)
|
||||
- DesignPanel extracted from PropertiesPanel
|
||||
- ChatMessage, ChatInput, APIKeySetup sub-components
|
||||
- reka-ui ScrollArea/Collapsible/Tooltip, tw-animate-css, vue-stream-markdown for streaming
|
||||
- Playwright tests with mock transport, tool call e2e test
|
||||
- X-OpenRouter-Title header for app identification
|
||||
|
||||
### Code tab / JSX export (c59d5fc)
|
||||
- sceneNodeToJsx() in @open-pencil/core: converts SceneNode subtree to JSX using builder syntax
|
||||
- CodePanel.vue with Prism.js syntax highlighting, line numbers, copy button
|
||||
- Third tab in properties panel
|
||||
- 14 new tests covering shapes, text, layout, effects, multi-selection
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# editor-ui Specification (delta)
|
||||
|
||||
## Modified Requirements
|
||||
|
||||
### Requirement: Properties panel with sections (MODIFIED)
|
||||
The properties panel SHALL be organized as a tabbed interface with Design | Code | AI tabs (reka-ui Tabs). The Design tab contains the existing property sections (DesignPanel). The Code tab shows JSX export. The AI tab shows the chat interface.
|
||||
|
||||
#### Scenario: Switch to Code tab
|
||||
- **WHEN** user clicks the Code tab in the properties panel
|
||||
- **THEN** the JSX code representation of the selection is displayed
|
||||
|
||||
#### Scenario: Switch to AI tab
|
||||
- **WHEN** user clicks the AI tab
|
||||
- **THEN** the AI chat interface is displayed
|
||||
|
||||
## New Requirements
|
||||
|
||||
### Requirement: AI chat panel
|
||||
The editor SHALL include an AI chat panel accessible via the AI tab in properties panel or ⌘J shortcut. The panel provides: message list with streaming markdown (vue-stream-markdown), tool call timeline with collapsible details (reka-ui Collapsible), typing indicator, API key setup for OpenRouter (stored in Tauri Stronghold). Messages scroll automatically (reka-ui ScrollArea).
|
||||
|
||||
#### Scenario: Send message
|
||||
- **WHEN** user types a message and presses Enter in the chat input
|
||||
- **THEN** the message is sent to OpenRouter and a streaming response appears
|
||||
|
||||
#### Scenario: Toggle chat
|
||||
- **WHEN** user presses ⌘J
|
||||
- **THEN** the properties panel switches to the AI tab (or back to Design)
|
||||
|
||||
### Requirement: AI model selector
|
||||
The chat input SHALL include a model selector with curated models: Claude, Gemini, GPT, DeepSeek, Qwen, Kimi, Llama. Models are stored in @open-pencil/core constants with benchmark-ranked tags.
|
||||
|
||||
#### Scenario: Change model
|
||||
- **WHEN** user selects a different model from the selector
|
||||
- **THEN** subsequent messages use the selected model
|
||||
|
||||
### Requirement: AI tools
|
||||
The chat SHALL support 10 design tools with valibot schemas: create_shape, set_fill, set_stroke, update_node, set_layout, delete_node, select_nodes, get_page_tree, get_selection, rename_node. Tools execute against the editor store. The ToolLoopAgent calls tools automatically in a loop.
|
||||
|
||||
#### Scenario: AI creates a shape
|
||||
- **WHEN** user asks "Create a blue rectangle 200×100"
|
||||
- **THEN** the AI calls create_shape with type RECTANGLE, width 200, height 100, and set_fill with blue color
|
||||
|
||||
#### Scenario: Tool call visible in chat
|
||||
- **WHEN** the AI executes a tool
|
||||
- **THEN** a collapsible tool call section shows the tool name, input, and output
|
||||
|
||||
### Requirement: DirectChatTransport
|
||||
The chat SHALL communicate directly with OpenRouter from the browser — no backend server required. The API key is stored securely in Tauri Stronghold (or localStorage fallback in browser). X-OpenRouter-Title header identifies the app.
|
||||
|
||||
#### Scenario: No backend required
|
||||
- **WHEN** user configures an OpenRouter API key and sends a message
|
||||
- **THEN** the request goes directly to OpenRouter without a proxy server
|
||||
|
||||
### Requirement: Code panel with JSX export
|
||||
The properties panel Code tab SHALL display the selected node(s) as JSX code using sceneNodeToJsx(). The panel provides Prism.js syntax highlighting, line numbers, and a copy-to-clipboard button. Multi-selection shows each node's JSX.
|
||||
|
||||
#### Scenario: View JSX for selection
|
||||
- **WHEN** user selects a frame and clicks the Code tab
|
||||
- **THEN** the JSX representation of the frame and its children is displayed with syntax highlighting
|
||||
|
||||
#### Scenario: Copy JSX
|
||||
- **WHEN** user clicks the copy button in the Code panel
|
||||
- **THEN** the JSX code is copied to the clipboard
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
# scene-graph Specification (delta)
|
||||
|
||||
## New Requirements
|
||||
|
||||
### Requirement: Scene node to JSX export
|
||||
@open-pencil/core SHALL export a sceneNodeToJsx() function that converts a SceneNode subtree into JSX string using builder function syntax (Frame, Text, Rectangle, etc.) with Tailwind-like shorthand props. The output is valid JSX that can be consumed by renderJsx().
|
||||
|
||||
#### Scenario: Export frame with children
|
||||
- **WHEN** sceneNodeToJsx is called on a frame with a rectangle and text child
|
||||
- **THEN** a JSX string with Frame wrapping Rectangle and Text is returned
|
||||
|
||||
#### Scenario: Export with effects
|
||||
- **WHEN** sceneNodeToJsx is called on a node with drop shadow
|
||||
- **THEN** the JSX includes shadow props in the output
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
# testing Specification (delta)
|
||||
|
||||
## New Requirements
|
||||
|
||||
### Requirement: AI chat Playwright tests
|
||||
The test suite SHALL include Playwright e2e tests for the AI chat panel with mock transport (no real LLM calls). Tests cover: sending a message, receiving a response, tool call display. Real LLM tests available via TEST_REAL_LLM=1 flag.
|
||||
|
||||
#### Scenario: Chat with mock transport
|
||||
- **WHEN** a Playwright test sends a message via the chat input
|
||||
- **THEN** the mock transport returns a response and the message appears in the chat
|
||||
|
||||
### Requirement: JSX export tests
|
||||
The test suite SHALL include tests for sceneNodeToJsx() covering shapes, text, layout props, effects, and multi-selection. Currently 14 tests.
|
||||
|
||||
#### Scenario: Export rectangle to JSX
|
||||
- **WHEN** sceneNodeToJsx is called on a rectangle with blue fill
|
||||
- **THEN** the output includes Rectangle component with bg prop
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Tasks: Sync AI chat, Code tab
|
||||
|
||||
Reference: 19 commits from master (6268d8b..c59d5fc).
|
||||
Delta-specs in `openspec/changes/sync-ai-chat-code-tab/specs/` (editor-ui, scene-graph, testing).
|
||||
Proposal: `proposal.md`, Design: `design.md` — validated and aligned with delta-specs.
|
||||
|
||||
Section 1 (specs) MUST complete before Section 2 (docs) — docs reference merged spec content.
|
||||
|
||||
## 1. Merge Delta-Specs into Main Specs
|
||||
|
||||
Each task merges ADDED and MODIFIED requirements from the delta-spec into the baseline at `openspec/specs/<domain>/spec.md`. Untouched baseline requirements are preserved. No conflicts between domains.
|
||||
|
||||
- [x] 1.1 Update `openspec/specs/editor-ui/spec.md` — MODIFIED: "Properties panel" → Design | Code | AI tabs. ADDED: "AI chat panel" (message list, streaming markdown, tool timeline, API key, ⌘J), "AI model selector" (curated models in core constants), "AI tools" (10 tools with valibot, ToolLoopAgent), "DirectChatTransport" (no backend, OpenRouter, Stronghold), "Code panel with JSX export" (Prism.js, line numbers, copy)
|
||||
- [x] 1.2 Update `openspec/specs/scene-graph/spec.md` — ADDED: "Scene node to JSX export" (sceneNodeToJsx function)
|
||||
- [x] 1.3 Update `openspec/specs/testing/spec.md` — ADDED: "AI chat Playwright tests" (mock transport, tool call e2e), "JSX export tests" (14 tests)
|
||||
|
||||
## 2. Update VitePress Docs
|
||||
|
||||
All target files already exist — no sidebar/nav changes needed.
|
||||
|
||||
- [x] 2.1 Update `docs/guide/features.md`:
|
||||
- **Modify "Properties Panel" bullet list**: add Code and AI tabs to description
|
||||
- **Add "AI Chat" section** (after "Code Quality"): ⌘J toggle, OpenRouter direct (no backend), Stronghold key storage, model selector (Claude/Gemini/GPT/DeepSeek/Qwen/Kimi/Llama), 10 AI tools (create_shape, set_fill, etc.), streaming markdown, tool call timeline, Playwright tests with mock transport
|
||||
- **Add "Code Panel" section** (after "AI Chat"): sceneNodeToJsx() in core, Prism.js highlighting, line numbers, copy button, Design | Code | AI tabs
|
||||
- [x] 2.2 Update `docs/guide/figma-comparison.md` — specific row changes:
|
||||
- "AI tools" 🔲→🟡: "10 AI tools via OpenRouter (create/modify/delete shapes, set fills/strokes, layout); no AI-generated content or AI search yet"
|
||||
- "Code snippets" 🔲→🟡: "JSX export from selection with syntax highlighting and copy; no CSS/Swift/Kotlin snippets"
|
||||
- "Dev Mode (inspect)" 🔲→🟡: "Code tab shows JSX representation; no CSS properties or handoff specs"
|
||||
- No other rows change status. After: 64✅, 19🟡, 67🔲 = 150 total. Update coverage line
|
||||
- [x] 2.3 Update `docs/development/roadmap.md` — Phase 5 Delivered: add AI chat (OpenRouter, 10 tools, model selector, Stronghold, ⌘J, Playwright tests), Code panel (sceneNodeToJsx, Prism.js, 14 tests)
|
||||
- [x] 2.4 Update `docs/reference/keyboard-shortcuts.md` — add ⌘J (Toggle AI chat) with ✅ status
|
||||
|
||||
## 3. Verify
|
||||
|
||||
- [x] 3.1 Run `bun run docs:build` — verify build passes. Confirm: coverage count matches actual ✅/🟡/🔲 tallies via grep -c, no broken anchor warnings
|
||||
|
|
@ -48,8 +48,8 @@ The layers panel SHALL display a tree view of the document hierarchy using Reka
|
|||
- **WHEN** user clicks the visibility icon next to a layer
|
||||
- **THEN** the node is hidden/shown on canvas
|
||||
|
||||
### Requirement: Properties panel with sections
|
||||
The properties panel SHALL be split into sections: Appearance (opacity, corner radius with independent mode, visibility toggle), Fill, Stroke, Effects, Typography, Layout, Position.
|
||||
### Requirement: Properties panel with tabs
|
||||
The properties panel SHALL be organized as a tabbed interface with Design | Code | AI tabs (reka-ui Tabs). The Design tab (DesignPanel) contains sections: Appearance (opacity, corner radius with independent mode, visibility toggle), Fill, Stroke, Effects, Typography, Layout, Position. The Code tab shows JSX export. The AI tab shows the chat interface.
|
||||
|
||||
#### Scenario: Properties panel shows fill section
|
||||
- **WHEN** user selects a rectangle with a blue fill
|
||||
|
|
@ -292,3 +292,50 @@ The TypographySection SHALL include B/I/U/S toggle buttons for Bold, Italic, Und
|
|||
#### Scenario: Underline button with no selection
|
||||
- **WHEN** user clicks the Underline button during editing with no selection
|
||||
- **THEN** the entire text node's underline style toggles
|
||||
|
||||
### Requirement: AI chat panel
|
||||
The editor SHALL include an AI chat panel accessible via the AI tab in properties panel or ⌘J shortcut. The panel provides: message list with streaming markdown (vue-stream-markdown), tool call timeline with collapsible details (reka-ui Collapsible), typing indicator, API key setup for OpenRouter (stored in Tauri Stronghold). Messages scroll automatically (reka-ui ScrollArea).
|
||||
|
||||
#### Scenario: Send message
|
||||
- **WHEN** user types a message and presses Enter in the chat input
|
||||
- **THEN** the message is sent to OpenRouter and a streaming response appears
|
||||
|
||||
#### Scenario: Toggle chat
|
||||
- **WHEN** user presses ⌘J
|
||||
- **THEN** the properties panel switches to the AI tab (or back to Design)
|
||||
|
||||
### Requirement: AI model selector
|
||||
The chat input SHALL include a model selector with curated models: Claude, Gemini, GPT, DeepSeek, Qwen, Kimi, Llama. Models are stored in @open-pencil/core constants with benchmark-ranked tags.
|
||||
|
||||
#### Scenario: Change model
|
||||
- **WHEN** user selects a different model from the selector
|
||||
- **THEN** subsequent messages use the selected model
|
||||
|
||||
### Requirement: AI tools
|
||||
The chat SHALL support 10 design tools with valibot schemas: create_shape, set_fill, set_stroke, update_node, set_layout, delete_node, select_nodes, get_page_tree, get_selection, rename_node. Tools execute against the editor store. The ToolLoopAgent calls tools automatically in a loop.
|
||||
|
||||
#### Scenario: AI creates a shape
|
||||
- **WHEN** user asks "Create a blue rectangle 200×100"
|
||||
- **THEN** the AI calls create_shape with type RECTANGLE, width 200, height 100, and set_fill with blue color
|
||||
|
||||
#### Scenario: Tool call visible in chat
|
||||
- **WHEN** the AI executes a tool
|
||||
- **THEN** a collapsible tool call section shows the tool name, input, and output
|
||||
|
||||
### Requirement: DirectChatTransport
|
||||
The chat SHALL communicate directly with OpenRouter from the browser — no backend server required. The API key is stored securely in Tauri Stronghold (or localStorage fallback in browser). X-OpenRouter-Title header identifies the app.
|
||||
|
||||
#### Scenario: No backend required
|
||||
- **WHEN** user configures an OpenRouter API key and sends a message
|
||||
- **THEN** the request goes directly to OpenRouter without a proxy server
|
||||
|
||||
### Requirement: Code panel with JSX export
|
||||
The properties panel Code tab SHALL display the selected node(s) as JSX code using sceneNodeToJsx(). The panel provides Prism.js syntax highlighting, line numbers, and a copy-to-clipboard button. Multi-selection shows each node's JSX.
|
||||
|
||||
#### Scenario: View JSX for selection
|
||||
- **WHEN** user selects a frame and clicks the Code tab
|
||||
- **THEN** the JSX representation of the frame and its children is displayed with syntax highlighting
|
||||
|
||||
#### Scenario: Copy JSX
|
||||
- **WHEN** user clicks the copy button in the Code panel
|
||||
- **THEN** the JSX code is copied to the clipboard
|
||||
|
|
|
|||
|
|
@ -263,3 +263,14 @@ SceneNode SHALL support a `styleRuns` array of `{start, length, style}` where st
|
|||
#### Scenario: Render JSX string
|
||||
- **WHEN** renderJsx('<Frame w={100}><Text>Hi</Text></Frame>') is called
|
||||
- **THEN** a scene graph with a FRAME parent and TEXT child is produced
|
||||
|
||||
### Requirement: Scene node to JSX export
|
||||
@open-pencil/core SHALL export a sceneNodeToJsx() function that converts a SceneNode subtree into JSX string using builder function syntax (Frame, Text, Rectangle, etc.) with Tailwind-like shorthand props. The output is valid JSX consumable by renderJsx().
|
||||
|
||||
#### Scenario: Export frame with children
|
||||
- **WHEN** sceneNodeToJsx is called on a frame with a rectangle and text child
|
||||
- **THEN** a JSX string with Frame wrapping Rectangle and Text is returned
|
||||
|
||||
#### Scenario: Export with effects
|
||||
- **WHEN** sceneNodeToJsx is called on a node with drop shadow
|
||||
- **THEN** the JSX includes shadow props in the output
|
||||
|
|
|
|||
|
|
@ -121,3 +121,17 @@ The test suite SHALL include tests for the JSX renderer covering all node types
|
|||
#### Scenario: Render Frame with children
|
||||
- **WHEN** a JSX tree with Frame containing Rectangle and Text is rendered
|
||||
- **THEN** the scene graph contains correct parent-child relationships and properties
|
||||
|
||||
### Requirement: AI chat Playwright tests
|
||||
The test suite SHALL include Playwright e2e tests for the AI chat panel with mock transport (no real LLM calls). Tests cover: sending a message, receiving a response, tool call display. Real LLM tests available via TEST_REAL_LLM=1 flag.
|
||||
|
||||
#### Scenario: Chat with mock transport
|
||||
- **WHEN** a Playwright test sends a message via the chat input
|
||||
- **THEN** the mock transport returns a response and the message appears in the chat
|
||||
|
||||
### Requirement: JSX export tests
|
||||
The test suite SHALL include tests for sceneNodeToJsx() covering shapes, text, layout props, effects, and multi-selection. Currently 14 tests.
|
||||
|
||||
#### Scenario: Export rectangle to JSX
|
||||
- **WHEN** sceneNodeToJsx is called on a rectangle with blue fill
|
||||
- **THEN** the output includes Rectangle component with bg prop
|
||||
|
|
|
|||
Loading…
Reference in a new issue