Enhance CLAUDE.md with detailed architecture, key modules, and AI configuration. Introduce LICENSE file with MIT License terms. Remove obsolete Header component to streamline the codebase.
5.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Commands
- Dev server:
bun --bun run dev(runs on port 3000) - Build:
bun --bun run build - Preview production build:
bun --bun run preview - Run all tests:
bun --bun run test(Vitest) - Run a single test:
bun --bun vitest run path/to/test.ts - Type check:
npx tsc --noEmit - Install dependencies:
bun install
Architecture
OpenPencil is an open-source vector design tool (alternative to Pencil.dev) with a Design-as-Code philosophy. Built as a TanStack Start full-stack React application with Bun runtime. Server API powered by Nitro.
Key technologies: React 19, Fabric.js v7 (canvas engine), Zustand v5 (state management), TanStack Router (file-based routing), Tailwind CSS v4, shadcn/ui (UI primitives), Vite 7, Nitro (server), TypeScript (strict mode).
Data Flow
React Components (Toolbar, LayerPanel, PropertyPanel)
│ Zustand hooks
▼
┌─────────────────┐ ┌───────────────────┐
│ canvas-store │ │ document-store │ ← single source of truth
│ (UI state: │ │ (PenDocument) │
│ tool/selection │ │ CRUD / tree ops │
│ /viewport) │ │ │
└────────┬────────┘ └────────┬──────────┘
│ │
▼ ▼
Fabric.js Canvas canvas-sync-lock
(imperative render) (prevents circular sync)
- document-store is the single source of truth. Fabric.js only renders.
- User edits on canvas → Fabric events → update document-store (with sync lock)
- User edits in panels → update document-store →
use-canvas-syncupdates Fabric canvas-sync-lock.tsprevents circular updates when Fabric events write to the store
Key Modules
src/canvas/— Fabric.js integration: canvas init, drawing events, viewport (pan/zoom), selection sync, smart guides, bidirectional document↔canvas sync, object factorysrc/stores/— Zustand stores:canvas-store(UI/tool/selection/viewport),document-store(PenDocument tree CRUD),history-store(undo/redo),ai-store(chat/code generation state)src/types/— Type system:pen.ts(PenDocument/PenNode),canvas.ts(ToolType),styles.ts(Fill/Stroke/Effect),variables.ts(VariableDefinition)src/components/editor/— Editor layout, toolbar, tool buttons, status barsrc/components/panels/— Layer panel, property panel (fill/stroke/size/corner-radius/effects/text/appearance sections), AI chat panel, code panelsrc/components/shared/— Reusable UI: ColorPicker, NumberInput, DropdownSelect, ExportDialog, SaveDialogsrc/components/ui/— shadcn/ui primitives: Button, Select, Separator, Slider, Toggle, Tooltipsrc/services/ai/— AI chat service, design prompts, design-to-node generationsrc/services/codegen/— React+Tailwind and HTML+CSS code generatorssrc/hooks/—use-keyboard-shortcuts(global keyboard event handling)src/lib/— Utility functions (utils.tswithcn()for class merging)src/utils/— File operations (save/open .pen), export (PNG/SVG), node clone, pen file normalization, syntax highlightserver/api/ai/— Nitro server API:chat.ts(streaming chat),generate.ts(non-streaming generation). Supports Anthropic API key or Claude Agent SDK (local OAuth) as dual providers
Fabric.js v7 Gotchas
- Default origin is
center/center— always setoriginX: 'left',originY: 'top'on objects soleft/topmeans top-left corner - Pointer capture — Fabric captures pointers on
upperCanvasEl; attach pointer listeners there, not ondocument - Coordinate conversion — use
canvas.getScenePoint(e)withcanvas.calcOffset()for accurate pointer-to-scene mapping - Default strokeWidth is 1 — explicitly set
strokeWidth: 0when no stroke is desired
Routing
File-based routing via TanStack Router. Routes in src/routes/, auto-generated tree in src/routeTree.gen.ts (do not edit).
/— Landing page/editor— Main design editor
Path Aliases
@/* maps to ./src/* (configured in tsconfig.json and vite.config.ts).
Styling
Tailwind CSS v4 imported via src/styles.css. UI primitives from shadcn/ui (src/components/ui/). Icons from lucide-react. shadcn/ui config in components.json.
Code Style
- 单个文件不要超过 800 行。超出时应拆分为更小的模块。
- 每个文件只导出一个组件,每个组件只承担单一职责。
.ts和.tsx文件命名使用 kebab-case(烤肉串风格),例如canvas-store.ts、use-keyboard-shortcuts.ts。- UI 组件统一使用 shadcn/ui 设计令牌(
bg-card、text-foreground、border-border等),禁止使用硬编码的gray-*、blue-*等 Tailwind 颜色。
Git Commit 规范
使用 Conventional Commits 格式:
<type>(<scope>): <subject>
<body>
Type
feat— 新功能fix— Bug 修复refactor— 重构(不改变行为)perf— 性能优化style— 代码格式(不影响逻辑)docs— 文档test— 测试chore— 构建/工具/依赖变更
Scope
按模块划分:editor、canvas、panels、history、ai、codegen、store、types。
规则
- subject 用英文,小写开头,不加句号,祈使语气(如
add、fix、remove)。 - body 可选,解释 why 而非 what,可用中英文。
- 一个 commit 只做一件事。不要把不相关的改动混在一起。
License
MIT License. See LICENSE for details.