DESIGN.md · alpha · 2026-10-20 · sha256 c0b356c86dedb6bc

DESIGN.md alphaA

Immutable. This exact content never changes and is served at /api/v1/blob/c0b356c86dedb6bc.

---
version: alpha
name: editonny
description: Studio visual language for editonny's guide, edit preview, landing surfaces, and design-system showcase. Dark studio is the default theme; light paper is the alternative theme visitors can choose.
colors:
  ink-950: "#050506"
  ink-900: "#0b0b0d"
  ink-850: "#111114"
  ink-800: "#17171b"
  ink-700: "#212126"
  ink-600: "#2c2c33"
  ink-500: "#3b3b44"
  ink-400: "#5a5a66"
  fog-50: "#fafafa"
  fog-200: "#e4e4e7"
  fog-400: "#a1a1aa"
  fog-500: "#8b8b94"
  fog-600: "#71717a"
  white: "#ffffff"
  orange-50: "#fff1ea"
  orange-100: "#ffd6c2"
  orange-300: "#ff8a52"
  orange-500: "#ff4f12"
  orange-600: "#e63f05"
  orange-700: "#b82f00"
  orange-800: "#7a1f00"
  orange-900: "#2b0b00"
  volt-300: "#e9ff8f"
  volt-400: "#d4ff3a"
  volt-600: "#a6d600"
  sun-300: "#ffe566"
  sun-400: "#ffd60a"
  rec-400: "#ff3b5c"
  sky-400: "#4dc3ff"
  paper-0: "#ffffff"
  paper-50: "#fafaf6"
  paper-100: "#f4f3ed"
  paper-200: "#e8ebdf"
  paper-300: "#d8dbcf"
  paper-400: "#bfc5b5"
  paper-500: "#aeb3a4"
  paper-600: "#6a6e61"
  paper-700: "#66695e"
  paper-750: "#606957"
  paper-900: "#242721"
  olive-100: "#e9eedc"
  olive-200: "#dce4ca"
  olive-250: "#d8e5b3"
  olive-300: "#c7d6b9"
  olive-350: "#b7c79e"
  olive-400: "#b3c78e"
  olive-450: "#91a56f"
  olive-500: "#84966c"
  olive-550: "#7e965b"
  olive-575: "#748858"
  olive-600: "#637d31"
  olive-650: "#627346"
  olive-700: "#557522"
  olive-800: "#526343"
  forest-700: "#354935"
  lime-400: "#d6f66b"
  lime-500: "#c9ec51"
  amber-700: "#7a5f00"
  crimson-700: "#c4122f"
  azure-700: "#0b6fa8"
  primary: "{colors.orange-500}"
  secondary: "{colors.volt-400}"
  tertiary: "{colors.sun-400}"
  neutral: "{colors.ink-900}"
  surface: "{colors.ink-900}"
  on-surface: "{colors.fog-50}"
  on-primary: "{colors.ink-950}"
  error: "{colors.rec-400}"
  light-surface: "{colors.paper-100}"
  light-on-surface: "{colors.paper-900}"
  light-secondary: "{colors.lime-400}"
  light-error: "{colors.crimson-700}"
typography:
  display:
    fontFamily: Figtree
    fontSize: 112px
    fontWeight: 800
    lineHeight: 0.94
    letterSpacing: -0.05em
  headline-lg:
    fontFamily: Figtree
    fontSize: 80px
    fontWeight: 800
    lineHeight: 0.92
    letterSpacing: -0.06em
  headline-md:
    fontFamily: Figtree
    fontSize: 56px
    fontWeight: 700
    lineHeight: 1.08
    letterSpacing: -0.035em
  headline-sm:
    fontFamily: Figtree
    fontSize: 32px
    fontWeight: 800
    lineHeight: 1.05
    letterSpacing: -0.04em
  title:
    fontFamily: Figtree
    fontSize: 24px
    fontWeight: 800
    lineHeight: 1.1
    letterSpacing: -0.03em
  body-lg:
    fontFamily: Figtree
    fontSize: 18px
    fontWeight: 500
    lineHeight: 1.6
  body-md:
    fontFamily: Figtree
    fontSize: 15px
    fontWeight: 400
    lineHeight: 1.55
  body-sm:
    fontFamily: Figtree
    fontSize: 13px
    fontWeight: 400
    lineHeight: 1.45
  label-md:
    fontFamily: Figtree
    fontSize: 13px
    fontWeight: 600
    lineHeight: 1.3
  label-button:
    fontFamily: Figtree
    fontSize: 15px
    fontWeight: 700
    lineHeight: 1
    letterSpacing: -0.01em
  eyebrow:
    fontFamily: ui-monospace
    fontSize: 11px
    fontWeight: 600
    lineHeight: 1.5
    letterSpacing: 0.16em
  timecode:
    fontFamily: ui-monospace
    fontSize: 13px
    fontWeight: 600
    lineHeight: 1
  kinetic:
    fontFamily: Anton
    fontSize: 56px
    fontWeight: 400
    lineHeight: 0.9
  caption-clean:
    fontFamily: Montserrat
    fontSize: 30px
    fontWeight: 900
    lineHeight: 1.05
  caption-hand:
    fontFamily: Caveat
    fontSize: 30px
    fontWeight: 700
    lineHeight: 1.05
  caption-marker:
    fontFamily: Permanent Marker
    fontSize: 30px
    fontWeight: 400
    lineHeight: 1.05
  editorial-body:
    fontFamily: Inter
    fontSize: 16px
    fontWeight: 400
    lineHeight: 1.6
