Files
agentic-dev/docs/product/veect-design-spec-current.md
Danijel Martinek 4d1d53432e docs(product): commit Veect product spec bundle under docs/product/
Sandcastle implementers run in git worktrees that contain only committed
files, so every PRD referencing the spec was unreadable to dispatch
agents while the bundle sat untracked in .proto/. The eight spec
documents are copied verbatim (filenames preserved) from
.proto/veect-product-docs/ and become the canonical source.

The stray veect-product-docs.zip at the repo root was already removed
before this change — that half of the task is a verified no-op.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
2026-07-12 13:15:26 +02:00

268 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Veect — Product & Design Specification
_v1.0 · July 2026 · covers `Veect.dc.html` (interactive prototype), `Veect Landing.dc.html`, and `veect-codebase/` (React 18 · TypeScript strict · Tailwind · shadcn-style)_
_[Stored verbatim as project ground truth for the current design/prototype — founder-provided 2026-07-10. Companion: `veect-ui-gap-spec.md` for what is NOT yet in this design.]_
---
## 1. Product
**Veect is a design-system-native canvas.** A designer brings their own tokens and
components; Veect composes screens from _only_ that system and exports production React
that imports their real library. The three invariants everything hangs on:
1. **One runtime** — canvas, preview, isolation and export render the same tree through
the same renderer. No "roughly how it'll look."
2. **0 unregistered elements** — AI output is whitelist-sanitized against the component
registry; anything outside it is refused, never faked.
3. **Deterministic code** — same tree → same code, every time. Export imports the
customer's library (`@solstice/ui` in the demo), never inlined clones.
Demo fiction: the customer is **Solstice** (warm team-scheduling brand), with designer
Maya (owner) and design engineer Devon (reviewer, owns the merge veto).
---
## 2. Brand & design language
### 2.1 Logo
Typographic wordmark: lowercase **`veect`**, Instrument Sans 600, letter-spacing 0.035em,
line-height 1, closed by a **square ink terminal** (the "vector point") sized ≈ 0.28 × font
size, baseline-aligned, `currentColor`. No pictorial mark. Codebase atom: `Logo size={n}`.
### 2.2 Color — chrome tokens
Color belongs to the customer's canvas; the instrument is monochrome. The accent IS the ink.
| Token | Light (default file value) | Dark |
|---|---|---|
| `--bg` / `--panel` | `#FCFCFB` | `#0E0E0D` |
| `--raised` / `--chip` | `#FFFFFF` / `#F4F3F0` | `#161615` |
| `--line` / `--line2` | `#E7E6E2` / `#CFCEC8` | `#262624` / `#3A3A37` |
| `--t1` / `--t2` / `--t3` | `#161513` / `#63615B` / `#9A978F` | `#F4F4F2` / `#A6A6A1` / `#73736E` |
| `--iris` (accent = ink) | `#161513` | `#F4F4F2` |
| `--iris-dim` | `rgba(22,21,19,.06)` | `rgba(244,244,242,.09)` |
| `--btn-ink` (text on accent) | `#FFFFFF` | `#0E0E0D` |
| `--warn` / `--err` / `--live` | `#9A7B3F` / `#B05E5E` / `#5B7F5E` | `#C2A36B` / `#C97070` / `#8BA88E` |
Amber (`--warn`) is reserved for AI-scope affordances (pick outline, scope chips, draw
strokes) and the unmapped-component warning. The prototype ships **dark by default**
(user preference); the codebase mirrors this (`index.html data-theme="dark"`).
### 2.3 Surfaces & elevation
Flat. Radius **2px everywhere** in chrome (customer canvas keeps its own `radius-md`
token). No floating shadows — separation is a hairline: popovers/menus use
`box-shadow: 0 0 0 1px var(--line2)`. Canvas frames sit on the board with a 1px
`rgba(0,0,0,.14)` ring.
### 2.4 Typography
- **UI**: Instrument Sans 400/500/600 — 13px base, 1112.5px controls.
- **Labels**: Fragment Mono, 911px, uppercase, letter-spacing .06.14em — all section
headers, metadata, and "engraved" captions.
- **Customer content**: the system's own font (demo: Bricolage Grotesque) — never used
for chrome.
- Scale discipline: chrome text never below 8px (activity-bar labels), canvas display
type responsive per view (§6).
### 2.5 Iconography
Hand-drawn 16-grid SVG, 1.5px stroke, round caps, `currentColor`. Set: chat (spark),
layers, library, tokens, history, inspect (sliders), polish (spark-4), code (chevrons),
pick (crosshair), draw (pen), eye / eye-off, mic. No icon fonts, no emoji.
### 2.6 Motion
120450ms, `cubic-bezier(.2,.7,.2,1)`. Keyframes: `riseIn`, `popIn`, `fadeIn`,
`lineFlash` (code sync), `nodePulse` (token ripple). Everything respects
`prefers-reduced-motion`.
### 2.7 Voice
Plainspoken, no hype, no emoji. Refusals teach ("You don't have a component for this
yet"), fixes explain the _why_ in the user's own tokens.
---
## 3. Screens
| Screen | Purpose | Key elements |
| ----------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sign in** | design-partner entry | email → straight through; SSO stubs; provisioning note |
| **Home** | projects + systems | project grid (1 live + placeholders), search, Solstice system card (ramp, open tokens, re-import), "bring a design system" |
| **Onboarding** | the re-theme reveal | two paths: paste tokens (parse → contrast checks) or 5-token quick path (brand, neutrals, radius, type, spacing) with live mini-kit; ends "Bring it to life →" |
| **Editor** | the canvas (§45) | |
| **Settings** | system + governance | token source card, component mappings ("merge bar"), craft standard picker, export defaults, plan, delete |
| **Profile** | account | identity card, theme preference, workspace members (Maya/Devon), keyboard map, sign out |
| **System update** | US-6 re-import | paste → diff (CHANGED/ADDED/REMOVED + swatches) → impact line → apply-with-undo → ripple |
| **Landing** | marketing (§10) | |
Navigation: project dropdown (top-left) is the hub — all projects, new project, export,
copy TSX, import tokens, upload component, settings, profile, onboarding demo. Escape and
outside-click dismiss. Avatar → Profile everywhere.
---
## 4. Editor anatomy
### 4.1 Top bar (36px)
Wordmark · project dropdown · `✓ saved` · **view switcher** (centered: Desktop / Tablet /
Mobile / ⧉ All) · Preview · **Export** (primary) · theme toggle ◐ · avatar.
### 4.2 Activity bar (44px, fixed left)
Toggleable icon+label buttons, grouped by dividers:
`✦ Chat``Layers · Library · Tokens · History``Inspect · Polish``Code`.
Click = open that panel/tab; click again = collapse. Active = `--iris-dim` chip. At
overlay widths (<1000px) panels are mutually exclusive and float over the board.
### 4.3 Panels (resizable via edge-drag; « » collapse chevrons)
- **Chat** (284px) vertical AI thread 7): bubbles, proposal Accept/Discard inline,
refusal actions, model picker (haiku/sonnet), image attachments, scope chip.
- **Board rail** (216px) LAYERS: collapsible tree (caret-expand, double-click reveal),
per-frame **variant chips** 6); LIBRARY: 10-component base kit with mapping badges,
isolation ◉, add +, drag-to-canvas, patterns, custom `.tsx/.jsx` upload; TOKENS: brand
ramp + curated swatches + hex, radius stepper, type picker, neutrals, spacing base
every change ripples live (`nodePulse`); HISTORY: labelled steps, restore cursor 8).
- **Inspector** (244px) selection card, Edit-with-AI (scoped), content/variant/weight/
tone/size controls, gap/pad steppers (system-scale steps), Tailwind utilities
(collapsible; w/h/max-w/shadow/opacity selects + custom string), token bindings,
FRAME settings (name, width ±80, **active view** line). Polish tab: §7.3.
- **Code** (380px, dark `#161311` always) file segs (`{Frame}.tsx` / `tokens.css`),
line-numbered TSX with click-lineselect-node sync and `lineFlash` on change; **edit
mode** (toggle syntax-highlighted textarea apply parses back via the generated
grammar, line-referenced errors); footer `prettier ✓ tsc ✓`.
- **Isolation** (over board) variant × state grid per component on a paper stage, real
runtime, Esc exits.
### 4.4 Board
Infinite surface: scroll pans, ⌘/ctrl-scroll zooms at cursor, two-finger pinch, drag
empty board pans, background click deselects. Zoom cluster ( % + · fit · + frame ·
board backdrop toggle). Frames render as **view clusters** 6) with a draggable name
tab (`Home · 34 nodes · one codebase`). Selection = ink ring; hover = neutral ring;
AI-target = amber ring. Tool pill (bottom-center): **Pick (V) · Draw (D) · Overlays (O)
· Voice (stub)** icon buttons with key hints.
### 4.5 Preview
Full-screen overlay, real hover/focus states, active view's width fills the screen
(mobile/tablet render as a centered device sheet).
### 4.6 Keyboard
`⌘K` commands · `✦` focus composer · `⌘Z/⇧⌘Z` undo/redo · `⌘0` fit · `⌘1` 100% ·
`⌘±` zoom · `V/D/O` tools · `⌫` delete selection · `Esc` dismiss cascade (menu modes
refusal proposal scope selection).
---
## 5. Canvas node model
`board → frame[] → (stack | card | heading | text | button | badge | input | avatar |
image | divider | custom)*`. Layout via `dir/gap/pad/padX/padY/align/justify/maxW/bg`
(4px scale). Content props per type; `tw` bag for curated utility classes. Frames carry
`x/y/w/views/view`. IDs are stable; comment anchors and code-line mapping key off them.
---
## 6. Responsive variants — one tree, three widths
- Views: **desktop** (frame's own `w`, default 1280) · **tablet 768** · **mobile 390**.
- A frame renders every enabled view side by side (120px gap) same children, so an
edit anywhere updates every view. Captions (`tablet · 768`) label each block; the
**active view** (drives preview, code, export width) is ink-highlighted.
- Renderer responds to view width: row-stacks wrap 900, cards get flex-basis 240,
display type steps down (xl: 54 44 34px) 900/≤480.
- Switcher semantics: Desktop/Tablet/Mobile = show only that view + make it active;
** All** = all three. Layer chips: label click = select frame + make active (opens
frame settings); eye icon = show/hide that view (min 1). Cluster growth shifts
right-neighbors by the width delta clusters never collide.
---
## 7. AI, constrained
### 7.1 Compose
Prompt system prompt embeds the registry JSON (types + allowed props) + brand voice
rules (one primary CTA per group, 4px spacing, no lorem). Response is sanitized: unknown
type **refusal**, numeric props clamped to scale, strings capped. Result stages as a
**dashed ghost** on the active frame Accept commits (history label `AI compose —
accepted`), Discard drops.
### 7.2 Scoped edits
Pick tool (V) or Inspector "✦ Edit with AI": amber target ring + composer scope chip
(`h1 · Scheduling…`), inline bubble at cursor, type-aware quick actions (punchier /
shorter / demote / colorize ×n…). Edit proposals ghost beside the original and swap in
on Accept.
### 7.3 Polish (the Impeccable pass)
Ranked issues (HIGH/MED/LOW): weak hierarchy (display heading at 400), competing primary
CTAs, off-scale gaps (`gap-[18px]` drift), uneven sibling padding, AA contrast failures
(with measured ratios). Each: title _why it matters_ one-click fix **in the user's
tokens**. Fix-all; empty state "Impeccable. Nothing to fix." Craft standard selectable
in Settings (Veect default / Impeccable / custom DESIGN.md).
### 7.4 Refusal protocol
Off-registry ask (3D globe, video, charts…) "You don't have a component for this yet"
- reason + **Compose from primitives** / Not now. Never generic markup. Models: Haiku 4.5
default, Sonnet 4.5 option; offline heuristics keep demos deterministic.
---
## 8. History
Every mutation is a labelled step (`Add Button`, `Polish — Two primary actions`,
`View → tablet`, `AI edit — accepted`…). History tab lists steps newest-first with age.
Clicking restores that state and sets a **cursor**: newer steps dim (35%); the next
meaningful edit truncates the dimmed trail. `⌘Z` walks steps; redo restores.
---
## 9. Code generation & round-trip
| Canvas | Export | Notes |
| ------------- | ------------------------------------- | --------------------------------------- |
| heading/text | `<h1h4>/<p>` + Tailwind | size/weight/tone classes, neutral ramp |
| button | `<Button kind size>` | `variant→kind` rename shown in mappings |
| card | `<Card>` | pad/gap classes |
| input | `<TextField label placeholder />` | |
| avatar | `<Avatar name />` | |
| badge | `@veect/base-kit` fallback + TODO | until mapped "map now" chip |
| stack | `<div>/<nav>` flex classes | |
| image/divider | semantic HTML | |
| custom upload | real `import X from "./components/…"` | props sniffed from source |
`tokens.css` generates from the live system. The **edit-mode parser** accepts exactly
this grammar back (line-referenced errors otherwise) the grammar runs both ways.
Export dialog: honest file tree, `npm i && npm run dev`, copy `{Frame}.tsx`, fidelity
badge. Guarantee line: _deterministic — same tree, same code_.
---
## 10. Landing page
Carbon-mono flat (same language). Sections: fixed nav (scroll-spy underline, blur on
scroll) · Hero ("Your system in. Real React out.", masked line reveal, magnetic CTAs,
live 5-token kit demo with 3D tilt) · proof strip (0 unregistered / <10% LOC / <20 min)
· three-pillar wedge · graceful-refusal chat (typewriter) · code panel (staggered lines)
· Polish demo (run/undo on a Solstice card) · CTA. Left ruler tracks scroll. GSAP +
ScrollTrigger, all reduced-motion-safe.
---
## 11. Codebase map & seams
See `veect-codebase/README.md` for the atomic-design map (config / engine / store /
hooks / ui / atoms / molecules / organisms / templates / pages), product invariants,
and **Handoff notes** the deliberate seams: model bridge (`engine/ai.ts#complete`),
export zip, placeholder projects, auth, persistence. Board substrate: React Flow
(`@xyflow/react`, MIT) frames as custom nodes, zustand as single source of truth.
Pre-flight: `npm run typecheck && npm run lint`.