Built-in design generation now runs as an agentic MCP tool-loop (reusing the agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the Settings experimental toggle; the orchestrator stays the default. - design-agent system prompt + in-process design toolset (parity-locked with the MCP surface) + flag-gated Intent::Design routing - spawn_agents execution as sequential sub-loops + live creation-mode badges (per-agent glow + 'N/M designing...' header) - new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state, export_nodes, spawn_agents; style-guide local audit - #27 AI panel restyle: rounded tool cards + green check-rings, gray user bubbles, model-pill bottom toolbar, header, empty-state pills, the PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown - multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI (switch / close / + / Cmd+T) with each run bound to its tab Large checkpoint commit spanning the working tree (Rust shell crates).
127 lines
8.1 KiB
Markdown
127 lines
8.1 KiB
Markdown
# Web App
|
|
|
|
TanStack Start full-stack React app (Vite + Nitro). Routes in `src/routes/`, auto-generated tree in `src/routeTree.gen.ts` (do not edit).
|
|
|
|
- `/` — Landing page
|
|
- `/editor` — Main design editor
|
|
|
|
## Canvas Engine (`src/canvas/`)
|
|
|
|
14 files + `skia/` subdir with 14 files.
|
|
|
|
### CanvasKit/Skia Architecture
|
|
|
|
- **GPU-accelerated WASM rendering** — CanvasKit (Skia compiled to WASM) renders all canvas content via WebGL surface
|
|
- **SkiaEngine class** (`skia-engine.ts`) is the core: owns the render loop, viewport transforms, node flattening, and `SpatialIndex` for hit testing
|
|
- **Dirty-flag rendering** — `markDirty()` schedules a `requestAnimationFrame` redraw; no continuous rendering loop
|
|
- **Node flattening** — `syncFromDocument()` walks the PenDocument tree, resolves auto-layout positions via layout engine, and produces flat `RenderNode[]` with absolute coordinates
|
|
- **SpatialIndex** (`skia-hit-test.ts`) — R-tree backed spatial queries for `hitTest()` (click) and `searchRect()` (marquee selection)
|
|
- **Coordinate conversion** — `screenToScene()` / `sceneToScreen()` in `skia-viewport.ts` handle viewport ↔ scene transforms
|
|
- **Event handling** — mouse/keyboard events managed by `SkiaInteractionManager` (`skia-interaction.ts`); hit testing for resize/rotate/arc handles in `skia-hit-handlers.ts`; `skia-canvas.tsx` is the React component (lifecycle, sync, rendering)
|
|
- **Parent-child transforms** — nodes are flattened to absolute coordinates; transforms propagate to descendants during drag/scale/rotate
|
|
|
|
### `skia/` Files
|
|
|
|
- `skia-canvas.tsx` — React component: lifecycle, sync effects, wheel zoom, text editing overlay; delegates interaction to `SkiaInteractionManager`
|
|
- `skia-interaction.ts` — `SkiaInteractionManager` class: all mouse/keyboard interaction state and handlers (select, drag, resize, rotate, draw, marquee, pen tool, arc editing, hover cursor)
|
|
- `skia-hit-handlers.ts` — Hit test functions: `hitTestHandle` (resize), `hitTestRotation` (rotation zone), `hitTestArcHandle` (ellipse arc)
|
|
- `skia-engine.ts` — Core rendering engine: `SkiaEngine` class, `syncFromDocument()`, viewport, node flattening, zoom/pan, dirty-flag loop
|
|
- `skia-renderer.ts` — GPU draw calls: shapes, text, paths, images, selection handles, guides, agent indicators
|
|
- `skia-init.ts` — CanvasKit WASM loader with CDN fallback
|
|
- `skia-hit-test.ts` — `SpatialIndex` R-tree for spatial queries
|
|
- `skia-viewport.ts` — Viewport math
|
|
- `skia-paint-utils.ts` — Color parsing, gradient creation, text line wrapping
|
|
- `skia-path-utils.ts` — SVG path to CanvasKit Path conversion
|
|
- `skia-image-loader.ts` — Async image loading and caching
|
|
- `skia-overlays.ts` — Selection overlays, hover highlights, dimension labels
|
|
- `skia-pen-tool.ts` — Pen tool: anchor points, control handles, path building
|
|
- `skia-font-manager.ts` — Font management
|
|
|
|
### Shared Canvas Modules
|
|
|
|
- `canvas-sync-lock.ts` — Prevents circular sync loops
|
|
- `canvas-sync-utils.ts` — `forcePageResync()` utility
|
|
- `canvas-constants.ts` — Default colors, zoom limits, stroke widths
|
|
- `canvas-node-creator.ts` — `createNodeForTool`, `isDrawingTool`
|
|
- `canvas-layout-engine.ts` — Auto-layout (delegates to `@zseven-w/pen-core`)
|
|
- `canvas-text-measure.ts` — Text width/height estimation, CJK detection
|
|
- `font-utils.ts`, `node-helpers.ts` — Re-exports from pen-core
|
|
- `insertion-indicator.ts`, `selection-context.ts`, `agent-indicator.ts`, `use-layout-indicator.ts`, `skia-engine-ref.ts`
|
|
|
|
## Zustand Stores (`src/stores/`)
|
|
|
|
- `canvas-store.ts` — UI/tool/selection/viewport/clipboard/interaction state, `activePageId`
|
|
- `document-store.ts` — PenDocument tree CRUD, variable CRUD, component management (all with history)
|
|
- `document-store-pages.ts` — Page actions: add, remove, rename, reorder, duplicate
|
|
- `document-tree-utils.ts` — Re-exports tree helpers and clone utilities from `@zseven-w/pen-core`
|
|
- `history-store.ts` — Undo/redo (max 300 states), batch mode
|
|
- `ai-store.ts` — Chat messages, streaming state, model selection
|
|
- `agent-settings-store.ts` — AI provider config, MCP CLI integrations, localStorage persistence
|
|
- `uikit-store.ts` — UIKit management
|
|
- `theme-preset-store.ts` — Theme preset management
|
|
|
|
## Components (`src/components/`)
|
|
|
|
- **`editor/`** — Editor UI: editor-layout, toolbar, boolean-toolbar, tool-button, shape-tool-dropdown, top-bar, status-bar, page-tabs, update-ready-banner
|
|
- **`panels/`** — 32 files: layer panel, property panel, fill/stroke/corner/size/text/effects/export/layout/appearance sections, AI chat panel, code panel, component browser, variables panel
|
|
- **`shared/`** — Reusable UI: ColorPicker, NumberInput, SectionHeader, ExportDialog, SaveDialog, AgentSettingsDialog, IconPickerDialog, VariablePicker, FigmaImportDialog, FontPicker, LanguageSelector
|
|
- **`icons/`** — Provider/brand logos
|
|
- **`ui/`** — shadcn/ui primitives
|
|
|
|
## AI Services (`src/services/ai/`)
|
|
|
|
35 files + `role-definitions/` + `design-principles/` subdirs:
|
|
|
|
- `ai-service.ts` — Main AI chat API wrapper, model negotiation, provider selection
|
|
- `ai-prompts.ts` — System prompts for design generation
|
|
- `ai-types.ts` — ChatMessage, ChatAttachment, AIDesignRequest, OrchestratorPlan
|
|
- `model-profiles.ts` — Adapts thinking mode, effort, timeouts per model tier
|
|
- `design-generator.ts` — Top-level `generateDesign`/`generateDesignModification`
|
|
- `design-parser.ts` — JSON/JSONL parsing
|
|
- `design-canvas-ops.ts` — Canvas mutation operations
|
|
- `design-node-sanitization.ts` — Node merging (re-exports `deepCloneNode` from pen-core)
|
|
- `design-validation.ts` / `design-pre-validation.ts` / `design-validation-fixes.ts` — Post-generation validation
|
|
- `icon-resolver.ts` — Auto-resolves icon names to Lucide SVG paths
|
|
- `orchestrator.ts` / `orchestrator-sub-agent.ts` / `orchestrator-prompts.ts` — Spatial decomposition orchestrator
|
|
- `context-optimizer.ts` — Chat history trimming
|
|
|
|
## Hooks (`src/hooks/`)
|
|
|
|
- `use-keyboard-shortcuts.ts` — Global keyboard: tools, clipboard, undo/redo, save, z-order, boolean ops
|
|
- `use-electron-menu.ts` — Electron native menu IPC listener
|
|
- `use-figma-paste.ts` — Figma clipboard paste
|
|
- `use-file-drop.ts` — File drag-and-drop
|
|
- `use-mcp-sync.ts` — MCP live canvas sync
|
|
- `use-system-fonts.ts` — System font detection
|
|
|
|
## MCP Server
|
|
|
|
MCP server code lives in `packages/pen-mcp/`. The web app communicates with it via HTTP API routes (`server/api/mcp/*.ts`) using `server/utils/mcp-server-manager.ts` to spawn/manage the server process.
|
|
|
|
## UIKit (`src/uikit/`)
|
|
|
|
- `built-in-registry.ts` — Default built-in UIKit
|
|
- `kit-import-export.ts` — Import/export UIKits from .pen files
|
|
- `kit-utils.ts` — Extract components, find reusable nodes (re-exports `deepCloneNode` from pen-core)
|
|
|
|
## Utilities (`src/utils/`)
|
|
|
|
File operations: save/open .pen, export PNG/SVG, node clone (re-exports `cloneNodesWithNewIds` from pen-core), pen file normalization, SVG parser, syntax highlight, boolean operations, `app-storage.ts`, `arc-path.ts`, `theme-preset-io.ts`, `id.ts`
|
|
|
|
### AI Prompt Skill System
|
|
|
|
Prompts for AI design generation live in `packages/pen-ai-skills/skills/` as Markdown files with YAML frontmatter. The skill engine loads prompts by phase and intent:
|
|
|
|
- **Phases:** `planning`, `generation`, `validation`, `maintenance` — each phase loads different base skills
|
|
- **Intent matching:** Domain skills (landing-page, dashboard, etc.) are loaded when keywords match the user message
|
|
- **Budget control:** Token budget per phase prevents context overflow
|
|
|
|
**Adding a new skill:** Create a `.md` file in the appropriate `skills/` subdirectory with frontmatter (name, phase, trigger, priority, budget, category). The Vite plugin auto-compiles on save.
|
|
|
|
**Usage:** `import { resolveSkills } from '@zseven-w/pen-ai-skills'` → `resolveSkills('generation', userMessage, { flags, dynamicContent })`
|
|
|
|
## Server API (`server/`)
|
|
|
|
- **`api/ai/`** — Nitro API (11 files): streaming chat, generation, agent connection, validation, MCP install, icon resolution, image generation/search. Supports Anthropic API key or Claude Agent SDK (local OAuth)
|
|
- **`utils/`** — Server utilities: Claude CLI resolver, OpenCode/Codex/Copilot clients, MCP server manager, sync state, server logger
|