rounded:
  2xs: 4px
  xs: 6px
  sm: 10px
  md: 14px
  lg: 20px
  xl: 24px
  2xl: 32px
  3xl: 40px
  device: 54px
  full: 999px
spacing:
  half: 2px
  "1": 4px
  "1-5": 6px
  "2": 8px
  "2-5": 10px
  "3": 12px
  "3-5": 14px
  "4": 16px
  "5": 20px
  "6": 24px
  "7": 28px
  "8": 32px
  "10": 40px
  "12": 48px
  "14": 56px
  "16": 64px
  "20": 80px
  "24": 96px
  "28": 112px
  "32": 128px
  gutter: 56px
  container: 1440px
  content: 1360px
  topbar: 64px
components:
  button-primary:
    backgroundColor: "{colors.orange-500}"
    textColor: "{colors.ink-950}"
    typography: "{typography.label-button}"
    rounded: "{rounded.full}"
    height: 50px
    padding: 24px
  button-primary-hover:
    backgroundColor: "{colors.orange-300}"
    textColor: "{colors.ink-950}"
  button-volt:
    backgroundColor: "{colors.volt-400}"
    textColor: "{colors.ink-950}"
    rounded: "{rounded.full}"
  button-sm:
    height: 38px
    padding: 16px
  button-lg:
    height: 60px
    padding: 28px
  icon-button-tile:
    backgroundColor: "{colors.ink-600}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.md}"
    size: 44px
  badge:
    backgroundColor: "{colors.ink-700}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.full}"
    height: 26px
    padding: 12px
  input-field:
    backgroundColor: "{colors.ink-850}"
    textColor: "{colors.fog-50}"
    typography: "{typography.body-md}"
    rounded: "{rounded.md}"
    padding: 14px
  select:
    backgroundColor: "{colors.ink-850}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.md}"
    height: 52px
  choice-card-selected:
    backgroundColor: "{colors.ink-700}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.lg}"
  chip:
    textColor: "{colors.fog-200}"
    rounded: "{rounded.full}"
    height: 36px
  chip-selected:
    backgroundColor: "{colors.fog-50}"
    textColor: "{colors.ink-950}"
  card:
    backgroundColor: "{colors.ink-800}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.xl}"
    padding: 24px
  dialog:
    backgroundColor: "{colors.ink-800}"
    textColor: "{colors.fog-50}"
    rounded: "{rounded.2xl}"
    padding: 32px
    width: 520px
  toast:
    backgroundColor: "{colors.fog-50}"
    textColor: "{colors.ink-900}"
    rounded: "{rounded.full}"
  guide-button:
    backgroundColor: "{colors.lime-400}"
    textColor: "{colors.paper-900}"
    rounded: "{rounded.2xs}"
    padding: 16px
---

# editonny design system

This file is the visual contract and the source of truth for tokens. The YAML front matter is normative; `design-system/tokens/*.css` implements it and `npm test` fails when a primitive color, radius, or spacing step drifts between the two. The component library, its map, and the reference pages live in [`design-system/`](design-system/README.md).

## Overview

A local video studio directed through conversation. The interface speaks like a calm editing director: direct, honest about what it does, and focused on the next decision. Visually it is solid color plus purposeful motion — near-black studio surfaces, saturated orange for the one main action, electric volt for live state and focus, and sun for caption highlights. No brown, sepia, or muddy gradients; light is an effect, not a UI background.

