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).
8.1 KiB
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, andSpatialIndexfor hit testing - Dirty-flag rendering —
markDirty()schedules arequestAnimationFrameredraw; no continuous rendering loop - Node flattening —
syncFromDocument()walks the PenDocument tree, resolves auto-layout positions via layout engine, and produces flatRenderNode[]with absolute coordinates - SpatialIndex (
skia-hit-test.ts) — R-tree backed spatial queries forhitTest()(click) andsearchRect()(marquee selection) - Coordinate conversion —
screenToScene()/sceneToScreen()inskia-viewport.tshandle viewport ↔ scene transforms - Event handling — mouse/keyboard events managed by
SkiaInteractionManager(skia-interaction.ts); hit testing for resize/rotate/arc handles inskia-hit-handlers.ts;skia-canvas.tsxis 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 toSkiaInteractionManagerskia-interaction.ts—SkiaInteractionManagerclass: 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:SkiaEngineclass,syncFromDocument(), viewport, node flattening, zoom/pan, dirty-flag loopskia-renderer.ts— GPU draw calls: shapes, text, paths, images, selection handles, guides, agent indicatorsskia-init.ts— CanvasKit WASM loader with CDN fallbackskia-hit-test.ts—SpatialIndexR-tree for spatial queriesskia-viewport.ts— Viewport mathskia-paint-utils.ts— Color parsing, gradient creation, text line wrappingskia-path-utils.ts— SVG path to CanvasKit Path conversionskia-image-loader.ts— Async image loading and cachingskia-overlays.ts— Selection overlays, hover highlights, dimension labelsskia-pen-tool.ts— Pen tool: anchor points, control handles, path buildingskia-font-manager.ts— Font management
Shared Canvas Modules
canvas-sync-lock.ts— Prevents circular sync loopscanvas-sync-utils.ts—forcePageResync()utilitycanvas-constants.ts— Default colors, zoom limits, stroke widthscanvas-node-creator.ts—createNodeForTool,isDrawingToolcanvas-layout-engine.ts— Auto-layout (delegates to@zseven-w/pen-core)canvas-text-measure.ts— Text width/height estimation, CJK detectionfont-utils.ts,node-helpers.ts— Re-exports from pen-coreinsertion-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,activePageIddocument-store.ts— PenDocument tree CRUD, variable CRUD, component management (all with history)document-store-pages.ts— Page actions: add, remove, rename, reorder, duplicatedocument-tree-utils.ts— Re-exports tree helpers and clone utilities from@zseven-w/pen-corehistory-store.ts— Undo/redo (max 300 states), batch modeai-store.ts— Chat messages, streaming state, model selectionagent-settings-store.ts— AI provider config, MCP CLI integrations, localStorage persistenceuikit-store.ts— UIKit managementtheme-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-bannerpanels/— 32 files: layer panel, property panel, fill/stroke/corner/size/text/effects/export/layout/appearance sections, AI chat panel, code panel, component browser, variables panelshared/— Reusable UI: ColorPicker, NumberInput, SectionHeader, ExportDialog, SaveDialog, AgentSettingsDialog, IconPickerDialog, VariablePicker, FigmaImportDialog, FontPicker, LanguageSelectoricons/— Provider/brand logosui/— 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 selectionai-prompts.ts— System prompts for design generationai-types.ts— ChatMessage, ChatAttachment, AIDesignRequest, OrchestratorPlanmodel-profiles.ts— Adapts thinking mode, effort, timeouts per model tierdesign-generator.ts— Top-levelgenerateDesign/generateDesignModificationdesign-parser.ts— JSON/JSONL parsingdesign-canvas-ops.ts— Canvas mutation operationsdesign-node-sanitization.ts— Node merging (re-exportsdeepCloneNodefrom pen-core)design-validation.ts/design-pre-validation.ts/design-validation-fixes.ts— Post-generation validationicon-resolver.ts— Auto-resolves icon names to Lucide SVG pathsorchestrator.ts/orchestrator-sub-agent.ts/orchestrator-prompts.ts— Spatial decomposition orchestratorcontext-optimizer.ts— Chat history trimming
Hooks (src/hooks/)
use-keyboard-shortcuts.ts— Global keyboard: tools, clipboard, undo/redo, save, z-order, boolean opsuse-electron-menu.ts— Electron native menu IPC listeneruse-figma-paste.ts— Figma clipboard pasteuse-file-drop.ts— File drag-and-dropuse-mcp-sync.ts— MCP live canvas syncuse-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 UIKitkit-import-export.ts— Import/export UIKits from .pen fileskit-utils.ts— Extract components, find reusable nodes (re-exportsdeepCloneNodefrom 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