From 15abce330fdb71673170550e20535993bbe84f52 Mon Sep 17 00:00:00 2001 From: Anton A S Date: Sun, 1 Mar 2026 12:33:57 +0300 Subject: [PATCH] Sync specs & docs: AI chat, Code panel, JSX export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- docs/development/roadmap.md | 3 + docs/guide/features.md | 26 +++++++- docs/guide/figma-comparison.md | 8 +-- docs/reference/keyboard-shortcuts.md | 7 ++- .../.openspec.yaml | 2 + .../design.md | 19 ++++++ .../proposal.md | 25 ++++++++ .../specs/editor-ui/spec.md | 63 +++++++++++++++++++ .../specs/scene-graph/spec.md | 14 +++++ .../specs/testing/spec.md | 17 +++++ .../2026-03-01-sync-ai-chat-code-tab/tasks.md | 35 +++++++++++ openspec/specs/editor-ui/spec.md | 51 ++++++++++++++- openspec/specs/scene-graph/spec.md | 11 ++++ openspec/specs/testing/spec.md | 14 +++++ 14 files changed, 283 insertions(+), 12 deletions(-) create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/.openspec.yaml create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/design.md create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/proposal.md create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/editor-ui/spec.md create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/scene-graph/spec.md create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/testing/spec.md create mode 100644 openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/tasks.md diff --git a/docs/development/roadmap.md b/docs/development/roadmap.md index 84cb4aba3..7d5e922e0 100644 --- a/docs/development/roadmap.md +++ b/docs/development/roadmap.md @@ -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:** diff --git a/docs/guide/features.md b/docs/guide/features.md index 6cab6d426..4e86a4ec7 100644 --- a/docs/guide/features.md +++ b/docs/guide/features.md @@ -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 โŒ˜J. 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 diff --git a/docs/guide/figma-comparison.md b/docs/guide/figma-comparison.md index f665ab75d..6efec7011 100644 --- a/docs/guide/figma-comparison.md +++ b/docs/guide/figma-comparison.md @@ -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 | diff --git a/docs/reference/keyboard-shortcuts.md b/docs/reference/keyboard-shortcuts.md index cbc278c7c..defffa138 100644 --- a/docs/reference/keyboard-shortcuts.md +++ b/docs/reference/keyboard-shortcuts.md @@ -68,6 +68,7 @@ Full Figma-compatible shortcut map. โœ… = implemented. | โŒ˜0 | Zoom to 100% | โœ… | | โŒ˜1 | Zoom to Fit | ๐Ÿ”ฒ | | โŒ˜2 | Zoom to Selection | ๐Ÿ”ฒ | +| โŒ˜J | Toggle AI Chat | โœ… | ## Object @@ -96,9 +97,9 @@ Full Figma-compatible shortcut map. โœ… = implemented. | Shortcut | Action | Status | |----------|--------|--------| -| โŒ˜B | Bold | ๐Ÿ”ฒ | -| โŒ˜I | Italic | ๐Ÿ”ฒ | -| โŒ˜U | Underline | ๐Ÿ”ฒ | +| โŒ˜B | Bold | โœ… | +| โŒ˜I | Italic | โœ… | +| โŒ˜U | Underline | โœ… | | โ‡งโŒ˜X | Strikethrough | ๐Ÿ”ฒ | ## Canvas Interaction diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/.openspec.yaml b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/.openspec.yaml new file mode 100644 index 000000000..0b4defe0e --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-01 diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/design.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/design.md new file mode 100644 index 000000000..f5992628e --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/design.md @@ -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) diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/proposal.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/proposal.md new file mode 100644 index 000000000..790919a96 --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/proposal.md @@ -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 diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/editor-ui/spec.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/editor-ui/spec.md new file mode 100644 index 000000000..7b0d17a02 --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/editor-ui/spec.md @@ -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 diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/scene-graph/spec.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/scene-graph/spec.md new file mode 100644 index 000000000..6c62cca53 --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/scene-graph/spec.md @@ -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 diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/testing/spec.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/testing/spec.md new file mode 100644 index 000000000..b38da0419 --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/specs/testing/spec.md @@ -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 diff --git a/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/tasks.md b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/tasks.md new file mode 100644 index 000000000..db1f2f7d6 --- /dev/null +++ b/openspec/changes/archive/2026-03-01-sync-ai-chat-code-tab/tasks.md @@ -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//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 diff --git a/openspec/specs/editor-ui/spec.md b/openspec/specs/editor-ui/spec.md index 56cc2a7d1..4c677c89a 100644 --- a/openspec/specs/editor-ui/spec.md +++ b/openspec/specs/editor-ui/spec.md @@ -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 diff --git a/openspec/specs/scene-graph/spec.md b/openspec/specs/scene-graph/spec.md index c93338958..9dbae9496 100644 --- a/openspec/specs/scene-graph/spec.md +++ b/openspec/specs/scene-graph/spec.md @@ -263,3 +263,14 @@ SceneNode SHALL support a `styleRuns` array of `{start, length, style}` where st #### Scenario: Render JSX string - **WHEN** renderJsx('Hi') 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 diff --git a/openspec/specs/testing/spec.md b/openspec/specs/testing/spec.md index 530fae253..29a4c1a5f 100644 --- a/openspec/specs/testing/spec.md +++ b/openspec/specs/testing/spec.md @@ -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