Copy the founder's design handoff bundle (.proto/design/) into docs/product/reference/ byte-for-byte so dispatch agents running in git worktrees can read the HTML prototypes, veect-codebase/ prototype, upload PNGs, and remaining bundle files (ADR-029: reference only, never vendored into packages/). Ignore-list entries so whole-codebase auditors and formatters skip reference material: .prettierignore (byte preservation through lint-staged), .fallowrc.json ignorePatterns, root ESLint ignores, and the coverage:diff allowlist in scripts/coverage/diff.mjs (+ unit test). .DS_Store files skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
Veect — design-system-native canvas
Full product & design specification:
SPEC.md
A React 18 + TypeScript (strict) + Tailwind + shadcn-style codebase for the Veect MVP: a canvas where a designer composes screens from their own tokens and components and gets real React out — constrained AI, a Polish (Impeccable) craft pass, and honest code.
Run
npm i
npm run dev # vite
npm run typecheck # tsc --noEmit
npm run lint # eslint
Architecture — atomic design
src/
types/ Domain types (VeectNode, DesignSystem, Proposal, PolishIssue…)
config/ Library manifest + node glyphs + demo fiction (customer identity, imports, team)
engine/ Pure logic, no React: color math, tree ops, views (responsive variants),
codegen, parser (code→tree), tw utilities, polish rules, isolation specs,
upload intake, constrained-AI prompt + sanitizer
store/ zustand store (navigation, document + labelled restorable history, panels + tabs, chat)
hooks/ usePanelResize, useAiCompose (AI orchestration)
lib/ cn(), clamp(), truncate()
components/
ui/ shadcn-style primitives (Button, Input, Badge, Select, Panel) — cva + tailwind-merge
atoms/ Logo, MonoLabel, Swatch
molecules/ SegmentedControl, Stepper, ChatBubble, ChatComposer, LayerTree, LibraryList,
TokenEditor, PolishIssueCard, CollapseButton, ZoomControls
organisms/ ActivityBar, NodeRenderer, BoardCanvas, FrameNode, ChatPanel, BoardSidebar,
Inspector, PolishTab, IsolationView, CodePanel, ExportDialog, TopBar
templates/ EditorLayout (activity bar + resizable columns), PageShell
pages/ SignIn, Home, Onboarding, Editor, Settings, Profile, SystemUpdate
Rules of the split
- Atoms render one thing, take no store access.
- Molecules compose atoms, still store-free (props in, events out).
- Organisms own a slice of store state and one product concern.
- Templates own layout only. Pages wire organisms to a screen.
engine/is framework-free and unit-testable; nothing in it imports React.
Product invariants encoded here
- One runtime —
NodeRendererbacks canvas and preview; codegen walks the same tree (engine/codegen.tsis deterministic: same tree → same code). - The board is React Flow (
@xyflow/react, MIT) — frames are custom nodes with.frame-drag-handlename tabs, so the DOM inside stays fully interactive. Scroll pans, ⌘/pinch zooms at the cursor, pane click deselects; the zustand tree remains the single source of truth (React Flow carries only positions + viewport). - 0 unregistered elements —
engine/ai.tswhitelist-sanitizes model output and refuses anything outside the registry rather than failing open to generic markup. - Green is reserved — the
LiveDotatom is the only green in the chrome; success states use neutral surfaces + accent check. - Craft is a pass, not a vibe —
engine/polish.tsholds the Impeccable-derived rules; every issue carries a why and a one-click fix expressed in the user's tokens.
Wiring the model
engine/ai.ts#complete expects a host-provided client (the prototype used one); point it
at your /api/compose endpoint in production. Everything else runs fully offline.
Handoff notes — deliberate seams
- Model bridge —
engine/ai.ts#completethrows without a host client; swap in your API. - Export zip —
ExportDialog's "Download .zip" is presentational; wire it to a bundler endpoint (the code it shows is real —engine/codegen.ts). - Placeholder projects —
HomePagelists two static placeholder cards; back with real data. - Auth —
SignInPagecontinues straight through; SSO buttons are visual. - Persistence — the zustand store is in-memory; add storage middleware for real sessions.
- Theme default is dark (
index.htmldata-theme+ store); light is one toggle away.
Prototype parity roadmap
Ported for parity with the prototype: activity bar (ActivityBar — toggleable icon
groups drive every panel; tabs live in the store), responsive variants
(engine/views.ts — one tree rendered at 1–3 widths per frame, view chips in Layers with
eye toggles, Desktop/Tablet/Mobile/All switcher in the top bar, cluster-shift on resize),
and the ultra-minimal flat restyle (paper/ink light default + carbon dark, 2px radii,
hairline borders instead of shadows — index.css + tailwind.config.ts).