Two themes share every component:

- **Dark studio** (default, `:root` or `data-theme="dark"`): the export's v2 language for the preview, landing surfaces, and showcase.
- **Light paper** (`data-theme="light"`): the editorial palette — paper, ink, olive, and lime — with the same orange brand accent. The guide in `web/` renders in the dark studio theme by default and switches to light paper through a saved visitor preference.

## Colors

Primitives never change with the theme; components consume only semantic roles, which each theme maps to primitives.

| Role | Dark studio | Light paper | Use |
|---|---|---|---|
| `--bg-page` / `--bg-deep` | ink-900 / ink-950 | paper-100 / paper-200 | Page and top bars |
| `--surface-card` / `--surface-raised` / `--surface-tile` | ink-800 / ink-700 / ink-600 | paper-50 / paper-0 / paper-200 | Panels, raised items, tool tiles |
| `--surface-well` / `--surface-selected` | ink-850 / ink-700 | paper-50 / olive-100 | Fields, selected choices |
| `--line-1` / `--line-2` / `--line-strong` | white 7% / 12% / 22% | paper-300 / 400 / 500 | Hairlines and borders |
| `--text-1` / `--text-2` / `--text-3` | fog-50 / fog-400 / fog-500 | paper-900 / 700 / 600 | Primary, secondary, tertiary text |
| `--text-label` | fog-200 | paper-900 | Field labels and compact control text |
| `--accent` / `--text-accent` | orange-500 / orange-500 | orange-500 / orange-700 | Main action, accent text |
| `--accent-2` / `--focus-ring` | volt-400 / volt-400 | lime-400 / olive-700 | Live, success, focus |
| `--success` `--warning` `--danger` `--info` | volt, sun, rec, sky | olive-700, amber-700, crimson-700, azure-700 | Status text and outlines |

- Orange carries black text (`--text-on-accent`), never white. One primary orange action per view.
- Solid blocks (orange, volt, white, fire gradient) are the main compositional motif for call-outs, service and offer cards, and tapes.
- Footage, captions, and glass controls over media use the theme-independent `--on-media`, `--glass-*`, and `--media-*` tokens.
- Text pairs meet WCAG AA 4.5:1 for body text. `--fog-500` was added because the export's `--fog-600` measured 3.7:1 on cards; `--fog-600` remains for decorative strokes only.

## Typography

- **Figtree** (`--font-sans`, `--font-display`) for interface and display; display weight 800 with −0.05 to −0.06em tracking and 0.9 leading.
- **Anton** (`--font-kinetic`) uppercase for impact: tapes, large numbers, call-outs, step numbers (outlined, then filled).
- **Mono** (`--font-mono`) for eyebrows with an index chip, commands, and timecodes.
- **Caption lettering** inside rendered videos: Anton (impact), Montserrat (clean), Caveat (hand), Permanent Marker (marker).
- **Editorial stacks** for editorial surfaces: `--font-editorial` (Inter, system sans) with `--font-serif` (Georgia) italic emphasis.

Sizes come only from `--size-*` tokens (10–160 px) and the fluid `--size-fluid-*` headline tokens. Highlight the keyword of a headline with a solid block (`Highlight` or `KineticText`), one per headline.

The `--text-label-font` shorthand implements `typography.label-md`; `--text-label` supplies the theme's label color.

## Layout

Spacing uses the `--space-*` scale (2–128 px, including the 2, 6, 10, 14, and 28 px half steps). Containers are 1360–1440 px with a 56 px gutter. Guide pages are airy (about 110 px between sections); the preview is compact (14–16 px card padding). Hero layouts use two columns (copy × a 9:16 workbench or phone), the landing hero headline uses `--size-fluid-landing`, card grids wrap with `auto-fit`, and every layout collapses to one column without horizontal scrolling at 390 px.

## Elevation & Depth

Depth comes from solid tonal steps and 1 px lines first, shadows second. Cards are solid `--surface-card` with `--line-1`. Use `--shadow-md` for lift on clickable cards, `--shadow-lg` for dialogs and popovers, `--shadow-glow` only on the active orange action or tool, and glass (`--surface-glass`, blur 20 px, `--inner-glass`) for headers and controls over media. The animated `beam` border marks a single hero object per view.

## Shapes

