mirror of
https://github.com/ZSeven-W/openpencil.git
synced 2026-06-01 03:14:29 +07:00
Set up the Fabric.js v7 canvas integration with bidirectional sync to a Zustand document store. Includes drawing tools (select, rectangle, ellipse, line, text, frame, hand), viewport pan/zoom, smart guides, dimension labels, and the main editor layout with toolbar and status bar. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.7 KiB
3.7 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.
Key technologies: React 19, Fabric.js v7 (canvas engine), Zustand v5 (state management), TanStack Router (file-based routing), Tailwind CSS v4, Vite 7, 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, bidirectional document↔canvas sync, object factorysrc/stores/— Zustand stores:canvas-store(UI state),document-store(PenDocument tree CRUD)src/types/— Type system:pen.ts(PenDocument/PenNode),canvas.ts(ToolType),styles.ts(Fill/Stroke/Effect)src/components/editor/— Editor layout, toolbar, tool buttonssrc/components/panels/— Layer panel, property panel with section componentssrc/components/shared/— Reusable UI: ColorPicker, NumberInput, SliderInput
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. Icons from lucide-react.
Code Style
- 单个文件不要超过 800 行。超出时应拆分为更小的模块。
- 每个文件只导出一个组件,每个组件只承担单一职责。
.ts和.tsx文件命名使用 kebab-case(烤肉串风格),例如canvas-store.ts、use-keyboard-shortcuts.ts。