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
14 KiB
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:
- One runtime — canvas, preview, isolation and export render the same tree through the same renderer. No "roughly how it'll look."
- 0 unregistered elements — AI output is whitelist-sanitized against the component registry; anything outside it is refused, never faked.
- Deterministic code — same tree → same code, every time. Export imports the
customer's library (
@solstice/uiin 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, 11–12.5px controls.
- Labels: Fragment Mono, 9–11px, 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
120–450ms, 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 (§4–5) | |
| 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/.jsxupload; 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
#161311always) — file segs ({Frame}.tsx/tokens.css), line-numbered TSX with click-line→select-node sync andlineFlashon change; edit mode (toggle → syntax-highlighted textarea → apply parses back via the generated grammar, line-referenced errors); footerprettier ✓ 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 | <h1–h4>/<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.