Radii come from `--radius-*`: tiles and fields 10–14 px, cards 24 px, hero blocks 32–40 px, devices 54/44 px, and every action is a pill. Text-relative shapes (highlight blocks, the wordmark "e") use em values. The wordmark block keeps its asymmetric corners (0.26 × size, 0.05 × size).

## Components

All 38 components live in `design-system/components/` and are imported from the workspace package `@editonny/design-system` (entry point `design-system/components/index.ts`). Every interactive one supports default, hover, active, focus-visible, and disabled; the showcase also shows loading, error, empty, and selected where they apply.

- **Core:** Button (primary, volt, white, dark, glass, outline, ghost; sm/md/lg; loading), IconButton (tile, glass, accent, volt, ghost; pressed), Icon, Wordmark, Eyebrow, Badge (nine tones, mono, live), Kbd.
- **Forms:** TextField (help, error, counter, multiline), Select, ChoiceCard (icon, media, compact; selected), Switch (row), SegmentedControl (glass or solid; awaiting dot).
- **Content:** Card (surface, raised, glass, orange, volt, white, fire; beam, spotlight, lift), MediaCard, SceneCard (eight schematic motifs), PromptCard, StepItem, CommandLine, Accordion.
- **Feedback:** Toast, Dialog (native modal or inline), StatusLine (idle, working, awaiting, offline, done), ProgressRing.
- **Editor:** Transport, Timeline (seekable slider), MarkItem, Waveform, KineticCaption.
- **Motion:** Marquee, KineticText, Counter, Aurora, Reveal.
- **Site:** SiteHeader, LanguageSelect, CreatorChip, Highlight, Chip.

The edit-preview composition template is in `design-system/templates/preview/`; the guide's compositions live in the web app (`web/src/features/`).

## Do's and Don'ts

- Do build new UI from the library and tokens; do not hard-code colors, font families, font sizes, spacing, or radii. ESLint (`design/tokens`, raw-literal rules) and `npm run typecheck` enforce this.
- Do keep one orange primary per view and black text on orange.
- Do use volt or olive for focus rings: 2 px, 3 px offset.
- Do respect `prefers-reduced-motion`; components already stop their timers.
- Do not use emoji; glyphs (↗ → ⧉ × ✦ ✓) only sparingly.
- Do not put light effects (aurora, beam) behind more than one object per view.
- Do not present schematic previews as rendered video; say they are illustrative.
- Do not invent product names, prices, results, or testimonials in examples.

## Motion

Easings: `--ease-out` (expo) for entrances, `--ease-spring` for interactions, `--ease-snap` for wipes and highlighter sweeps, `--ease-in-out` for loops. Durations: 120, 200, 320, 600, and 1200 ms with a 70 ms stagger. Hover lifts 2 px with a glow and a shine sweep; press scales to 0.95 with the spring. Entrances blur and slide up (`ed-word-in`, `Reveal`). Loops (waves, live pulses, floating chips, marquees) are decorative. The `ed-*` keyframe library is in `design-system/tokens/motion.css`.

## Iconography

Lucide line icons with a 2 px round stroke, inheriting `currentColor`. The bundled set (Lucide 0.460.0, ISC) is in `design-system/assets/icons/` and is rendered inline by `Icon`; pass `base` only for an external folder served over HTTP. Tool icons sit in rounded tiles; controls over media sit in glass circles. Round flags for the language picker are in `design-system/assets/flags/`.

## Content

Commands, code, and source text are English (see `AGENTS.md`); the guide's interface and requests are also localized for Brazilian Portuguese and Spanish, following the same voice. Speak to the reader as "you"; the product says "we" only when it takes on work, and the AI is "your AI" or "the agent". Use sentence case for titles and buttons, mono uppercase eyebrows with an index ("HOW IT WORKS / 01"), verb-first actions (Create, Copy request, Use in my request, Approve, Mark start), and "For example," in placeholders. House vocabulary: request, cut, sample, finish, hook, call to action, scene, mark, section, raw footage. State limits honestly: "The guide does not access or upload files."

## Implementation

- Tokens: `design-system/tokens/` (`colors.css` holds primitives and both themes); apps import them through `@editonny/design-system/styles.css`.
- Change a token in this front matter and in the token CSS together; `tests/design-system.test.mjs` checks primitives, radii, and spacing.
- Fonts are the engine's bundled OFL/Apache files, loaded by the web app with `next/font` and exposed to the tokens as `--font-*-face`; footage stills and 3D objects are referenced from the skill rather than copied.
- The showcase at `/design-system` (web app route) renders every component, state, and the preview template in both themes.