mirror of
https://github.com/MaksTinyWorkshop/_Assistant_Lead_Tech
synced 2026-06-28 10:03:40 +02:00
chore(bmad): migrate 80_bmad/base from 6.0.4 to 6.9 + port customizations to TOML overrides
Migration des modules via l'installer officiel (Quick update, en place) : - core/bmm 6.0.4 -> 6.9.0 - tea 1.5.3 -> 1.19.0 - cis 0.1.8 -> 0.2.1 Portage des customisations Lead_tech vers le nouveau mécanisme d'overrides (_bmad/custom/<skill>.toml, couche "team" résolue par resolve_customization.py) : - 6 agents directs (analyst, architect, dev, pm, tech-writer, ux-designer) - module tea - workflows: dev-story, create-story, code-review, quick-dev, qa-generate-e2e-tests - agents disparus en 6.9 reportés vers leurs workflows hôtes (QA -> code-review, SM -> create-story, quick-flow-solo-dev -> quick-dev) - règle de capitalisation 95_a_capitaliser factorisée dans _bmad/custom/leadtech-capitalisation.md (référencée via persistent_facts) Nettoyage du legacy 6.0.4 : - suppression des 17 *.customize.yaml (non lus par 6.9) - suppression des .bak générés par l'installer (contenu porté en .toml) - suppression de 17 skills orphelins dans .agents/skills (anciens noms, .agents/.claude réalignés 66=66) - suppression des coquilles de workflows disparus Tous les overrides validés par le resolver officiel (12/12 JSON valide, base préservée + ajouts Lead_tech). Le cœur (couche customize.toml) n'est plus modifié, donc les updates 6.x futurs ne pourront plus écraser ces customisations. Note env: resolve_customization.py exige Python >=3.11 (uv installé, python3 -> 3.12.13). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
---
|
||||
name: bmad-ux
|
||||
description: Plan UX patterns and design specifications. Use when the user says "lets create UX design" or "create UX specifications" or "help me plan the UX"
|
||||
---
|
||||
# BMad UX
|
||||
|
||||
## Overview
|
||||
|
||||
You are a master UX facilitator. **Elicit and capture** the user's vision, never impose yours. Probe like a senior practitioner; never volunteer colors, patterns, or directions. Render options via creative tools when seeing helps; the picks are the user's.
|
||||
|
||||
Produce two peer contracts: **`DESIGN.md`** (visual identity per the [Google Labs spec](https://github.com/google-labs-code/design.md) — owns *how it looks*) and **`EXPERIENCE.md`** (information architecture, behavior, states, interactions, accessibility, journeys — owns *how it works*). EXPERIENCE.md cross-references DESIGN.md tokens by name using `{path.to.token}` syntax. Both spines win on conflict with any mock, wireframe, or import.
|
||||
|
||||
## The DESIGN.md spine
|
||||
|
||||
Per the [Google Labs spec](https://github.com/google-labs-code/design.md). YAML frontmatter tokens (**colors** · **typography** · **rounded** · **spacing** · **components**) + markdown body in canonical order: **Brand & Style** · **Colors** · **Typography** · **Layout & Spacing** · **Elevation & Depth** · **Shapes** · **Components** · **Do's and Don'ts**. Sections omittable; order locked when present. Spec rules: `references/design-md-spec.md`. Shape: read every entry in `{workflow.design_md_examples}`.
|
||||
|
||||
## The EXPERIENCE.md spine
|
||||
|
||||
Always: **Foundation** (form-factor, UI system when present; DESIGN.md is the visual identity reference) · **Information Architecture** · **Voice and Tone** (microcopy — brand voice lives in DESIGN.md.Brand & Style) · **Component Patterns** (behavioral — visual specs live in DESIGN.md.Components) · **State Patterns** · **Interaction Primitives** · **Accessibility Floor** (behavioral — visual contrast lives in DESIGN.md) · **Key Flows** (named-protagonist journeys with a climax beat).
|
||||
|
||||
When triggered: **Inspiration & Anti-patterns** · **Responsive & Platform**.
|
||||
|
||||
Invent sections for product-specific concerns. Shape: read every entry in `{workflow.experience_md_examples}`.
|
||||
|
||||
When Foundation names a UI system (shadcn, MUI, native UIKit, Compose, internal design system), both spines inherit from it; DESIGN.md tokens reference or extend the system's defaults, EXPERIENCE.md specifies only the behavioral delta.
|
||||
|
||||
## Sources
|
||||
|
||||
UX may lead, follow, or stand alone. Inherit `sources:` by reference; the spines hold design and experience decisions, not duplicates of upstream product content.
|
||||
|
||||
## On Activation
|
||||
|
||||
1. Resolve customization: `uv run {project-root}/_bmad/scripts/resolve_customization.py --skill {skill-root} --key workflow`. On failure, read `{skill-root}/customize.toml` directly and use defaults.
|
||||
2. Run `{workflow.activation_steps_prepend}`. Treat `{workflow.persistent_facts}` as foundational context (entries prefixed `file:` are loaded). `{workflow.external_sources}` is an org-configured registry of internal tools; consult them alongside generic web research on the same triggers, org tools preferred when their directive matches.
|
||||
3. Load `{project-root}/_bmad/bmm/config.yaml` (+ `config.user.yaml` if present). Resolve `{user_name}`, `{communication_language}`, `{document_output_language}`, `{planning_artifacts}`, `{project_name}`, `{date}`. Missing keys → neutral defaults; never block.
|
||||
4. If headless, follow `references/headless.md` for the whole run. Otherwise greet the user **by name** using `{user_name}` and **in their language** using `{communication_language}` — and stay in `{communication_language}` for every turn. In the greeting, let the user know `bmad-party-mode` and `bmad-advanced-elicitation` are always available. Then scan for misroute on the first message: PRD → `bmad-prd`; architecture → `bmad-architecture`; game UX → BMad GDS; agent/skill → `bmad-workflow-builder`; brief → `bmad-product-brief`.
|
||||
5. Detect intent: **Create**, **Update**, **Validate**. For Create, before binding a fresh workspace, scan `{workflow.ux_output_path}` for prior in-progress runs (folders matching `{workflow.run_folder_pattern}` whose `DESIGN.md` frontmatter `status` is not `final`) and offer to resume rather than starting over.
|
||||
|
||||
Run `{workflow.activation_steps_append}`.
|
||||
|
||||
Activation is complete. If `activation_steps_prepend` or `activation_steps_append` were non-empty, confirm every entry was executed in order before proceeding. Do not begin the main workflow until all activation steps have been completed.
|
||||
|
||||
## Modes
|
||||
|
||||
**Create.** Bind `{doc_workspace}` to `{workflow.ux_output_path}/{workflow.run_folder_pattern}/`. Create `.working/` and `imports/`; seed the memlog with `uv run {project-root}/_bmad/scripts/memlog.py init --workspace {doc_workspace} --field topic="<product/UX>"`; create `DESIGN.md` (frontmatter only) and `EXPERIENCE.md` (frontmatter only). Run Discovery → Finalize.
|
||||
|
||||
**Update.** Read spines + memlog + sources. If `.memlog.md` is missing, init it with `uv run {project-root}/_bmad/scripts/memlog.py init --workspace {doc_workspace}` — this update is entry one. Surface conflicts with prior decisions. Run Finalize.
|
||||
|
||||
**Validate.** See `references/validate.md`.
|
||||
|
||||
## Discovery
|
||||
|
||||
**Capture; do not author.** The spines are distilled at Finalize toward the memlog. Decisions → `.memlog.md` (canonical), each appended via `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type <decision|change|override|assumption|event> --text "…"` — never hand-edited; a resume reloads it. Creative-tool artifacts → `.working/`. User-supplied visuals (Figma, sketches, brand decks, image folders) → `imports/`, one `memlog.py append` per item. Spines win on conflict.
|
||||
|
||||
**Source scan.** Glob `{planning_artifacts}/` for candidate input paths; surface paths only — never read content in the parent. User confirms which apply or adds others; subagent-extracts on confirm.
|
||||
|
||||
Brain dump first — even when the user opens with paragraphs (that's intake). Subagent-extract big docs. One "anything else?" probe. Stakes: hobby / internal / consumer / regulated.
|
||||
|
||||
Working mode:
|
||||
|
||||
- **Fast path** — batch gaps, draft both spines with `[ASSUMPTION]` tags, skip creative tools.
|
||||
- **Coaching path** — walk decisions; creative tools woven in.
|
||||
- **Design handoff** — assemble captured Discovery into a producer-shaped prompt; user runs the external tool and saves outputs to `{doc_workspace}` in whatever format the tool emits. Producer registry: `{workflow.design_handoffs}` (default: Google Stitch). EXPERIENCE.md can follow via Update mode when ready.
|
||||
|
||||
Creative tools — scan `{workflow.creative_tools}`, invoke when seeing helps. Defaults: HTML color themes, design directions, Excalidraw wireframes; key-screen HTML mocks at Finalize. See `references/creative-tools.md`. Research subagents on demand; consult `{workflow.external_sources}` when entries match.
|
||||
|
||||
Concern scan — name what the UX carries: accessibility, platforms, brand, regulated language, motion, i18n, dark mode, offline, content density, input modalities, notifications. Open list; drives invented sections.
|
||||
|
||||
Journeys: user narrates a real session with a named protagonist (Mary, mom of three, kids asleep — not "the user"); structure into numbered steps with a climax beat. Mirror source-spec names verbatim when defined.
|
||||
|
||||
Form-factor: mobile / web / desktop / multi-surface must resolve before IA closes. Named-protagonist journeys often derive it (Pary on iPad implies an iPad surface; Skeeter on Android adds a multi-surface need); when journeys don't disambiguate, probe.
|
||||
|
||||
Surface closure: stated needs become screens through journeys. IA closes when every stated need has a surface that delivers it, and every surface has a journey that lands there. When closure fails, probe — never invent the missing piece.
|
||||
|
||||
## Reviewer Gate
|
||||
|
||||
Used by Validate and Finalize. **Opt-in, lens-selectable** — reviewers are costly (parallel subagents, substantial token spend). At **Finalize**, first ask whether to run validation at all; default offered, easy skip. At **Validate** intent the user already opted in — skip that question. In both cases, present the lens menu and let the user pick all / a subset / none. Menu: rubric walker (`references/validate.md`) + `{workflow.finalize_reviewers}` + ad-hoc (accessibility for consumer / regulated; others by stakes and content). Picked lenses dispatch as parallel subagents → each writes `review-{slug}.md`, returns a compact summary. If any lens ran, run the synthesis pipeline in `references/validate.md`.
|
||||
|
||||
## Finalize
|
||||
|
||||
Outcomes, in order:
|
||||
|
||||
- **Spines distilled.** Subagent reads `.memlog.md`, `.working/`, `imports/`, sources; produces `DESIGN.md` against `## The DESIGN.md spine` + `{workflow.design_md_examples}` and `EXPERIENCE.md` against `## The EXPERIENCE.md spine` + `{workflow.experience_md_examples}`. Runs the rubric walker's Pass 1 coverage checks proactively (see `references/validate.md`). Surface gaps; never invent.
|
||||
- **Inputs reconciled.** Subagent per user-supplied input → `reconcile-{slug}.md`. Surface dropped qualitative ideas.
|
||||
- **Reviewer Gate offered.** Ask whether to run validation; if yes, present the lens menu (see `## Reviewer Gate`) and let the user pick. If any lens ran, resolve findings before polish; otherwise proceed.
|
||||
- **Open items triaged.** Open Questions, `[ASSUMPTION]`, `[NOTE FOR UX]`. Phase-blockers one at a time; non-blockers → `memlog.py append`.
|
||||
- **Key-screen mocks rendered.** Key-screens tool → `.working/` for surfaces where layout drives behavior or anchors visual language.
|
||||
- **Mock coverage confirmed.** Walk every IA surface; classify *mocked* vs *spine-only*. Ask: *"These will be built from spine tables alone — any need a visual reference?"* Render more if named; log spine-only choices.
|
||||
- **Layout extracted, artifacts promoted.** Distill subagent re-reads each `.working/` and `imports/` artifact; lifts visual decisions into DESIGN.md and behavioral decisions into EXPERIENCE.md. Promote `.working/` keepers to `mockups/` (HTML) or `wireframes/` (Excalidraw); imports stay. Inline relative links at relevant spine sections; state spines-win-on-conflict once.
|
||||
- **Polished, handed off, closed.** Apply `{workflow.doc_standards}` in order. Execute `{workflow.external_handoffs}`; surface URLs. Set both files' `status: final`, `updated: {date}`. Log finalization via `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type event --text "spines finalized"`. Share paths. Common next: `bmad-architecture`, `bmad-create-epics-and-stories`, `bmad-dev-story`. Run `{workflow.on_complete}`.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Color Themes Renderer
|
||||
|
||||
Subagent prompt. Produce one self-contained HTML page at the supplied `.working/color-themes-{n}.html` path showing 4-6 distinct theme variations side by side so the user can pick.
|
||||
|
||||
Each variation: header (name + one-line emotional register), token chips for every semantic role decided so far, and one realistic UI snippet using the palette (content drawn from the conversation, not lorem). Include light and dark side-by-side when both modes are in scope. Avoid near-identical pastels — variations must differ in register, not just hue.
|
||||
|
||||
Inline CSS only, system font stack, no JS, no network. Document concrete hex values in `<style>` comments per variation so the user can lift them if they pick that theme. The spine itself stays semantic.
|
||||
|
||||
Return to the parent: file path, one-line per variation, mode coverage. Do not dump HTML into the parent context. If interactive, open the file with `python3 -c "import webbrowser, pathlib; webbrowser.open(pathlib.Path('PATH').resolve().as_uri())"`.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Design Directions Renderer
|
||||
|
||||
Subagent prompt. Produce 3-6 distinct visual directions for the product's hero screen, each a separate self-contained HTML file at `.working/direction-{slug}.html` (or one combined `directions-{n}.html` if the parent's intent says side-by-side).
|
||||
|
||||
Each direction is a *complete visual personality* applied to the same key screen — not a palette swap. Differ on density, type weight, motion implication, brand register. Each file: 2-3 sentence rationale, near-1:1 hero screen mockup in a phone or browser frame, ideally a secondary screen, at least one state variant visible (aging row, empty state, etc).
|
||||
|
||||
Use real product content from the conversation. Voice/tone from `.memlog.md` applied to every visible string — no lorem. Inline CSS, system fonts, no JS or network. Document hex values in `<style>` comments per direction.
|
||||
|
||||
Return to the parent: file paths, one-line personality summary per direction, what hero screen was depicted. Do not dump HTML into parent context. If interactive, open each file in the browser.
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
name: Linen & Logic
|
||||
colors:
|
||||
surface: '#fbf9f4'
|
||||
surface-dim: '#dbdad5'
|
||||
surface-bright: '#fbf9f4'
|
||||
surface-container-lowest: '#ffffff'
|
||||
surface-container-low: '#f5f3ee'
|
||||
surface-container: '#f0eee9'
|
||||
surface-container-high: '#eae8e3'
|
||||
surface-container-highest: '#e4e2dd'
|
||||
on-surface: '#1b1c19'
|
||||
on-surface-variant: '#4e453d'
|
||||
inverse-surface: '#30312e'
|
||||
inverse-on-surface: '#f2f1ec'
|
||||
outline: '#80756b'
|
||||
outline-variant: '#d1c4b9'
|
||||
surface-tint: '#715a3f'
|
||||
primary: '#59452b'
|
||||
on-primary: '#ffffff'
|
||||
primary-container: '#735c41'
|
||||
on-primary-container: '#f5d6b4'
|
||||
inverse-primary: '#e0c1a1'
|
||||
secondary: '#a43b2c'
|
||||
on-secondary: '#ffffff'
|
||||
secondary-container: '#fd7d69'
|
||||
on-secondary-container: '#71160b'
|
||||
tertiary: '#374a5f'
|
||||
on-tertiary: '#ffffff'
|
||||
tertiary-container: '#4f6278'
|
||||
on-tertiary-container: '#caddf8'
|
||||
error: '#ba1a1a'
|
||||
on-error: '#ffffff'
|
||||
error-container: '#ffdad6'
|
||||
on-error-container: '#93000a'
|
||||
primary-fixed: '#fdddbb'
|
||||
primary-fixed-dim: '#e0c1a1'
|
||||
on-primary-fixed: '#281804'
|
||||
on-primary-fixed-variant: '#58432a'
|
||||
secondary-fixed: '#ffdad4'
|
||||
secondary-fixed-dim: '#ffb4a7'
|
||||
on-secondary-fixed: '#400200'
|
||||
on-secondary-fixed-variant: '#842417'
|
||||
tertiary-fixed: '#d0e4ff'
|
||||
tertiary-fixed-dim: '#b4c8e2'
|
||||
on-tertiary-fixed: '#071d30'
|
||||
on-tertiary-fixed-variant: '#35485d'
|
||||
background: '#fbf9f4'
|
||||
on-background: '#1b1c19'
|
||||
surface-variant: '#e4e2dd'
|
||||
typography:
|
||||
display-lg:
|
||||
fontFamily: Libre Caslon Text
|
||||
fontSize: 48px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.1'
|
||||
letterSpacing: -0.02em
|
||||
display-lg-mobile:
|
||||
fontFamily: Libre Caslon Text
|
||||
fontSize: 36px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.1'
|
||||
headline-md:
|
||||
fontFamily: Libre Caslon Text
|
||||
fontSize: 32px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.2'
|
||||
headline-sm:
|
||||
fontFamily: Libre Caslon Text
|
||||
fontSize: 24px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.3'
|
||||
body-lg:
|
||||
fontFamily: DM Sans
|
||||
fontSize: 18px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.6'
|
||||
letterSpacing: 0.01em
|
||||
body-md:
|
||||
fontFamily: DM Sans
|
||||
fontSize: 16px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.6'
|
||||
label-caps:
|
||||
fontFamily: DM Sans
|
||||
fontSize: 12px
|
||||
fontWeight: '500'
|
||||
lineHeight: '1.4'
|
||||
letterSpacing: 0.1em
|
||||
caption:
|
||||
fontFamily: DM Sans
|
||||
fontSize: 13px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.4'
|
||||
rounded:
|
||||
sm: 0.125rem
|
||||
DEFAULT: 0.25rem
|
||||
md: 0.375rem
|
||||
lg: 0.5rem
|
||||
xl: 0.75rem
|
||||
full: 9999px
|
||||
spacing:
|
||||
unit: 8px
|
||||
gutter: 24px
|
||||
margin-mobile: 20px
|
||||
margin-desktop: 64px
|
||||
editorial-gap: 80px
|
||||
---
|
||||
|
||||
## Brand & Style
|
||||
|
||||
The design system is rooted in the philosophy of "Slow Design"—an intentional departure from the frantic pace of fast fashion. It evokes a tactile, "linen-weight" sensation through high-end editorial layouts and a restrained aesthetic. The target audience values provenance over presence, seeking a reflective and sophisticated discovery experience that feels as much like a boutique magazine as a digital marketplace.
|
||||
|
||||
The style is **Editorial Minimalism** with **Tactile** accents. It prioritizes breathable white space, asymmetrical layouts that mimic printed lookbooks, and a soft, sun-faded palette. Every interaction is designed to be deliberate and "anti-hype," eschewing aggressive animations for subtle transitions and quiet confidence.
|
||||
|
||||
## Colors
|
||||
|
||||
The palette is inspired by natural fibers and weathered landscapes.
|
||||
- **Warm White (#F9F7F2)** serves as the primary canvas, providing a soft, non-clinical background that reduces eye strain.
|
||||
- **Bone (#E3DED1)** and **Dust (#C2B9A7)** are used for structural depth, subtle dividers, and secondary surfaces.
|
||||
- **Tobacco (#735C41)** is the primary ink color, used for high-contrast typography and essential UI elements.
|
||||
- **Sun-faded Red (#B84A39)** and **Wool Blanket Blue (#4A5D73)** are used sparingly as "organic accents"—highlighting editorial picks or signifying subtle state changes without disrupting the tranquil atmosphere.
|
||||
|
||||
## Typography
|
||||
|
||||
Typography is the primary vehicle for the brand’s sophisticated voice.
|
||||
- **Libre Caslon Text** is the voice of the curator. Its classic proportions and elegant serifs provide the editorial weight required for discovery and storytelling.
|
||||
- **DM Sans** provides a quiet, functional counterpoint. It is used for body copy and navigational elements, ensuring clarity without competing with the headlines.
|
||||
|
||||
Large display titles should often use "optical sizing" logic—tighter leading and slightly negative letter spacing to create a cohesive visual block. Labels are always tracked out (0.1em) to maintain a sense of airy premiumness.
|
||||
|
||||
## Layout & Spacing
|
||||
|
||||
This design system employs a **Fluid Editorial Grid**. While it follows a 12-column structure on desktop, it encourages "asymmetrical breathing room"—intentionally leaving columns empty to direct focus toward high-quality imagery.
|
||||
|
||||
Spacing is generous. The `editorial-gap` (80px+) should be used between major content sections to allow the user to pause and reflect. Mobile layouts should maintain a minimum of 20px side margins to ensure the content feels framed like a page, rather than bleeding to the edges of the device. Elements should lean toward vertical stacks to mimic the scroll of a digital journal.
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
Depth is communicated through **Tonal Layering** and **Ambient Shadows** rather than sharp borders.
|
||||
- **Surfaces:** Use the "Bone" color to define containers against the "Warm White" base.
|
||||
- **Shadows:** Shadows are highly diffused and tinted with the "Tobacco" hue (`rgba(115, 92, 65, 0.08)`). They should feel like a soft glow of light hitting fabric, with large blur radii (20px+) and very low opacity.
|
||||
- **Borders:** When borders are necessary, they are 1px thick and rendered in "Dust," creating a "ghost" outline that barely separates elements from the background.
|
||||
|
||||
## Shapes
|
||||
|
||||
The shape language is **Soft (0.25rem)**. While a sharp edge feels too aggressive and a pill-shape feels too digital/tech-heavy, a subtle rounding of corners mimics the natural softening of woven textiles over time.
|
||||
|
||||
Larger containers (Cards, Modals) may use `rounded-lg` (0.5rem) to emphasize their tactile, object-like quality. Imagery should always follow these corner radii to maintain a cohesive, "framed" appearance.
|
||||
|
||||
## Components
|
||||
|
||||
- **Buttons:** Primary buttons use a solid "Tobacco" fill with "Warm White" text. Secondary buttons are "Bone" with "Tobacco" text or simply "Tobacco" text with a 1px "Dust" border. Padding is generous horizontally to create an elegant, elongated silhouette.
|
||||
- **Cards:** Editorial cards feature large imagery, a "headline-sm" title, and a "caption" subline. Shadows are only applied on hover to simulate a gentle lift.
|
||||
- **Inputs:** Minimalist underlines in "Dust" that transition to "Tobacco" on focus. Label text remains in "label-caps" above the field.
|
||||
- **Chips/Tags:** Used for material types (e.g., "100% Linen"). These are rendered in "Bone" backgrounds with "Tobacco" text, using the "Soft" corner radius.
|
||||
- **Icons:** Must be "Hand-drawn" or "Fine-line" style. Lines should have slight imperfections and vary in weight to reinforce the tactile, artisanal nature of the fashion being discovered.
|
||||
- **Navigation:** A simple, centered bottom bar or a top-weighted "Ghost" header that disappears on scroll to maximize the editorial viewport.
|
||||
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: Quill
|
||||
description: Daily writing companion. Calm, intentional, dark-mode-by-default. No streaks, no gamification.
|
||||
colors:
|
||||
surface-base: '#FAF9F7'
|
||||
surface-raised: '#FFFFFF'
|
||||
ink-primary: '#1A1B1F'
|
||||
ink-secondary: '#6B655A'
|
||||
ink-disabled: '#B5AFA5'
|
||||
accent: '#A87434'
|
||||
border-hairline: '#E8E4DD'
|
||||
surface-base-dark: '#1A1B1F'
|
||||
surface-raised-dark: '#23252B'
|
||||
ink-primary-dark: '#F0EDE8'
|
||||
ink-secondary-dark: '#A39E94'
|
||||
ink-disabled-dark: '#5E5A53'
|
||||
accent-dark: '#D4A574'
|
||||
border-hairline-dark: '#2E3036'
|
||||
typography:
|
||||
title:
|
||||
note: 'Platform native — iOS Title 1 · Android Headline Small'
|
||||
body:
|
||||
note: 'Platform native — iOS Body · Android Body Large'
|
||||
meta:
|
||||
note: 'Platform native — iOS Footnote · Android Body Small'
|
||||
rounded:
|
||||
sm: 6px
|
||||
md: 12px
|
||||
spacing:
|
||||
'1': 4px
|
||||
'2': 8px
|
||||
'3': 12px
|
||||
'4': 16px
|
||||
'5': 24px
|
||||
'6': 32px
|
||||
---
|
||||
|
||||
## Brand & Style
|
||||
|
||||
Quill is designed against the grain of contemporary habit apps. Where most products weaponize the user's calendar with streak counters and re-engagement nudges, Quill insists on something quieter — a daily prompt, a place to write, and the unspoken assurance that today's entry is enough. Showing up is the point, not the streak.
|
||||
|
||||
The visual language follows. Calm surfaces in warm off-white (light) or deep ink (dark, the default). Generous breathing room. No chromatic color competing for attention except a single warm tobacco that signals save-and-send. Text-first. Hand-on-paper, not buzz-on-screen.
|
||||
|
||||
## Colors
|
||||
|
||||
The palette is restrained on purpose — a writing surface should not compete with the writing.
|
||||
|
||||
- **Warm White (`#FAF9F7`)** is the primary canvas in light mode. Slightly warm to reduce eye strain and keep the surface from feeling clinical.
|
||||
- **Deep Ink (`#1A1B1F`)** is the dark-mode canvas and the primary body text color in light mode. Quill defaults to dark because most writing happens at night.
|
||||
- **Tobacco (`#A87434` light / `#D4A574` dark)** is the only chromatic color. Used exclusively for the save indicator and primary action — never for decoration, never for state badges.
|
||||
- **Hairline (`#E8E4DD` light / `#2E3036` dark)** separates list items at the lowest possible contrast. Anything heavier feels like UI rather than paper.
|
||||
|
||||
Avoid: red error fills (Quill is a journal, not a form), gradients (the surface is paper), and saturated accent variants — one accent, used sparingly.
|
||||
|
||||
## Typography
|
||||
|
||||
Platform conventions are the spec. iOS uses Title 1 / Body / Footnote; Android uses Headline Small / Body Large / Body Small. Dynamic type honored at every level — the largest accessibility setting must still render legibly without truncation.
|
||||
|
||||
Headlines are rare. The Today prompt is set in `title`; everything else is `body` or `meta`. No display sizes, no all-caps labels.
|
||||
|
||||
## Layout & Spacing
|
||||
|
||||
Scale: 4 / 8 / 12 / 16 / 24 / 32 px. The largest gaps land between major surfaces; the smallest sit between tightly related elements. Vertical rhythm follows a hard rule: composer breathes, list items don't.
|
||||
|
||||
Mobile margins follow platform conventions (iOS 16pt, Android 16dp). Single-column always; modal stacks one level deep, never two.
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
Quill avoids elevation as a visual device. Cards and composer surfaces sit on `surface-raised`, distinguished from `surface-base` only by tone. Shadows are reserved for the rare moment of literal physical metaphor — never for hierarchy. Hierarchy comes from layout and typography, not shadow.
|
||||
|
||||
## Shapes
|
||||
|
||||
`rounded/sm` (6px) for inputs, list rows, and small surfaces. `rounded/md` (12px) for cards and the composer. Nothing fully rounded; no pills, no perfect circles for surfaces. The aesthetic is paper-with-soft-corners, not iOS-button-pill.
|
||||
|
||||
Imagery follows container corners exactly.
|
||||
|
||||
## Components
|
||||
|
||||
- **Prompt card** — `surface-raised`. One per day. Today's prompt in `title`. Tap to open composer. No icon, no decoration; the prompt itself is the affordance.
|
||||
- **Composer** — Full-screen text view. Clean text field, generous vertical padding, single-line save indicator in the header.
|
||||
- **Save indicator** — Text only. Uses `ink-secondary`, never a checkmark icon, never a colored badge.
|
||||
- **Entry row** (Library) — Date in `meta`, first line of body in `body` (truncated to one line). Hairline divider only, no fill.
|
||||
- **Settings row** — Label left, value or chevron right. Tobacco accent only on destructive confirmations.
|
||||
|
||||
## Do's and Don'ts
|
||||
|
||||
| Do | Don't |
|
||||
|---|---|
|
||||
| Single accent color, used sparingly on save & primary action | Color-code by sentiment, mood, or category |
|
||||
| Text-only state indicators (`Saved.`) | Iconography for state (✓, ⚠, ●) |
|
||||
| Hairline dividers at lowest legible contrast | Card shadows, gradient fills, accent fills behind text |
|
||||
| Generous vertical rhythm in composer | Compress to fit more on screen |
|
||||
| Honor platform conventions for navigation | Override platform nav with custom drawer or hamburger |
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
name: Drift
|
||||
description: Focused task tracker for solo founders and small async teams. shadcn/ui on Next.js + Tailwind; this DESIGN.md specifies the brand-layer delta only.
|
||||
colors:
|
||||
# Brand overrides on top of shadcn defaults. All unlisted tokens inherit
|
||||
# from shadcn (background, foreground, muted, muted-foreground, popover,
|
||||
# popover-foreground, card, card-foreground, border, input, ring, destructive).
|
||||
primary: '#0F4C81'
|
||||
primary-foreground: '#FFFFFF'
|
||||
accent: '#F59E0B'
|
||||
accent-foreground: '#1A1208'
|
||||
primary-dark: '#5C8AC2'
|
||||
primary-foreground-dark: '#0A1A2A'
|
||||
accent-dark: '#FBC470'
|
||||
accent-foreground-dark: '#1A1208'
|
||||
typography:
|
||||
# Body, label, and muted inherit from shadcn (Geist Sans). Only display is overridden.
|
||||
display:
|
||||
fontFamily: 'Instrument Serif'
|
||||
fontSize: 36px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.15'
|
||||
letterSpacing: -0.01em
|
||||
display-sm:
|
||||
fontFamily: 'Instrument Serif'
|
||||
fontSize: 24px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.2'
|
||||
rounded:
|
||||
# Tighter than shadcn defaults — Drift reads sharper.
|
||||
sm: 4px
|
||||
md: 6px
|
||||
lg: 8px
|
||||
spacing:
|
||||
# shadcn / Tailwind defaults inherited; no overrides.
|
||||
components:
|
||||
button-primary:
|
||||
background: '{colors.primary}'
|
||||
foreground: '{colors.primary-foreground}'
|
||||
radius: '{rounded.md}'
|
||||
focus-card:
|
||||
background: '{colors.accent}'
|
||||
foreground: '{colors.accent-foreground}'
|
||||
radius: '{rounded.md}'
|
||||
border: 'none'
|
||||
command-palette-result-active:
|
||||
background: '{colors.accent}'
|
||||
foreground: '{colors.accent-foreground}'
|
||||
---
|
||||
|
||||
## Brand & Style
|
||||
|
||||
Drift is a focused task tracker for solo founders and small async teams. The product premise is that *work is a moving thing* — momentum matters more than perfectly groomed backlogs, and the right tool surfaces what you're working on *now* without making you administer a system to find it. The brand expression follows: a serif display moment in an otherwise sober sans-serif surface, a single warm accent that means *this is what's live*, and visual restraint everywhere else.
|
||||
|
||||
Drift inherits shadcn/ui defaults wholesale. This DESIGN.md specifies only the brand-layer deltas — primary color, accent color, display typography, slightly tighter corners, and a handful of brand-specific components. The 80% of components that ship from shadcn (Button, Card, Dialog, Sheet, Command, Popover, Toast) inherit shadcn's visual specs as-is. Customizing those is *explicitly* against the brand discipline — shadcn's defaults are the contract.
|
||||
|
||||
## Colors
|
||||
|
||||
The Drift palette is two colors of brand-layer plus shadcn defaults for everything else.
|
||||
|
||||
- **Primary Navy (`#0F4C81` light / `#5C8AC2` dark)** is the brand color. Used on primary buttons, active nav items, link underlines, and the "current week" indicator. Replaces shadcn's default `primary`.
|
||||
- **Focus Amber (`#F59E0B` light / `#FBC470` dark)** is the accent. Used exclusively to indicate the task or project currently in focus — the one you're working on *right now*. Never used for chrome, never used decoratively, never used for state badges. Amber means "live."
|
||||
- **All other tokens** (`background`, `foreground`, `muted`, `muted-foreground`, `border`, `input`, `ring`, `card`, `popover`, `destructive`) inherit from shadcn defaults. If the brand can't justify overriding a token, it doesn't override it.
|
||||
|
||||
Avoid: chromatic flourishes, gradient surfaces, custom destructive colors (use shadcn's), more than two brand colors. The discipline is two-colors-and-stop.
|
||||
|
||||
## Typography
|
||||
|
||||
Body / label / caption inherit shadcn's Geist Sans ramp. Only the `display` role is brand-overridden, set in **Instrument Serif** at 36px (24px small variant). The serif moment appears in:
|
||||
|
||||
- Empty-state hero text on Today and project surfaces
|
||||
- Project titles in the project detail header
|
||||
- The "Welcome back, {name}" greeting at first session of the day
|
||||
|
||||
Everything else stays in Geist Sans. The serif is a punctuation mark, not a default voice.
|
||||
|
||||
## Layout & Spacing
|
||||
|
||||
shadcn / Tailwind spacing scale inherited as-is (the 4-based scale: 4, 8, 12, 16, 20, 24, 32, 40, 48, 64). Maximum content width: `max-w-3xl` (768px) — Drift is not a wide-table product, and forcing one-column reading keeps the surface focused.
|
||||
|
||||
Single-column layout. Sidebar nav on `lg` (1024px+); on smaller viewports, the sidebar becomes a sheet triggered from the top bar.
|
||||
|
||||
## Elevation & Depth
|
||||
|
||||
Inherited from shadcn — subtle shadow on hover/active states, no elevation as a visual hierarchy device. Drift adds nothing on top of this; brand discipline is "shadcn's shadows are correct."
|
||||
|
||||
## Shapes
|
||||
|
||||
Tighter than shadcn defaults: `rounded/sm` (4px) for inputs, `rounded/md` (6px) for cards and buttons, `rounded/lg` (8px) for dialogs and the command palette. The crispness reads "tool" rather than "consumer app." Pill shapes (`rounded/full`) appear only on status badges.
|
||||
|
||||
## Components
|
||||
|
||||
Drift uses the following shadcn components as-is, unchanged: `Button`, `Card`, `Dialog`, `Sheet`, `Popover`, `DropdownMenu`, `Toast`, `Tabs`, `Avatar`, `Separator`. The contract: don't customize these.
|
||||
|
||||
Brand-layer-overridden components:
|
||||
|
||||
- **Button (primary variant)** — `{colors.primary}` fill, `{colors.primary-foreground}` text, `{rounded.md}` corner. Other variants (secondary, outline, ghost, destructive) inherit shadcn defaults.
|
||||
- **Focus card** — Custom Drift component. The "this is what you're working on now" card on Today and project detail. `{colors.accent}` fill, no border, slightly elevated. Appears at most once per surface.
|
||||
- **Command palette result (active)** — Override on shadcn's `Command` component: the highlighted/keyboard-selected result row uses `{colors.accent}` instead of shadcn's default `accent` token. Reinforces "this is what will fire if you hit Enter."
|
||||
|
||||
## Do's and Don'ts
|
||||
|
||||
| Do | Don't |
|
||||
|---|---|
|
||||
| Inherit shadcn defaults for everything not in the brand layer | Override shadcn's color tokens beyond `primary` and `accent` |
|
||||
| Use `{colors.accent}` only for "live / now / in-focus" | Use accent for state, chrome, or hover affordances |
|
||||
| `display` typography sparingly — empty states, hero greetings | Set body text in `display` to "make it pretty" |
|
||||
| Tighter corners than shadcn (4 / 6 / 8) | Use shadcn's default 6/8/12 (Drift reads sharper) |
|
||||
| Single-column layouts inside `max-w-3xl` | Wide multi-column tables (Drift is not a spreadsheet) |
|
||||
@@ -0,0 +1,19 @@
|
||||
# Excalidraw Wireframe Renderer
|
||||
|
||||
Subagent prompt. Produce one `.excalidraw` file at `.working/ia-{date}.excalidraw` (IA diagram) or `.working/flow-{name}-{date}.excalidraw` (flow wireframe).
|
||||
|
||||
## CRITICAL: two-character `index` fields only
|
||||
|
||||
Every element's `index` field must be **exactly two characters** (`a0`, `aZ`, `b3`, ...). Three-character indices cause a silent *"Error: invalid file"* with no diagnostic output. Assign sequentially across all elements; advance the leading letter when the trailing alphanumeric exhausts (`a0..a9, aA..aZ`, then `b0..`). Verify before writing.
|
||||
|
||||
## Shape
|
||||
|
||||
Valid Excalidraw file: `{type: "excalidraw", version: 2, source: "https://excalidraw.com", elements: [...], appState: {gridSize: null, viewBackgroundColor: "#ffffff"}, files: {}}`. Each element needs the standard Excalidraw element fields (`id, type, x, y, width, height, angle, strokeColor, backgroundColor, fillStyle, strokeWidth, strokeStyle, roughness, opacity, groupIds, frameId, roundness, seed, version, versionNonce, isDeleted, boundElements, updated, link, locked, index`). Text elements add `text, fontSize, fontFamily, textAlign, verticalAlign, baseline, containerId, originalText, lineHeight`.
|
||||
|
||||
## Content
|
||||
|
||||
**IA diagram:** boxes-and-arrows of auth stack, main app surfaces, modal routes, settings stack, cross-cutting affordances. Color sparingly to distinguish category. Layout for human legibility, not graph correctness.
|
||||
|
||||
**Flow wireframe:** screen-by-screen rectangles left-to-right, simple shapes inside (nav bar, CTA, content blocks) at low fidelity. Arrows labeled with the user action that causes transition. Annotations alongside for climax and edge-case beats.
|
||||
|
||||
Return to the parent: file path, kind, one-line subject, element count, confirmation that all indices are two-character. Do not dump JSON into parent context. Tell the user to open in Excalidraw desktop or excalidraw.com.
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
name: Quill
|
||||
status: final
|
||||
sources:
|
||||
- {planning_artifacts}/prds/quill-2025-08-15/prd.md
|
||||
updated: 2025-09-02
|
||||
---
|
||||
|
||||
# Quill — Experience Spine
|
||||
|
||||
> Illustrative example. Single-surface mobile (iOS + Android parity). Consumer posture, calm by default. Paired with `design-example-mobile.md` (Quill DESIGN.md). Demonstrates: microcopy as gating discipline, Inspiration & Anti-patterns earning its place, Responsive & Platform omitted (single-surface).
|
||||
|
||||
## Foundation
|
||||
|
||||
Single-surface mobile, iOS + Android with parity. No UI system named — inherits platform conventions for navigation, system gestures, dynamic type. `DESIGN.md` is the visual identity reference; this spine is the experience. Dark mode is the default surface; light is a setting.
|
||||
|
||||
## Information Architecture
|
||||
|
||||
| Surface | Reached from | Purpose |
|
||||
|---|---|---|
|
||||
| Today | App open (cold) | Today's prompt + entry composer |
|
||||
| Library | Tab bar | Past entries, searchable |
|
||||
| Entry detail | Library row tap | Read / edit one entry |
|
||||
| Settings | Today header gear | Account, export, theme |
|
||||
|
||||
Bottom tab bar (Today / Library / Settings). No drawer. Modal stacks one level deep, never two.
|
||||
|
||||
→ Composition reference: `mockups/today-cold.html`, `mockups/composer.html`. Spine wins on conflict.
|
||||
|
||||
## Voice and Tone
|
||||
|
||||
Microcopy. Brand voice and aesthetic posture live in `DESIGN.md`.
|
||||
|
||||
| Do | Don't |
|
||||
|---|---|
|
||||
| "Today's prompt." | "Time to write!" |
|
||||
| "Saved." | "✓ Auto-saved successfully" |
|
||||
| "We couldn't reach the cloud — your work is on this device." | "Network error" |
|
||||
| Short, complete sentences. | Streak counters, encouragement, exclamation marks. |
|
||||
|
||||
## Component Patterns
|
||||
|
||||
Behavioral. Visual specs live in `DESIGN.md.Components`.
|
||||
|
||||
| Component | Use | Behavioral rules |
|
||||
|---|---|---|
|
||||
| Prompt card | Today | One per day. Tap opens composer. |
|
||||
| Composer | Today + entry detail | No formatting toolbar in v1. Autosave on pause ≥ 600ms. |
|
||||
| Entry row | Library list | Tap → entry detail. Long-press reserved for system text selection. |
|
||||
| Save indicator | Composer header | Cycles `Editing…` → `Saved.` (≥ 800ms visible). |
|
||||
| Settings row | Settings list | Tap → detail or toggle. |
|
||||
|
||||
## State Patterns
|
||||
|
||||
| State | Surface | Treatment |
|
||||
|---|---|---|
|
||||
| Cold open | Today | Show today's prompt (cached). If no cache, `Today's prompt is loading.` with skeleton. |
|
||||
| Empty library | Library | `No entries yet — Today's prompt is your first.` Link to Today. |
|
||||
| Search empty | Library search | `No matches.` No suggestions. |
|
||||
| Offline write | Composer | Save locally. No banner. Sync on next foreground. |
|
||||
| Sync error | Settings → Account | Surfaced here only. Never block writing. |
|
||||
| Focus | Composer | Native cursor + keyboard. No custom focus chrome. |
|
||||
|
||||
## Interaction Primitives
|
||||
|
||||
- Tap to act. Long-press reserved for system text selection.
|
||||
- Swipe-to-delete on entry rows (native pattern, confirm sheet).
|
||||
- Pull-to-refresh on Library only.
|
||||
- **Banned:** carousels, hero animations on open, badge counts, streaks, push-notification re-engagement.
|
||||
|
||||
## Accessibility Floor
|
||||
|
||||
Behavioral. Visual contrast lives in `DESIGN.md`.
|
||||
|
||||
- VoiceOver / TalkBack: every interactive element labeled with role + state. Save indicator announces `Saved` on transition.
|
||||
- Dynamic type honored through `DESIGN.md` typography tokens. UI must remain legible at largest setting — no truncated controls.
|
||||
- Reduce Motion: skip the save-indicator fade; show `Saved.` immediately.
|
||||
- Tap targets ≥ 44pt (iOS) / 48dp (Android).
|
||||
- Focus traversal follows reading order on every surface.
|
||||
|
||||
## Inspiration & Anti-patterns
|
||||
|
||||
- **Lifted from Day One:** the single daily entry framing — one prompt, one composer, no inbox.
|
||||
- **Lifted from iA Writer:** the no-toolbar composer; formatting is a settings-level decision, not a per-entry one.
|
||||
- **Rejected — Streaks (Duolingo, most habit apps):** streaks weaponize the user's calendar. Quill's value is showing up *today*, not punishing missed days.
|
||||
- **Rejected — AI prompt suggestions inside the composer:** the composer is for writing, not negotiating with a model. AI lives only in the daily prompt generation.
|
||||
|
||||
## Key Flows
|
||||
|
||||
### Flow 1 — Daily write (Mira, late evening, after work)
|
||||
|
||||
1. Mira opens app.
|
||||
2. Today surface shows today's prompt (cached if offline).
|
||||
3. She taps the composer entry point.
|
||||
4. Composer opens, keyboard active.
|
||||
5. She writes; autosave fires on pause.
|
||||
6. She taps Back.
|
||||
7. **Climax:** Today surface shows `Saved.` and the entry's first line below the prompt — proof the day is captured.
|
||||
|
||||
Failure: cold prompt fetch fails → composer still opens with cached generic prompt; banner on Today only after Mira returns.
|
||||
|
||||
### Flow 2 — Recall past entry (Mira, three weeks later, looking for what she wrote about her mother)
|
||||
|
||||
1. Mira taps Library.
|
||||
2. Scrolls or searches.
|
||||
3. Taps entry row.
|
||||
4. Entry detail opens in read mode.
|
||||
5. She taps anywhere to enter edit mode (cursor at tap point).
|
||||
6. Edits autosave.
|
||||
7. **Climax:** `Saved.` visible in entry header — the older self and the present self are in continuous conversation.
|
||||
|
||||
Empty state: no entries → message routes back to Today.
|
||||
@@ -0,0 +1,133 @@
|
||||
---
|
||||
name: Drift
|
||||
status: final
|
||||
sources:
|
||||
- {planning_artifacts}/prds/drift-2026-03-12/prd.md
|
||||
updated: 2026-04-02
|
||||
---
|
||||
|
||||
# Drift — Experience Spine
|
||||
|
||||
> Illustrative example. Single-surface responsive web. shadcn/ui on Next.js + Tailwind. Paired with `design-example-shadcn.md` (Drift DESIGN.md). Demonstrates: component-library inheritance, keyboard-first interaction primitives, the "shadcn + brand-layer" pattern that covers most modern web SaaS.
|
||||
|
||||
## Foundation
|
||||
|
||||
Single-surface responsive web. shadcn/ui on Next.js 15+ with Tailwind CSS. The component library does most of the work; brand discipline is "respect the defaults except where the brand layer overrides them." `DESIGN.md` is the visual identity reference and names the override surface; this spine is the experience. Single-tenant per project; users can belong to multiple projects but each project is a self-contained workspace.
|
||||
|
||||
## Information Architecture
|
||||
|
||||
| Surface | Reached from | Purpose |
|
||||
|---|---|---|
|
||||
| Today | App open / `g t` | Current focus, in-progress tasks pulled from all projects |
|
||||
| Projects | Sidebar / `g p` | List of active and archived projects |
|
||||
| Project detail | Projects row / `g 1`–`g 9` | Tasks in this project, organized by lane |
|
||||
| Search | `⌘K` / `Ctrl+K` | Command palette — surface, navigate, act |
|
||||
| Settings | Avatar menu | Account, theme, keyboard shortcuts, billing |
|
||||
|
||||
Sidebar collapses to icons on `md`; becomes a `Sheet` on `sm`. Modal stacks one level deep (e.g., open `Dialog` on top of a surface, never on top of another dialog).
|
||||
|
||||
→ Composition reference: `mockups/today.html`, `mockups/project-detail.html`, `mockups/command-palette.html`. Spine wins on conflict.
|
||||
|
||||
## Voice and Tone
|
||||
|
||||
Microcopy. Brand voice and aesthetic posture live in `DESIGN.md`.
|
||||
|
||||
| Do | Don't |
|
||||
|---|---|
|
||||
| "What are you working on?" | "Let's get productive! 🚀" |
|
||||
| "3 tasks in motion" | "You have 3 active items." |
|
||||
| "Closed. Nice work." | "Task completed successfully ✓" |
|
||||
| "Nothing in motion. Pick something." | "No active tasks. Click below to get started!" |
|
||||
| Manager-facing: counts and verbs. Employee-facing: same. | Different tone per audience — Drift talks to everyone the same way. |
|
||||
|
||||
## Component Patterns
|
||||
|
||||
Behavioral. Visual specs live in `DESIGN.md.Components` (or in shadcn defaults, when inherited).
|
||||
|
||||
| Component | Use | Behavioral rules |
|
||||
|---|---|---|
|
||||
| Task row | Projects, Today | Click anywhere on row opens edit dialog. Checkbox toggles done state with optimistic update. Hover reveals quick-actions (`focus`, `defer`, `archive`). |
|
||||
| Focus card | Today, Project detail | At most one focus card per surface — the task or project marked with `focus` state. `f` keyboard shortcut sets focus on the active row. |
|
||||
| Command palette | Global (⌘K) | Fuzzy search across all projects, tasks, and commands. `Enter` fires the highlighted result. `→` previews a result. Escape closes. |
|
||||
| Project header | Project detail | Inline-editable title (click to edit, blur to save). Status pill: active / archived / done. |
|
||||
| Empty state | Anywhere | shadcn's empty pattern + one Drift-specific sentence. `display-sm` for the headline, body text below, single primary action. |
|
||||
|
||||
## State Patterns
|
||||
|
||||
| State | Surface | Treatment |
|
||||
|---|---|---|
|
||||
| Cold app load | Today | shadcn `Skeleton` rows (4-6) match expected layout. Resolves on data. |
|
||||
| No focus | Today | `display-sm`: "Nothing in motion. Pick something." Below: list of in-progress tasks from all projects. |
|
||||
| Empty project | Project detail | `display-sm`: "{Project title} is empty." Body: "Add a first task to get going." Single primary button. |
|
||||
| Command palette no matches | ⌘K | "No matches. Start typing a task or project name, or pick an action below." Followed by 4-5 common commands. |
|
||||
| Offline | Global (status bar) | shadcn `Toast` once: "You're offline. Changes will sync when you reconnect." Local writes continue. |
|
||||
| Permission denied | Projects (others' private) | Surface hidden from sidebar. No "blocked" screen. |
|
||||
| Stale data | Project detail | If background refresh detects changes, shadcn `Toast`: "Updated by {user_name}. Refresh." Manual refresh, no auto. |
|
||||
|
||||
## Interaction Primitives
|
||||
|
||||
**Keyboard-first.** Drift's primary audience is developers and power users; the keyboard surface is the product, the mouse is fallback.
|
||||
|
||||
- `⌘K` / `Ctrl+K` — Command palette (universal)
|
||||
- `g t` / `g p` — Go to Today / Projects (vim-style)
|
||||
- `g 1`–`g 9` — Go to project by sidebar position
|
||||
- `f` — Set focus on highlighted task/project
|
||||
- `c` — Create new task (context-aware: in the active project)
|
||||
- `Esc` — Close dialogs, exit edit mode, clear command palette
|
||||
- `/` — Focus search in current surface
|
||||
|
||||
**Mouse:** click to act, drag deferred to v2. Hover reveals row actions on `md+` (touch users tap to reveal).
|
||||
|
||||
**Banned everywhere:** infinite scroll (pagination only), drag-to-reorder in v1, hover-only affordances on `sm` viewports, modal stacks > 1 level deep.
|
||||
|
||||
## Accessibility Floor
|
||||
|
||||
Behavioral. Visual contrast lives in `DESIGN.md` (inherits shadcn's WCAG AA-compliant defaults; brand overrides verified to maintain ratios).
|
||||
|
||||
- WCAG 2.2 AA across the responsive web surface.
|
||||
- Screen reader announces page surface on navigation: "Today, focus surface" / "Project: {name}, task list, {N} tasks."
|
||||
- Keyboard shortcuts available without modifier on most surfaces (vim-style `g t` etc.) — users with motor-control limitations get the same surface as power users.
|
||||
- `Tab` order matches reading order on every surface. `Esc` always closes the topmost modal/popover.
|
||||
- Command palette is fully keyboard-operable; results announce as they update via `aria-live`.
|
||||
- Focus rings inherit shadcn's `ring` token — visible at AA contrast against `background`.
|
||||
|
||||
## Responsive & Platform
|
||||
|
||||
| Breakpoint | Behavior |
|
||||
|---|---|
|
||||
| `≥ lg` (1024px+) | Sidebar visible. Today is a 2-column layout: focus + in-motion list. |
|
||||
| `md` (768–1023px) | Sidebar collapses to icons. Today stacks to single column. |
|
||||
| `< md` (`sm`) | Sidebar becomes a `Sheet` triggered from top bar. Command palette opens fullscreen. |
|
||||
|
||||
Drift is responsive web, not a native mobile app. The product works on phones for read + simple-edit, but the primary surface is desktop / laptop.
|
||||
|
||||
## Inspiration & Anti-patterns
|
||||
|
||||
- **Lifted from Linear:** the keyboard-first discipline. `⌘K` is the command center; vim-style nav (`g t`); no drag for primary navigation; status pill vocabulary.
|
||||
- **Lifted from Notion:** inline-editable titles. Click-to-edit on project header, blur to save. No edit/view mode toggle.
|
||||
- **Lifted from shadcn:** the entire surface vocabulary. Drift's brand is *what we add to shadcn*, not a from-scratch design system. This is a deliberate posture, not a shortcut.
|
||||
- **Rejected — Streaks, badges, achievement notifications:** Drift is a tool, not a habit app. Task closure is its own reward; no celebratory animation, no "🎉 5-day streak!" toast.
|
||||
- **Rejected — AI-suggested next tasks:** Drift surfaces what's in motion, doesn't tell the user what to work on. The user picks focus; the tool surfaces consequences.
|
||||
- **Rejected — Multi-column kanban as default project view:** lists are linear; kanban hides progress behind columns. Optional v2; not the default.
|
||||
|
||||
## Key Flows
|
||||
|
||||
### Flow 1 — Morning focus (Sarah, solo founder, 8:45am Tuesday)
|
||||
|
||||
1. Sarah opens Drift in a browser tab.
|
||||
2. App loads Today. `display-sm`: "Welcome back, Sarah." Focus card shows yesterday's marked task — "Finish landing page hero copy" — still in motion.
|
||||
3. She hits `⌘K`, types "ship hero", sees the matching task and presses Enter to open it.
|
||||
4. Inline edit: she updates the task description with two new bullets. Tab + Tab triggers save.
|
||||
5. **Climax:** Sarah closes the dialog. Today re-renders: focus card still shows the hero task, but now with the updated body text visible at a glance. She doesn't have to navigate anywhere — the surface that greeted her now reflects the work she just did. She picks up her coffee and starts writing.
|
||||
|
||||
Failure: data save fails → shadcn `Toast` (destructive variant): "Couldn't save. Trying again." Inline edit retained; another `Enter` retries.
|
||||
|
||||
### Flow 2 — Async handoff (Devon and Mara, small remote team, mid-afternoon)
|
||||
|
||||
1. Devon finishes wiring up the auth flow and marks the task `done`.
|
||||
2. Mara, time-zoned three hours ahead and online during overlap, opens Drift.
|
||||
3. Today loads; her focus is on her own front-end work, but the in-motion list shows Devon's auth task now marked done and one task below it newly assigned to her — "Wire up post-auth redirect" — that Devon set during checkout.
|
||||
4. She hits `f` on the row to mark it as her focus, then `Enter` to open it.
|
||||
5. **Climax:** The focus card swaps. Her surface now shows the post-auth redirect task as the live thing she's working on; the projects sidebar shows the Auth project highlighted; the command palette `⌘K` defaults its first result to "Go to Auth project." The state of the team's progress is *embedded in her surface* — no Slack thread to scroll, no status doc to read.
|
||||
|
||||
Failure: Devon hadn't actually assigned the follow-up — Mara mis-assigned to herself. She hits `Esc`, `f` again to unfocus, and reassigns to Devon. No "are you sure" dialog; Drift trusts the user.
|
||||
@@ -0,0 +1,84 @@
|
||||
# Headless Mode JSON Schemas
|
||||
|
||||
Every headless run ends with one of these payloads. Omit keys for artifacts not produced.
|
||||
|
||||
## Common fields
|
||||
|
||||
- `status` — `"complete"`, `"blocked"`, or `"partial"`
|
||||
- `intent` — `"create"`, `"update"`, or `"validate"` (matches the detected intent)
|
||||
- `reason` — required when `status` is `"blocked"`; one-sentence explanation
|
||||
- `assumptions` — array of inferred values that were not directly confirmed by inputs
|
||||
- `open_questions` — array of items that need a human decision before the artifact can be considered final
|
||||
|
||||
## Create
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "complete",
|
||||
"intent": "create",
|
||||
"design": "{doc_workspace}/DESIGN.md",
|
||||
"experience": "{doc_workspace}/EXPERIENCE.md",
|
||||
"memlog": "{doc_workspace}/.memlog.md",
|
||||
"working_artifacts": ["{doc_workspace}/.working/color-themes-1.html"],
|
||||
"promoted_artifacts": {
|
||||
"mockups": ["{doc_workspace}/mockups/direction-calm-sage.html"],
|
||||
"wireframes": ["{doc_workspace}/wireframes/ia-2026-05-19.excalidraw"]
|
||||
},
|
||||
"open_questions": [],
|
||||
"assumptions": [],
|
||||
"external_handoffs": [
|
||||
{"directive": "Confluence upload", "tool": "corp:confluence_upload", "url": "https://confluence.corp/DESIGN/123", "status": "ok"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The `working_artifacts` and `promoted_artifacts` keys are optional and omitted entirely when empty. Headless Create runs default to not enabling creative tools — both keys are typically absent in headless output unless the caller enabled them.
|
||||
|
||||
## Update
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "complete",
|
||||
"intent": "update",
|
||||
"design": "{doc_workspace}/DESIGN.md",
|
||||
"experience": "{doc_workspace}/EXPERIENCE.md",
|
||||
"memlog": "{doc_workspace}/.memlog.md",
|
||||
"changes_summary": "1-3 sentences describing what changed and why",
|
||||
"conflicts_with_prior_decisions": [],
|
||||
"open_questions": [],
|
||||
"external_handoffs": [
|
||||
{"directive": "Confluence upload", "tool": "corp:confluence_upload", "url": "https://confluence.corp/DESIGN/123", "status": "ok"}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Validate
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "complete",
|
||||
"intent": "validate",
|
||||
"validation_report": "{doc_workspace}/validation-report.md",
|
||||
"findings_summary": {
|
||||
"critical": 0,
|
||||
"high": 0,
|
||||
"medium": 0,
|
||||
"low": 0
|
||||
},
|
||||
"offer_to_update": true
|
||||
}
|
||||
```
|
||||
|
||||
`validation_report` is always written for Validate intent — the path here is required, not optional.
|
||||
|
||||
## Blocked
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "blocked",
|
||||
"intent": "update",
|
||||
"reason": "Change signal ambiguous — could be a brand refresh or an accessibility audit response; no inferred direction"
|
||||
}
|
||||
```
|
||||
|
||||
Always include the intent (best-guess if not certain) and a one-sentence `reason`.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Key Screens Renderer
|
||||
|
||||
Subagent prompt. Fired at Finalize (or during late Discovery once layout decisions firm up). Produces 1:1 HTML mocks of the load-bearing surfaces so the spine can link to them as visual reference. Spine remains the contract; mocks illustrate.
|
||||
|
||||
## Inputs
|
||||
|
||||
`.memlog.md`, the current drafts `DESIGN.md` and `EXPERIENCE.md`, `.working/` (especially the chosen color-theme and direction mocks), source PRD. The user names which surfaces to render — typically 2-4: the canonical entry surface, the most complex flow's hero screen, any load-bearing overlay/modal, and (when present) the Week / list / dashboard view.
|
||||
|
||||
## What to render
|
||||
|
||||
One HTML file per screen, at `.working/key-{slug}.html`. Each file: realistic device frame (phone or browser), real product content from the conversation (no lorem), every visible string voice-checked against `.memlog.md`, all decided tokens applied. Show one canonical state per screen; if a surface has a load-bearing alternate state (focus, error, crisis-card-present), render it as a second column or section in the same file.
|
||||
|
||||
Inline CSS, system fonts, no JS, no network. The mock must render fully offline. Comment block at the top of the `<style>` notes which spine sections govern this screen so a future reader knows what to check.
|
||||
|
||||
## What to return
|
||||
|
||||
A compact summary to the parent:
|
||||
- file path per screen
|
||||
- one-line caption per screen ("Today picker at rest; accent on Thought record")
|
||||
- which spine sections each mock illustrates (Component Patterns rows, State Patterns rows, Flow steps)
|
||||
|
||||
The parent, at Finalize "Promote working artifacts," uses this summary to insert inline `mockups/...` links into the relevant spine sections.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- Do not invent layout — every composition decision must trace to a `.working/` artifact or a confirmation in `.memlog.md`. If a layout question is open, the mock is premature.
|
||||
- Do not show every screen of every flow — 2-4 load-bearing surfaces, not 14.
|
||||
- Do not stage marketing copy. Strings come from `.memlog.md` and voice rules.
|
||||
- Do not introduce a new pattern not in the spine's Component Patterns table. If you need one, log it and ask before rendering.
|
||||
@@ -0,0 +1,319 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
UX Design Validation Report — skeleton template.
|
||||
|
||||
This file is a starter the synthesis pass fills in directly. There is no
|
||||
substitution engine. The LLM:
|
||||
1. Reads {doc_workspace}/review-rubric.md and every review-{slug}.md from
|
||||
additional reviewers.
|
||||
2. Copies this skeleton.
|
||||
3. Replaces the placeholder content (everything between TEMPLATE markers)
|
||||
with the consolidated review, preserving the structure and CSS.
|
||||
4. Writes the result to {doc_workspace}/validation-report.html.
|
||||
5. Writes a markdown twin to {doc_workspace}/validation-report.md.
|
||||
|
||||
Visual rules the LLM must preserve:
|
||||
- The container width, the color tokens, the typography.
|
||||
- One dimension = one collapsible <section class="dimension">.
|
||||
- Verdict pill uses the verdict-* class matching its judgment.
|
||||
- Severity badge uses the badge-sev-* class matching its level.
|
||||
- Each extra reviewer (accessibility, adversarial, etc.) gets its own
|
||||
collapsible section below the rubric dimensions.
|
||||
- The footer always shows the artifact paths and timestamp.
|
||||
-->
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>UX Design Validation: TEMPLATE_UX_SPEC_NAME</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #fafaf9;
|
||||
--surface: #ffffff;
|
||||
--border: #e7e5e4;
|
||||
--text: #1c1917;
|
||||
--muted: #78716c;
|
||||
|
||||
--verdict-strong: #16a34a;
|
||||
--verdict-adequate: #65a30d;
|
||||
--verdict-thin: #d97706;
|
||||
--verdict-broken: #dc2626;
|
||||
|
||||
--sev-low: #64748b;
|
||||
--sev-medium: #ca8a04;
|
||||
--sev-high: #ea580c;
|
||||
--sev-critical: #dc2626;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Inter, system-ui, sans-serif;
|
||||
background: var(--bg);
|
||||
color: var(--text);
|
||||
line-height: 1.6;
|
||||
font-size: 15px;
|
||||
}
|
||||
.container { max-width: 960px; margin: 0 auto; padding: 32px 24px 64px; }
|
||||
|
||||
header.report-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.title h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
|
||||
.title .subtitle { color: var(--muted); font-size: 13px; margin-top: 4px; font-family: ui-monospace, "SF Mono", Menlo, monospace; }
|
||||
|
||||
.synthesis {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-left: 3px solid var(--muted);
|
||||
border-radius: 8px;
|
||||
padding: 18px 22px;
|
||||
margin-bottom: 24px;
|
||||
font-size: 15.5px;
|
||||
}
|
||||
.synthesis p { margin: 0 0 10px; }
|
||||
.synthesis p:last-child { margin-bottom: 0; }
|
||||
|
||||
.dimension-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 10px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.dim-card {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
.dim-card .dim-name { font-size: 13px; color: var(--muted); margin-bottom: 6px; }
|
||||
.dim-card .dim-verdict { font-size: 14px; font-weight: 600; }
|
||||
|
||||
section.dimension, section.reviewer-section { margin-bottom: 14px; }
|
||||
section.dimension details, section.reviewer-section details {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
section summary {
|
||||
padding: 14px 20px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
section summary::-webkit-details-marker { display: none; }
|
||||
section summary::before {
|
||||
content: "▸";
|
||||
display: inline-block;
|
||||
color: var(--muted);
|
||||
transition: transform 0.15s ease;
|
||||
}
|
||||
section details[open] summary::before { transform: rotate(90deg); }
|
||||
section summary h2 {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.005em;
|
||||
flex: 1;
|
||||
}
|
||||
.verdict-pill {
|
||||
font-size: 11px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 999px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: white;
|
||||
}
|
||||
.verdict-strong { background: var(--verdict-strong); }
|
||||
.verdict-adequate { background: var(--verdict-adequate); }
|
||||
.verdict-thin { background: var(--verdict-thin); }
|
||||
.verdict-broken { background: var(--verdict-broken); }
|
||||
|
||||
.dim-body { padding: 4px 20px 18px; }
|
||||
.dim-judgment { color: var(--text); font-size: 14.5px; }
|
||||
.dim-judgment p { margin: 0 0 10px; }
|
||||
|
||||
.findings-list { padding: 0 20px 4px; }
|
||||
article.finding {
|
||||
padding: 14px 0;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
article.finding:first-child { border-top: none; }
|
||||
article.finding header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.badge {
|
||||
font-size: 10.5px;
|
||||
padding: 3px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.badge-sev-low { background: rgba(100, 116, 139, 0.12); color: var(--sev-low); }
|
||||
.badge-sev-medium { background: rgba(202, 138, 4, 0.14); color: var(--sev-medium); }
|
||||
.badge-sev-high { background: rgba(234, 88, 12, 0.14); color: var(--sev-high); }
|
||||
.badge-sev-critical { background: rgba(220, 38, 38, 0.14); color: var(--sev-critical); }
|
||||
.finding-title { margin: 0; font-size: 15px; font-weight: 500; flex: 1; min-width: 200px; }
|
||||
.finding-location { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 12.5px; color: var(--muted); }
|
||||
.finding-note, .finding-fix { margin-top: 6px; font-size: 14px; }
|
||||
.finding-fix strong { color: var(--muted); font-weight: 500; }
|
||||
|
||||
.reviewer-source {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
||||
}
|
||||
|
||||
.mechanical {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 16px 20px;
|
||||
margin-top: 24px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.mechanical h3 { margin: 0 0 10px; font-size: 14px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
|
||||
.mechanical ul { margin: 0; padding-left: 20px; }
|
||||
.mechanical li { margin-bottom: 4px; color: var(--text); }
|
||||
|
||||
footer.report-footer {
|
||||
margin-top: 40px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid var(--border);
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
font-family: ui-monospace, "SF Mono", Menlo, monospace;
|
||||
}
|
||||
footer .meta { display: flex; gap: 24px; flex-wrap: wrap; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<!-- TEMPLATE: header. Fill ux spec name and ux spec path. No overall grade —
|
||||
per-category verdicts and severity counts below carry the picture. -->
|
||||
<header class="report-header">
|
||||
<div class="title">
|
||||
<h1>TEMPLATE_UX_SPEC_NAME — UX Design Validation Report</h1>
|
||||
<div class="subtitle">TEMPLATE_UX_SPEC_PATH</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- TEMPLATE: overall synthesis paragraphs. Lift directly from
|
||||
review-rubric.md "Overall verdict" section; expand if extra reviewers
|
||||
(accessibility, adversarial, etc.) materially shift the picture.
|
||||
Wrap each paragraph in <p>. -->
|
||||
<div class="synthesis">
|
||||
<p>TEMPLATE_SYNTHESIS_PARAGRAPH</p>
|
||||
</div>
|
||||
|
||||
<!-- TEMPLATE: dimension summary cards. One per rubric category, in this
|
||||
canonical order (from references/validate.md):
|
||||
1. Flow coverage
|
||||
2. Token completeness
|
||||
3. Component coverage
|
||||
4. State coverage
|
||||
5. Visual reference coverage
|
||||
6. Bloat & overspecification
|
||||
7. Inheritance discipline
|
||||
8. Shape fit
|
||||
The dim-verdict text uses one of: strong | adequate | thin | broken. -->
|
||||
<div class="dimension-summary">
|
||||
<div class="dim-card">
|
||||
<div class="dim-name">TEMPLATE_CATEGORY_NAME</div>
|
||||
<div class="dim-verdict" style="color: var(--verdict-TEMPLATE_VERDICT)">TEMPLATE_VERDICT_TEXT</div>
|
||||
</div>
|
||||
<!-- repeat for each of the eight rubric categories -->
|
||||
</div>
|
||||
|
||||
<!-- TEMPLATE: one section per rubric category, same canonical order as the
|
||||
summary cards above. Skip a category entirely if the rubric review
|
||||
marked it n/a for this UX spec. Open the section by default if verdict
|
||||
is thin or broken. -->
|
||||
<section class="dimension">
|
||||
<details open>
|
||||
<summary>
|
||||
<h2>TEMPLATE_CATEGORY_NAME</h2>
|
||||
<span class="verdict-pill verdict-TEMPLATE_VERDICT">TEMPLATE_VERDICT_TEXT</span>
|
||||
</summary>
|
||||
<div class="dim-body">
|
||||
<div class="dim-judgment">
|
||||
<p>TEMPLATE_DIMENSION_JUDGMENT</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="findings-list">
|
||||
<!-- TEMPLATE: zero or more findings -->
|
||||
<article class="finding">
|
||||
<header>
|
||||
<span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
|
||||
<h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
|
||||
<span class="finding-location">TEMPLATE_LOCATION</span>
|
||||
</header>
|
||||
<div class="finding-note">TEMPLATE_FINDING_NOTE</div>
|
||||
<div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
|
||||
</article>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- TEMPLATE: one section per extra reviewer that ran (accessibility,
|
||||
adversarial, brand-conformance, etc.). Skip this block entirely if
|
||||
only the rubric walker ran. -->
|
||||
<section class="reviewer-section">
|
||||
<details>
|
||||
<summary>
|
||||
<h2>Accessibility review</h2>
|
||||
<span class="reviewer-source">TEMPLATE_REVIEWER_SOURCE_FILE</span>
|
||||
</summary>
|
||||
<div class="dim-body">
|
||||
<div class="dim-judgment">
|
||||
<p>TEMPLATE_REVIEWER_PREAMBLE</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="findings-list">
|
||||
<article class="finding">
|
||||
<header>
|
||||
<span class="badge badge-sev-TEMPLATE_SEVERITY">TEMPLATE_SEVERITY</span>
|
||||
<h3 class="finding-title">TEMPLATE_FINDING_TITLE</h3>
|
||||
<span class="finding-location">TEMPLATE_LOCATION</span>
|
||||
</header>
|
||||
<div class="finding-note">TEMPLATE_FINDING_NOTE</div>
|
||||
<div class="finding-fix"><strong>Fix:</strong> TEMPLATE_SUGGESTED_FIX</div>
|
||||
</article>
|
||||
</div>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
<!-- TEMPLATE: mechanical notes — short, bulleted. Skip if there are none. -->
|
||||
<div class="mechanical">
|
||||
<h3>Mechanical notes</h3>
|
||||
<ul>
|
||||
<li>TEMPLATE_MECHANICAL_NOTE</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<footer class="report-footer">
|
||||
<div class="meta">
|
||||
<span>Rubric: TEMPLATE_RUBRIC_PATH</span>
|
||||
<span>Generated: TEMPLATE_TIMESTAMP</span>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,100 @@
|
||||
# DO NOT EDIT -- overwritten on every update.
|
||||
#
|
||||
# Workflow customization surface for bmad-ux.
|
||||
# Overrides:
|
||||
# {project-root}/_bmad/custom/bmad-ux.toml (team)
|
||||
# {project-root}/_bmad/custom/bmad-ux.user.toml (personal)
|
||||
# Merge rules: scalars override, arrays append.
|
||||
|
||||
[workflow]
|
||||
|
||||
# Steps to run before/after standard activation. Append-only.
|
||||
activation_steps_prepend = []
|
||||
activation_steps_append = []
|
||||
|
||||
# Persistent facts loaded at activation and kept in mind for the run.
|
||||
# Entries: literal sentence, `skill:NAME`, or `file:PATH` (glob ok).
|
||||
persistent_facts = [
|
||||
"file:{project-root}/**/project-context.md",
|
||||
]
|
||||
|
||||
# Runs at workflow completion. String or array of instructions.
|
||||
on_complete = ""
|
||||
|
||||
# Reference DESIGN.md spines the distillation subagent reads to anchor shape
|
||||
# and editorial richness. Convention-compliant with the Google Labs DESIGN.md
|
||||
# spec (https://github.com/google-labs-code/design.md). Append entries via
|
||||
# override TOML to seed an org-specific canonical aesthetic.
|
||||
# Each entry: `file:PATH` (or bare relative path, resolved skill-relative).
|
||||
design_md_examples = [
|
||||
"assets/design-example-mobile.md",
|
||||
"assets/design-example-shadcn.md",
|
||||
"assets/design-example-editorial.md",
|
||||
]
|
||||
|
||||
# Reference EXPERIENCE.md spines for the behavioral/flow/IA layer. Each entry:
|
||||
# `file:PATH` (or bare relative path, resolved skill-relative).
|
||||
experience_md_examples = [
|
||||
"assets/experience-example-mobile.md",
|
||||
"assets/experience-example-shadcn.md",
|
||||
]
|
||||
|
||||
# Design handoff targets — external tools that can take over the design /
|
||||
# visual identity work. The user runs the tool externally and saves outputs
|
||||
# (whatever the tool produces — DESIGN.md, Figma files, React components,
|
||||
# HTML mocks) to {doc_workspace}.
|
||||
# Each entry: `tool:NAME: <directive>`, `skill:NAME`, or plain-text descriptor.
|
||||
# Default: Google Stitch (emits DESIGN.md + per-screen HTML). Other producers:
|
||||
# Vercel v0, Figma, Galileo, Anima, internal generators.
|
||||
design_handoffs = [
|
||||
"Google Stitch (https://stitch.withgoogle.com) — emits DESIGN.md + per-screen HTML. Paste assembled prompt; save outputs to {doc_workspace}.",
|
||||
]
|
||||
|
||||
# HTML skeleton filled in by the validation synthesis pass.
|
||||
validation_report_template = "assets/validation-report-template.html"
|
||||
|
||||
# Run folder. DESIGN.md, EXPERIENCE.md, .memlog.md, .working/
|
||||
# (creative-tool artifacts), imports/ (user-supplied screens / brand decks /
|
||||
# Figma exports / sketches), optional mockups/ and wireframes/ (promoted
|
||||
# artifacts), optional validation-report.* all land inside
|
||||
# {ux_output_path}/{run_folder_pattern}/.
|
||||
ux_output_path = "{planning_artifacts}/ux-designs"
|
||||
run_folder_pattern = "ux-{project_name}-{date}"
|
||||
|
||||
# Creative tools registry. Collaborative renderers invoked on demand during
|
||||
# Discovery and at Finalize. Entry forms: `file:PATH`, `skill:NAME`,
|
||||
# `tool:MCP_TOOL: <directive>`, or plain text. Defaults ship for HTML color
|
||||
# themes, HTML design directions, Excalidraw wireframes (Discovery), and
|
||||
# 1:1 HTML key-screen mockups (Finalize). Working artifacts land in
|
||||
# {doc_workspace}/.working/; finalize promotes those with lasting reference
|
||||
# value to mockups/ or wireframes/. See references/creative-tools.md.
|
||||
creative_tools = [
|
||||
"file:assets/color-themes.md",
|
||||
"file:assets/design-directions.md",
|
||||
"file:assets/excalidraw-wireframe.md",
|
||||
"file:assets/key-screens.md",
|
||||
]
|
||||
|
||||
# Polish passes applied to DESIGN.md and EXPERIENCE.md at finalize.
|
||||
# Entries: `skill:NAME`, `file:PATH`, or plain text directive.
|
||||
# Suggested order: structural → content/voice → prose mechanics.
|
||||
doc_standards = [
|
||||
"skill:bmad-editorial-review-structure",
|
||||
"skill:bmad-editorial-review-prose",
|
||||
]
|
||||
|
||||
# Information retrieval registry. Consulted on demand when the conversation
|
||||
# surfaces a matching need. Distinct from creative_tools (artifact production).
|
||||
# Example: "When researching component patterns, consult corp:design_system_search."
|
||||
external_sources = []
|
||||
|
||||
# Routes outputs beyond local files at Finalize. Returned URLs/IDs surfaced
|
||||
# to the user. Unavailable tools skipped and flagged.
|
||||
# Example: "Upload DESIGN.md to Confluence via corp:confluence_upload (space_key='DESIGN')."
|
||||
external_handoffs = []
|
||||
|
||||
# Reviewers spawned at Finalize step 4 and at Validate intent, alongside
|
||||
# the rubric walker. Entries: `skill:NAME`, `file:PATH`, or plain text.
|
||||
# Common ad-hoc add (judged by the skill): accessibility-focused reviewer
|
||||
# for consumer / regulated work.
|
||||
finalize_reviewers = []
|
||||
@@ -0,0 +1,19 @@
|
||||
# Creative Tools
|
||||
|
||||
`{workflow.creative_tools}` is a registry of collaborative renderers invoked on demand when seeing options helps the user decide. Entries follow the standard prefix convention: `skill:NAME`, `file:PATH`, `tool:MCP_TOOL_NAME: <directive>`, or plain-text directive.
|
||||
|
||||
Defaults ship for HTML color themes, HTML design directions, Excalidraw wireframes (Discovery), and 1:1 HTML key-screen mocks (Finalize). Teams append more via override TOML — Figma MCP, custom skills, prompt-based mood boards.
|
||||
|
||||
## When to invoke
|
||||
|
||||
Decision moments where a visual beats more conversation: picking color tokens, picking a visual personality among directions, sketching IA, mocking a tricky flow. Fast-path users typically skip; coaching-path users typically lean in. Read the room.
|
||||
|
||||
## Artifact handling
|
||||
|
||||
Every renderer writes to `{doc_workspace}/.working/` with a descriptive filename. `.working/` is the audit trail and survives the run. At Finalize, the facilitator walks `.working/` with the user and promotes artifacts with lasting reference value to `{doc_workspace}/mockups/` (HTML anchoring a brand or layout decision) or `{doc_workspace}/wireframes/` (Excalidraw a dev would glance at). Bar for promotion: *would a future reader of `DESIGN.md` or `EXPERIENCE.md` open this?* Default is leave-in-`.working/`.
|
||||
|
||||
## Renderer contract
|
||||
|
||||
The parent passes the subagent: current `.memlog.md`, relevant prior `.working/` captures, the user's stated intent for this pass, the output path. The subagent writes its artifact under `.working/` and returns ONLY a compact summary (file path, one line per variant, mode coverage). Parent never holds the full payload.
|
||||
|
||||
For HTML, open in browser when interactive: `python3 -c "import webbrowser, pathlib; webbrowser.open(pathlib.Path('PATH').resolve().as_uri())"`. Skip in headless.
|
||||
@@ -0,0 +1,50 @@
|
||||
# DESIGN.md Spec — Working Reference
|
||||
|
||||
Source of truth: [google-labs-code/design.md](https://github.com/google-labs-code/design.md) (Apache 2.0, Google Labs, April 2026). This file is a working summary; the URL wins on conflict.
|
||||
|
||||
## Structure
|
||||
|
||||
YAML frontmatter (machine-readable tokens) + markdown body (human-readable rationale, prose sections).
|
||||
|
||||
## Frontmatter tokens
|
||||
|
||||
| Key | Type | Notes |
|
||||
|---|---|---|
|
||||
| `name` | string | Required. Brand or system name. |
|
||||
| `description` | string | One-line statement of what this system is. |
|
||||
| `colors` | flat object | Kebab-case keys. Values are hex strings (`'#FBF9F4'`). |
|
||||
| `typography` | nested object | Each value: an object with any subset of `fontFamily`, `fontSize`, `fontWeight`, `lineHeight`, `letterSpacing`. |
|
||||
| `rounded` | object | Scale names (`sm`, `md`, `lg`, `xl`, `full`, `DEFAULT`) → CSS dimensions. `full` is conventionally `9999px`. |
|
||||
| `spacing` | object | Scale levels (`'1'`, `'2'`, ...) or named tokens (`gutter`, `margin-mobile`, `editorial-gap`) → dimensions. |
|
||||
| `components` | object | Component-name → object of component tokens mapped to values or `{path.to.token}` references. |
|
||||
|
||||
## Body sections (omittable, order-locked when present)
|
||||
|
||||
1. **Brand & Style** — Aesthetic posture in prose. The editorial voice — what *kind* of thing this is.
|
||||
2. **Colors** — Per-color story. Why each exists, where it's used, what it's *not* used for.
|
||||
3. **Typography** — Type roles, ramp, and rules. Platform conventions noted semantically when inherited.
|
||||
4. **Layout & Spacing** — Spacing scale narrative, grid behavior, margins, gutters, breakpoint rules.
|
||||
5. **Elevation & Depth** — Shadow language and tonal layering rules.
|
||||
6. **Shapes** — Corner radii rules and the aesthetic logic behind them.
|
||||
7. **Components** — Per-component visual specs: anatomy, color usage, sizing, state appearance.
|
||||
8. **Do's and Don'ts** — Hard visual rules — what to do, what to avoid.
|
||||
|
||||
Sections may be omitted when not relevant; order is locked when present.
|
||||
|
||||
## Cross-reference syntax
|
||||
|
||||
`{path.to.token}` used in prose and inside component objects to reference frontmatter tokens. Examples:
|
||||
|
||||
- `{colors.primary}`
|
||||
- `{typography.body.fontSize}`
|
||||
- `{rounded.md}`
|
||||
- `{spacing.4}`
|
||||
|
||||
The path follows the YAML structure.
|
||||
|
||||
## Common patterns
|
||||
|
||||
- **Light/dark mode.** Either separate kebab-case tokens (`surface-base` / `surface-base-dark`) or separate DESIGN.md files per mode. The spec allows either; pick the form that reads cleanest for the product.
|
||||
- **Platform conventions.** When inheriting from native platforms (iOS UIKit, Android Compose, Apple Human Interface Guidelines), use a `note` field instead of literal values: `{ note: 'iOS Title 1 · Android Headline Small' }`. The spec is the spec; the platform owns the rendered values.
|
||||
- **UI-system inheritance.** When inheriting from shadcn / MUI / Tailwind / internal design system, reference the system's tokens by name rather than restating values. DESIGN.md specifies only the deltas (brand color overrides, typography swaps, component customizations).
|
||||
- **Component tokens.** The `components` frontmatter entry maps each named component (e.g., `button-primary`) to its specific token values. Use `{path.to.token}` references freely; the resolver flattens at consumption time.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Headless Mode
|
||||
|
||||
Load this file when invoked headless. Follow it for the whole run.
|
||||
|
||||
## Detection
|
||||
|
||||
Headless when any of: caller sets `headless: true` (or harness equivalent); invocation is from another skill or non-interactive runner; `{workflow.activation_steps_prepend}` declares it; first message is an automation context pre-supplying inputs. Ambiguous → default interactive.
|
||||
|
||||
## Inputs
|
||||
|
||||
Free-form structured payload in the first message:
|
||||
|
||||
- `intent` — `"create"`, `"update"`, or `"validate"`. If absent, infer from the artifact set.
|
||||
- **Create**: any source spec (PRD, brief, requirements list, design-thinking output, prior UX — text, path, or URL) plus brand / platform / accessibility notes; `doc_workspace` if a specific run folder is required.
|
||||
- **Update**: existing workspace containing `DESIGN.md` + `EXPERIENCE.md` (or path to either) + change signal.
|
||||
- **Validate**: existing workspace containing `DESIGN.md` + `EXPERIENCE.md` (or path to either). Workspace defaults to the spines' containing directory.
|
||||
|
||||
Inferences → `assumptions[]`. Gaps needing a human decision → `open_questions[]`. Do not invent persona, brand, accessibility, or scope detail.
|
||||
|
||||
Creative tools default off in headless. Caller can override; artifacts land in `.working/` and are not promoted unless the caller signals.
|
||||
|
||||
## Behavior
|
||||
|
||||
Do not ask. Do not greet. Complete the intent from what's provided, what exists in `{doc_workspace}`, or what you can discover. If intent stays ambiguous after inference, halt with `status: "blocked"` and a one-sentence `reason`.
|
||||
|
||||
`status`:
|
||||
- `"complete"` — stands on its own.
|
||||
- `"partial"` — artifact produced but `open_questions[]` non-empty or critical inputs inferred.
|
||||
- `"blocked"` — no artifact produced.
|
||||
|
||||
End with JSON matching `assets/headless-schemas.md`. `intent` reflects detected intent. Omit keys for artifacts not produced.
|
||||
|
||||
## Mode-specific overrides
|
||||
|
||||
**Update.** Apply the change. Log it via `uv run {project-root}/_bmad/scripts/memlog.py append --workspace {doc_workspace} --type change --text "<change + rationale>"`. Surface conflicts in `conflicts_with_prior_decisions[]`.
|
||||
|
||||
**Validate.** Always write both `validation-report.html` and `validation-report.md` regardless of finding count. Always include `"offer_to_update": true`. Skip the browser-open step.
|
||||
@@ -0,0 +1,115 @@
|
||||
# Validate
|
||||
|
||||
Critique an existing spine pair (`DESIGN.md` + `EXPERIENCE.md`) or any format of UX the user provides, without changing it. The synthesis pipeline below is also used at the Reviewer Gate during Create / Update Finalize.
|
||||
|
||||
## Orient
|
||||
|
||||
Subagent-extract from `.memlog.md`, sources in frontmatter, `imports/`, `mockups/`, `wireframes/`, `DESIGN.md`, `EXPERIENCE.md`. Parent assembles from extracts.
|
||||
|
||||
## Reviewer Gate
|
||||
|
||||
**Opt-in.** Reviewers are costly. At Finalize, ask first if the user wants to run UX validation with multiple subagent lenses. Default offered, easy skip. At Validate intent, skip that question, the user already invoked it.
|
||||
|
||||
**Lens menu.** UNLESS HEADLESS MODE: Always present the lens picks before dispatching. Build the menu from: rubric walker (this file) + `{workflow.finalize_reviewers}` + ad-hoc reviewers the skill judges relevant. The user picks all, a subset, or none. Only picked lenses dispatch.
|
||||
|
||||
Rubric walker prompt:
|
||||
|
||||
> Validate the spine pair (`DESIGN.md` + `EXPERIENCE.md`) as the contract for downstream consumers (architecture, story-dev — human or AI). Can a consumer source-extract cleanly, with every reference resolving and every load-bearing decision committed? Read `{workflow.design_md_examples}` and `{workflow.experience_md_examples}` first.
|
||||
>
|
||||
> **Pass 1 — mechanical coverage.** Per category: extract, then list misses with location citations. No misses = **strong**.
|
||||
>
|
||||
> 1. **Flow coverage** (EXPERIENCE.md). Sources frontmatter → extract every UJ / requirement name. Verify each has a Key Flow with named protagonist, numbered steps, a climax beat, and a failure path where applicable.
|
||||
>
|
||||
> 2. **Token completeness** (DESIGN.md). Extract every token in the YAML frontmatter and every `{path.to.token}` reference in the prose. Verify each defined (see `references/design-md-spec.md` for type rules). **Color tokens missing hex (or light/dark pairs where applicable) are critical** — downstream code mirrors the spine. Platform conventions (native dynamic type, 8pt grid) may stay semantic. Contrast targets stated for load-bearing combinations.
|
||||
>
|
||||
> 3. **Component coverage** (both spines). Extract every component name used anywhere. Verify each has a row in DESIGN.md.Components (visual spec) *and* EXPERIENCE.md.Component Patterns (behavioral spec) — real rules, not one-word descriptions.
|
||||
>
|
||||
> 4. **State coverage** (EXPERIENCE.md). Walk every IA surface. List states it should have (empty, cold-load, focus, error, offline, permission-denied — whichever apply). Verify each covered.
|
||||
>
|
||||
> 5. **Visual reference coverage.** List every file in `mockups/`, `wireframes/`, `imports/`. Spines link to each inline at the relevant section and name what it illustrates; spines-win-on-conflict stated once. List orphans and unspecific references.
|
||||
>
|
||||
> **Pass 2 — judgment.** Verdict per category (*strong / adequate / thin / broken*); findings only where they add information.
|
||||
>
|
||||
> 6. **Bloat & overspecification.** Pixel specs where tokens cover it; source restatement (personas, FRs, scope); prose where a table works; sections no downstream consumer would read; decorative narrative untied to a decision. DESIGN.md prose may carry editorial voice; EXPERIENCE.md prose should not.
|
||||
>
|
||||
> 7. **Inheritance discipline.** `sources` frontmatter resolves. UJ / requirement names verbatim from sources. Glossary identical across spines and sources. Component names identical across all sections in both files. EXPERIENCE.md token references resolve to DESIGN.md tokens by name.
|
||||
>
|
||||
> 8. **Shape fit.** DESIGN.md sections in canonical order (Brand & Style → Colors → Typography → Layout & Spacing → Elevation & Depth → Shapes → Components → Do's and Don'ts; omittable but order-locked when present). EXPERIENCE.md required defaults present (Foundation, IA, Voice and Tone, Component Patterns, State Patterns, Interaction Primitives, Accessibility Floor, Key Flows). Dropped defaults defensible. Required-when-applicable present where triggered (Inspiration when sources / memlog show reference products or rejects; Responsive when multi-surface or breakpoints). Invented sections earn their place.
|
||||
>
|
||||
> Severity = downstream impact, not fix difficulty.
|
||||
>
|
||||
> Write to `{doc_workspace}/review-rubric.md`:
|
||||
>
|
||||
> ```markdown
|
||||
> # Spine Pair Review — {project_name}
|
||||
>
|
||||
> ## Overall verdict
|
||||
> [2–3 sentences]
|
||||
>
|
||||
> ## 1. Flow coverage — [verdict]
|
||||
> [What was checked.]
|
||||
> ### Findings
|
||||
> - **[critical|high|medium|low]** [finding] (location). *Fix:* [suggestion].
|
||||
>
|
||||
> (repeat 2–8)
|
||||
>
|
||||
> ## Mechanical notes
|
||||
> [Name inconsistencies, broken cross-refs, frontmatter completeness, Mermaid syntax.]
|
||||
> ```
|
||||
>
|
||||
> Return ONLY a compact summary: overall verdict, per-section verdicts, finding counts by severity, file path.
|
||||
|
||||
The gate may dispatch `{workflow.finalize_reviewers}` and ad-hoc reviewers (accessibility for consumer / regulated). Each writes `review-{slug}.md` and returns a compact summary. Parallel.
|
||||
|
||||
## Synthesis pipeline
|
||||
|
||||
Under Validate intent, after every reviewer returns, render one consolidated report. Don't skip.
|
||||
|
||||
1. Read every `{doc_workspace}/review-*.md`.
|
||||
2. Fill `{workflow.validation_report_template}`. No overall grade — the per-category verdicts and severity counts already say what's true. Synthesis paragraph lifts the rubric's overall verdict; add a second if extra reviewers shift the picture. One section per rubric category (open if thin / broken), one per extra reviewer (closed, adversarial voice preserved).
|
||||
3. Write `{doc_workspace}/validation-report.html`.
|
||||
4. Write the Markdown twin `{doc_workspace}/validation-report.md` — same content grouped by severity.
|
||||
5. Open HTML: `python3 -c "import webbrowser, pathlib; webbrowser.open(pathlib.Path('{doc_workspace}/validation-report.html').resolve().as_uri())"`. Skip headless.
|
||||
|
||||
Re-running overwrites the consolidated report; individual `review-*.md` files persist.
|
||||
|
||||
## Markdown twin shape
|
||||
|
||||
```markdown
|
||||
# Validation Report — {project_name}
|
||||
|
||||
- **DESIGN.md:** `{design_path}`
|
||||
- **EXPERIENCE.md:** `{experience_path}`
|
||||
- **Run at:** {ISO timestamp}
|
||||
|
||||
## Overall verdict
|
||||
{synthesis paragraphs}
|
||||
|
||||
## Category verdicts
|
||||
- Flow coverage — {verdict}
|
||||
- Token completeness — {verdict}
|
||||
- Component coverage — {verdict}
|
||||
- State coverage — {verdict}
|
||||
- Visual reference coverage — {verdict}
|
||||
- Bloat & overspecification — {verdict}
|
||||
- Inheritance discipline — {verdict}
|
||||
- Shape fit — {verdict}
|
||||
|
||||
## Findings by severity
|
||||
|
||||
### Critical (n)
|
||||
**[Category or Reviewer]** — Title (§ location)
|
||||
{Note}
|
||||
Fix: {suggested fix}
|
||||
|
||||
### High (n) / Medium (n) / Low (n)
|
||||
...
|
||||
|
||||
## Reviewer files
|
||||
- `review-rubric.md`
|
||||
- ...
|
||||
```
|
||||
|
||||
## Close
|
||||
|
||||
Surface artifact paths. Always offer to roll findings into an Update.
|
||||
Reference in New Issue
Block a user