# Veect — design-system-native canvas > Full product & design specification: [`SPEC.md`](./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 ```bash 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** — `NodeRenderer` backs canvas *and* preview; codegen walks the same tree (`engine/codegen.ts` is deterministic: same tree → same code). - **The board is React Flow** (`@xyflow/react`, MIT) — frames are custom nodes with `.frame-drag-handle` name 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.ts` whitelist-sanitizes model output and refuses anything outside the registry rather than failing open to generic markup. - **Green is reserved** — the `LiveDot` atom is the only green in the chrome; success states use neutral surfaces + accent check. - **Craft is a pass, not a vibe** — `engine/polish.ts` holds 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#complete` throws 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** — `HomePage` lists two static placeholder cards; back with real data. - **Auth** — `SignInPage` continues straight through; SSO buttons are visual. - **Persistence** — the zustand store is in-memory; add storage middleware for real sessions. - Theme default is dark (`index.html` `data-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`).