feat: port 4 new UI team skills to Codex v4 format

Convert team-interactive-craft, team-motion-design, team-visual-a11y,
team-ui-polish from Claude agent format to Codex v4 API (spawn_agent,
wait_agent, close_agent, request_user_input). Each skill includes
SKILL.md with Delegation Lock + v4 Coordination, coordinator with
Scope Lock, worker roles with preserved domain content, and specs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
catlog22
2026-03-30 10:19:37 +08:00
parent 46d4d4b20f
commit cac126e7bf
58 changed files with 10196 additions and 0 deletions

View File

@@ -0,0 +1,220 @@
---
name: team-interactive-craft
description: Unified team skill for interactive component crafting. Vanilla JS + CSS interactive components with zero dependencies. Research -> interaction design -> build -> a11y test. Uses team-worker agent architecture with roles/ for domain logic. Coordinator orchestrates pipeline with GC loops and sync points. Triggers on "team interactive craft", "interactive component".
allowed-tools: spawn_agent(*), wait_agent(*), send_message(*), assign_task(*), close_agent(*), list_agents(*), report_agent_job_result(*), request_user_input(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), mcp__ace-tool__search_context(*), mcp__ccw-tools__read_file(*), mcp__ccw-tools__write_file(*), mcp__ccw-tools__edit_file(*), mcp__ccw-tools__team_msg(*)
---
# Team Interactive Craft
Systematic interactive component pipeline: research -> interaction design -> build -> a11y test. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
## Architecture
```
Skill(skill="team-interactive-craft", args="task description")
|
SKILL.md (this file) = Router
|
+--------------+--------------+
| |
no --role flag --role <name>
| |
Coordinator Worker
roles/coordinator/role.md roles/<name>/role.md
|
+-- analyze -> dispatch -> spawn workers -> STOP
|
+-------+-------+-------+-------+
v v v v
[team-worker agents, each loads roles/<role>/role.md]
researcher interaction-designer builder a11y-tester
```
## Role Registry
| Role | Path | Prefix | Inner Loop |
|------|------|--------|------------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
| researcher | [roles/researcher/role.md](roles/researcher/role.md) | RESEARCH-* | false |
| interaction-designer | [roles/interaction-designer/role.md](roles/interaction-designer/role.md) | INTERACT-* | false |
| builder | [roles/builder/role.md](roles/builder/role.md) | BUILD-* | true |
| a11y-tester | [roles/a11y-tester/role.md](roles/a11y-tester/role.md) | A11Y-* | false |
## Role Router
Parse `$ARGUMENTS`:
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
- No `--role` -> `roles/coordinator/role.md`, execute entry router
## Delegation Lock
**Coordinator is a PURE ORCHESTRATOR. It coordinates, it does NOT do.**
Before calling ANY tool, apply this check:
| Tool Call | Verdict | Reason |
|-----------|---------|--------|
| `spawn_agent`, `wait_agent`, `close_agent`, `send_message`, `assign_task` | ALLOWED | Orchestration |
| `list_agents` | ALLOWED | Agent health check |
| `request_user_input` | ALLOWED | User interaction |
| `mcp__ccw-tools__team_msg` | ALLOWED | Message bus |
| `Read/Write` on `.workflow/.team/` files | ALLOWED | Session state |
| `Read` on `roles/`, `commands/`, `specs/` | ALLOWED | Loading own instructions |
| `Read/Grep/Glob` on project source code | BLOCKED | Delegate to worker |
| `Edit` on any file outside `.workflow/` | BLOCKED | Delegate to worker |
| `Bash("ccw cli ...")` | BLOCKED | Only workers call CLI |
| `Bash` running build/test/lint commands | BLOCKED | Delegate to worker |
**If a tool call is BLOCKED**: STOP. Create a task, spawn a worker.
**No exceptions for "simple" tasks.** Even a single-file read-and-report MUST go through spawn_agent.
---
## Shared Constants
- **Session prefix**: `IC`
- **Session path**: `.workflow/.team/IC-<slug>-<date>/`
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
- **Max GC rounds**: 2
## Worker Spawn Template
Coordinator spawns workers using this template:
```
spawn_agent({
agent_type: "team_worker",
task_name: "<task-id>",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: <role>
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
requirement: <task-description>
inner_loop: <true|false>
Read role_spec file (<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: <task-id>
title: <task-title>
description: <task-description>
pipeline_phase: <pipeline-phase>` },
{ type: "text", text: `## Upstream Context
<prev_context>` }
]
})
```
After spawning, use `wait_agent({ targets: [...], timeout_ms: 900000 })` to collect results, then `close_agent({ target })` each worker.
### Model Selection Guide
Interactive craft is a technical pipeline where research informs interaction design, which guides implementation. Builder needs creative problem-solving for vanilla JS constraints, a11y-tester needs thorough analysis.
| Role | reasoning_effort | Rationale |
|------|-------------------|-----------|
| researcher | high | Deep analysis of existing interactive patterns and browser APIs |
| interaction-designer | high | Creative state machine and event flow design |
| builder | high | Complex vanilla JS implementation with GPU animation and touch handling |
| a11y-tester | high | Thorough accessibility audit must catch all keyboard/screen reader issues |
### Research-to-Design Context Flow
Researcher findings must reach interaction-designer via coordinator's upstream context:
```
// After RESEARCH-001 completes, coordinator sends findings to interaction-designer
spawn_agent({
agent_type: "team_worker",
task_name: "INTERACT-001",
fork_context: false,
items: [
...,
{ type: "text", text: `## Upstream Context
Research findings: <session>/research/interaction-inventory.json
Browser API audit: <session>/research/browser-api-audit.json
Pattern reference: <session>/research/pattern-reference.json` }
]
})
```
## User Commands
| Command | Action |
|---------|--------|
| `check` / `status` | View execution status graph |
| `resume` / `continue` | Advance to next step |
## Specs Reference
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
- [specs/interaction-patterns.md](specs/interaction-patterns.md) -- Interaction pattern catalog
- [specs/vanilla-constraints.md](specs/vanilla-constraints.md) -- Zero-dependency rules
## Session Directory
```
.workflow/.team/IC-<slug>-<date>/
+-- .msg/
| +-- messages.jsonl # Team message bus
| +-- meta.json # Pipeline config + GC state
+-- research/ # Researcher output
| +-- interaction-inventory.json
| +-- browser-api-audit.json
| +-- pattern-reference.json
+-- interaction/ # Interaction designer output
| +-- blueprints/
| +-- {component-name}.md
+-- build/ # Builder output
| +-- components/
| +-- {name}.js
| +-- {name}.css
+-- a11y/ # A11y tester output
| +-- a11y-audit-{NNN}.md
+-- wisdom/ # Cross-task knowledge
```
## v4 Agent Coordination
### Message Semantics
| Intent | API | Example |
|--------|-----|---------|
| Queue supplementary info (don't interrupt) | `send_message` | Send research findings to running interaction-designer |
| Assign build from reviewed blueprints | `assign_task` | Assign BUILD task after blueprint review |
| Check running agents | `list_agents` | Verify agent health during resume |
### Agent Health Check
Use `list_agents({})` in handleResume and handleComplete:
```
// Reconcile session state with actual running agents
const running = list_agents({})
// Compare with tasks.json active_agents
// Reset orphaned tasks (in_progress but agent gone) to pending
```
### Named Agent Targeting
Workers are spawned with `task_name: "<task-id>"` enabling direct addressing:
- `send_message({ target: "INTERACT-001", items: [...] })` -- send research findings to interaction-designer
- `assign_task({ target: "BUILD-001", items: [...] })` -- assign implementation from interaction blueprint
- `close_agent({ target: "A11Y-001" })` -- cleanup after a11y audit
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown command | Error with available command list |
| Role not found | Error with role registry |
| Session corruption | Attempt recovery, fallback to manual |
| Fast-advance conflict | Coordinator reconciles on next callback |
| Completion action fails | Default to Keep Active |
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |

View File

@@ -0,0 +1,159 @@
---
role: a11y-tester
prefix: A11Y
inner_loop: false
message_types: [state_update]
---
# Accessibility Tester
Test interactive components for keyboard navigation, screen reader compatibility, reduced motion fallback, focus management, and color contrast. Act as Critic in the builder<->a11y-tester Generator-Critic loop. Serve as quality gate before pipeline completion.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Built components | <session>/build/components/*.js, *.css | Yes |
| Interaction blueprints | <session>/interaction/blueprints/*.md | Yes |
| Research artifacts | <session>/research/browser-api-audit.json | No |
| Previous audits | <session>/a11y/a11y-audit-*.md | Only for GC re-audit |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
1. Extract session path from task description
2. Read all built component files (JS + CSS)
3. Read interaction blueprints for expected behavior reference
4. If GC re-audit: read previous audit to track improvement/regression
5. Load audit history from meta.json for trend analysis
## Phase 3: Audit Execution
Test 5 accessibility dimensions. For each, evaluate every built component:
### Dimension 1: Keyboard Navigation (Weight: 25%)
| Check | Method | Pass Criteria |
|-------|--------|---------------|
| Tab order | Scan tabindex values, focusable elements | Logical tab order, no tabindex > 0 |
| Arrow key navigation | Check onKeyDown for ArrowLeft/Right/Up/Down | All navigable items reachable via arrows |
| Enter/Space activation | Check onKeyDown for Enter, Space | All interactive elements activatable |
| Escape dismissal | Check onKeyDown for Escape | Overlays/modals dismiss on Escape |
| Focus trap (overlays) | Check focus cycling logic | Tab stays within overlay when open |
| No keyboard trap | Verify all states have keyboard exit | Can always Tab/Escape out of component |
Score: count(pass) / count(total_checks) * 10
### Dimension 2: Screen Reader Compatibility (Weight: 25%)
| Check | Method | Pass Criteria |
|-------|--------|---------------|
| ARIA role | Scan for role attribute | Appropriate role set (slider, dialog, tablist, etc.) |
| ARIA label | Scan for aria-label, aria-labelledby | All interactive elements have accessible name |
| ARIA states | Scan for aria-expanded, aria-selected, aria-hidden | Dynamic states update with interaction |
| Live regions | Scan for aria-live, aria-atomic | State changes announced (polite/assertive as needed) |
| Semantic HTML | Check element types | Uses button/a/input where appropriate, not div-only |
| Alt text | Check img/svg elements | Decorative: aria-hidden; informative: alt/aria-label |
Score: count(pass) / count(total_checks) * 10
### Dimension 3: Reduced Motion (Weight: 20%)
| Check | Method | Pass Criteria |
|-------|--------|---------------|
| Media query present | Search CSS for prefers-reduced-motion | @media (prefers-reduced-motion: reduce) exists |
| Transitions disabled | Check reduced-motion block | transition-duration near 0 or removed |
| Animations disabled | Check reduced-motion block | animation-duration near 0 or removed |
| Content still accessible | Verify no content depends on animation | Information conveyed without motion |
| JS respects preference | Check matchMedia usage | JS checks prefers-reduced-motion before animating |
Score: count(pass) / count(total_checks) * 10
### Dimension 4: Focus Management (Weight: 20%)
| Check | Method | Pass Criteria |
|-------|--------|---------------|
| Visible focus indicator | Search CSS for :focus-visible | Visible outline/ring on keyboard focus |
| Focus contrast | Check outline color against background | >= 3:1 contrast ratio |
| Focus on open | Check overlay/modal open logic | Focus moves to first interactive element |
| Focus on close | Check overlay/modal close logic | Focus returns to trigger element |
| No focus loss | Check state transitions | Focus never moves to non-interactive element |
| Skip link (page mode) | Check for skip navigation | Present if multiple interactive sections |
Score: count(pass) / count(total_checks) * 10
### Dimension 5: Color Contrast (Weight: 10%)
| Check | Method | Pass Criteria |
|-------|--------|---------------|
| Text contrast | Evaluate CSS color vs background | >= 4.5:1 for normal text, >= 3:1 for large text |
| UI component contrast | Evaluate interactive element borders/fills | >= 3:1 against adjacent colors |
| Focus indicator contrast | Evaluate outline color | >= 3:1 against background |
| State indication | Check non-color state indicators | State not conveyed by color alone |
Score: count(pass) / count(total_checks) * 10
### Overall Score Calculation
`overallScore = round(keyboard*0.25 + screenReader*0.25 + reducedMotion*0.20 + focus*0.20 + contrast*0.10)`
### Issue Classification
| Severity | Definition | Examples |
|----------|-----------|----------|
| Critical | Component unusable for assistive tech users | No keyboard access, no ARIA role, focus trap |
| High | Significant barrier, workaround exists | Missing aria-label, no reduced motion, poor focus |
| Medium | Minor inconvenience | Suboptimal tab order, missing live region |
| Low | Enhancement opportunity | Could improve contrast, better semantic HTML |
### Signal Determination
| Condition | Signal |
|-----------|--------|
| 0 critical AND 0 high issues | `a11y_passed` (GC CONVERGED) |
| 0 critical AND high_count > 0 | `a11y_result` (GC REVISION NEEDED) |
| critical_count > 0 | `fix_required` (CRITICAL FIX NEEDED) |
## Phase 4: Report & Output
1. Write audit report to `<session>/a11y/a11y-audit-{NNN}.md`:
```markdown
# A11y Audit Report - {NNN}
## Summary
- **Overall Score**: X/10
- **Signal**: a11y_passed | a11y_result | fix_required
- **Critical**: N | **High**: N | **Medium**: N | **Low**: N
## Dimension Scores
| Dimension | Score | Weight | Weighted |
|-----------|-------|--------|----------|
| Keyboard Navigation | X/10 | 25% | X.XX |
| Screen Reader | X/10 | 25% | X.XX |
| Reduced Motion | X/10 | 20% | X.XX |
| Focus Management | X/10 | 20% | X.XX |
| Color Contrast | X/10 | 10% | X.XX |
## Issues
### Critical
- [C-001] {description} | File: {file}:{line} | Fix: {remediation}
### High
- [H-001] {description} | File: {file}:{line} | Fix: {remediation}
### Medium
- [M-001] {description} | File: {file}:{line} | Fix: {remediation}
## GC Loop Status
- **Signal**: {signal}
- **Action Required**: {none | builder fix | escalate}
## Trend (if previous audit exists)
- Previous score: X/10 -> Current: X/10 ({improving|stable|declining})
- Resolved issues: [list]
- New issues: [list]
```
2. Update `<session>/wisdom/.msg/meta.json` under `a11y-tester` namespace:
- Read existing -> merge `{ "a11y-tester": { audit_id, score, critical_count, high_count, signal, timestamp } }` -> write back

View File

@@ -0,0 +1,216 @@
---
role: builder
prefix: BUILD
inner_loop: true
message_types: [state_update]
---
# Interactive Component Builder
Implement vanilla JS + CSS interactive components from interaction blueprints. Zero dependencies, ES modules, progressive enhancement, GPU-only animations, touch-aware. Act as Generator in the builder<->a11y-tester Generator-Critic loop.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Interaction blueprints | <session>/interaction/blueprints/*.md | Yes |
| Research artifacts | <session>/research/*.json | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| A11y audit feedback | <session>/a11y/a11y-audit-*.md | Only for GC fix tasks |
1. Extract session path from task description
2. Read interaction blueprint for target component
3. Read research artifacts: browser-api-audit.json (API availability), pattern-reference.json (reference patterns)
4. Detect task type from subject: numbered -> New component, "fix" -> GC fix
5. If GC fix task: read latest a11y audit feedback
## Phase 3: Implementation Execution
**Component Implementation (BUILD-001, BUILD-002, etc.)**:
### JavaScript (ES Module)
Implement component class in `<session>/build/components/{name}.js`:
```javascript
// Structure template (adapt to component type)
export class ComponentName {
// --- Configuration ---
static defaults = { /* configurable params from blueprint */ };
// --- Lifecycle ---
constructor(element, options = {}) { /* merge options, query DOM, bind events */ }
init() { /* setup observers, initial state */ }
destroy() { /* cleanup: remove listeners, disconnect observers */ }
// --- State Machine ---
#state = 'idle';
#setState(next) { /* validate transition, update, trigger side effects */ }
// --- Event Handlers (from blueprint event flow map) ---
#onPointerDown(e) { /* setPointerCapture, transition state */ }
#onPointerMove(e) { /* lerp interpolation, update transform */ }
#onPointerUp(e) { /* releasePointerCapture, settle animation */ }
#onKeyDown(e) { /* keyboard mapping from blueprint */ }
// --- Animation ---
#lerp(current, target, speed) { return current + (target - current) * speed; }
#animate() { /* requestAnimationFrame loop, GPU-only transforms */ }
// --- Observers ---
#resizeObserver = null; // responsive behavior
#intersectionObserver = null; // scroll triggers
// --- Accessibility ---
#announceToScreenReader(message) { /* aria-live region update */ }
}
// Auto-init: progressive enhancement
document.querySelectorAll('[data-component-name]').forEach(el => {
new ComponentName(el);
});
```
Requirements:
- Pure ES module with `export` (no CommonJS, no bundler)
- Class-based with private fields (#)
- Constructor accepts DOM element + options object
- State machine from blueprint with validated transitions
- Event handlers from blueprint event flow map
- Lerp interpolation for smooth drag/follow (speed from blueprint)
- requestAnimationFrame for frame-synced updates
- setPointerCapture for reliable drag tracking
- ResizeObserver for responsive layout adjustments
- IntersectionObserver for scroll-triggered behavior (when applicable)
- Proper cleanup in destroy() method
- Auto-init via data attribute for progressive enhancement
### CSS (Custom Properties)
Implement styles in `<session>/build/components/{name}.css`:
```css
/* Structure template */
/* --- Custom Properties (configurable) --- */
.component-name {
--component-duration: 400ms;
--component-easing: cubic-bezier(0.16, 1, 0.3, 1);
--component-color-primary: #1a1a2e;
/* ... from blueprint animation choreography */
}
/* --- Base Layout (works without JS) --- */
.component-name { /* progressive enhancement base */ }
/* --- States (from blueprint state machine) --- */
.component-name[data-state="idle"] { }
.component-name[data-state="hover"] { }
.component-name[data-state="active"] { }
.component-name[data-state="dragging"] { }
/* --- Animations (GPU-only: transform + opacity) --- */
.component-name__element {
transform: translateX(0);
opacity: 1;
transition: transform var(--component-duration) var(--component-easing),
opacity var(--component-duration) var(--component-easing);
will-change: transform, opacity;
}
/* --- Focus Styles --- */
.component-name:focus-visible {
outline: 2px solid var(--component-focus-color, #4a9eff);
outline-offset: 2px;
}
/* --- Reduced Motion --- */
@media (prefers-reduced-motion: reduce) {
.component-name,
.component-name * {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
}
}
/* --- Responsive --- */
@media (max-width: 768px) { /* touch-optimized sizes */ }
```
Requirements:
- CSS custom properties for all configurable values (no preprocessor)
- Base layout works without JavaScript (progressive enhancement)
- State-driven via data attributes (`data-state`, `data-active`)
- GPU-only animations: transform + opacity ONLY (no width/height/top/left)
- `will-change` on animated elements
- `prefers-reduced-motion` media query with instant transitions
- `focus-visible` for keyboard-only focus ring
- Responsive breakpoints for touch targets (min 44x44px)
- No inline styles from JS -- use CSS classes and custom properties
### Native Platform APIs (prefer over custom implementations)
**Dialog API** (`<dialog>`):
- Use `<dialog>` for modals -- provides built-in focus trap and backdrop
- `dialog.showModal()` for modal (with backdrop, escape-to-close, focus trap)
- `dialog.show()` for non-modal
- `dialog.close()` to dismiss
- Style `::backdrop` pseudo-element for overlay
- Returns focus to trigger element on close
- Add `inert` attribute to siblings when modal is open (prevents background interaction)
**Popover API** (native tooltips/dropdowns):
- `<div popover>` for light-dismiss popovers (click-outside-to-close)
- `<button popovertarget="id">` for trigger
- Auto-stacking (no z-index management needed)
- Built-in accessibility (focus management, escape-to-close)
- Use for: tooltips, dropdown menus, date pickers, color pickers
**CSS Anchor Positioning** (Chrome 125+, progressive enhancement):
- `anchor-name: --trigger` on trigger element
- `position-anchor: --trigger` on positioned element
- `@position-try` for fallback positioning
- Fallback: `position: fixed` with JS-calculated coordinates
**GC Fix Mode (BUILD-fix-N)**:
- Parse a11y audit feedback for specific issues
- Re-read affected component files
- Apply targeted fixes: missing ARIA attributes, keyboard handlers, focus management, contrast adjustments
- Re-write affected files
- Signal `build_revision` instead of `build_ready`
## Phase 4: Self-Validation & Output
1. Zero-dependency check:
| Check | Pass Criteria |
|-------|---------------|
| No imports from npm | No `import` from node_modules paths |
| No require() | No CommonJS require statements |
| ES module exports | Uses `export class` or `export function` |
| No build tools needed | Runs directly in browser with `<script type="module">` |
2. State machine completeness:
| Check | Pass Criteria |
|-------|---------------|
| All states from blueprint | Every blueprint state has corresponding code path |
| All transitions | Every transition has handler code |
| Error recovery | All states can reach idle via reset |
3. Accessibility baseline:
| Check | Pass Criteria |
|-------|---------------|
| Keyboard handlers | onKeyDown handles Enter, Space, Escape, Arrows |
| ARIA attributes | role, aria-label, aria-expanded (as needed) set |
| Focus management | tabindex, focus-visible styles present |
| Reduced motion | prefers-reduced-motion media query in CSS |
4. Performance baseline:
| Check | Pass Criteria |
|-------|---------------|
| GPU-only transforms | No width/height/top/left in transitions |
| No forced reflow | No offsetWidth/getBoundingClientRect in animation loop |
| Cleanup | destroy() disconnects all observers and listeners |
5. Update `<session>/wisdom/.msg/meta.json` under `builder` namespace:
- Read existing -> merge `{ "builder": { task_type, component_name, file_count, output_dir, states_implemented, events_bound } }` -> write back

View File

@@ -0,0 +1,71 @@
# Analyze Task
Parse user task -> detect interactive component scope -> identify browser APIs -> determine pipeline mode.
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
## Signal Detection
| Keywords | Capability | Pipeline Hint |
|----------|------------|---------------|
| split, compare, before/after, slider, divider | split-compare | single |
| gallery, carousel, scroll-snap, horizontal scroll | scroll-snap-gallery | gallery |
| lightbox, modal, overlay, fullscreen view | lightbox | single |
| scroll reveal, appear on scroll, fade in, stagger | scroll-reveal | single or gallery |
| glass, terminal, frosted, blur, backdrop | glass-terminal | single |
| lens, magnify, zoom, loupe | lens-effect | single |
| drag, resize, pointer, touch | pointer-interaction | single |
| page, landing, sections, multi-section | interactive-page | page |
| multiple components, collection, set | multi-component | gallery or page |
## Scope Determination
| Signal | Pipeline Mode |
|--------|---------------|
| Single component mentioned | single |
| Gallery or scroll-based multi-component | gallery |
| Full interactive page or multi-section | page |
| Unclear | ask user |
## Complexity Scoring
| Factor | Points |
|--------|--------|
| Single component | +1 |
| Gallery / scroll collection | +2 |
| Full interactive page | +3 |
| Pointer/drag interactions | +1 |
| Scroll-based triggers (IntersectionObserver) | +1 |
| Touch gestures (pinch, swipe) | +1 |
| Overlay/modal with focus trap | +1 |
| Animation choreography (stagger, sequence) | +1 |
Results: 1-2 Low (single), 3-4 Medium (gallery), 5+ High (page)
## Browser API Detection
| Keywords | Browser API |
|----------|-------------|
| scroll, appear, visibility, threshold | IntersectionObserver |
| resize, container, responsive, layout | ResizeObserver |
| drag, pointer, mouse, click | Pointer Events |
| touch, swipe, pinch, gesture | Touch Events |
| scroll snap, snap point, mandatory | CSS scroll-snap |
| clip, mask, reveal, wipe | CSS clip-path |
| blur, frosted, glass | CSS backdrop-filter |
| animate, transition, keyframe | Web Animations API |
| focus, trap, tab, keyboard | Focus Management |
## Output
Write scope context to coordinator memory:
```json
{
"pipeline_mode": "<single|gallery|page>",
"scope": "<description>",
"interaction_type": "<pointer|scroll|overlay|mixed>",
"components": ["<detected-component-types>"],
"browser_apis": ["<detected-apis>"],
"complexity": { "score": 0, "level": "Low|Medium|High" }
}
```

View File

@@ -0,0 +1,162 @@
# Command: Dispatch
Create the interactive craft task chain with correct dependencies and structured task descriptions. Supports single, gallery, and page pipeline modes.
## Phase 2: Context Loading
| Input | Source | Required |
|-------|--------|----------|
| User requirement | From coordinator Phase 1 | Yes |
| Session folder | From coordinator Phase 2 | Yes |
| Pipeline mode | From tasks.json `pipeline_mode` | Yes |
| Interaction type | From tasks.json `interaction_type` | Yes |
1. Load user requirement and scope from tasks.json
2. Load pipeline stage definitions from specs/pipelines.md
3. Read `pipeline_mode` and `interaction_type` from tasks.json
## Phase 3: Task Chain Creation (Mode-Branched)
### Task Entry Template
Each task in tasks.json `tasks` object:
```json
{
"<TASK-ID>": {
"title": "<concise title>",
"description": "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>\nTASK:\n - <step 1: specific action>\n - <step 2: specific action>\n - <step 3: specific action>\nCONTEXT:\n - Session: <session-folder>\n - Scope: <interaction-scope>\n - Components: <component-list>\n - Upstream artifacts: <artifact-1>, <artifact-2>\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <deliverable path> + <quality criteria>\nCONSTRAINTS: <scope limits, focus areas>",
"role": "<role-name>",
"prefix": "<PREFIX>",
"deps": ["<dependency-list>"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
### Mode Router
| Mode | Action |
|------|--------|
| `single` | Create 4 tasks: RESEARCH -> INTERACT -> BUILD -> A11Y |
| `gallery` | Create 6 tasks: RESEARCH -> INTERACT-001 -> BUILD-001 -> INTERACT-002 -> BUILD-002 -> A11Y |
| `page` | Create 4+ tasks: RESEARCH -> INTERACT -> [BUILD-001..N parallel] -> A11Y |
---
### Single Pipeline Task Chain
**RESEARCH-001** (researcher):
```json
{
"RESEARCH-001": {
"title": "Interaction pattern analysis and browser API audit",
"description": "PURPOSE: Analyze interaction patterns, browser API availability, and reference implementations | Success: 3 research artifacts with valid data\nTASK:\n - Catalog existing interactive components in project\n - Audit browser API usage (IntersectionObserver, ResizeObserver, Pointer Events, Touch Events)\n - Collect reference patterns for target component type\nCONTEXT:\n - Session: <session-folder>\n - Scope: <interaction-scope>\n - Components: <component-list>\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/research/*.json | All 3 research files with valid JSON\nCONSTRAINTS: Read-only analysis | Focus on <interaction-scope>",
"role": "researcher",
"prefix": "RESEARCH",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**INTERACT-001** (interaction-designer):
```json
{
"INTERACT-001": {
"title": "Interaction blueprint with state machine and event flows",
"description": "PURPOSE: Design complete interaction blueprint with state machine and event flows | Success: Blueprint with all states, events, and keyboard mappings defined\nTASK:\n - Define state machine (idle -> hover -> active -> animating -> complete)\n - Map event flows (pointer/touch/keyboard -> handlers -> state transitions)\n - Specify gesture parameters (lerp speed, thresholds, easing)\n - Design animation choreography (entry/exit/idle transitions)\n - Create touch/keyboard/mouse mapping table\nCONTEXT:\n - Session: <session-folder>\n - Scope: <interaction-scope>\n - Upstream artifacts: research/*.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/interaction/blueprints/<component-name>.md | Complete state machine + event map + keyboard coverage\nCONSTRAINTS: Vanilla JS only | GPU-only animations | Progressive enhancement",
"role": "interaction-designer",
"prefix": "INTERACT",
"deps": ["RESEARCH-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**BUILD-001** (builder):
```json
{
"BUILD-001": {
"title": "Vanilla JS + CSS interactive component implementation",
"description": "PURPOSE: Implement interactive component as vanilla JS + CSS | Success: Working ES module + CSS with all states, touch-aware, keyboard accessible\nTASK:\n - Implement ES module component class from interaction blueprint\n - Write CSS with custom properties (no preprocessor)\n - Add progressive enhancement (content works without JS)\n - Use GPU-only animations (transform + opacity)\n - Implement pointer events with touch fallback\n - Add ResizeObserver for responsive behavior\n - Add IntersectionObserver for scroll triggers (if applicable)\nCONTEXT:\n - Session: <session-folder>\n - Scope: <interaction-scope>\n - Upstream artifacts: interaction/blueprints/*.md, research/*.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/build/components/<name>.js + <name>.css | Zero dependencies, all states implemented\nCONSTRAINTS: No npm packages | ES modules only | No inline styles | < 5ms per frame",
"role": "builder",
"prefix": "BUILD",
"deps": ["INTERACT-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**A11Y-001** (a11y-tester):
```json
{
"A11Y-001": {
"title": "Accessibility audit of built component",
"description": "PURPOSE: Audit accessibility of built component | Success: Audit report with pass/fail per check, 0 critical issues\nTASK:\n - Test keyboard navigation (tab order, arrow keys, escape, enter/space)\n - Check screen reader compatibility (ARIA roles, states, live regions)\n - Verify reduced motion fallback (prefers-reduced-motion)\n - Test focus management (visible indicator, focus trap for overlays)\n - Check color contrast (foreground/background ratio)\nCONTEXT:\n - Session: <session-folder>\n - Scope: <interaction-scope>\n - Upstream artifacts: build/components/*.js, build/components/*.css, interaction/blueprints/*.md\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/a11y/a11y-audit-001.md | Per-check pass/fail with remediation suggestions\nCONSTRAINTS: Read-only analysis | GC convergence: 0 critical issues",
"role": "a11y-tester",
"prefix": "A11Y",
"deps": ["BUILD-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
---
### Gallery Pipeline Task Chain
Create tasks in dependency order:
| Task | Role | deps | Description |
|------|------|------|-------------|
| RESEARCH-001 | researcher | [] | Interaction patterns + browser API audit |
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Base component interaction blueprint |
| BUILD-001 | builder | [INTERACT-001] | Base component implementation |
| INTERACT-002 | interaction-designer | [BUILD-001] | Gallery/scroll-snap interaction blueprint |
| BUILD-002 | builder | [INTERACT-002] | Gallery container + navigation implementation |
| A11Y-001 | a11y-tester | [BUILD-002] | Full gallery accessibility audit |
Task descriptions follow same template as single pipeline, with subject-specific content:
- INTERACT-002 focuses on scroll-snap container, navigation dots, active item detection
- BUILD-002 focuses on gallery container with CSS scroll-snap, IntersectionObserver for active item, navigation controls
---
### Page Pipeline Task Chain
| Task | Role | deps | Description |
|------|------|------|-------------|
| RESEARCH-001 | researcher | [] | Interaction patterns for all page sections |
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Blueprints for all interactive sections |
| BUILD-001..N | builder | [INTERACT-001] | One task per section (parallel fan-out) |
| A11Y-001 | a11y-tester | [BUILD-001..N] | Full page accessibility audit |
**Parallel fan-out**: Create one BUILD task per distinct interactive section detected in the interaction blueprint. Each BUILD task deps only on INTERACT-001. A11Y-001 deps on ALL BUILD tasks.
Task descriptions for each BUILD-00N specify which section to implement, referencing the corresponding section in the interaction blueprint.
---
## Phase 4: Validation
Verify task chain integrity:
| Check | Method | Expected |
|-------|--------|----------|
| Task count correct | tasks.json count | single: 4, gallery: 6, page: 3+N |
| Dependencies correct | Trace dependency graph | Acyclic, correct deps |
| No circular dependencies | Trace dependency graph | Acyclic |
| Task IDs use correct prefixes | Pattern check | RESEARCH/INTERACT/BUILD/A11Y |
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
If validation fails, fix the specific task and re-validate.

View File

@@ -0,0 +1,233 @@
# Monitor Pipeline
Synchronous pipeline coordination using spawn_agent + wait_agent.
## Constants
- WORKER_AGENT: team_worker
- MAX_GC_ROUNDS: 2
## Handler Router
| Source | Handler |
|--------|---------|
| "capability_gap" | handleAdapt |
| "check" or "status" | handleCheck |
| "resume" or "continue" | handleResume |
| All tasks completed | handleComplete |
| Default | handleSpawnNext |
## handleCallback
Worker completed (wait_agent returns). Process and advance.
1. Determine role from completed task prefix:
| Task Prefix | Role |
|-------------|------|
| `RESEARCH-*` | researcher |
| `INTERACT-*` | interaction-designer |
| `BUILD-*` | builder |
| `A11Y-*` | a11y-tester |
2. Mark task completed in tasks.json: `state.tasks[taskId].status = 'completed'`
3. Record completion in session state
4. Check checkpoint for completed task:
| Completed Task | Checkpoint | Action |
|---------------|------------|--------|
| RESEARCH-001 | - | Notify user: research complete |
| INTERACT-001 | - | Proceed to BUILD-001 (single/gallery) or BUILD-001..N (page parallel) |
| INTERACT-002 | - | Proceed to BUILD-002 (gallery) |
| BUILD-001 | - | Check mode: single -> A11Y-001; gallery -> INTERACT-002; page -> check if all BUILD done |
| BUILD-001..N | - | Page mode: check if all BUILD tasks done -> A11Y-001 |
| BUILD-002 | - | Gallery: proceed to A11Y-001 |
| A11Y-001 | QUALITY: A11y Gate | Check a11y signal -> GC loop or complete |
5. **A11y Gate handling** (A11Y task completed):
Read a11y signal from result: `a11y_passed`, `a11y_result`, or `fix_required`
| Signal | Condition | Action |
|--------|-----------|--------|
| `a11y_passed` | 0 critical issues | GC converged -> record gate -> handleComplete |
| `a11y_result` | Minor issues only | gc_rounds < max -> create BUILD-fix task in tasks.json |
| `fix_required` | Critical issues found | gc_rounds < max -> create BUILD-fix task (CRITICAL) in tasks.json |
| Any | gc_rounds >= max | Escalate to user |
**GC Fix Task Creation** (add to tasks.json):
```json
{
"BUILD-fix-<round>": {
"title": "Address a11y audit feedback",
"description": "PURPOSE: Address a11y audit feedback | Success: All critical/high issues resolved\nTASK:\n - Parse a11y audit feedback for specific issues\n - Apply targeted fixes to component JS/CSS\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: a11y/a11y-audit-<NNN>.md",
"role": "builder",
"prefix": "BUILD",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
Then create new A11Y task in tasks.json with deps on fix. Increment gc_state.round.
**GC Escalation Options** (when max rounds exceeded):
1. Accept current implementation - skip remaining a11y fixes
2. Try one more round
3. Terminate
6. -> handleSpawnNext
## handleCheck
Read-only status report from tasks.json, then STOP.
```
Pipeline Status (<pipeline-mode>):
[DONE] RESEARCH-001 (researcher) -> research/*.json
[DONE] INTERACT-001 (interaction-designer) -> blueprints/*.md
[RUN] BUILD-001 (builder) -> building component...
[WAIT] A11Y-001 (a11y-tester) -> blocked by BUILD-001
GC Rounds: 0/2
Session: <session-id>
Commands: 'resume' to advance | 'check' to refresh
```
Output status -- do NOT advance pipeline.
## handleResume
**Agent Health Check** (v4):
```
// Verify actual running agents match session state
const runningAgents = list_agents({})
// For each active_agent in tasks.json:
// - If agent NOT in runningAgents -> agent crashed
// - Reset that task to pending, remove from active_agents
// This prevents stale agent references from blocking the pipeline
```
1. Audit tasks.json for inconsistencies:
- Tasks stuck in "in_progress" -> reset to "pending"
- Tasks with completed deps but still "pending" -> include in spawn list
2. -> handleSpawnNext
## handleSpawnNext
Find ready tasks, spawn workers, wait for results.
1. Read tasks.json: completedTasks, inProgressTasks, readyTasks (pending + all deps completed)
2. No ready + work in progress -> report waiting, STOP
3. No ready + nothing in progress -> handleComplete
4. Has ready -> for each:
a. Check inner loop role with active worker -> skip (worker picks up)
b. Update task status to in_progress in tasks.json
c. team_msg log -> task_unblocked
d. Spawn team_worker:
```javascript
// 1) Update status in tasks.json
state.tasks[taskId].status = 'in_progress'
// 2) Spawn worker
const agentId = spawn_agent({
agent_type: "team_worker",
task_name: taskId, // e.g., "BUILD-001" -- enables named targeting
items: [
{ type: "text", text: `## Role Assignment
role: ${role}
role_spec: ${skillRoot}/roles/${role}/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${taskDescription}
inner_loop: ${innerLoop}` },
{ type: "text", text: `Read role_spec file to load Phase 2-4 domain instructions.
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).` }
]
})
// 3) Track agent
state.active_agents[taskId] = { agentId, role, started_at: now }
// 4) Wait for completion -- use task_name for stable targeting (v4)
const waitResult = wait_agent({ targets: [taskId], timeout_ms: 900000 })
if (waitResult.timed_out) {
state.tasks[taskId].status = 'timed_out'
close_agent({ target: taskId })
delete state.active_agents[taskId]
} else {
// 5) Collect results and update tasks.json
state.tasks[taskId].status = 'completed'
close_agent({ target: taskId }) // Use task_name, not agentId
delete state.active_agents[taskId]
}
```
**Parallel spawn rules by mode**:
| Mode | Scenario | Spawn Behavior |
|------|----------|---------------|
| single | Sequential | One task at a time |
| gallery | Sequential | One task at a time |
| page | After INTERACT-001 | Spawn BUILD-001..N in parallel, wait_agent for all |
| page | After all BUILD done | Spawn A11Y-001 |
**Cross-Agent Supplementary Context** (v4):
When spawning workers in a later pipeline phase, send upstream results as supplementary context to already-running workers:
```
// Example: Send research results to running interaction-designer
send_message({
target: "<running-agent-task-name>",
items: [{ type: "text", text: `## Supplementary Context\n${upstreamFindings}` }]
})
// Note: send_message queues info without interrupting the agent's current work
```
Use `send_message` (not `assign_task`) for supplementary info that enriches but doesn't redirect the agent's current task.
5. Update tasks.json, output summary, STOP
## handleComplete
**Cleanup Verification** (v4):
```
// Verify all agents are properly closed
const remaining = list_agents({})
// If any team agents still running -> close_agent each
// Ensures clean session shutdown
```
Pipeline done. Generate report and completion action.
**Completion check by mode**:
| Mode | Completion Condition |
|------|---------------------|
| single | All 4 tasks (+ fix tasks) completed |
| gallery | All 6 tasks (+ fix tasks) completed |
| page | All 3+N tasks (+ fix tasks) completed |
1. If any tasks not completed -> handleSpawnNext
2. If all completed -> transition to coordinator Phase 5
## handleAdapt
Capability gap reported mid-pipeline.
1. Parse gap description
2. Check if existing role covers it -> redirect
3. Role count < 5 -> generate dynamic role spec
4. Create new task in tasks.json, spawn worker
5. Role count >= 5 -> merge or pause
## Fast-Advance Reconciliation
On every coordinator wake:
1. Read tasks.json for completed tasks
2. Sync active_agents with actual state
3. No duplicate spawns

View File

@@ -0,0 +1,209 @@
# Coordinator Role
Interactive Craft Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages task chains for interactive component creation, GC loops between builder and a11y-tester, parallel fan-out for page mode.
## Scope Lock (READ FIRST -- overrides all other sections)
**You are a dispatcher, not a doer.** Your ONLY outputs are:
- Session state files (`.workflow/.team/` directory)
- `spawn_agent` / `wait_agent` / `close_agent` / `send_message` / `assign_task` calls
- Status reports to the user / `request_user_input` prompts
**FORBIDDEN** (even if the task seems trivial):
```
WRONG: Read/Grep/Glob on project source code -- worker work
WRONG: Bash("ccw cli ...") -- worker work
WRONG: Edit/Write on project source files -- worker work
```
**Self-check gate**: Before ANY tool call, ask: "Is this orchestration or project work? If project work -> STOP -> spawn worker."
---
## Identity
- **Name**: coordinator | **Tag**: [coordinator]
- **Responsibility**: Analyze task -> Create session -> Dispatch tasks -> Monitor progress -> Report results
## Boundaries
### MUST
- All output (team_msg, logs) must carry `[coordinator]` identifier
- Use `team_worker` agent type for all worker spawns (NOT `general-purpose`)
- Dispatch tasks with proper dependency chains and deps in tasks.json
- Monitor worker progress via wait_agent and process results
- Handle Generator-Critic loops with max 2 iterations
- Maintain session state persistence (tasks.json)
- **Always proceed through full Phase 1-5 workflow, never skip to direct execution**
- Use `send_message` for supplementary context (non-interrupting) and `assign_task` for triggering new work
- Use `list_agents` for session resume health checks and cleanup verification
### MUST NOT
- Implement domain logic (researching, designing, building, testing) -- workers handle this
- Spawn workers without creating tasks first
- Skip sync points when configured
- Force-advance pipeline past failed a11y audit
- Modify source code or component artifacts directly -- delegate to workers
- Omit `[coordinator]` identifier in any output
- Call CLI tools (ccw cli) -- only workers use CLI
## Command Execution Protocol
When coordinator needs to execute a command (analyze, dispatch, monitor):
1. Read `commands/<command>.md`
2. Follow the workflow defined in the command
3. Commands are inline execution guides, NOT separate agents
4. Execute synchronously, complete before proceeding
## Entry Router
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
| Capability gap | Message contains "capability_gap" | -> handleAdapt (monitor.md) |
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
| Interrupted session | Active/paused session exists in .workflow/.team/IC-* | -> Phase 0 |
| New session | None of above | -> Phase 1 |
For check/resume/adapt/complete: load `@commands/monitor.md`, execute matched handler, STOP.
## Phase 0: Session Resume Check
1. Scan `.workflow/.team/IC-*/tasks.json` for active/paused sessions
2. No sessions -> Phase 1
3. Single session -> reconcile (read tasks.json, reset in_progress->pending, kick first ready task)
4. Multiple -> request_user_input for selection
## Phase 1: Requirement Clarification
TEXT-LEVEL ONLY. No source code reading.
1. Parse task description from arguments
2. Detect interactive scope:
| Signal | Pipeline Mode |
|--------|---------------|
| Single component (split compare, lightbox, lens, scroll reveal, glass terminal) | single |
| Gallery, carousel, scroll-snap collection, multi-component scroll | gallery |
| Full interactive page, landing page, multi-section interactive | page |
| Unclear | ask user |
3. Ask for missing parameters if scope unclear:
```
request_user_input({
questions: [
{ question: "Interactive component scope?", header: "Scope", options: [
{ label: "Single component", description: "One interactive element (split compare, lightbox, etc.)" },
{ label: "Gallery / Scroll collection", description: "Scroll-snap gallery or multi-component scroll" },
{ label: "Full interactive page", description: "Complete page with multiple interactive sections" }
]},
{ question: "Primary interaction type?", header: "Interaction", options: [
{ label: "Pointer/drag", description: "Drag, resize, slider interactions" },
{ label: "Scroll-based", description: "Scroll snap, scroll reveal, parallax" },
{ label: "Overlay/modal", description: "Lightbox, lens, tooltip overlays" },
{ label: "Mixed" }
]}
]
})
```
4. Delegate to `@commands/analyze.md` -> output scope context
5. Record: pipeline_mode, interaction_type, complexity
## Phase 2: Create Session + Initialize
1. Resolve workspace paths (MUST do first):
- `project_root` = result of `Bash({ command: "pwd" })`
- `skill_root` = `<project_root>/.codex/skills/team-interactive-craft`
2. Generate session ID: `IC-<slug>-<YYYY-MM-DD>`
3. Create session folder structure:
```
.workflow/.team/IC-<slug>-<date>/research/
.workflow/.team/IC-<slug>-<date>/interaction/blueprints/
.workflow/.team/IC-<slug>-<date>/build/components/
.workflow/.team/IC-<slug>-<date>/a11y/
.workflow/.team/IC-<slug>-<date>/wisdom/
.workflow/.team/IC-<slug>-<date>/.msg/
```
4. Initialize `.msg/meta.json` via team_msg state_update with pipeline metadata
5. Write initial tasks.json:
```json
{
"session_id": "<id>",
"pipeline_mode": "<single|gallery|page>",
"interaction_type": "<pointer|scroll|overlay|mixed>",
"created_at": "<ISO timestamp>",
"gc_rounds": 0,
"max_gc_rounds": 2,
"active_agents": {},
"tasks": {}
}
```
6. Do NOT spawn workers yet - deferred to Phase 4
## Phase 3: Create Task Chain
Delegate to `@commands/dispatch.md`. Task chains by mode:
| Mode | Task Chain |
|------|------------|
| single | RESEARCH-001 -> INTERACT-001 -> BUILD-001 -> A11Y-001 |
| gallery | RESEARCH-001 -> INTERACT-001 -> BUILD-001 -> INTERACT-002 -> BUILD-002 -> A11Y-001 |
| page | RESEARCH-001 -> INTERACT-001 -> [BUILD-001..N parallel] -> A11Y-001 |
## Phase 4: Spawn-and-Wait
Delegate to `@commands/monitor.md#handleSpawnNext`:
1. Find ready tasks (pending + deps resolved)
2. Spawn team_worker agents via spawn_agent, wait_agent for results
3. Output status summary
4. STOP
## Phase 5: Report + Completion Action
1. Read session state -> collect all results
2. List deliverables:
| Deliverable | Path |
|-------------|------|
| Interaction Inventory | <session>/research/interaction-inventory.json |
| Browser API Audit | <session>/research/browser-api-audit.json |
| Pattern Reference | <session>/research/pattern-reference.json |
| Interaction Blueprints | <session>/interaction/blueprints/*.md |
| Component JS Files | <session>/build/components/*.js |
| Component CSS Files | <session>/build/components/*.css |
| A11y Audit Reports | <session>/a11y/a11y-audit-*.md |
3. Calculate: completed_tasks, gc_rounds, a11y_score, components_built
4. Output pipeline summary with [coordinator] prefix
5. Execute completion action:
```
request_user_input({
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
{ label: "Archive & Clean", description: "Archive session and clean up resources" },
{ label: "Keep Active", description: "Keep session for follow-up work" },
{ label: "Export Results", description: "Export deliverables to specified location" }
]}]
})
```
## v4 Coordination Patterns
### Message Semantics
- **send_message**: Queue supplementary info to a running agent. Does NOT interrupt current processing. Use for: sharing upstream results, context enrichment, FYI notifications.
- **assign_task**: Assign new work and trigger processing. Use for: waking idle agents, redirecting work, requesting new output.
### Agent Lifecycle Management
- **list_agents({})**: Returns all running agents. Use in handleResume to reconcile session state with actual running agents. Use in handleComplete to verify clean shutdown.
- **Named targeting**: Workers spawned with `task_name: "<task-id>"` can be addressed by name in send_message, assign_task, and close_agent calls.
## Error Handling
| Error | Resolution |
|-------|------------|
| Task timeout | Log, mark failed, ask user to retry or skip |
| Worker crash | Reset task to pending, respawn worker |
| Dependency cycle | Detect, report to user, halt |
| Invalid scope | Reject with error, ask to clarify |
| Session corruption | Attempt recovery, fallback to manual reconciliation |
| GC loop stuck > 2 rounds | Escalate to user: accept / try one more / terminate |

View File

@@ -0,0 +1,144 @@
---
role: interaction-designer
prefix: INTERACT
inner_loop: false
message_types: [state_update]
---
# Interaction Blueprint Designer
Design complete interaction blueprints: state machines, event flows, gesture specifications, animation choreography, and input mapping tables. Consume research artifacts to produce blueprints for the builder role.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Research artifacts | <session>/research/*.json | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Existing blueprints | <session>/interaction/blueprints/*.md | Only for INTERACT-002+ |
1. Extract session path from task description
2. Read research findings: interaction-inventory.json, browser-api-audit.json, pattern-reference.json
3. Detect task type from subject: "001" -> Primary blueprint, "002" -> Secondary/gallery blueprint
4. If INTERACT-002+: read existing blueprints for consistency with base component
## Phase 3: Design Execution
**Primary Blueprint (INTERACT-001)**:
For each target component, produce a blueprint document containing:
### State Machine
Define complete state diagram:
```
[idle] --(pointerenter)--> [hover]
[hover] --(pointerdown)--> [active]
[hover] --(pointerleave)--> [idle]
[active] --(pointermove)--> [dragging/animating]
[active] --(pointerup)--> [hover]
[dragging] --(pointerup)--> [settling]
[settling] --(transitionend)--> [idle]
[any] --(focus)--> [focused]
[focused] --(blur)--> [previous-state]
[any] --(keydown:Escape)--> [idle]
```
- All states must be reachable
- All states must have exit transitions
- Error/reset transitions from every state back to idle
### Event Flow Map
Map events to handlers to state transitions:
| Event | Source | Handler | State Transition | Side Effect |
|-------|--------|---------|-----------------|-------------|
| pointerdown | element | onPointerDown | idle->active | setPointerCapture, preventDefault |
| pointermove | document | onPointerMove | active->dragging | update position via lerp |
| pointerup | document | onPointerUp | dragging->settling | releasePointerCapture |
| keydown:ArrowLeft | element | onKeyDown | - | decrement value |
| keydown:ArrowRight | element | onKeyDown | - | increment value |
| keydown:Escape | element | onKeyDown | any->idle | reset to default |
| keydown:Enter/Space | element | onKeyDown | idle->active | toggle/activate |
### Gesture Specification
For pointer/touch interactions:
| Gesture | Detection | Parameters |
|---------|-----------|------------|
| Drag | pointerdown + pointermove > 3px | lerp speed: 0.15, axis: x/y/both |
| Swipe | pointerup with velocity > 0.5px/ms | direction: left/right/up/down |
| Pinch | 2+ touch points, distance change | scale factor, min/max zoom |
| Scroll snap | CSS scroll-snap-type: x mandatory | align: start/center, behavior: smooth |
- Lerp interpolation: `current += (target - current) * speed`
- Dead zone: ignore movements < 3px from start
- Velocity tracking: store last 3-5 pointer positions with timestamps
### Animation Choreography
Define animation sequences:
| Animation | Trigger | Properties | Duration | Easing | GPU |
|-----------|---------|------------|----------|--------|-----|
| Entry | mount/reveal | opacity 0->1, translateY 20px->0 | 400ms | cubic-bezier(0.16,1,0.3,1) | Yes |
| Exit | unmount/hide | opacity 1->0, translateY 0->-10px | 200ms | ease-in | Yes |
| Drag follow | pointermove | translateX via lerp | per-frame | linear (lerp) | Yes |
| Settle | pointerup | translateX to snap point | 300ms | cubic-bezier(0.16,1,0.3,1) | Yes |
| Hover | pointerenter | scale 1->1.02 | 200ms | ease-out | Yes |
| Focus ring | focus-visible | outline-offset 0->2px | 150ms | ease-out | No (outline) |
| Stagger | intersection | delay: index * 80ms | 400ms+delay | cubic-bezier(0.16,1,0.3,1) | Yes |
- ALL animations must use transform + opacity only (GPU-composited)
- Exception: outline for focus indicators
- Reduced motion: replace all motion with opacity-only crossfade (200ms)
### Input Mapping Table
Unified mapping across input methods:
| Action | Mouse | Touch | Keyboard | Screen Reader |
|--------|-------|-------|----------|--------------|
| Activate | click | tap | Enter/Space | Enter/Space |
| Navigate prev | - | swipe-right | ArrowLeft | ArrowLeft |
| Navigate next | - | swipe-left | ArrowRight | ArrowRight |
| Drag/adjust | pointerdown+move | pointerdown+move | Arrow keys (step) | Arrow keys (step) |
| Dismiss | click outside | tap outside | Escape | Escape |
| Focus | pointermove (hover) | - | Tab | Tab |
### Platform API Preference
When designing interaction blueprints, prefer native APIs over custom implementations:
| Need | Native API | Custom Fallback |
|------|-----------|-----------------|
| Modal dialog | `<dialog>` + `showModal()` | Custom with focus trap + inert |
| Tooltip/popover | Popover API (`popover` attribute) | Custom with click-outside listener |
| Dropdown positioning | CSS Anchor Positioning | `position: fixed` + JS coords |
| Focus trap | `<dialog>` built-in or `inert` attribute | Manual focus cycling with tabindex |
| Escape-to-close | Built into `<dialog>` and Popover | Manual keydown listener |
Document in blueprint: which native API to use, what the fallback is for unsupported browsers, and how to feature-detect.
**Gallery/Secondary Blueprint (INTERACT-002)**:
- Design scroll-snap container interaction
- Navigation controls (prev/next arrows, dots/indicators)
- Active item detection via IntersectionObserver
- Keyboard navigation within gallery (ArrowLeft/ArrowRight between items)
- Touch momentum and snap behavior
- Reference base component blueprint for consistency
Output: `<session>/interaction/blueprints/{component-name}.md`
## Phase 4: Self-Validation
| Check | Pass Criteria |
|-------|---------------|
| State machine complete | All states reachable, all states have exit |
| Event coverage | All events mapped to handlers |
| Keyboard complete | All interactive actions have keyboard equivalent |
| Touch parity | All mouse actions have touch equivalent |
| GPU-only animations | No width/height/top/left animations |
| Reduced motion | prefers-reduced-motion fallback defined |
| Screen reader path | All actions accessible via screen reader |
If any check fails, revise the blueprint before output.
Update `<session>/wisdom/.msg/meta.json` under `interaction-designer` namespace:
- Read existing -> merge `{ "interaction-designer": { task_type, components_designed, states_count, events_count, gestures } }` -> write back

View File

@@ -0,0 +1,131 @@
---
role: researcher
prefix: RESEARCH
inner_loop: false
message_types: [state_update]
---
# Interaction Pattern Researcher
Analyze existing interactive components, audit browser API usage, and collect reference patterns for target component types. Produce foundation data for downstream interaction-designer, builder, and a11y-tester roles.
## Phase 2: Context & Environment Detection
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | No |
1. Extract session path and target scope from task description
2. Detect project structure and existing interactive patterns:
| File Pattern | Detected Pattern |
|--------------|-----------------|
| *.js with addEventListener | Event-driven components |
| IntersectionObserver usage | Scroll-triggered animations |
| ResizeObserver usage | Responsive layout components |
| pointer/mouse/touch events | Interactive drag/gesture components |
| scroll-snap in CSS | Scroll-snap gallery |
| backdrop-filter in CSS | Glass/frosted effects |
| clip-path in CSS | Reveal/mask animations |
3. Use CLI tools (e.g., `ccw cli -p "..." --tool gemini --mode analysis`) or direct tools (Glob, Grep) to scan for existing interactive components, animation patterns, event handling approaches
4. Read interaction type context from session config
## Phase 3: Research Execution
Execute 3 analysis streams:
**Stream 1 -- Interaction Inventory**:
- Search for existing interactive components (event listeners, observers, animation code)
- Identify interaction patterns in use (drag, scroll, overlay, reveal)
- Map component lifecycle (init, mount, resize, destroy)
- Find dependency patterns (any external libs vs vanilla)
- Catalog gesture handling approaches (pointer vs mouse+touch)
- Output: `<session>/research/interaction-inventory.json`
- Schema:
```json
{
"existing_components": [
{ "name": "", "type": "", "events": [], "observers": [], "file": "" }
],
"patterns": {
"event_handling": "",
"animation_approach": "",
"lifecycle": "",
"dependency_model": ""
},
"summary": { "total_interactive": 0, "vanilla_count": 0, "lib_count": 0 }
}
```
**Stream 2 -- Browser API Audit**:
- Check availability and usage of target browser APIs:
- IntersectionObserver (scroll triggers, lazy loading, visibility detection)
- ResizeObserver (responsive layout, container queries)
- Pointer Events (unified mouse/touch/pen input)
- Touch Events (gesture recognition, multi-touch)
- CSS scroll-snap (snap points, scroll behavior)
- CSS clip-path (shape masking, reveal animations)
- CSS backdrop-filter (blur, brightness, glass effects)
- Web Animations API (programmatic animation control)
- requestAnimationFrame (frame-synced updates)
- Identify polyfill needs for target browser support
- Output: `<session>/research/browser-api-audit.json`
- Schema:
```json
{
"apis": {
"<api-name>": {
"available": true,
"in_use": false,
"support": "baseline|modern|polyfill-needed",
"usage_count": 0,
"notes": ""
}
},
"polyfill_needs": [],
"min_browser_target": ""
}
```
**Stream 3 -- Pattern Reference**:
- Collect reference patterns for each target component type
- For each component, document: state machine pattern, event flow, animation approach, touch handling, accessibility pattern
- Reference well-known implementations (e.g., scroll-snap gallery, split-view compare, lightbox overlay)
- Note performance considerations and gotchas per pattern
- Output: `<session>/research/pattern-reference.json`
- Schema:
```json
{
"patterns": [
{
"component_type": "",
"state_machine": { "states": [], "transitions": [] },
"events": { "primary": [], "fallback": [] },
"animation": { "approach": "", "gpu_only": true, "easing": "" },
"touch": { "gestures": [], "threshold_px": 0 },
"a11y": { "role": "", "aria_states": [], "keyboard": [] },
"performance": { "budget_ms": 0, "gotchas": [] }
}
]
}
```
Compile research summary metrics: existing_interactive_count, vanilla_ratio, apis_available, polyfill_count, patterns_collected.
## Phase 4: Validation & Output
1. Verify all 3 output files exist and contain valid JSON with required fields:
| File | Required Fields |
|------|----------------|
| interaction-inventory.json | existing_components array, patterns object |
| browser-api-audit.json | apis object |
| pattern-reference.json | patterns array |
2. If any file missing or invalid, re-run corresponding stream
3. Update `<session>/wisdom/.msg/meta.json` under `researcher` namespace:
- Read existing -> merge `{ "researcher": { interactive_count, vanilla_ratio, apis_available, polyfill_needs, scope } }` -> write back

View File

@@ -0,0 +1,362 @@
# Interaction Pattern Catalog
Reference patterns for common interactive components. Each pattern defines the core interaction model, browser APIs, state machine, animation approach, and accessibility requirements.
---
## Glass Terminal Pattern
Split-view layout with frosted glass effect, tab navigation, and command input simulation.
**Core Interaction**:
- Tab-based view switching (2-4 panels)
- Command input field with syntax-highlighted output
- Frosted glass background via `backdrop-filter: blur()`
- Resize-aware layout via ResizeObserver
**State Machine**:
```
[idle] --(tab-click)--> [switching]
[switching] --(transition-end)--> [idle]
[idle] --(input-focus)--> [input-active]
[input-active] --(Enter)--> [processing]
[processing] --(output-ready)--> [idle]
[input-active] --(Escape)--> [idle]
```
**Browser APIs**: ResizeObserver, CSS backdrop-filter, CSS custom properties
**Animation**:
- Tab switch: opacity crossfade (200ms, ease-out), GPU-only
- Output appear: translateY(10px)->0 + opacity (300ms, ease-out)
- Cursor blink: CSS animation (1s steps(2))
**CSS Key Properties**:
```css
.glass-terminal {
backdrop-filter: blur(12px) saturate(180%);
-webkit-backdrop-filter: blur(12px) saturate(180%);
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
}
```
**Accessibility**:
- role="tablist" + role="tab" + role="tabpanel"
- aria-selected on active tab
- Arrow keys navigate tabs, Enter/Space activates
- Input field: role="textbox", aria-label
- Output: aria-live="polite" for new content
---
## Split Compare Pattern
Before/after overlay with draggable divider for visual comparison.
**Core Interaction**:
- Draggable vertical divider splits two overlapping images/views
- Pointer events for drag with Lerp interpolation (speed: 0.15)
- clip-path animation reveals before/after content
- Touch-friendly with full pointer event support
**State Machine**:
```
[idle] --(pointerenter)--> [hover]
[hover] --(pointerdown on divider)--> [dragging]
[hover] --(pointerleave)--> [idle]
[dragging] --(pointermove)--> [dragging] (update position)
[dragging] --(pointerup)--> [settling]
[settling] --(lerp-complete)--> [idle]
[any] --(focus + ArrowLeft/Right)--> [keyboard-adjusting]
[keyboard-adjusting] --(keyup)--> [idle]
```
**Browser APIs**: Pointer Events, CSS clip-path, ResizeObserver, requestAnimationFrame
**Animation**:
- Divider follow: Lerp `current += (target - current) * 0.15` per frame
- Clip-path update: `clip-path: inset(0 0 0 ${position}%)` on after layer
- Settle: natural Lerp deceleration to final position
- Hover hint: divider scale(1.1) + glow (200ms, ease-out)
**CSS Key Properties**:
```css
.split-compare__after {
clip-path: inset(0 0 0 var(--split-position, 50%));
transition: none; /* JS-driven via lerp */
}
.split-compare__divider {
cursor: col-resize;
touch-action: none; /* prevent scroll during drag */
}
```
**Keyboard**:
- Tab to divider element (tabindex="0")
- ArrowLeft/ArrowRight: move divider 2% per keypress
- Home/End: move to 0%/100%
**Accessibility**:
- role="slider", aria-valuenow, aria-valuemin="0", aria-valuemax="100"
- aria-label="Image comparison slider"
- Keyboard step: 2%, large step (PageUp/PageDown): 10%
---
## Scroll-Snap Gallery Pattern
Horizontal scroll with CSS scroll-snap, navigation controls, and active item detection.
**Core Interaction**:
- CSS scroll-snap-type: x mandatory on container
- scroll-snap-align: start on children
- Touch-friendly: native momentum scrolling
- Navigation dots/arrows update with IntersectionObserver
- Keyboard: ArrowLeft/ArrowRight navigate between items
**State Machine**:
```
[idle] --(scroll-start)--> [scrolling]
[scrolling] --(scroll-end)--> [snapped]
[snapped] --(intersection-change)--> [idle] (update active)
[idle] --(arrow-click)--> [navigating]
[navigating] --(scrollTo-complete)--> [idle]
[idle] --(keyboard-arrow)--> [navigating]
```
**Browser APIs**: CSS scroll-snap, IntersectionObserver, Element.scrollTo(), Pointer Events
**Animation**:
- Scroll: native CSS scroll-snap (browser-handled, smooth)
- Active dot: scale(1) -> scale(1.3) + opacity change (200ms, ease-out)
- Item entry: opacity 0->1 as intersection threshold crossed (CSS transition)
- Arrow hover: translateX(+-2px) (150ms, ease-out)
**CSS Key Properties**:
```css
.gallery__track {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
scrollbar-width: none; /* Firefox */
}
.gallery__track::-webkit-scrollbar { display: none; }
.gallery__item {
scroll-snap-align: start;
flex: 0 0 100%; /* or 80% for peek */
}
```
**IntersectionObserver Config**:
```javascript
new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) updateActiveItem(entry.target);
});
}, { root: trackElement, threshold: 0.5 });
```
**Accessibility**:
- role="region", aria-label="Image gallery"
- role="group" on each item, aria-roledescription="slide"
- aria-label="Slide N of M" on each item
- Navigation: role="tablist" on dots, role="tab" on each dot
- ArrowLeft/ArrowRight between items, Home/End to first/last
---
## Scroll Reveal Pattern
Elements animate into view as user scrolls, using IntersectionObserver with staggered delays.
**Core Interaction**:
- IntersectionObserver with threshold: 0.1 triggers entry animation
- data-reveal attribute marks revealable elements
- Staggered delay: index * 80ms for grouped items
- GPU-only: translateY(20px)->0 + opacity 0->1
- One-shot: element stays visible after reveal
**State Machine**:
```
[hidden] --(intersection: entering)--> [revealing]
[revealing] --(animation-end)--> [visible]
[visible] -- (terminal state, no transition out)
```
**Browser APIs**: IntersectionObserver, CSS transitions, requestAnimationFrame
**Animation**:
- Entry: translateY(20px) -> translateY(0) + opacity 0->1
- Duration: 400ms
- Easing: cubic-bezier(0.16, 1, 0.3, 1)
- Stagger: CSS custom property `--reveal-delay: calc(var(--reveal-index) * 80ms)`
- Reduced motion: opacity-only crossfade (200ms)
**CSS Key Properties**:
```css
[data-reveal] {
opacity: 0;
transform: translateY(20px);
transition: opacity 400ms cubic-bezier(0.16, 1, 0.3, 1),
transform 400ms cubic-bezier(0.16, 1, 0.3, 1);
transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal="visible"] {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
[data-reveal] {
transform: none;
transition: opacity 200ms ease;
}
}
```
**IntersectionObserver Config**:
```javascript
new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.dataset.reveal = 'visible';
observer.unobserve(entry.target); // one-shot
}
});
}, { threshold: 0.1 });
```
**Accessibility**:
- Content must be accessible in DOM before reveal (no display:none)
- Use opacity + transform only (content readable by screen readers at all times)
- aria-hidden NOT used (content is always in accessibility tree)
- Stagger delay < 500ms total to avoid perception of broken page
---
## Lens/Overlay Pattern
Magnification overlay that follows pointer position over an image or content area.
**Core Interaction**:
- Circular/rectangular lens follows pointer over source content
- Magnified view rendered via CSS transform: scale() on background
- Lens positioned via transform: translate() (GPU-only)
- Toggle on click/tap, follow on pointermove
**State Machine**:
```
[inactive] --(click/tap on source)--> [active]
[active] --(pointermove)--> [active] (update lens position)
[active] --(click/tap)--> [inactive]
[active] --(pointerleave)--> [inactive]
[active] --(Escape)--> [inactive]
[inactive] --(Enter/Space on source)--> [active-keyboard]
[active-keyboard] --(Arrow keys)--> [active-keyboard] (move lens)
[active-keyboard] --(Escape)--> [inactive]
```
**Browser APIs**: Pointer Events, CSS transform, CSS clip-path/border-radius, requestAnimationFrame
**Animation**:
- Lens appear: opacity 0->1 + scale(0.8)->scale(1) (200ms, ease-out)
- Lens follow: Lerp position tracking (speed: 0.2)
- Lens dismiss: opacity 1->0 + scale(1)->scale(0.9) (150ms, ease-in)
**CSS Key Properties**:
```css
.lens__overlay {
position: absolute;
width: 150px;
height: 150px;
border-radius: 50%;
overflow: hidden;
pointer-events: none;
transform: translate(var(--lens-x), var(--lens-y));
will-change: transform;
}
.lens__magnified {
transform: scale(var(--lens-zoom, 2));
transform-origin: var(--lens-origin-x) var(--lens-origin-y);
}
```
**Accessibility**:
- Source: role="img" with descriptive aria-label
- Lens toggle: aria-expanded on source element
- Keyboard: Enter/Space to activate, Arrow keys to pan, Escape to dismiss
- Screen reader: aria-live="polite" announces zoom state changes
- Not essential content: decorative enhancement, base content always visible
---
## Lightbox Pattern
Full-viewport overlay for content viewing with background dim and entry animation.
**Core Interaction**:
- Click/tap thumbnail opens full-viewport overlay
- Background dim via backdrop-filter + background overlay
- Scale-up entry animation from thumbnail position
- Dismiss: click outside, Escape key, close button
- Focus trap: Tab cycles within lightbox
- Scroll lock on body while open
**State Machine**:
```
[closed] --(click thumbnail)--> [opening]
[opening] --(animation-end)--> [open]
[open] --(click-outside / Escape / close-btn)--> [closing]
[closing] --(animation-end)--> [closed]
[open] --(ArrowLeft)--> [navigating-prev]
[open] --(ArrowRight)--> [navigating-next]
[navigating-*] --(content-loaded)--> [open]
```
**Browser APIs**: CSS backdrop-filter, Focus trap (manual), CSS transitions, Pointer Events
**Animation**:
- Open: scale(0.85)->scale(1) + opacity 0->1 (300ms, cubic-bezier(0.16,1,0.3,1))
- Close: scale(1)->scale(0.95) + opacity 1->0 (200ms, ease-in)
- Backdrop: opacity 0->1 (250ms, ease-out)
- Navigation: translateX crossfade between items (250ms)
**CSS Key Properties**:
```css
.lightbox__backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(4px);
z-index: 1000;
}
.lightbox__content {
transform: scale(var(--lb-scale, 0.85));
opacity: var(--lb-opacity, 0);
transition: transform 300ms cubic-bezier(0.16, 1, 0.3, 1),
opacity 300ms cubic-bezier(0.16, 1, 0.3, 1);
}
.lightbox--open .lightbox__content {
--lb-scale: 1;
--lb-opacity: 1;
}
```
**Focus Trap Implementation**:
```javascript
// On open: store trigger, move focus to first focusable in lightbox
// On Tab: cycle within lightbox (first <-> last focusable)
// On close: restore focus to original trigger element
// Prevent body scroll: document.body.style.overflow = 'hidden'
```
**Accessibility**:
- role="dialog", aria-modal="true", aria-label="Image viewer"
- Close button: aria-label="Close lightbox"
- Focus trap: Tab cycles within dialog
- Escape dismisses
- ArrowLeft/ArrowRight for gallery navigation
- aria-live="polite" announces current item "Image N of M"
- Scroll lock: prevent background scroll while open

View File

@@ -0,0 +1,85 @@
# Pipeline Definitions
Interactive craft pipeline modes and task registry.
## Pipeline Modes
| Mode | Description | Task Count |
|------|-------------|------------|
| single | Single component: research -> interaction design -> build -> a11y test | 4 tasks |
| gallery | Gallery: base component + scroll container, two build phases | 6 tasks |
| page | Full page: parallel component builds after single interaction design | 3 + N tasks |
## Single Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| RESEARCH-001 | researcher | [] | Interaction inventory, browser API audit, pattern reference |
| INTERACT-001 | interaction-designer | [RESEARCH-001] | State machine, event flow, gesture spec, animation choreography |
| BUILD-001 | builder | [INTERACT-001] | Vanilla JS + CSS component: ES module, GPU animations, touch-aware |
| A11Y-001 | a11y-tester | [BUILD-001] | Keyboard, screen reader, reduced motion, focus, contrast audit |
## Gallery Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| RESEARCH-001 | researcher | [] | Interaction patterns for base component + gallery container |
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Base component interaction blueprint |
| BUILD-001 | builder | [INTERACT-001] | Base component implementation |
| INTERACT-002 | interaction-designer | [BUILD-001] | Gallery/scroll-snap container blueprint |
| BUILD-002 | builder | [INTERACT-002] | Gallery container + navigation implementation |
| A11Y-001 | a11y-tester | [BUILD-002] | Full gallery accessibility audit |
## Page Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| RESEARCH-001 | researcher | [] | Interaction patterns for all page sections |
| INTERACT-001 | interaction-designer | [RESEARCH-001] | Blueprints for all interactive sections |
| BUILD-001 | builder | [INTERACT-001] | Section 1 component |
| BUILD-002 | builder | [INTERACT-001] | Section 2 component |
| ... | builder | [INTERACT-001] | Additional sections (parallel) |
| BUILD-00N | builder | [INTERACT-001] | Section N component |
| A11Y-001 | a11y-tester | [BUILD-001..N] | Full page accessibility audit |
## Quality Gate (A11y Checkpoint)
| Checkpoint | Task | Condition | Action |
|------------|------|-----------|--------|
| A11Y Gate | A11Y-001 completes | 0 critical, 0 high | Pipeline complete |
| A11Y GC Loop | A11Y-* completes | Critical or high issues | Create BUILD-fix task, new A11Y task (max 2 rounds) |
## GC Loop Behavior
| Signal | Condition | Action |
|--------|-----------|--------|
| a11y_passed | 0 critical, 0 high | GC converged -> pipeline complete |
| a11y_result | 0 critical, high > 0 | gc_rounds < max -> create BUILD-fix task |
| fix_required | critical > 0 | gc_rounds < max -> create BUILD-fix task (CRITICAL) |
| Any | gc_rounds >= max | Escalate to user: accept / try one more / terminate |
## Parallel Spawn Rules
| Mode | After | Spawn Behavior |
|------|-------|----------------|
| single | Sequential | One task at a time |
| gallery | Sequential | One task at a time |
| page | INTERACT-001 | Spawn BUILD-001..N in parallel |
| page | All BUILD complete | Spawn A11Y-001 |
## Collaboration Patterns
| Pattern | Roles | Description |
|---------|-------|-------------|
| CP-1 Linear Pipeline | All | Base sequential flow for single/gallery modes |
| CP-2 Review-Fix | builder <-> a11y-tester | GC loop with max 2 rounds |
| CP-3 Parallel Fan-out | builder (multiple) | Page mode: multiple BUILD tasks in parallel |
## Output Artifacts
| Task | Output Path |
|------|-------------|
| RESEARCH-001 | <session>/research/*.json |
| INTERACT-* | <session>/interaction/blueprints/*.md |
| BUILD-* | <session>/build/components/*.js + *.css |
| A11Y-* | <session>/a11y/a11y-audit-*.md |

View File

@@ -0,0 +1,105 @@
{
"team_name": "interactive-craft",
"team_display_name": "Interactive Craft",
"description": "Interactive component team with vanilla JS + CSS. Research -> interaction design -> build -> a11y test.",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Scope assessment, pipeline orchestration, GC loop control between builder and a11y-tester",
"message_types": ["task_unblocked", "a11y_checkpoint", "fix_required", "error", "shutdown"]
},
"researcher": {
"task_prefix": "RESEARCH",
"responsibility": "Interaction pattern analysis, browser API audit, reference pattern collection",
"message_types": ["research_ready", "research_progress", "error"]
},
"interaction-designer": {
"task_prefix": "INTERACT",
"responsibility": "State machine design, event flow mapping, gesture specification, animation choreography",
"message_types": ["blueprint_ready", "blueprint_revision", "blueprint_progress", "error"]
},
"builder": {
"task_prefix": "BUILD",
"inner_loop": true,
"responsibility": "Vanilla JS + CSS component implementation, progressive enhancement, GPU-only animations",
"message_types": ["build_ready", "build_revision", "build_progress", "error"]
},
"a11y-tester": {
"task_prefix": "A11Y",
"responsibility": "Keyboard navigation, screen reader, reduced motion, focus management, contrast testing",
"message_types": ["a11y_passed", "a11y_result", "fix_required", "error"]
}
},
"pipelines": {
"single": {
"description": "Single component: research -> interaction design -> build -> a11y test",
"task_chain": ["RESEARCH-001", "INTERACT-001", "BUILD-001", "A11Y-001"],
"complexity": "low"
},
"gallery": {
"description": "Gallery with base component + scroll container: two build phases",
"task_chain": [
"RESEARCH-001",
"INTERACT-001", "BUILD-001",
"INTERACT-002", "BUILD-002",
"A11Y-001"
],
"complexity": "medium"
},
"page": {
"description": "Full interactive page with parallel component builds",
"task_chain": [
"RESEARCH-001",
"INTERACT-001",
"BUILD-001..N (parallel)",
"A11Y-001"
],
"parallel_stage": "BUILD-001..N",
"complexity": "high"
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "builder",
"critic": "a11y-tester",
"max_rounds": 2,
"convergence": "a11y.critical_count === 0 && a11y.high_count === 0",
"escalation": "Coordinator intervenes after max rounds"
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"researcher": ["interaction_inventory", "browser_apis"],
"interaction-designer": ["state_machines", "event_flows"],
"builder": ["component_registry", "implementation_decisions"],
"a11y-tester": ["audit_history"]
}
},
"dynamic_pipeline": {
"criteria": {
"single": "scope.component_count <= 1",
"gallery": "scope.has_gallery || scope.has_scroll_collection",
"page": "scope.is_full_page || scope.section_count > 2"
}
},
"parallel_fanout": {
"pattern": "CP-3",
"description": "Multiple BUILD tasks spawned in parallel after single INTERACT blueprint",
"trigger": "page mode after INTERACT-001 completes",
"fallback": "If parallel fails, coordinator falls back to sequential execution"
}
},
"session_dirs": {
"base": ".workflow/.team/IC-{slug}-{YYYY-MM-DD}/",
"research": "research/",
"interaction": "interaction/blueprints/",
"build": "build/components/",
"a11y": "a11y/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,83 @@
# Vanilla Constraints
Zero-dependency rules for all interactive components built by this team. These constraints are non-negotiable and apply to every BUILD task output.
## Dependency Rules
| Rule | Requirement |
|------|-------------|
| No npm packages | Zero `import` from node_modules or CDN URLs |
| No build tools required | Components run directly via `<script type="module">` |
| No framework dependency | No React, Vue, Svelte, Angular, jQuery, etc. |
| No CSS preprocessor | No Sass, Less, PostCSS, Tailwind -- pure CSS only |
| No bundler required | No webpack, Vite, Rollup, esbuild in critical path |
## JavaScript Rules
| Rule | Requirement |
|------|-------------|
| ES modules only | `export class`, `export function`, `import` syntax |
| Class-based components | Private fields (#), constructor(element, options) |
| No inline styles from JS | Set CSS custom properties or toggle CSS classes |
| No document.write | Use DOM APIs (createElement, append, etc.) |
| No eval or innerHTML | Use textContent or DOM construction |
| requestAnimationFrame | All animation loops use rAF, not setInterval |
| Pointer Events primary | Use pointer events; touch events as fallback only |
| Cleanup required | destroy() method disconnects all observers/listeners |
| Auto-init pattern | `document.querySelectorAll('[data-component]')` on load |
## CSS Rules
| Rule | Requirement |
|------|-------------|
| Custom properties | All configurable values as CSS custom properties |
| No inline styles | JS sets `--custom-prop` values, not style.left/top |
| State via data attributes | `[data-state="active"]`, not inline style changes |
| GPU-only animations | `transform` and `opacity` ONLY in transitions/animations |
| No layout animations | Never animate `width`, `height`, `top`, `left`, `margin`, `padding` |
| will-change on animated | Hint browser for animated elements |
| Reduced motion | `@media (prefers-reduced-motion: reduce)` with instant fallback |
| focus-visible | `:focus-visible` for keyboard-only focus indicators |
| Responsive | Min touch target 44x44px on mobile, use @media breakpoints |
## Progressive Enhancement
| Rule | Requirement |
|------|-------------|
| Content without JS | Base content visible and readable without JavaScript |
| CSS-only fallback | Essential layout works with CSS alone |
| No-JS class | Optional `[data-js-enabled]` class for JS-enhanced styles |
| Semantic HTML base | Use appropriate elements (button, a, nav, dialog) |
## Performance Budget
| Metric | Budget |
|--------|--------|
| Frame time | < 5ms per frame (leaves room for browser work in 16ms budget) |
| Interaction response | < 50ms from input to visual feedback |
| Animation jank | 0 frames dropped at 60fps for GPU-composited animations |
| Observer callbacks | < 1ms per IntersectionObserver/ResizeObserver callback |
| Component init | < 100ms from constructor to interactive |
| Memory | No detached DOM nodes after destroy() |
| Listeners | All removed in destroy(), no orphaned listeners |
## Forbidden Patterns
| Pattern | Why |
|---------|-----|
| `element.style.left = ...` | Forces layout recalc, not GPU composited |
| `element.offsetWidth` in animation loop | Forces synchronous layout (reflow) |
| `setInterval` for animation | Not synced to display refresh rate |
| `setTimeout` for animation | Not synced to display refresh rate |
| `innerHTML = userContent` | XSS vector |
| Passive: false on scroll/touch without need | Blocks scrolling performance |
| `!important` in component CSS | Breaks cascade, unmaintainable |
| Global CSS selectors (tag-only) | Leaks styles outside component scope |
## File Output Convention
| File | Purpose | Location |
|------|---------|----------|
| `{name}.js` | ES module component class | `<session>/build/components/` |
| `{name}.css` | Component styles with custom properties | `<session>/build/components/` |
| `demo.html` | Optional: standalone demo page | `<session>/build/components/` |

View File

@@ -0,0 +1,222 @@
---
name: team-motion-design
description: Unified team skill for motion design. Animation token systems, scroll choreography, GPU-accelerated transforms, reduced-motion fallback. Uses team-worker agent architecture. Triggers on "team motion design", "animation system".
allowed-tools: spawn_agent(*), wait_agent(*), send_message(*), assign_task(*), close_agent(*), list_agents(*), report_agent_job_result(*), request_user_input(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), mcp__ccw-tools__read_file(*), mcp__ccw-tools__write_file(*), mcp__ccw-tools__edit_file(*), mcp__ccw-tools__team_msg(*), mcp__chrome-devtools__evaluate_script(*), mcp__chrome-devtools__take_screenshot(*), mcp__chrome-devtools__performance_start_trace(*), mcp__chrome-devtools__performance_stop_trace(*), mcp__chrome-devtools__performance_analyze_insight(*)
---
# Team Motion Design
Systematic motion design pipeline: research -> choreography -> animation -> performance testing. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
## Architecture
```
Skill(skill="team-motion-design", args="task description")
|
SKILL.md (this file) = Router
|
+--------------+--------------+
| |
no --role flag --role <name>
| |
Coordinator Worker
roles/coordinator/role.md roles/<name>/role.md
|
+-- analyze -> dispatch -> spawn workers -> STOP
|
+-------+-------+-------+-------+
v v v v
[team-worker agents, each loads roles/<role>/role.md]
motion-researcher choreographer animator motion-tester
```
## Role Registry
| Role | Path | Prefix | Inner Loop |
|------|------|--------|------------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
| motion-researcher | [roles/motion-researcher/role.md](roles/motion-researcher/role.md) | MRESEARCH-* | false |
| choreographer | [roles/choreographer/role.md](roles/choreographer/role.md) | CHOREO-* | false |
| animator | [roles/animator/role.md](roles/animator/role.md) | ANIM-* | true |
| motion-tester | [roles/motion-tester/role.md](roles/motion-tester/role.md) | MTEST-* | false |
## Role Router
Parse `$ARGUMENTS`:
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
- No `--role` -> `roles/coordinator/role.md`, execute entry router
## Delegation Lock
**Coordinator is a PURE ORCHESTRATOR. It coordinates, it does NOT do.**
Before calling ANY tool, apply this check:
| Tool Call | Verdict | Reason |
|-----------|---------|--------|
| `spawn_agent`, `wait_agent`, `close_agent`, `send_message`, `assign_task` | ALLOWED | Orchestration |
| `list_agents` | ALLOWED | Agent health check |
| `request_user_input` | ALLOWED | User interaction |
| `mcp__ccw-tools__team_msg` | ALLOWED | Message bus |
| `Read/Write` on `.workflow/.team/` files | ALLOWED | Session state |
| `Read` on `roles/`, `commands/`, `specs/` | ALLOWED | Loading own instructions |
| `Read/Grep/Glob` on project source code | BLOCKED | Delegate to worker |
| `Edit` on any file outside `.workflow/` | BLOCKED | Delegate to worker |
| `Bash("ccw cli ...")` | BLOCKED | Only workers call CLI |
| `Bash` running build/test/lint commands | BLOCKED | Delegate to worker |
**If a tool call is BLOCKED**: STOP. Create a task, spawn a worker.
**No exceptions for "simple" tasks.** Even a single-file read-and-report MUST go through spawn_agent.
---
## Shared Constants
- **Session prefix**: `MD`
- **Session path**: `.workflow/.team/MD-<slug>-<date>/`
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
- **Max GC rounds**: 2
## Worker Spawn Template
Coordinator spawns workers using this template:
```
spawn_agent({
agent_type: "team_worker",
task_name: "<task-id>",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: <role>
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
requirement: <task-description>
inner_loop: <true|false>
Read role_spec file (<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: <task-id>
title: <task-title>
description: <task-description>
pipeline_phase: <pipeline-phase>` },
{ type: "text", text: `## Upstream Context
<prev_context>` }
]
})
```
After spawning, use `wait_agent({ targets: [...], timeout_ms: 900000 })` to collect results, then `close_agent({ target })` each worker.
### Model Selection Guide
Motion design is a performance-critical pipeline where research informs choreography decisions and animations must pass strict GPU performance gates. Researcher needs thorough profiling, animator needs creative implementation with inner loop capability.
| Role | reasoning_effort | Rationale |
|------|-------------------|-----------|
| motion-researcher | high | Deep performance profiling and animation audit across codebase |
| choreographer | high | Creative token system design and scroll choreography sequencing |
| animator | high | Complex CSS/JS animation implementation with compositor constraints |
| motion-tester | medium | Performance validation follows defined test criteria and scoring |
### Research-to-Choreography Context Flow
Researcher findings must reach choreographer via coordinator's upstream context:
```
// After MRESEARCH-001 completes, coordinator sends findings to choreographer
spawn_agent({
agent_type: "team_worker",
task_name: "CHOREO-001",
fork_context: false,
items: [
...,
{ type: "text", text: `## Upstream Context
Research findings: <session>/research/animation-inventory.json
Performance baseline: <session>/research/performance-baseline.json
Easing catalog: <session>/research/easing-catalog.json` }
]
})
```
## User Commands
| Command | Action |
|---------|--------|
| `check` / `status` | View execution status graph |
| `resume` / `continue` | Advance to next step |
## Specs Reference
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
- [specs/motion-tokens.md](specs/motion-tokens.md) -- Animation token schema
- [specs/gpu-constraints.md](specs/gpu-constraints.md) -- Compositor-only animation rules
- [specs/reduced-motion.md](specs/reduced-motion.md) -- Accessibility motion preferences
## Session Directory
```
.workflow/.team/MD-<slug>-<date>/
+-- .msg/
| +-- messages.jsonl # Team message bus
| +-- meta.json # Pipeline config + GC state
+-- research/ # Motion researcher output
| +-- perf-traces/ # Chrome DevTools performance traces
| +-- animation-inventory.json
| +-- performance-baseline.json
| +-- easing-catalog.json
+-- choreography/ # Choreographer output
| +-- motion-tokens.json
| +-- sequences/ # Scroll choreography sequences
+-- animations/ # Animator output
| +-- keyframes/ # CSS @keyframes files
| +-- orchestrators/ # JS animation orchestrators
+-- testing/ # Motion tester output
| +-- traces/ # Performance trace data
| +-- reports/ # Performance reports
+-- wisdom/ # Cross-task knowledge
```
## v4 Agent Coordination
### Message Semantics
| Intent | API | Example |
|--------|-----|---------|
| Queue supplementary info (don't interrupt) | `send_message` | Send research findings to running choreographer |
| Assign implementation from reviewed specs | `assign_task` | Assign ANIM task after choreography passes |
| Check running agents | `list_agents` | Verify agent health during resume |
### Agent Health Check
Use `list_agents({})` in handleResume and handleComplete:
```
// Reconcile session state with actual running agents
const running = list_agents({})
// Compare with tasks.json active_agents
// Reset orphaned tasks (in_progress but agent gone) to pending
```
### Named Agent Targeting
Workers are spawned with `task_name: "<task-id>"` enabling direct addressing:
- `send_message({ target: "CHOREO-001", items: [...] })` -- send additional research findings to choreographer
- `assign_task({ target: "ANIM-001", items: [...] })` -- assign animation from reviewed choreography specs
- `close_agent({ target: "MTEST-001" })` -- cleanup after performance test
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown command | Error with available command list |
| Role not found | Error with role registry |
| Session corruption | Attempt recovery, fallback to manual |
| Fast-advance conflict | Coordinator reconciles on next callback |
| Completion action fails | Default to Keep Active |
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |

View File

@@ -0,0 +1,194 @@
---
role: animator
prefix: ANIM
inner_loop: true
message_types: [state_update]
---
# Animation Implementer
Implement CSS animations/transitions and JS orchestration from choreography specs. Build @keyframes with motion tokens as custom properties, IntersectionObserver-based scroll triggers, requestAnimationFrame coordination, and prefers-reduced-motion overrides. GPU-accelerated, compositor-only animations.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Motion tokens | <session>/choreography/motion-tokens.json | Yes |
| Choreography sequences | <session>/choreography/sequences/*.md | Yes (component/page) |
| Research artifacts | <session>/research/*.json | Yes |
| GPU constraints | specs/gpu-constraints.md | Yes |
| Reduced motion spec | specs/reduced-motion.md | Yes |
| Performance report | <session>/testing/reports/perf-report-*.md | Only for GC fix tasks |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
1. Extract session path from task description
2. Read motion tokens from choreography/motion-tokens.json
3. Read choreography sequences (if applicable) from choreography/sequences/*.md
4. Read research artifacts for existing animation context
5. Read GPU constraints and reduced motion specs
6. Detect task type from subject: "token" -> Token CSS, "section" -> Section animation, "fix" -> GC fix
7. If GC fix task: read latest performance report from testing/reports/
## Phase 3: Implementation Execution
### Token CSS Implementation (ANIM-001 in tokens mode)
Generate CSS custom properties and utility classes:
**File: `<session>/animations/keyframes/motion-tokens.css`**:
```css
:root {
/* Easing functions */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
/* Duration scale */
--duration-fast: 0.15s;
--duration-base: 0.3s;
--duration-slow: 0.6s;
--duration-slower: 0.8s;
--duration-slowest: 1.2s;
/* Stagger */
--stagger-increment: 0.05s;
}
/* Reduced motion overrides */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
**File: `<session>/animations/keyframes/utility-animations.css`**:
- `@keyframes fade-in` (opacity 0->1)
- `@keyframes fade-up` (opacity 0->1, translateY 20px->0)
- `@keyframes fade-down` (opacity 0->1, translateY -20px->0)
- `@keyframes slide-in-left` (translateX -100%->0)
- `@keyframes slide-in-right` (translateX 100%->0)
- `@keyframes scale-in` (scale 0.95->1, opacity 0->1)
- Utility classes: `.animate-fade-in`, `.animate-fade-up`, etc.
- All animations consume motion token custom properties
- All use compositor-only properties (transform, opacity)
### Component/Section Animation (ANIM-001..N in component/page mode)
For each section or component defined in choreography sequences:
**CSS @keyframes** (`<session>/animations/keyframes/<name>.css`):
- Define @keyframes consuming motion tokens via `var(--ease-out)`, `var(--duration-slow)`
- Use `will-change: transform, opacity` on animated elements (remove after animation via JS)
- Only animate compositor-safe properties: transform (translate, scale, rotate), opacity, filter
- NEVER animate: width, height, top, left, margin, padding, border, color, background-color
**JS Orchestrator** (`<session>/animations/orchestrators/<name>.js`):
```javascript
// IntersectionObserver-based scroll trigger
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target); // one-shot
}
});
}, { threshold: 0.2, rootMargin: '0px 0px -100px 0px' });
// Staggered animation orchestrator
function staggerReveal(container, itemSelector) {
const items = container.querySelectorAll(itemSelector);
const increment = parseFloat(getComputedStyle(document.documentElement)
.getPropertyValue('--stagger-increment')) || 0.05;
items.forEach((item, index) => {
item.style.transitionDelay = `${index * increment}s`;
});
// Trigger via IntersectionObserver on container
observer.observe(container);
}
// Reduced motion detection
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
if (prefersReducedMotion.matches) {
// Skip parallax, disable springs, use instant transitions
}
// requestAnimationFrame for scroll-linked effects (parallax)
function parallaxScroll(element, rate) {
if (prefersReducedMotion.matches) return; // skip for reduced motion
let ticking = false;
window.addEventListener('scroll', () => {
if (!ticking) {
requestAnimationFrame(() => {
const scrolled = window.pageYOffset;
element.style.transform = `translateY(${scrolled * rate}px)`;
ticking = false;
});
ticking = true;
}
});
}
```
### Height Animation Workaround
Since `height` triggers layout (NEVER animate), use the grid trick:
```css
.expandable {
display: grid;
grid-template-rows: 0fr;
transition: grid-template-rows var(--duration-normal) var(--ease-out-quart);
}
.expandable.open {
grid-template-rows: 1fr;
}
.expandable > .content {
overflow: hidden;
}
```
This achieves smooth height animation using only grid layout changes (compositor-friendly).
### Perceived Performance
- **80ms threshold**: Any response under 80ms feels instant to the human brain
- **Preemptive starts**: Begin animation on `pointerdown` not `click` (saves ~80-120ms perceived)
- **Early completion**: Visual feedback can "finish" before actual operation completes (optimistic UI)
- **Ease-in compresses perceived time**: Use ease-in for waiting states (progress bars) -- makes them feel faster
- **Ease-out satisfies entrances**: Use ease-out for content appearing -- natural deceleration feels "settled"
### GC Fix Mode (ANIM-fix-N)
- Parse performance report for specific issues
- Replace layout-triggering properties with compositor-only alternatives:
- `width/height` -> `transform: scale()`
- `top/left` -> `transform: translate()`
- `background-color` -> `opacity` on overlay
- Reduce will-change elements to max 3-4 simultaneous
- Add missing prefers-reduced-motion overrides
- Signal `animation_revision` instead of `animation_ready`
## Phase 4: Self-Validation & Output
1. Animation integrity checks:
| Check | Pass Criteria |
|-------|---------------|
| no_layout_triggers | No width, height, top, left, margin, padding in @keyframes |
| will_change_budget | Max 3-4 elements with will-change simultaneously |
| reduced_motion | @media (prefers-reduced-motion: reduce) query present |
| token_consumption | Animations use var(--token) references, no hardcoded values |
| compositor_only | Only transform, opacity, filter in animation properties |
2. JS orchestrator checks:
| Check | Pass Criteria |
|-------|---------------|
| intersection_observer | IntersectionObserver used for scroll triggers (not scroll events) |
| raf_throttled | requestAnimationFrame used with ticking guard for scroll |
| reduced_motion_js | `matchMedia('(prefers-reduced-motion: reduce)')` check present |
| cleanup | will-change removed after animation completes (if applicable) |
3. Update `<session>/wisdom/.msg/meta.json` under `animator` namespace:
- Read existing -> merge `{ "animator": { task_type, keyframe_count, orchestrator_count, uses_intersection_observer, has_parallax, has_stagger } }` -> write back

View File

@@ -0,0 +1,164 @@
---
role: choreographer
prefix: CHOREO
inner_loop: false
message_types: [state_update]
---
# Motion Choreographer
Design animation token systems (easing functions, duration/delay scales), scroll-triggered reveal sequences, and transition state diagrams. Consume research findings from motion-researcher. Define the motion language that the animator implements.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Research artifacts | <session>/research/*.json | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Motion token spec | specs/motion-tokens.md | Yes |
| GPU constraints | specs/gpu-constraints.md | Yes |
| Reduced motion spec | specs/reduced-motion.md | Yes |
1. Extract session path from task description
2. Read research findings: animation-inventory.json, performance-baseline.json, easing-catalog.json
3. Read motion token schema from specs/motion-tokens.md
4. Read GPU constraints from specs/gpu-constraints.md for safe property list
5. Read reduced motion guidelines from specs/reduced-motion.md
## Phase 3: Design Execution
### Motion Token System
Define complete token system as CSS custom properties + JSON:
**Easing Functions**:
- `--ease-out`: `cubic-bezier(0.16, 1, 0.3, 1)` -- emphasis exit, deceleration
- `--ease-in-out`: `cubic-bezier(0.65, 0, 0.35, 1)` -- smooth symmetrical
- `--ease-spring`: `cubic-bezier(0.34, 1.56, 0.64, 1)` -- overshoot bounce
- Integrate existing easing functions from research (avoid duplicates, reconcile naming)
**Duration Scale**:
- `--duration-fast`: `0.15s` -- micro-interactions (button press, toggle)
- `--duration-base`: `0.3s` -- standard transitions (hover, focus)
- `--duration-slow`: `0.6s` -- content reveals, panel slides
- `--duration-slower`: `0.8s` -- page transitions, large moves
- `--duration-slowest`: `1.2s` -- hero animations, splash
**Delay Scale**:
- `--stagger-base`: `0s` -- first item in stagger sequence
- `--stagger-increment`: `0.05s` to `0.1s` -- per-item delay addition
- Formula: `delay = base_delay + (index * stagger_increment)`
- Max visible stagger: 8 items (avoid >0.8s total delay)
**Reduced Motion Overrides**:
- All durations -> `0.01ms`
- All easings -> `linear` (instant)
- No parallax, no bounce/spring
- Opacity-only fades allowed (<0.15s)
Output: `<session>/choreography/motion-tokens.json`
```json
{
"easing": {
"ease-out": { "value": "cubic-bezier(0.16, 1, 0.3, 1)", "use": "exit emphasis, deceleration" },
"ease-in-out": { "value": "cubic-bezier(0.65, 0, 0.35, 1)", "use": "smooth symmetrical" },
"ease-spring": { "value": "cubic-bezier(0.34, 1.56, 0.64, 1)", "use": "overshoot bounce" }
},
"duration": {
"fast": { "value": "0.15s", "use": "micro-interactions" },
"base": { "value": "0.3s", "use": "standard transitions" },
"slow": { "value": "0.6s", "use": "content reveals" },
"slower": { "value": "0.8s", "use": "page transitions" },
"slowest": { "value": "1.2s", "use": "hero animations" }
},
"stagger": {
"base_delay": "0s",
"increment": "0.05s",
"max_items": 8
},
"reduced_motion": {
"duration_override": "0.01ms",
"easing_override": "linear",
"allowed": ["opacity"],
"disallowed": ["parallax", "bounce", "spring", "infinite-loop"]
}
}
```
### Scroll Choreography Sequences
For component and page modes, define reveal sequences:
- IntersectionObserver thresholds per section (typical: 0.1 to 0.3)
- Entry direction: fade-up, fade-in, slide-left, slide-right
- Stagger groups: which elements stagger together, with calculated delays
- Parallax depths: foreground (1x), midground (0.5x), background (0.2x) scroll rates
- Scroll-linked effects: progress-based opacity, transform interpolation
Output per section: `<session>/choreography/sequences/<section-name>.md`
```markdown
# Section: <name>
## Trigger
- Observer threshold: 0.2
- Root margin: "0px 0px -100px 0px"
## Sequence
1. Heading: fade-up, duration-slow, ease-out, delay 0s
2. Subheading: fade-up, duration-slow, ease-out, delay 0.05s
3. Cards[0..N]: fade-up, duration-slow, ease-out, stagger 0.08s each
## Parallax (if applicable)
- Background image: 0.2x scroll rate
- Foreground elements: 1x (normal)
## Reduced Motion Fallback
- All elements: opacity fade only, duration-fast
- No parallax, no directional movement
```
### Transition State Diagrams
Define state transitions for interactive elements:
| State Pair | Properties | Duration | Easing |
|------------|-----------|----------|--------|
| hidden -> visible (entry) | opacity: 0->1, transform: translateY(20px)->0 | duration-slow | ease-out |
| visible -> hidden (exit) | opacity: 1->0, transform: 0->translateY(-10px) | duration-base | ease-in-out |
| idle -> hover | opacity: 1->0.8, transform: scale(1)->scale(1.02) | duration-fast | ease-out |
| idle -> focus | outline: none->2px solid, outline-offset: 0->2px | duration-fast | ease-out |
| idle -> active (pressed) | transform: scale(1)->scale(0.98) | duration-fast | ease-out |
| idle -> loading | opacity: 1->0.6, add pulse animation | duration-base | ease-in-out |
All transitions use compositor-only properties (transform, opacity) per GPU constraints.
## Phase 4: Self-Validation
1. Token completeness checks:
| Check | Pass Criteria |
|-------|---------------|
| easing_complete | All 3 easing functions defined with valid cubic-bezier |
| duration_complete | All 5 duration steps defined |
| stagger_defined | Base delay, increment, and max items specified |
| reduced_motion | Override values defined for all token categories |
2. Sequence checks (if applicable):
| Check | Pass Criteria |
|-------|---------------|
| threshold_valid | IntersectionObserver threshold between 0 and 1 |
| safe_properties | Only compositor-safe properties in animations |
| stagger_budget | No stagger sequence exceeds 0.8s total |
| fallback_present | Reduced motion fallback defined for each sequence |
3. State diagram checks:
| Check | Pass Criteria |
|-------|---------------|
| states_covered | entry, exit, hover, focus, active states defined |
| compositor_only | All animated properties are transform or opacity |
| durations_use_tokens | All durations reference token scale values |
4. Update `<session>/wisdom/.msg/meta.json` under `choreographer` namespace:
- Read existing -> merge `{ "choreographer": { token_count, sequence_count, state_diagrams, has_parallax, has_stagger } }` -> write back

View File

@@ -0,0 +1,64 @@
# Analyze Task
Parse user task -> detect motion design scope -> build dependency graph -> determine pipeline mode.
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
## Signal Detection
| Keywords | Capability | Pipeline Hint |
|----------|------------|---------------|
| easing, cubic-bezier, duration, timing | token system | tokens |
| scroll, parallax, reveal, stagger, intersection | scroll choreography | page |
| transition, hover, focus, state change | component animation | component |
| @keyframes, will-change, transform, opacity | animation implementation | component |
| page transition, route animation, full page | page-level motion | page |
| motion tokens, animation system, design system | token system | tokens |
| spring, bounce, overshoot | easing design | tokens |
| reduced-motion, prefers-reduced-motion, a11y | accessibility | component or tokens |
## Scope Determination
| Signal | Pipeline Mode |
|--------|---------------|
| Token/easing/duration system mentioned | tokens |
| Animate specific component(s) | component |
| Full page scroll choreography or page transitions | page |
| Unclear | ask user |
## Complexity Scoring
| Factor | Points |
|--------|--------|
| Single easing/token system | +1 |
| Component animation | +2 |
| Full page choreography | +3 |
| Multiple scroll sections | +1 |
| Parallax effects | +1 |
| Reduced-motion required | +1 |
| Performance constraints mentioned | +1 |
Results: 1-2 Low (tokens), 3-4 Medium (component), 5+ High (page)
## Framework Detection
| Keywords | Framework |
|----------|-----------|
| react, jsx, tsx | React |
| vue, v-bind | Vue |
| svelte | Svelte |
| vanilla, plain js | Vanilla JS |
| css-only, pure css | CSS-only |
| Default | CSS + Vanilla JS |
## Output
Write scope context to coordinator memory:
```json
{
"pipeline_mode": "<tokens|component|page>",
"scope": "<description>",
"framework": "<detected-framework>",
"complexity": { "score": 0, "level": "Low|Medium|High" }
}
```

View File

@@ -0,0 +1,168 @@
# Command: Dispatch
Create the motion design task chain with correct dependencies and structured task descriptions. Supports tokens, component, and page pipeline modes.
## Phase 2: Context Loading
| Input | Source | Required |
|-------|--------|----------|
| User requirement | From coordinator Phase 1 | Yes |
| Session folder | From coordinator Phase 2 | Yes |
| Pipeline mode | From tasks.json `pipeline_mode` | Yes |
| Framework config | From tasks.json `framework` | Yes |
1. Load user requirement and motion scope from tasks.json
2. Load pipeline stage definitions from specs/pipelines.md
3. Read `pipeline_mode` and `framework` from tasks.json
## Phase 3: Task Chain Creation (Mode-Branched)
### Task Description Template
Every task is added to tasks.json with structured format:
```json
{
"<TASK-ID>": {
"title": "<task title>",
"description": "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>\nTASK:\n - <step 1: specific action>\n - <step 2: specific action>\n - <step 3: specific action>\nCONTEXT:\n - Session: <session-folder>\n - Scope: <motion-scope>\n - Framework: <framework>\n - Upstream artifacts: <artifact-1>, <artifact-2>\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <deliverable path> + <quality criteria>\nCONSTRAINTS: <scope limits, focus areas>",
"role": "<role>",
"prefix": "<PREFIX>",
"deps": ["<dependency-list>"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
### Mode Router
| Mode | Action |
|------|--------|
| `tokens` | Create 4 tasks: MRESEARCH -> CHOREO -> ANIM -> MTEST |
| `component` | Create 4 tasks: MRESEARCH -> CHOREO -> ANIM -> MTEST (GC loop) |
| `page` | Create 4+ tasks: MRESEARCH -> CHOREO -> [ANIM-001..N parallel] -> MTEST |
---
### Tokens Pipeline Task Chain
**MRESEARCH-001** (motion-researcher):
```json
{
"MRESEARCH-001": {
"title": "Audit existing animations and measure performance baseline",
"description": "PURPOSE: Audit existing animations, measure performance baseline, catalog easing patterns | Success: 3 research artifacts produced with valid data\nTASK:\n - Scan codebase for existing CSS @keyframes, transitions, JS animation code\n - Measure paint/composite costs via Chrome DevTools performance traces (if available)\n - Catalog existing easing functions and timing patterns\n - Identify properties being animated (safe vs unsafe for compositor)\nCONTEXT:\n - Session: <session-folder>\n - Scope: <motion-scope>\n - Framework: <framework>\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/research/*.json | All 3 research files with valid JSON\nCONSTRAINTS: Read-only analysis | Focus on existing animation patterns",
"role": "motion-researcher",
"prefix": "MRESEARCH",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**CHOREO-001** (choreographer):
```json
{
"CHOREO-001": {
"title": "Design animation token system",
"description": "PURPOSE: Design animation token system with easing functions, duration scale, stagger formulas | Success: Complete motion-tokens.json with all token categories\nTASK:\n - Define easing functions (ease-out, ease-in-out, ease-spring) as cubic-bezier values\n - Define duration scale (fast, base, slow, slower, slowest)\n - Define stagger formula with base delay and increment\n - Define reduced-motion fallback tokens\n - Reference specs/motion-tokens.md for token schema\nCONTEXT:\n - Session: <session-folder>\n - Scope: <motion-scope>\n - Framework: <framework>\n - Upstream artifacts: research/*.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/choreography/motion-tokens.json | Complete token system\nCONSTRAINTS: Follow motion-tokens.md schema | All tokens must have reduced-motion fallback",
"role": "choreographer",
"prefix": "CHOREO",
"deps": ["MRESEARCH-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**ANIM-001** (animator):
```json
{
"ANIM-001": {
"title": "Implement CSS custom properties and utility classes from motion tokens",
"description": "PURPOSE: Implement CSS custom properties and utility classes from motion tokens | Success: Production-ready CSS with token consumption and reduced-motion overrides\nTASK:\n - Generate CSS custom properties from motion-tokens.json\n - Create utility animation classes consuming tokens\n - Add prefers-reduced-motion media query overrides\n - Ensure compositor-only properties (transform, opacity) per specs/gpu-constraints.md\nCONTEXT:\n - Session: <session-folder>\n - Scope: <motion-scope>\n - Framework: <framework>\n - Upstream artifacts: choreography/motion-tokens.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/animations/keyframes/*.css | Token CSS + utility classes + reduced-motion\nCONSTRAINTS: Compositor-only animations | No layout-triggering properties | will-change budget",
"role": "animator",
"prefix": "ANIM",
"deps": ["CHOREO-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**MTEST-001** (motion-tester):
```json
{
"MTEST-001": {
"title": "Verify animation performance and accessibility compliance",
"description": "PURPOSE: Verify animation performance and accessibility compliance | Success: 60fps confirmed, no layout thrashing, reduced-motion present\nTASK:\n - Start Chrome DevTools performance trace (if available)\n - Verify compositor-only animations (no paint/layout triggers)\n - Check will-change usage (not excessive, max 3-4 elements)\n - Validate prefers-reduced-motion @media query presence\n - Static code analysis as fallback if Chrome DevTools unavailable\nCONTEXT:\n - Session: <session-folder>\n - Scope: <motion-scope>\n - Framework: <framework>\n - Upstream artifacts: animations/keyframes/*.css, choreography/motion-tokens.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/testing/reports/perf-report-001.md | Performance validation report\nCONSTRAINTS: Target 60fps | Flag any layout-triggering properties",
"role": "motion-tester",
"prefix": "MTEST",
"deps": ["ANIM-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
---
### Component Pipeline Task Chain
Same as Tokens pipeline with enhanced task descriptions:
- **MRESEARCH-001**: Same as tokens, plus focus on target component(s) existing animation
- **CHOREO-001**: Same token design, plus transition state diagrams (entry/exit/hover/focus/loading) and scroll-triggered reveal sequences for the component(s)
- **ANIM-001**: Implement component-specific animations: @keyframes, IntersectionObserver triggers, rAF coordination, staggered orchestration
- **MTEST-001**: Same as tokens, plus GC loop -- if FPS < 60 or layout thrashing, send `fix_required` signal
GC loop between animator and motion-tester (max 2 rounds).
---
### Page Pipeline Task Chain
**MRESEARCH-001** and **CHOREO-001**: Same as component, but scope is full page with multiple scroll sections.
**CHOREO-001** additionally defines scroll section boundaries, parallax depths, and staggered entry sequences per section.
**ANIM-001..N** (parallel): One ANIM task per scroll section or page area:
```json
{
"ANIM-<NNN>": {
"title": "Implement animations for <section-name>",
"description": "PURPOSE: Implement animations for <section-name> | Success: Scroll-triggered reveals with 60fps performance\nTASK:\n - Implement IntersectionObserver-based scroll triggers for <section-name>\n - Apply staggered entry animations with calculated delays\n - Add scroll-linked parallax (if specified in choreography)\n - Ensure prefers-reduced-motion fallback\nCONTEXT:\n - Session: <session-folder>\n - Section: <section-name>\n - Upstream artifacts: choreography/sequences/<section>.md, choreography/motion-tokens.json\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/animations/keyframes/<section>.css + orchestrators/<section>.js\nCONSTRAINTS: Compositor-only | will-change budget | Follow motion-tokens",
"role": "animator",
"prefix": "ANIM",
"deps": ["CHOREO-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**MTEST-001**: Blocked by all ANIM tasks. Full page performance validation.
---
## Phase 4: Validation
Verify task chain integrity:
| Check | Method | Expected |
|-------|--------|----------|
| Task count correct | tasks.json count | tokens: 4, component: 4, page: 4+N |
| Dependencies correct | Trace dependency graph | Acyclic, correct deps |
| No circular dependencies | Trace dependency graph | Acyclic |
| Task IDs use correct prefixes | Pattern check | MRESEARCH/CHOREO/ANIM/MTEST |
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
If validation fails, fix the specific task and re-validate.

View File

@@ -0,0 +1,242 @@
# Monitor Pipeline
Synchronous pipeline coordination using spawn_agent + wait_agent.
## Constants
- WORKER_AGENT: team_worker
- MAX_GC_ROUNDS: 2
## Handler Router
| Source | Handler |
|--------|---------|
| "capability_gap" | handleAdapt |
| "check" or "status" | handleCheck |
| "resume" or "continue" | handleResume |
| All tasks completed | handleComplete |
| Default | handleSpawnNext |
## handleCallback
Worker completed (wait_agent returns). Process and advance.
1. Determine role from completed task prefix:
| Task Prefix | Role |
|-------------|------|
| `MRESEARCH-*` | motion-researcher |
| `CHOREO-*` | choreographer |
| `ANIM-*` | animator |
| `MTEST-*` | motion-tester |
2. Mark task completed in tasks.json: `state.tasks[taskId].status = 'completed'`
3. Record completion in session state
4. Check checkpoint for completed task:
| Completed Task | Checkpoint | Action |
|---------------|------------|--------|
| MRESEARCH-001 | - | Notify user: research complete |
| CHOREO-001 | - | Proceed to ANIM task(s) |
| ANIM-* (single) | - | Proceed to MTEST-001 |
| ANIM-* (page mode) | - | Check if all ANIM tasks complete, then unblock MTEST-001 |
| MTEST-001 | PERF-001: Performance Gate | Check perf signal -> GC loop or complete |
5. **Performance Gate handling** (MTEST task completed):
Read performance signal from result: `perf_passed`, `perf_warning`, or `fix_required`
| Signal | Condition | Action |
|--------|-----------|--------|
| `perf_passed` | FPS >= 60, no layout thrashing, reduced-motion present | Performance gate passed -> pipeline complete |
| `perf_warning` | Minor issues (will-change count high, near 60fps) | gc_rounds < max -> create ANIM-fix task |
| `fix_required` | FPS < 60 or layout thrashing detected | gc_rounds < max -> create ANIM-fix task (CRITICAL) |
| Any | gc_rounds >= max | Escalate to user |
**GC Fix Task Creation** (add to tasks.json):
```json
{
"ANIM-fix-<round>": {
"title": "Address performance issues from motion-tester report",
"description": "PURPOSE: Address performance issues from motion-tester report | Success: All critical perf issues resolved\nTASK:\n - Parse performance report for specific issues (layout thrashing, unsafe properties, excessive will-change)\n - Replace layout-triggering properties with compositor-only alternatives\n - Optimize will-change usage\n - Verify reduced-motion fallback completeness\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: testing/reports/perf-report-<NNN>.md",
"role": "animator",
"prefix": "ANIM",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
Then create new MTEST task in tasks.json with deps on fix. Increment gc_state.round.
**GC Escalation Options** (when max rounds exceeded):
1. Accept current animations - skip performance review, continue
2. Try one more round
3. Terminate
6. -> handleSpawnNext
## handleCheck
Read-only status report from tasks.json, then STOP.
```
Pipeline Status (<pipeline-mode>):
[DONE] MRESEARCH-001 (motion-researcher) -> research/*.json
[DONE] CHOREO-001 (choreographer) -> motion-tokens.json + sequences/
[RUN] ANIM-001 (animator) -> implementing animations...
[WAIT] MTEST-001 (motion-tester) -> blocked by ANIM-001
GC Rounds: 0/2
Performance Gate: pending
Session: <session-id>
Commands: 'resume' to advance | 'check' to refresh
```
Output status -- do NOT advance pipeline.
## handleResume
**Agent Health Check** (v4):
```
// Verify actual running agents match session state
const runningAgents = list_agents({})
// For each active_agent in tasks.json:
// - If agent NOT in runningAgents -> agent crashed
// - Reset that task to pending, remove from active_agents
// This prevents stale agent references from blocking the pipeline
```
1. Audit tasks.json for inconsistencies:
- Tasks stuck in "in_progress" -> reset to "pending"
- Tasks with completed deps but still "pending" -> include in spawn list
2. -> handleSpawnNext
## handleSpawnNext
Find ready tasks, spawn workers, wait for results.
1. Read tasks.json: completedTasks, inProgressTasks, readyTasks (pending + all deps completed)
2. No ready + work in progress -> report waiting, STOP
3. No ready + nothing in progress -> handleComplete
4. Has ready -> for each:
a. Check inner loop role with active worker -> skip (worker picks up)
b. Update task status to in_progress in tasks.json
c. team_msg log -> task_unblocked
d. Spawn team_worker:
```javascript
// 1) Update status in tasks.json
state.tasks[taskId].status = 'in_progress'
// 2) Spawn worker
const agentId = spawn_agent({
agent_type: "team_worker",
task_name: taskId, // e.g., "ANIM-001" -- enables named targeting
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: ${role}
role_spec: ${skillRoot}/roles/${role}/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${taskDescription}
inner_loop: ${innerLoop}
Read role_spec file to load Phase 2-4 domain instructions.
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).` },
{ type: "text", text: `## Task Context
task_id: ${taskId}
title: ${taskTitle}
description: ${taskDescription}
pipeline_phase: ${pipelinePhase}` },
{ type: "text", text: `## Upstream Context
${prevContext}` }
]
})
// 3) Track agent
state.active_agents[taskId] = { agentId, role, started_at: now }
// 4) Wait for completion -- use task_name for stable targeting (v4)
const waitResult = wait_agent({ targets: [taskId], timeout_ms: 900000 })
if (waitResult.timed_out) {
state.tasks[taskId].status = 'timed_out'
close_agent({ target: taskId })
delete state.active_agents[taskId]
} else {
// 5) Collect results and update tasks.json
state.tasks[taskId].status = 'completed'
close_agent({ target: taskId }) // Use task_name, not agentId
delete state.active_agents[taskId]
}
```
**Parallel spawn rules by mode**:
| Mode | Scenario | Spawn Behavior |
|------|----------|---------------|
| tokens | Sequential | One task at a time |
| component | Sequential | One task at a time, GC loop on MTEST |
| page | After CHOREO-001 | Spawn ANIM-001..N in parallel, wait_agent for all |
| page | After all ANIM complete | Spawn MTEST-001 |
**Cross-Agent Supplementary Context** (v4):
When spawning workers in a later pipeline phase, send upstream results as supplementary context to already-running workers:
```
// Example: Send research results to running choreographer
send_message({
target: "<running-agent-task-name>",
items: [{ type: "text", text: `## Supplementary Context\n${upstreamFindings}` }]
})
// Note: send_message queues info without interrupting the agent's current work
```
Use `send_message` (not `assign_task`) for supplementary info that enriches but doesn't redirect the agent's current task.
5. Update tasks.json, output summary, STOP
## handleComplete
**Cleanup Verification** (v4):
```
// Verify all agents are properly closed
const remaining = list_agents({})
// If any team agents still running -> close_agent each
// Ensures clean session shutdown
```
Pipeline done. Generate report and completion action.
**Completion check by mode**:
| Mode | Completion Condition |
|------|---------------------|
| tokens | All 4 tasks (+ fix tasks) completed |
| component | All 4 tasks (+ fix tasks) completed |
| page | All 4+N tasks (+ fix tasks) completed |
1. If any tasks not completed -> handleSpawnNext
2. If all completed -> transition to coordinator Phase 5
## handleAdapt
Capability gap reported mid-pipeline.
1. Parse gap description
2. Check if existing role covers it -> redirect
3. Role count < 5 -> generate dynamic role spec
4. Create new task in tasks.json, spawn worker
5. Role count >= 5 -> merge or pause
## Fast-Advance Reconciliation
On every coordinator wake:
1. Read tasks.json for completed tasks
2. Sync active_agents with actual state
3. No duplicate spawns

View File

@@ -0,0 +1,210 @@
# Coordinator Role
Motion Design Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages animation task chains with GC loops for performance validation.
## Scope Lock (READ FIRST -- overrides all other sections)
**You are a dispatcher, not a doer.** Your ONLY outputs are:
- Session state files (`.workflow/.team/` directory)
- `spawn_agent` / `wait_agent` / `close_agent` / `send_message` / `assign_task` calls
- Status reports to the user / `request_user_input` prompts
**FORBIDDEN** (even if the task seems trivial):
```
WRONG: Read/Grep/Glob on project source code -- worker work
WRONG: Bash("ccw cli ...") -- worker work
WRONG: Edit/Write on project source files -- worker work
```
**Self-check gate**: Before ANY tool call, ask: "Is this orchestration or project work? If project work -> STOP -> spawn worker."
---
## Identity
- **Name**: coordinator | **Tag**: [coordinator]
- **Responsibility**: Analyze task -> Create session -> Dispatch tasks -> Monitor progress -> Report results
## Boundaries
### MUST
- All output (team_msg, logs) must carry `[coordinator]` identifier
- Use `team_worker` agent type for all worker spawns (NOT `general-purpose`)
- Dispatch tasks with proper dependency chains and deps in tasks.json
- Monitor worker progress via wait_agent and process results
- Handle Generator-Critic loops with max 2 iterations
- Maintain session state persistence (tasks.json)
- **Always proceed through full Phase 1-5 workflow, never skip to direct execution**
- Use `send_message` for supplementary context (non-interrupting) and `assign_task` for triggering new work
- Use `list_agents` for session resume health checks and cleanup verification
### MUST NOT
- Implement domain logic (researching, choreographing, animating, testing) -- workers handle this
- Spawn workers without creating tasks first
- Skip sync points when configured
- Force-advance pipeline past failed performance test
- Modify source code or animation artifacts directly -- delegate to workers
- Omit `[coordinator]` identifier in any output
- Call CLI tools (ccw cli) -- only workers use CLI
## Command Execution Protocol
When coordinator needs to execute a command (analyze, dispatch, monitor):
1. Read `commands/<command>.md`
2. Follow the workflow defined in the command
3. Commands are inline execution guides, NOT separate agents
4. Execute synchronously, complete before proceeding
## Entry Router
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
| Capability gap | Message contains "capability_gap" | -> handleAdapt (monitor.md) |
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
| Interrupted session | Active/paused session exists in .workflow/.team/MD-* | -> Phase 0 |
| New session | None of above | -> Phase 1 |
For check/resume/adapt/complete: load `@commands/monitor.md`, execute matched handler, STOP.
## Phase 0: Session Resume Check
1. Scan `.workflow/.team/MD-*/tasks.json` for active/paused sessions
2. No sessions -> Phase 1
3. Single session -> reconcile (read tasks.json, reset in_progress->pending, kick first ready task)
4. Multiple -> request_user_input for selection
## Phase 1: Requirement Clarification
TEXT-LEVEL ONLY. No source code reading.
1. Parse task description from arguments
2. Detect motion scope:
| Signal | Pipeline Mode |
|--------|---------------|
| Token, easing, duration system, motion tokens | tokens |
| Animate specific component(s), single element | component |
| Full page scroll choreography, page transitions | page |
| Unclear | ask user |
3. Ask for missing parameters if scope unclear:
```
request_user_input({
questions: [
{ question: "Motion design scope?", header: "Scope", options: [
{ label: "Animation token system", description: "Easing functions, duration scale, stagger formulas" },
{ label: "Component animation", description: "Animate specific component(s) with transitions" },
{ label: "Page scroll choreography", description: "Full page scroll-triggered reveals and transitions" }
]},
{ question: "Target framework?", header: "Framework", options: [
{ label: "CSS-only" }, { label: "React" },
{ label: "Vue" }, { label: "Vanilla JS" }, { label: "Other" }
]}
]
})
```
4. Delegate to `@commands/analyze.md` -> output scope context
5. Record: pipeline_mode, framework, complexity
## Phase 2: Create Session + Initialize
1. Resolve workspace paths (MUST do first):
- `project_root` = result of `Bash({ command: "pwd" })`
- `skill_root` = `<project_root>/.codex/skills/team-motion-design`
2. Generate session ID: `MD-<slug>-<YYYY-MM-DD>`
3. Create session folder structure:
```
.workflow/.team/MD-<slug>-<date>/research/perf-traces/
.workflow/.team/MD-<slug>-<date>/choreography/sequences/
.workflow/.team/MD-<slug>-<date>/animations/keyframes/
.workflow/.team/MD-<slug>-<date>/animations/orchestrators/
.workflow/.team/MD-<slug>-<date>/testing/traces/
.workflow/.team/MD-<slug>-<date>/testing/reports/
.workflow/.team/MD-<slug>-<date>/wisdom/
.workflow/.team/MD-<slug>-<date>/.msg/
```
4. Initialize `.msg/meta.json` via team_msg state_update with pipeline metadata
5. Write initial tasks.json:
```json
{
"session_id": "<id>",
"pipeline_mode": "<tokens|component|page>",
"framework": "<framework>",
"created_at": "<ISO timestamp>",
"gc_rounds": 0,
"max_gc_rounds": 2,
"active_agents": {},
"tasks": {}
}
```
6. Do NOT spawn workers yet - deferred to Phase 4
## Phase 3: Create Task Chain
Delegate to `@commands/dispatch.md`. Task chains by mode:
| Mode | Task Chain |
|------|------------|
| tokens | MRESEARCH-001 -> CHOREO-001 -> ANIM-001 -> MTEST-001 |
| component | MRESEARCH-001 -> CHOREO-001 -> ANIM-001 -> MTEST-001 (GC loop) |
| page | MRESEARCH-001 -> CHOREO-001 -> [ANIM-001..N parallel] -> MTEST-001 |
## Phase 4: Spawn-and-Wait
Delegate to `@commands/monitor.md#handleSpawnNext`:
1. Find ready tasks (pending + deps resolved)
2. Spawn team_worker agents via spawn_agent, wait_agent for results
3. Output status summary
4. STOP
## Phase 5: Report + Completion Action
1. Read session state -> collect all results
2. List deliverables:
| Deliverable | Path |
|-------------|------|
| Animation Inventory | <session>/research/animation-inventory.json |
| Performance Baseline | <session>/research/performance-baseline.json |
| Easing Catalog | <session>/research/easing-catalog.json |
| Motion Tokens | <session>/choreography/motion-tokens.json |
| Choreography Sequences | <session>/choreography/sequences/*.md |
| CSS Keyframes | <session>/animations/keyframes/*.css |
| JS Orchestrators | <session>/animations/orchestrators/*.js |
| Performance Reports | <session>/testing/reports/perf-report-*.md |
3. Calculate: completed_tasks, gc_rounds, perf_score, final_fps
4. Output pipeline summary with [coordinator] prefix
5. Execute completion action:
```
request_user_input({
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
{ label: "Archive & Clean", description: "Archive session and clean up resources" },
{ label: "Keep Active", description: "Keep session for follow-up work" },
{ label: "Export Results", description: "Export deliverables to specified location" }
]}]
})
```
## v4 Coordination Patterns
### Message Semantics
- **send_message**: Queue supplementary info to a running agent. Does NOT interrupt current processing. Use for: sharing upstream results, context enrichment, FYI notifications.
- **assign_task**: Assign new work and trigger processing. Use for: waking idle agents, redirecting work, requesting new output.
### Agent Lifecycle Management
- **list_agents({})**: Returns all running agents. Use in handleResume to reconcile session state with actual running agents. Use in handleComplete to verify clean shutdown.
- **Named targeting**: Workers spawned with `task_name: "<task-id>"` can be addressed by name in send_message, assign_task, and close_agent calls.
## Error Handling
| Error | Resolution |
|-------|------------|
| Task timeout | Log, mark failed, ask user to retry or skip |
| Worker crash | Reset task to pending, respawn worker |
| Dependency cycle | Detect, report to user, halt |
| Invalid scope | Reject with error, ask to clarify |
| Session corruption | Attempt recovery, fallback to manual reconciliation |
| GC loop stuck > 2 rounds | Escalate to user: accept / try one more / terminate |

View File

@@ -0,0 +1,115 @@
---
role: motion-researcher
prefix: MRESEARCH
inner_loop: false
message_types: [state_update]
---
# Motion & Animation Researcher
Audit existing animations in the codebase, measure paint/composite costs via Chrome DevTools performance traces, and catalog easing patterns. Produce foundation data for downstream choreographer, animator, and motion-tester roles.
## Phase 2: Context & Environment Detection
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | No |
1. Extract session path and target scope from task description
2. Detect project type and tech stack from package.json or equivalent:
| Package | Detected Stack |
|---------|---------------|
| next | nextjs |
| react | react |
| vue | vue |
| svelte | svelte |
| gsap | gsap |
| framer-motion | framer-motion |
| @react-spring/web | react-spring |
| (default) | css-vanilla |
3. Use CLI tools (e.g., `ccw cli -p "..." --tool gemini --mode analysis`) or direct tools (Glob, Grep) to scan for existing animations, transitions, keyframes
4. Read framework context from session config
## Phase 3: Research Execution
Execute 3 analysis streams:
**Stream 1 -- Animation Inventory**:
- Search for CSS @keyframes declarations (pattern: `@keyframes`)
- Search for CSS transition properties (pattern: `transition:`, `transition-property:`)
- Search for JS animation APIs (requestAnimationFrame, Web Animations API, GSAP, Framer Motion)
- Search for IntersectionObserver usage (scroll-triggered animations)
- Catalog each animation: name, properties animated, duration, easing, trigger mechanism
- Flag unsafe properties (width, height, top, left, margin, padding, color, background-color)
- Output: `<session>/research/animation-inventory.json`
```json
{
"css_keyframes": [{ "name": "", "file": "", "properties": [], "safe": true }],
"css_transitions": [{ "file": "", "line": 0, "properties": [], "duration": "", "easing": "" }],
"js_animations": [{ "file": "", "type": "rAF|WAAPI|gsap|framer", "properties": [] }],
"scroll_triggers": [{ "file": "", "type": "IntersectionObserver|scroll-event", "threshold": 0 }],
"unsafe_animations": [{ "file": "", "line": 0, "property": "", "suggestion": "" }],
"summary": { "total": 0, "safe_count": 0, "unsafe_count": 0 }
}
```
**Stream 2 -- Performance Baseline**:
- If Chrome DevTools MCP available:
- Start performance trace: `mcp__chrome-devtools__performance_start_trace()`
- Trigger page load or scroll interaction
- Stop trace: `mcp__chrome-devtools__performance_stop_trace()`
- Analyze: `mcp__chrome-devtools__performance_analyze_insight()`
- Extract: FPS data, paint/composite times, layout thrashing events, layer count
- If Chrome DevTools unavailable:
- Static analysis: count layout-triggering properties, estimate performance from code patterns
- Mark `_source: "static-analysis"`
- Output: `<session>/research/performance-baseline.json`
```json
{
"_source": "chrome-devtools|static-analysis",
"fps": { "average": 0, "minimum": 0, "drops": [] },
"paint_time_ms": 0,
"composite_time_ms": 0,
"layout_thrashing": [],
"layer_count": 0,
"will_change_count": 0
}
```
**Stream 3 -- Easing Catalog**:
- Search for cubic-bezier declarations in CSS
- Search for named easing functions (ease, ease-in, ease-out, ease-in-out, linear)
- Search for JS easing implementations (spring physics, custom curves)
- Catalog each: name/value, usage count, context (hover, scroll, entry)
- Recommend additions based on gaps (missing ease-spring, missing stagger patterns)
- Reference specs/motion-tokens.md for recommended token schema
- Output: `<session>/research/easing-catalog.json`
```json
{
"existing": [{ "value": "", "usage_count": 0, "contexts": [] }],
"recommended_additions": [{ "name": "", "value": "", "reason": "" }],
"duration_patterns": [{ "value": "", "usage_count": 0, "contexts": [] }],
"stagger_patterns": [{ "found": false, "details": "" }]
}
```
Compile research summary metrics: animation_count, safe_percentage, fps_baseline, easing_count, has_reduced_motion.
## Phase 4: Validation & Output
1. Verify all 3 output files exist and contain valid JSON with required fields:
| File | Required Fields |
|------|----------------|
| animation-inventory.json | css_keyframes array, summary |
| performance-baseline.json | _source |
| easing-catalog.json | existing array |
2. If any file missing or invalid, re-run corresponding stream
3. Update `<session>/wisdom/.msg/meta.json` under `motion-researcher` namespace:
- Read existing -> merge `{ "motion-researcher": { detected_stack, animation_count, safe_percentage, fps_baseline, easing_count, has_reduced_motion } }` -> write back

View File

@@ -0,0 +1,175 @@
---
role: motion-tester
prefix: MTEST
inner_loop: false
message_types: [state_update]
---
# Motion Performance Tester
Test animation performance via Chrome DevTools performance traces and static code analysis. Verify compositor-only animations, measure FPS, detect layout thrashing, and validate prefers-reduced-motion accessibility compliance. Act as Critic in the animator<->motion-tester Generator-Critic loop.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Animation files | <session>/animations/keyframes/*.css | Yes |
| JS orchestrators | <session>/animations/orchestrators/*.js | Yes |
| Motion tokens | <session>/choreography/motion-tokens.json | Yes |
| Choreography sequences | <session>/choreography/sequences/*.md | Yes (component/page) |
| GPU constraints | specs/gpu-constraints.md | Yes |
| Reduced motion spec | specs/reduced-motion.md | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
1. Extract session path from task description
2. Read all animation CSS files from animations/keyframes/
3. Read all JS orchestrator files from animations/orchestrators/
4. Read motion tokens for reference values
5. Read choreography sequences for expected behavior
6. Read GPU constraints and reduced motion specs for validation rules
## Phase 3: Test Execution
### Test 1: Compositor-Only Verification
Scan all CSS @keyframes and transition properties for unsafe values:
**SAFE** (compositor thread, no repaint):
- `transform` (translate, scale, rotate, skew)
- `opacity`
- `filter` (blur, brightness, contrast)
- `backdrop-filter`
**UNSAFE** (trigger layout/paint):
- `width`, `height`, `top`, `left`, `right`, `bottom`
- `margin`, `padding`, `border`
- `font-size`, `color`, `background-color`
- `box-shadow` (partial -- expensive paint)
For each animation file:
1. Parse @keyframes blocks, extract animated properties
2. Parse transition declarations, extract properties
3. Flag any UNSAFE property with file:line reference
4. Score: `safe_percentage = safe_count / total_count * 100`
### Test 2: Frame Rate Analysis
**If Chrome DevTools MCP available**:
1. `mcp__chrome-devtools__performance_start_trace()` -- start recording
2. `mcp__chrome-devtools__evaluate_script({ expression: "/* trigger animations */" })` -- trigger
3. `mcp__chrome-devtools__performance_stop_trace()` -- stop recording
4. `mcp__chrome-devtools__performance_analyze_insight()` -- analyze
5. Extract: average FPS, minimum FPS, frame drops, long frames (>16.67ms)
6. Target: average >= 60fps, minimum >= 45fps, no consecutive drops
**If Chrome DevTools unavailable** (static analysis fallback):
1. Count total animated properties per frame (concurrent animations)
2. Estimate frame budget: < 5ms style+layout, < 5ms paint+composite
3. Flag: >10 concurrent animations, nested animations, forced synchronous layouts
4. Mark `_source: "static-analysis"` and note limitations
### Test 3: Layout Thrashing Detection
Scan JS orchestrators for read-write-read patterns:
**Thrashing patterns** (DOM read -> write -> read in same frame):
- `offsetHeight` / `offsetWidth` read followed by style write followed by read
- `getBoundingClientRect()` interleaved with style mutations
- `getComputedStyle()` followed by DOM writes
For each JS file:
1. Parse for DOM read APIs: `offsetHeight`, `offsetWidth`, `clientHeight`, `getBoundingClientRect`, `getComputedStyle`, `scrollTop`, `scrollHeight`
2. Check if style writes (`.style.*`, `.classList.*`, `.setAttribute`) occur between reads
3. Flag thrashing sequences with file:line references
### Test 4: will-change Audit
1. Count elements with `will-change` in CSS
2. Flag if count > 4 (memory cost)
3. Check for `will-change: auto` on collections (anti-pattern)
4. Verify will-change is removed after animation completes (in JS orchestrators)
5. Check for missing will-change on heavily animated elements
### Test 5: Reduced Motion Compliance
1. Verify `@media (prefers-reduced-motion: reduce)` block exists
2. Check all animation-duration and transition-duration are overridden
3. Verify scroll-behavior set to auto
4. Check JS for `matchMedia('(prefers-reduced-motion: reduce)')` detection
5. Verify parallax effects disabled in reduced motion
6. Verify no auto-playing or infinite loop animations in reduced motion
### Perceived Performance Checks
| Check | Pass Criteria |
|-------|---------------|
| Preemptive animation start | Hover/click animations start on pointerdown, not click |
| No height/width animation | Grid-template-rows trick used instead of height transitions |
| Ease-in for progress | Progress indicators use ease-in (compresses perceived wait) |
| Ease-out for entrances | Content entrances use ease-out (natural settle) |
**Scoring**:
| Check | Weight | Criteria |
|-------|--------|----------|
| Compositor-only | 30% | 100% safe = 10, each unsafe -2 |
| Frame rate | 25% | >= 60fps = 10, 50-59 = 7, 40-49 = 4, < 40 = 1 |
| Layout thrashing | 20% | 0 instances = 10, each instance -3 |
| will-change budget | 10% | <= 4 = 10, 5-6 = 7, 7+ = 3 |
| Reduced motion | 15% | All 5 checks pass = 10, each miss -2 |
**Overall score**: `round(compositor*0.30 + fps*0.25 + thrashing*0.20 + willchange*0.10 + reducedmotion*0.15)`
**Signal determination**:
| Condition | Signal |
|-----------|--------|
| Score >= 8 AND no layout thrashing AND FPS >= 60 | `perf_passed` (GATE PASSED) |
| Score >= 6 AND no critical issues | `perf_warning` (REVISION SUGGESTED) |
| Score < 6 OR layout thrashing OR FPS < 60 | `fix_required` (CRITICAL FIX NEEDED) |
## Phase 4: Report & Output
1. Write performance report to `<session>/testing/reports/perf-report-{NNN}.md`:
```markdown
# Performance Report {NNN}
## Summary
- Overall Score: X/10
- Signal: perf_passed|perf_warning|fix_required
- Source: chrome-devtools|static-analysis
## Compositor-Only Verification
- Safe: X/Y properties (Z%)
- Unsafe properties found:
- [file:line] property: suggestion
## Frame Rate
- Average FPS: X
- Minimum FPS: X
- Frame drops: X
- Long frames (>16.67ms): X
## Layout Thrashing
- Instances found: X
- Details:
- [file:line] pattern: description
## will-change Audit
- Elements with will-change: X
- Budget status: OK|OVER
- Issues:
- [file:line] issue: description
## Reduced Motion Compliance
- @media query present: yes|no
- Duration override: yes|no
- JS detection: yes|no
- Parallax disabled: yes|no|N/A
- No infinite loops: yes|no
## Recommendations
1. [Priority] Description
```
2. Update `<session>/wisdom/.msg/meta.json` under `motion-tester` namespace:
- Read existing -> merge `{ "motion-tester": { report_id, score, signal, fps_average, safe_percentage, thrashing_count, will_change_count, reduced_motion_complete } }` -> write back

View File

@@ -0,0 +1,114 @@
# GPU Constraints
Compositor-only animation rules for 60fps performance.
## Property Classification
### SAFE Properties (Compositor Thread, No Repaint)
These properties are handled by the GPU compositor thread and do not trigger layout or paint:
| Property | Examples | Notes |
|----------|---------|-------|
| `transform` | `translate()`, `scale()`, `rotate()`, `skew()` | Primary animation property |
| `opacity` | `0` to `1` | Cheap compositor operation |
| `filter` | `blur()`, `brightness()`, `contrast()`, `saturate()` | GPU-accelerated in modern browsers |
| `backdrop-filter` | `blur()`, `brightness()` | Composited separately |
### UNSAFE Properties (Trigger Layout/Paint)
**NEVER animate these properties** -- they force layout recalculation and/or paint:
| Property | Impact | Alternative |
|----------|--------|-------------|
| `width` | Layout | `transform: scaleX()` |
| `height` | Layout | `transform: scaleY()` |
| `top` | Layout | `transform: translateY()` |
| `left` | Layout | `transform: translateX()` |
| `right` | Layout | `transform: translateX()` (negative) |
| `bottom` | Layout | `transform: translateY()` (negative) |
| `margin` | Layout | `transform: translate()` |
| `padding` | Layout | Use inner element with transform |
| `border` | Layout + Paint | `outline` (no layout) or `box-shadow` |
| `font-size` | Layout | `transform: scale()` |
| `color` | Paint | Overlay with `opacity` |
| `background-color` | Paint | Overlay element with `opacity` |
| `box-shadow` | Paint | Use `filter: drop-shadow()` or pre-rendered layers |
## will-change Budget
### Rules
1. **Max 3-4 elements** with `will-change` simultaneously
2. **Remove after animation completes** -- do not leave permanent will-change
3. **Never use `will-change: auto`** on collections or many elements
4. **Explicit properties only**: `will-change: transform` or `will-change: opacity`, not `will-change: all`
### Implementation Pattern
```css
/* Static: no will-change */
.element {
transition: transform var(--duration-base) var(--ease-out);
}
/* Add will-change just before animation via JS */
.element.will-animate {
will-change: transform;
}
/* Or via CSS for hover-triggered animations */
.element:hover {
will-change: transform;
}
```
```javascript
// JS: add before, remove after
element.style.willChange = 'transform';
element.addEventListener('transitionend', () => {
element.style.willChange = 'auto';
}, { once: true });
```
### Layer Promotion
- `transform: translateZ(0)` or `will-change: transform` promotes to own compositor layer
- Each layer costs GPU memory (~width * height * 4 bytes)
- Avoid promoting too many layers -- profile with Chrome DevTools Layers panel
- Use sparingly: hero elements, frequently animated elements, scroll-linked elements
## Performance Targets
| Metric | Target | Budget |
|--------|--------|--------|
| Frame rate | 60fps | 16.67ms per frame |
| Style + Layout | < 5ms | ~30% of frame budget |
| Paint + Composite | < 5ms | ~30% of frame budget |
| JavaScript | < 5ms | ~30% of frame budget |
| Idle buffer | ~1.67ms | Headroom for GC, etc. |
## Measurement
### Chrome DevTools Performance Panel
1. Record performance trace during animation
2. Check "Frames" section for frame drops (red/yellow bars)
3. Check "Main" thread for long tasks during animation
4. Check "Compositor" thread for smooth operation
5. Look for "Layout" and "Paint" events during animation (should be minimal)
### Key Indicators of Problems
- Purple "Layout" bars during animation = layout-triggering property
- Green "Paint" bars during animation = paint-triggering property
- Red frame markers = dropped frames (>16.67ms)
- "Forced reflow" warnings = layout thrashing in JS
## Quick Reference Card
```
ANIMATE: transform, opacity, filter
AVOID: width, height, top, left, margin, padding, color, background-color
BUDGET: will-change on max 3-4 elements, remove after use
TARGET: 60fps = 16.67ms per frame
MEASURE: Chrome DevTools Performance panel
```

View File

@@ -0,0 +1,128 @@
# Motion Token Schema
Animation token system for consistent motion design. Derived from Impeccable design principles.
## Easing Functions
| Token | Value | Use Case |
|-------|-------|----------|
| ease-out | `cubic-bezier(0.16, 1, 0.3, 1)` | Emphasis exit, deceleration. Elements entering view. |
| ease-in-out | `cubic-bezier(0.65, 0, 0.35, 1)` | Smooth symmetrical. State changes, toggles. |
| ease-spring | `cubic-bezier(0.34, 1.56, 0.64, 1)` | Overshoot bounce. Playful interactions, notifications. |
**Usage guidelines**:
- `ease-out` is the default for most animations (content reveals, transitions)
- `ease-in-out` for reversible state changes (expand/collapse, toggle)
- `ease-spring` sparingly for emphasis (new item added, attention-grabbing)
- Never use `ease-in` alone (feels sluggish for UI)
## Duration Scale
| Token | Value | Use Case |
|-------|-------|----------|
| fast | `0.15s` | Micro-interactions: button press, toggle, checkbox |
| base | `0.3s` | Standard transitions: hover, focus, dropdown |
| slow | `0.6s` | Content reveals: card entry, panel slide, accordion |
| slower | `0.8s` | Page transitions: route change, large element moves |
| slowest | `1.2s` | Hero animations: splash screen, onboarding, first load |
**Guidelines**:
- Faster for small elements, slower for large elements
- Faster for frequent interactions, slower for infrequent
- Never exceed 1.2s for any single animation
- Total page animation sequence should complete within 2s
## Stagger Formula
```
delay = base_delay + (index * stagger_increment)
```
| Parameter | Typical Value | Range |
|-----------|---------------|-------|
| base_delay | `0s` | 0-0.1s |
| stagger_increment | `0.05s` | 0.03-0.1s |
| max visible stagger | 8 items | -- |
**Guidelines**:
- Max 8 items in a stagger sequence (avoid >0.8s total delay)
- For >8 items: batch into groups of 4-6 with group-level stagger
- Stagger increment scales with duration: fast animations use smaller increments
- First item always has 0 delay (no waiting)
## CSS Custom Property Format
```css
:root {
/* Easing functions */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
/* Duration scale */
--duration-fast: 0.15s;
--duration-base: 0.3s;
--duration-slow: 0.6s;
--duration-slower: 0.8s;
--duration-slowest: 1.2s;
/* Stagger */
--stagger-increment: 0.05s;
}
```
## Token Consumption Pattern
```css
/* Correct: consume tokens via custom properties */
.card-enter {
animation: fade-up var(--duration-slow) var(--ease-out) both;
}
/* Correct: stagger via inline style or calc */
.card-enter:nth-child(n) {
animation-delay: calc(var(--stagger-increment) * var(--stagger-index, 0));
}
/* WRONG: hardcoded values */
.card-enter {
animation: fade-up 0.6s cubic-bezier(0.16, 1, 0.3, 1) both; /* BAD */
}
```
## JSON Token Format
```json
{
"easing": {
"ease-out": {
"value": "cubic-bezier(0.16, 1, 0.3, 1)",
"use": "exit emphasis, deceleration",
"css_property": "--ease-out"
},
"ease-in-out": {
"value": "cubic-bezier(0.65, 0, 0.35, 1)",
"use": "smooth symmetrical",
"css_property": "--ease-in-out"
},
"ease-spring": {
"value": "cubic-bezier(0.34, 1.56, 0.64, 1)",
"use": "overshoot bounce",
"css_property": "--ease-spring"
}
},
"duration": {
"fast": { "value": "0.15s", "use": "micro-interactions", "css_property": "--duration-fast" },
"base": { "value": "0.3s", "use": "standard transitions", "css_property": "--duration-base" },
"slow": { "value": "0.6s", "use": "content reveals", "css_property": "--duration-slow" },
"slower": { "value": "0.8s", "use": "page transitions", "css_property": "--duration-slower" },
"slowest": { "value": "1.2s", "use": "hero animations", "css_property": "--duration-slowest" }
},
"stagger": {
"base_delay": "0s",
"increment": "0.05s",
"max_items": 8,
"css_property": "--stagger-increment"
}
}
```

View File

@@ -0,0 +1,74 @@
# Pipeline Definitions
Motion design pipeline modes and task registry.
## Pipeline Modes
| Mode | Description | Task Count |
|------|-------------|------------|
| tokens | Animation token system: research -> choreography -> animation -> test | 4 tasks |
| component | Component animation with GC loop for performance | 4 tasks (+fix) |
| page | Full page scroll choreography with parallel animations | 4+N tasks |
## Tokens Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| MRESEARCH-001 | motion-researcher | [] | Audit existing animations, measure perf baseline, catalog easing patterns |
| CHOREO-001 | choreographer | [MRESEARCH-001] | Design motion token system (easing, duration, stagger, reduced-motion) |
| ANIM-001 | animator | [CHOREO-001] | Implement CSS custom properties, utility animations, reduced-motion overrides |
| MTEST-001 | motion-tester | [ANIM-001] | Verify compositor-only, FPS, will-change budget, reduced-motion compliance |
## Component Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| MRESEARCH-001 | motion-researcher | [] | Audit target component animations, measure perf baseline |
| CHOREO-001 | choreographer | [MRESEARCH-001] | Design tokens + transition state diagrams + scroll sequences |
| ANIM-001 | animator | [CHOREO-001] | Implement component animations: @keyframes, IntersectionObserver, rAF |
| MTEST-001 | motion-tester | [ANIM-001] | Performance gate: FPS, compositor-only, layout thrashing, reduced-motion |
GC loop: MTEST-001 -> ANIM-fix-1 -> MTEST-002 (max 2 rounds)
## Page Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| MRESEARCH-001 | motion-researcher | [] | Full page animation audit, scroll section inventory |
| CHOREO-001 | choreographer | [MRESEARCH-001] | Page-level motion tokens + scroll choreography per section |
| ANIM-001..N | animator | [CHOREO-001] | Parallel: one ANIM task per scroll section (CP-3 Fan-out) |
| MTEST-001 | motion-tester | [ANIM-001..N] | Full page performance validation after all sections complete |
## Performance Gate (Sync Point)
| Checkpoint | Task | Condition | Action |
|------------|------|-----------|--------|
| PERF-001: Performance Gate | MTEST-* completes | FPS >= 60, no thrashing, reduced-motion OK | Pipeline complete |
| PERF-001: GC Loop | MTEST-* completes | FPS < 60 or thrashing | Create ANIM-fix task, new MTEST task (max 2 rounds) |
## GC Loop Behavior
| Signal | Condition | Action |
|--------|-----------|--------|
| perf_passed | Score >= 8, FPS >= 60, no thrashing | Performance gate passed -> pipeline complete |
| perf_warning | Score 6-7, minor issues | gc_rounds < max -> create ANIM-fix task |
| fix_required | Score < 6 or FPS < 60 or thrashing | gc_rounds < max -> create ANIM-fix task (CRITICAL) |
| Any | gc_rounds >= max | Escalate to user: accept / try one more / terminate |
## Parallel Spawn Rules
| Mode | After | Spawn Behavior |
|------|-------|----------------|
| tokens | Sequential | One task at a time |
| component | Sequential | One task at a time, GC loop on MTEST |
| page | CHOREO-001 | Spawn ANIM-001..N in parallel (CP-3 Fan-out) |
| page | All ANIM complete | Spawn MTEST-001 |
## Output Artifacts
| Task | Output Path |
|------|-------------|
| MRESEARCH-001 | <session>/research/*.json |
| CHOREO-001 | <session>/choreography/motion-tokens.json + sequences/*.md |
| ANIM-* | <session>/animations/keyframes/*.css + orchestrators/*.js |
| MTEST-* | <session>/testing/reports/perf-report-{NNN}.md |

View File

@@ -0,0 +1,129 @@
# Reduced Motion Accessibility
Implementation guidelines for `prefers-reduced-motion` compliance.
## Strategy
Wrap all motion in `@media` query, provide instant fallback. Users who prefer reduced motion should still perceive state changes but without disorienting movement.
## CSS Implementation
### Global Override
```css
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
### Per-Component Override (Preferred)
```css
.card-enter {
animation: fade-up var(--duration-slow) var(--ease-out) both;
}
@media (prefers-reduced-motion: reduce) {
.card-enter {
animation: fade-in 0.01ms linear both; /* opacity only, instant */
}
}
```
### Parallax Disable
```css
.parallax-element {
transform: translateY(calc(var(--scroll-y) * 0.5));
}
@media (prefers-reduced-motion: reduce) {
.parallax-element {
transform: none !important;
}
}
```
## JavaScript Detection
```javascript
// Check preference
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
// Use in animation logic
if (prefersReducedMotion.matches) {
// Skip parallax
// Disable spring/bounce animations
// Use instant transitions
// Skip scroll-linked transforms
}
// Listen for changes (user toggles setting)
prefersReducedMotion.addEventListener('change', (event) => {
if (event.matches) {
disableMotion();
} else {
enableMotion();
}
});
```
## Allowed in Reduced Motion
These subtle effects are acceptable and help maintain usability:
| Effect | Duration | Notes |
|--------|----------|-------|
| Opacity fades | < 0.15s | Short, non-directional |
| Color transitions | < 0.15s | Subtle state indicator |
| Essential state indicators | Instant | Focus rings, selection highlights |
| Progress indicators | N/A | Spinner -> static progress bar |
## Disallowed in Reduced Motion
These effects must be completely disabled:
| Effect | Reason | Fallback |
|--------|--------|----------|
| Parallax scrolling | Vestibular triggers | Static positioning |
| Scroll-linked transforms | Continuous motion | No transform |
| Bouncing/spring animations | Overshoot causes discomfort | Instant state change |
| Auto-playing content | Unexpected motion | Pause by default |
| Infinite loop animations | Continuous distraction | Single iteration or static |
| Large-scale movements | Disorienting | Opacity fade only |
| Zoom/scale animations | Vestibular triggers | Opacity fade |
| Rotating animations | Vestibular triggers | Static or opacity |
## Testing Checklist
| Check | Method | Expected |
|-------|--------|----------|
| `@media` query present | Grep CSS for `prefers-reduced-motion` | At least one global override |
| Duration override | Check `animation-duration` and `transition-duration` | Set to `0.01ms` |
| Scroll behavior | Check `scroll-behavior` | Set to `auto` |
| JS detection | Grep JS for `matchMedia.*reduced-motion` | Present with listener |
| Parallax disabled | Check parallax elements in reduced motion | `transform: none` |
| No infinite loops | Check `animation-iteration-count` | Set to `1` |
| No auto-play | Check auto-playing animations | Paused or removed |
## Implementation Order
1. Add global CSS override first (catches everything)
2. Add per-component overrides for nuanced fallbacks
3. Add JS detection for runtime animation control
4. Test with browser setting toggled ON
5. Verify no motion remains except allowed effects
## Browser Support
- `prefers-reduced-motion: reduce` -- supported in all modern browsers
- Safari 10.1+, Chrome 74+, Firefox 63+, Edge 79+
- iOS Safari 10.3+ (respects system Accessibility settings)
- Android Chrome 74+ (respects system Accessibility settings)

View File

@@ -0,0 +1,99 @@
{
"team_name": "motion-design",
"team_display_name": "Motion Design",
"description": "Motion design team for animation token systems, scroll choreography, GPU-accelerated transforms, reduced-motion fallback",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Scope assessment, pipeline orchestration, performance gate management, GC loop control",
"message_types": ["task_unblocked", "perf_checkpoint", "fix_required", "error", "shutdown"]
},
"motion-researcher": {
"task_prefix": "MRESEARCH",
"responsibility": "Audit existing animations, measure paint/composite costs, catalog easing patterns",
"message_types": ["research_ready", "research_progress", "error"]
},
"choreographer": {
"task_prefix": "CHOREO",
"responsibility": "Design animation token system, scroll-triggered reveal sequences, transition state diagrams",
"message_types": ["choreography_ready", "choreography_progress", "error"]
},
"animator": {
"task_prefix": "ANIM",
"inner_loop": true,
"responsibility": "Implement CSS animations/transitions, JS orchestration, IntersectionObserver triggers, rAF coordination",
"message_types": ["animation_ready", "animation_revision", "animation_progress", "error"]
},
"motion-tester": {
"task_prefix": "MTEST",
"responsibility": "Chrome DevTools perf traces, compositor-only verification, FPS measurement, layout thrashing detection, reduced-motion validation",
"message_types": ["perf_passed", "perf_warning", "fix_required", "error"]
}
},
"pipelines": {
"tokens": {
"description": "Animation token system: research -> choreography -> animation -> test",
"task_chain": ["MRESEARCH-001", "CHOREO-001", "ANIM-001", "MTEST-001"],
"complexity": "low"
},
"component": {
"description": "Component animation: research -> choreography -> animation -> test (GC loop)",
"task_chain": ["MRESEARCH-001", "CHOREO-001", "ANIM-001", "MTEST-001"],
"gc_loop": { "generator": "ANIM", "critic": "MTEST", "trigger": "FPS < 60 or layout thrashing" },
"complexity": "medium"
},
"page": {
"description": "Page scroll choreography: research -> choreography -> parallel animations -> test",
"task_chain": [
"MRESEARCH-001", "CHOREO-001",
"ANIM-001..N:parallel",
"MTEST-001"
],
"parallel_fan_out": { "after": "CHOREO-001", "tasks": "ANIM-*", "join_before": "MTEST-001" },
"complexity": "high"
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "animator",
"critic": "motion-tester",
"max_rounds": 2,
"convergence": "perf.score >= 8 && perf.fps >= 60 && perf.thrashing_count === 0",
"trigger": "FPS < 60 or layout thrashing detected",
"escalation": "Coordinator intervenes after max rounds"
},
"shared_memory": {
"file": "shared-memory.json",
"fields": {
"motion-researcher": ["animation_inventory", "performance_baseline", "easing_catalog"],
"choreographer": ["motion_tokens", "scroll_sequences", "state_diagrams"],
"animator": ["keyframe_registry", "orchestrator_registry"],
"motion-tester": ["perf_history", "issue_registry"]
}
},
"parallel_fan_out": {
"pattern": "CP-3",
"description": "Multiple ANIM tasks execute in parallel for page mode, joined before MTEST",
"trigger": "page pipeline after CHOREO-001 completion"
},
"review_fix": {
"pattern": "CP-2",
"description": "Animator and motion-tester in Generator-Critic loop",
"max_rounds": 2,
"trigger": "FPS < 60 or layout thrashing detected"
}
},
"session_dirs": {
"base": ".workflow/.team/MD-{slug}-{YYYY-MM-DD}/",
"research": "research/",
"choreography": "choreography/",
"animations": "animations/",
"testing": "testing/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,218 @@
---
name: team-ui-polish
description: Unified team skill for UI polish. Auto-discover and fix UI design issues using Impeccable design standards. Anti-AI-slop detection, color/typography/spacing quality, motion, interaction states, visual hierarchy. Uses team-worker agent architecture. Triggers on "team ui polish", "ui polish", "design polish".
allowed-tools: spawn_agent(*), wait_agent(*), send_message(*), assign_task(*), close_agent(*), list_agents(*), report_agent_job_result(*), request_user_input(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), mcp__ccw-tools__read_file(*), mcp__ccw-tools__write_file(*), mcp__ccw-tools__edit_file(*), mcp__ccw-tools__team_msg(*), mcp__chrome-devtools__evaluate_script(*), mcp__chrome-devtools__take_screenshot(*), mcp__chrome-devtools__navigate_page(*), mcp__chrome-devtools__resize_page(*)
---
# Team UI Polish
Automatic UI quality improvement pipeline: scan -> diagnose -> optimize -> verify. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
## Architecture
```
Skill(skill="team-ui-polish", args="task description")
|
SKILL.md (this file) = Router
|
+--------------+--------------+
| |
no --role flag --role <name>
| |
Coordinator Worker
roles/coordinator/role.md roles/<name>/role.md
|
+-- analyze -> dispatch -> spawn workers -> STOP
|
+-------+-------+-------+
v v v v
[team-worker agents, each loads roles/<role>/role.md]
scanner diagnostician optimizer <-> verifier (GC loop)
```
## Role Registry
| Role | Path | Prefix | Inner Loop |
|------|------|--------|------------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
| scanner | [roles/scanner/role.md](roles/scanner/role.md) | SCAN-* | false |
| diagnostician | [roles/diagnostician/role.md](roles/diagnostician/role.md) | DIAG-* | false |
| optimizer | [roles/optimizer/role.md](roles/optimizer/role.md) | OPT-* | true |
| verifier | [roles/verifier/role.md](roles/verifier/role.md) | VERIFY-* | false |
## Role Router
Parse `$ARGUMENTS`:
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
- No `--role` -> `roles/coordinator/role.md`, execute entry router
## Delegation Lock
**Coordinator is a PURE ORCHESTRATOR. It coordinates, it does NOT do.**
Before calling ANY tool, apply this check:
| Tool Call | Verdict | Reason |
|-----------|---------|--------|
| `spawn_agent`, `wait_agent`, `close_agent`, `send_message`, `assign_task` | ALLOWED | Orchestration |
| `list_agents` | ALLOWED | Agent health check |
| `request_user_input` | ALLOWED | User interaction |
| `mcp__ccw-tools__team_msg` | ALLOWED | Message bus |
| `Read/Write` on `.workflow/.team/` files | ALLOWED | Session state |
| `Read` on `roles/`, `commands/`, `specs/` | ALLOWED | Loading own instructions |
| `Read/Grep/Glob` on project source code | BLOCKED | Delegate to worker |
| `Edit` on any file outside `.workflow/` | BLOCKED | Delegate to worker |
| `Bash("ccw cli ...")` | BLOCKED | Only workers call CLI |
| `Bash` running build/test/lint commands | BLOCKED | Delegate to worker |
**If a tool call is BLOCKED**: STOP. Create a task, spawn a worker.
**No exceptions for "simple" tasks.** Even a single-file read-and-report MUST go through spawn_agent.
---
## Shared Constants
- **Session prefix**: `UIP`
- **Session path**: `.workflow/.team/UIP-<slug>-<date>/`
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
- **Max GC rounds**: 2
## Worker Spawn Template
Coordinator spawns workers using this template:
```
spawn_agent({
agent_type: "team_worker",
task_name: "<task-id>",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: <role>
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
requirement: <task-description>
inner_loop: <true|false>
Read role_spec file (<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: <task-id>
title: <task-title>
description: <task-description>
pipeline_phase: <pipeline-phase>` },
{ type: "text", text: `## Upstream Context
<prev_context>` }
]
})
```
After spawning, use `wait_agent({ targets: [...], timeout_ms: 900000 })` to collect results, then `close_agent({ target })` each worker.
### Model Selection Guide
UI polish is a sequential pipeline where scan findings drive all downstream work. Scanner and verifier need thorough analysis, optimizer needs creative problem-solving.
| Role | reasoning_effort | Rationale |
|------|-------------------|-----------|
| scanner | high | Deep 8-dimension audit must catch every issue |
| diagnostician | high | Root cause analysis requires careful classification |
| optimizer | high | Creative fix application following design standards |
| verifier | high | Regression detection must be thorough |
### Scan-to-Diagnosis Context Flow
Scanner findings must reach diagnostician via coordinator's upstream context:
```
// After SCAN-001 completes, coordinator sends findings to diagnostician
spawn_agent({
agent_type: "team_worker",
task_name: "DIAG-001",
fork_context: false,
items: [
...,
{ type: "text", text: `## Upstream Context
Scan report: <session>/scan/scan-report.md` }
]
})
```
## User Commands
| Command | Action |
|---------|--------|
| `check` / `status` | View execution status graph |
| `resume` / `continue` | Advance to next step |
## Specs Reference
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
- [specs/team-config.json](specs/team-config.json) -- Team configuration
- [specs/anti-patterns.md](specs/anti-patterns.md) -- AI slop and design anti-pattern catalog
- [specs/design-standards.md](specs/design-standards.md) -- Impeccable positive design standards
- [specs/fix-strategies.md](specs/fix-strategies.md) -- Issue-to-fix mapping
- [specs/scoring-guide.md](specs/scoring-guide.md) -- Scoring rubric
## Session Directory
```
.workflow/.team/UIP-<slug>-<date>/
+-- .msg/
| +-- messages.jsonl # Team message bus
| +-- meta.json # Pipeline config + GC state
+-- scan/ # Scanner output
| +-- scan-report.md
+-- diagnosis/ # Diagnostician output
| +-- diagnosis-report.md
+-- optimization/ # Optimizer output
| +-- fix-log.md
+-- verification/ # Verifier output
| +-- verify-report.md
+-- evidence/ # Screenshots (before/after)
| +-- *.png
+-- wisdom/ # Cross-task knowledge
```
## v4 Agent Coordination
### Message Semantics
| Intent | API | Example |
|--------|-----|---------|
| Queue supplementary info (don't interrupt) | `send_message` | Send scan findings to running diagnostician |
| Assign fix from verification feedback | `assign_task` | Assign OPT-fix task after verify fails |
| Check running agents | `list_agents` | Verify agent health during resume |
### Agent Health Check
Use `list_agents({})` in handleResume and handleComplete:
```
// Reconcile session state with actual running agents
const running = list_agents({})
// Compare with tasks.json active tasks
// Reset orphaned tasks (in_progress but agent gone) to pending
```
### Named Agent Targeting
Workers are spawned with `task_name: "<task-id>"` enabling direct addressing:
- `send_message({ target: "DIAG-001", items: [...] })` -- send additional scan findings to diagnostician
- `assign_task({ target: "OPT-001", items: [...] })` -- assign optimization from diagnosis report
- `close_agent({ target: "VERIFY-001" })` -- cleanup after verification
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown command | Error with available command list |
| Role not found | Error with role registry |
| Session corruption | Attempt recovery, fallback to manual |
| Fast-advance conflict | Coordinator reconciles on next callback |
| Completion action fails | Default to Keep Active |
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |

View File

@@ -0,0 +1,77 @@
# Analyze Task
Parse user task -> detect polish scope -> determine pipeline mode -> estimate complexity.
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
## Signal Detection
| Keywords | Dimension | Priority |
|----------|-----------|----------|
| AI slop, generic, templated, looks like AI | Anti-Patterns | P0 |
| color, palette, contrast, OKLCH, dark mode, theme | Color Quality | P1 |
| font, typography, heading, text size, type scale | Typography | P1 |
| spacing, padding, margin, rhythm, gap, grid | Spacing/Layout | P1 |
| animation, transition, motion, easing, animate | Motion | P2 |
| hover, focus, active, disabled, states, interaction | Interaction States | P2 |
| hierarchy, visual weight, composition, squint | Visual Hierarchy | P2 |
| responsive, mobile, breakpoint, viewport | Responsive | P2 |
## Scope Determination
| Signal | Pipeline Mode |
|--------|---------------|
| "scan", "audit", "check", "report", "analyze", "review" | scan-only |
| "fix color", "fix typography", specific dimension keyword | targeted |
| "polish", "fix all", "full", "improve", "clean up", "redesign" | full |
| Unclear | ask user |
## Dimension Filter (targeted mode only)
When targeted mode detected, extract which dimensions to focus on:
| Keywords | Dimension Filter |
|----------|-----------------|
| AI slop, generic | anti_patterns |
| color, palette, contrast | color |
| font, typography, type | typography |
| spacing, layout, grid | spacing |
| animation, motion | motion |
| hover, focus, states | interaction |
| hierarchy, visual weight | hierarchy |
| responsive, mobile | responsive |
## Target Detection
| Signal | Target Type |
|--------|-------------|
| URL provided (http/https) | url |
| File path provided (.tsx, .css, .html) | component |
| "all", "full site", "entire", "everything" | full_site |
| Directory path | directory |
## Complexity Scoring
| Factor | Points |
|--------|--------|
| Single component / single URL | +1 |
| Multiple components | +2 |
| Full site | +3 |
| Multiple dimensions targeted | +1 |
| Chrome DevTools required | +1 |
| Responsive checks needed | +1 |
Results: 1-2 Low (scan-only), 3-4 Medium (targeted), 5+ High (full)
## Output
Write scope context to coordinator memory:
```json
{
"pipeline_mode": "<scan-only|targeted|full>",
"target": "<url|component-path|full_site>",
"target_type": "<url|component|directory|full_site>",
"dimension_filters": ["<dimension-names or empty for all>"],
"complexity": { "score": 0, "level": "Low|Medium|High" }
}
```

View File

@@ -0,0 +1,167 @@
# Command: Dispatch
Create the UI polish task chain with correct dependencies and structured task descriptions. Supports scan-only, targeted, and full pipeline modes.
## Phase 2: Context Loading
| Input | Source | Required |
|-------|--------|----------|
| User requirement | From coordinator Phase 1 | Yes |
| Session folder | From coordinator Phase 2 | Yes |
| Pipeline mode | From tasks.json `pipeline_mode` | Yes |
| Target | From tasks.json `target` (url/component/full_site) | Yes |
| Dimension filters | From tasks.json (targeted mode only) | No |
1. Load user requirement and polish scope from tasks.json
2. Load pipeline stage definitions from specs/pipelines.md
3. Read `pipeline_mode`, `target`, and `dimension_filters` from tasks.json
## Phase 3: Task Chain Creation (Mode-Branched)
### Task Entry Template
Each task in tasks.json `tasks` object:
```json
{
"<TASK-ID>": {
"title": "<concise title>",
"description": "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>\nTASK:\n - <step 1: specific action>\n - <step 2: specific action>\n - <step 3: specific action>\nCONTEXT:\n - Session: <session-folder>\n - Target: <url|component-path|full_site>\n - Dimension filters: <all | specific dimensions>\n - Upstream artifacts: <artifact-1>, <artifact-2>\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <deliverable path> + <quality criteria>\nCONSTRAINTS: <scope limits, focus areas>",
"role": "<role-name>",
"prefix": "<PREFIX>",
"deps": ["<dependency-list>"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
### Mode Router
| Mode | Action |
|------|--------|
| `scan-only` | Create 2 tasks: SCAN -> DIAG |
| `targeted` | Create 4 tasks: SCAN -> DIAG -> OPT -> VERIFY |
| `full` | Create 4 tasks: SCAN -> DIAG -> OPT -> VERIFY (with GC loop enabled) |
---
### Scan-Only Pipeline Task Chain
**SCAN-001** (scanner):
```json
{
"SCAN-001": {
"title": "8-dimension UI audit against Impeccable design standards",
"description": "PURPOSE: Scan UI against Impeccable's 8 audit dimensions to discover all design problems | Success: Complete scan report with per-dimension scores and issue inventory\nTASK:\n - Load target files or take screenshots via Chrome DevTools\n - Extract color values, font definitions, spacing values, animation declarations\n - Score all 8 dimensions: anti-patterns, color, typography, spacing, motion, interaction, hierarchy, responsive\n - Generate issue inventory with file:line locations and severity\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - Dimension filters: all\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/scan/scan-report.md | 8-dimension scored report with issue inventory\nCONSTRAINTS: Read-only analysis | Reference specs/anti-patterns.md and specs/design-standards.md",
"role": "scanner",
"prefix": "SCAN",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**DIAG-001** (diagnostician):
```json
{
"DIAG-001": {
"title": "Root cause analysis and fix dependency graph",
"description": "PURPOSE: Deep-dive root cause analysis of scan findings, classify severity, group systemic vs one-off | Success: Prioritized diagnosis with fix dependency graph\nTASK:\n - Read scan report and classify each issue as systemic or one-off\n - Group issues by root cause\n - Build fix dependency graph (which fixes must come first)\n - Prioritize by severity (P0 -> P1 -> P2 -> P3)\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: scan/scan-report.md\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/diagnosis/diagnosis-report.md | Root cause groups with fix strategies and dependency graph\nCONSTRAINTS: Read-only analysis | Reference specs/fix-strategies.md",
"role": "diagnostician",
"prefix": "DIAG",
"deps": ["SCAN-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
---
### Targeted Pipeline Task Chain
Same as scan-only SCAN-001 and DIAG-001, plus:
**Note**: For targeted mode, SCAN-001 description adds dimension filter:
```
- Dimension filters: <specific dimensions from analyze output>
```
**OPT-001** (optimizer):
```json
{
"OPT-001": {
"title": "Apply targeted fixes following Impeccable design standards",
"description": "PURPOSE: Apply targeted fixes for specified dimensions following Impeccable design standards | Success: All P0/P1 issues in targeted dimensions resolved\nTASK:\n - Read diagnosis report for prioritized fix plan\n - Apply fixes in dependency order (systemic first, then one-off)\n - Follow Impeccable fix strategies per dimension\n - Self-validate: no regressions, code compiles/lints\nCONTEXT:\n - Session: <session-folder>\n - Dimension filters: <targeted dimensions>\n - Upstream artifacts: scan/scan-report.md, diagnosis/diagnosis-report.md\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: Modified source files + <session>/optimization/fix-log.md | Each fix documented with before/after\nCONSTRAINTS: Only fix targeted dimensions | Reference specs/fix-strategies.md and specs/design-standards.md",
"role": "optimizer",
"prefix": "OPT",
"deps": ["DIAG-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**VERIFY-001** (verifier):
```json
{
"VERIFY-001": {
"title": "Verify fixes improved scores without regressions",
"description": "PURPOSE: Verify fixes improved scores without introducing regressions | Success: Score improved or maintained in all dimensions, zero regressions\nTASK:\n - Re-scan fixed code against same 8 dimensions\n - Calculate before/after score delta per dimension\n - Check for regressions (new issues introduced by fixes)\n - Take after screenshots if Chrome DevTools available\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: scan/scan-report.md, optimization/fix-log.md\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: <session>/verification/verify-report.md | Before/after comparison with regression check\nCONSTRAINTS: Read-only verification | Signal fix_required if regressions found",
"role": "verifier",
"prefix": "VERIFY",
"deps": ["OPT-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
---
### Full Pipeline Task Chain
Same as targeted pipeline. The difference is in GC loop behavior:
- When VERIFY-001 reports `fix_required`, coordinator creates OPT-fix task (see monitor.md)
- Full mode enables GC loop; targeted mode does not create GC fix tasks
---
### GC Fix Task Template (created by monitor.md when verify fails)
```json
{
"OPT-fix-<round>": {
"title": "Address verification regressions from round <round>",
"description": "PURPOSE: Address verification regressions from round <round> | Success: All regressions resolved, no new issues\nTASK:\n - Parse verification feedback for specific regressions\n - Apply targeted fixes for regression issues only\n - Self-validate before reporting\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: verification/verify-report.md, optimization/fix-log.md\n - Shared memory: <session>/wisdom/.msg/meta.json\nEXPECTED: Updated source files + appended <session>/optimization/fix-log.md\nCONSTRAINTS: Fix regressions only, do not expand scope",
"role": "optimizer",
"prefix": "OPT",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
Then create new VERIFY task with deps on OPT-fix.
## Phase 4: Validation
Verify task chain integrity:
| Check | Method | Expected |
|-------|--------|----------|
| Task count correct | tasks.json count | scan-only: 2, targeted: 4, full: 4 |
| Dependencies correct | Trace dependency graph | Acyclic, correct deps |
| No circular dependencies | Trace dependency graph | Acyclic |
| Task IDs use correct prefixes | Pattern check | SCAN/DIAG/OPT/VERIFY |
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
If validation fails, fix the specific task and re-validate.

View File

@@ -0,0 +1,230 @@
# Monitor Pipeline
Synchronous pipeline coordination using spawn_agent + wait_agent.
## Constants
- WORKER_AGENT: team_worker
- MAX_GC_ROUNDS: 2
## Handler Router
| Source | Handler |
|--------|---------|
| "capability_gap" | handleAdapt |
| "check" or "status" | handleCheck |
| "resume" or "continue" | handleResume |
| All tasks completed | handleComplete |
| Default | handleSpawnNext |
## handleCallback
Worker completed (wait_agent returns). Process and advance.
1. Determine role from completed task prefix:
| Task Prefix | Role |
|-------------|------|
| `SCAN-*` | scanner |
| `DIAG-*` | diagnostician |
| `OPT-*` | optimizer |
| `VERIFY-*` | verifier |
2. Mark task completed in tasks.json: `state.tasks[taskId].status = 'completed'`
3. Record completion in session state
4. Check checkpoint for completed task:
| Completed Task | Checkpoint | Action |
|---------------|------------|--------|
| SCAN-001 | - | Notify user: scan complete, proceed to diagnosis |
| DIAG-001 | - | Check pipeline mode: scan-only -> handleComplete, else proceed to OPT |
| OPT-001 / OPT-fix-* | - | Proceed to VERIFY |
| VERIFY-001 / VERIFY-* | GC Checkpoint | Check verify signal -> GC loop or handleComplete |
5. **GC Checkpoint handling** (VERIFY task completed):
Read verify signal from result: `verify_passed`, `verify_failed`, or `fix_required`
| Signal | Condition | Action |
|--------|-----------|--------|
| `verify_passed` | No regressions, score_delta >= 0 | GC converged -> handleComplete |
| `verify_failed` | Regressions found but non-critical | gc_rounds < max -> create OPT-fix task |
| `fix_required` | Score dropped or critical regressions | gc_rounds < max -> create OPT-fix task (CRITICAL) |
| Any | gc_rounds >= max | Escalate to user |
**GC Fix Task Creation** (add to tasks.json):
```json
{
"OPT-fix-<round>": {
"title": "Address verification regressions",
"description": "PURPOSE: Address verification regressions | Success: All regressions resolved\nTASK:\n - Parse verification feedback for specific regressions\n - Apply targeted fixes for regression issues only\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: verification/verify-report.md",
"role": "optimizer",
"prefix": "OPT",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
Then create new VERIFY task in tasks.json with deps on fix. Increment gc_state.round.
**GC Escalation Options** (when max rounds exceeded):
1. Accept current state - skip further fixes, complete pipeline
2. Try one more round
3. Terminate
6. -> handleSpawnNext
## handleCheck
Read-only status report from tasks.json, then STOP.
```
Pipeline Status (<pipeline-mode>):
[DONE] SCAN-001 (scanner) -> scan-report.md
[DONE] DIAG-001 (diagnostician) -> diagnosis-report.md
[RUN] OPT-001 (optimizer) -> applying fixes...
[WAIT] VERIFY-001 (verifier) -> blocked by OPT-001
GC Rounds: 0/2
Score: <before-score>/32 -> pending
Session: <session-id>
Commands: 'resume' to advance | 'check' to refresh
```
Output status -- do NOT advance pipeline.
## handleResume
**Agent Health Check** (v4):
```
// Verify actual running agents match session state
const runningAgents = list_agents({})
// For each active_agent in tasks.json:
// - If agent NOT in runningAgents -> agent crashed
// - Reset that task to pending, remove from active_agents
// This prevents stale agent references from blocking the pipeline
```
1. Audit tasks.json for inconsistencies:
- Tasks stuck in "in_progress" -> reset to "pending"
- Tasks with completed deps but still "pending" -> include in spawn list
2. -> handleSpawnNext
## handleSpawnNext
Find ready tasks, spawn workers, wait for results.
1. Read tasks.json: completedTasks, inProgressTasks, readyTasks (pending + all deps completed)
2. No ready + work in progress -> report waiting, STOP
3. No ready + nothing in progress -> handleComplete
4. Has ready -> for each:
a. Check inner loop role with active worker -> skip (worker picks up)
b. Update task status to in_progress in tasks.json
c. team_msg log -> task_unblocked
d. Spawn team_worker:
```javascript
// 1) Update status in tasks.json
state.tasks[taskId].status = 'in_progress'
// 2) Spawn worker
const agentId = spawn_agent({
agent_type: "team_worker",
task_name: taskId, // e.g., "SCAN-001" -- enables named targeting
items: [
{ type: "text", text: `## Role Assignment
role: ${role}
role_spec: ${skillRoot}/roles/${role}/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${taskDescription}
inner_loop: ${innerLoop}` },
{ type: "text", text: `Read role_spec file to load Phase 2-4 domain instructions.
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).` }
]
})
// 3) Track agent
state.active_agents[taskId] = { agentId, role, started_at: now }
// 4) Wait for completion -- use task_name for stable targeting (v4)
const waitResult = wait_agent({ targets: [taskId], timeout_ms: 900000 })
if (waitResult.timed_out) {
state.tasks[taskId].status = 'timed_out'
close_agent({ target: taskId })
delete state.active_agents[taskId]
} else {
// 5) Collect results and update tasks.json
state.tasks[taskId].status = 'completed'
close_agent({ target: taskId }) // Use task_name, not agentId
delete state.active_agents[taskId]
}
```
**Spawn rules by mode**:
| Mode | Behavior |
|------|----------|
| scan-only | Sequential: SCAN-001 then DIAG-001 |
| targeted | Sequential: SCAN -> DIAG -> OPT -> VERIFY |
| full | Sequential: SCAN -> DIAG -> OPT -> VERIFY, then GC loop if verify triggers |
**Cross-Agent Supplementary Context** (v4):
When spawning workers in a later pipeline phase, send upstream results as supplementary context to already-running workers:
```
// Example: Send scan results to running diagnostician
send_message({
target: "<running-agent-task-name>",
items: [{ type: "text", text: `## Supplementary Context\n${upstreamFindings}` }]
})
// Note: send_message queues info without interrupting the agent's current work
```
Use `send_message` (not `assign_task`) for supplementary info that enriches but doesn't redirect the agent's current task.
5. Update tasks.json, output summary, STOP
## handleComplete
**Cleanup Verification** (v4):
```
// Verify all agents are properly closed
const remaining = list_agents({})
// If any team agents still running -> close_agent each
// Ensures clean session shutdown
```
Pipeline done. Generate report and completion action.
**Completion check by mode**:
| Mode | Completion Condition |
|------|---------------------|
| scan-only | SCAN-001 + DIAG-001 completed |
| targeted | All 4 tasks (+ any fix tasks) completed |
| full | All 4 tasks (+ any fix tasks) completed |
1. If any tasks not completed -> handleSpawnNext
2. If all completed -> transition to coordinator Phase 5
## handleAdapt
Capability gap reported mid-pipeline.
1. Parse gap description
2. Check if existing role covers it -> redirect
3. Role count < 5 -> generate dynamic role spec
4. Create new task in tasks.json, spawn worker
5. Role count >= 5 -> merge or pause
## Fast-Advance Reconciliation
On every coordinator wake:
1. Read tasks.json for completed tasks
2. Sync active_agents with actual state
3. No duplicate spawns

View File

@@ -0,0 +1,213 @@
# Coordinator Role
UI Polish Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages linear task chains (scan -> diagnose -> optimize -> verify) with optimizer<->verifier GC loops.
## Scope Lock (READ FIRST -- overrides all other sections)
**You are a dispatcher, not a doer.** Your ONLY outputs are:
- Session state files (`.workflow/.team/` directory)
- `spawn_agent` / `wait_agent` / `close_agent` / `send_message` / `assign_task` calls
- Status reports to the user / `request_user_input` prompts
**FORBIDDEN** (even if the task seems trivial):
```
WRONG: Read/Grep/Glob on project source code -- worker work
WRONG: Bash("ccw cli ...") -- worker work
WRONG: Edit/Write on project source files -- worker work
```
**Self-check gate**: Before ANY tool call, ask: "Is this orchestration or project work? If project work -> STOP -> spawn worker."
---
## Identity
- **Name**: coordinator | **Tag**: [coordinator]
- **Responsibility**: Analyze task -> Create session -> Dispatch tasks -> Monitor progress -> Report results
## Boundaries
### MUST
- All output (team_msg, logs) must carry `[coordinator]` identifier
- Use `team_worker` agent type for all worker spawns (NOT `general-purpose`)
- Dispatch tasks with proper dependency chains and deps in tasks.json
- Monitor worker progress via wait_agent and process results
- Handle Generator-Critic loops (optimizer<->verifier) with max 2 iterations
- Maintain session state persistence (tasks.json)
- **Always proceed through full Phase 1-5 workflow, never skip to direct execution**
- Use `send_message` for supplementary context (non-interrupting) and `assign_task` for triggering new work
- Use `list_agents` for session resume health checks and cleanup verification
### MUST NOT
- Implement domain logic (scanning, diagnosing, optimizing, verifying) -- workers handle this
- Spawn workers without creating tasks first
- Force-advance pipeline past failed verification
- Modify source code or design artifacts directly -- delegate to workers
- Omit `[coordinator]` identifier in any output
- Call CLI tools (ccw cli) -- only workers use CLI
## Command Execution Protocol
When coordinator needs to execute a command (analyze, dispatch, monitor):
1. Read `commands/<command>.md`
2. Follow the workflow defined in the command
3. Commands are inline execution guides, NOT separate agents
4. Execute synchronously, complete before proceeding
## Entry Router
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
| Capability gap | Message contains "capability_gap" | -> handleAdapt (monitor.md) |
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
| Interrupted session | Active/paused session exists in .workflow/.team/UIP-* | -> Phase 0 |
| New session | None of above | -> Phase 1 |
For check/resume/adapt/complete: load `@commands/monitor.md`, execute matched handler, STOP.
## Phase 0: Session Resume Check
1. Scan `.workflow/.team/UIP-*/tasks.json` for active/paused sessions
2. No sessions -> Phase 1
3. Single session -> reconcile (read tasks.json, reset in_progress->pending, kick first ready task)
4. Multiple -> request_user_input for selection
## Phase 1: Requirement Clarification
TEXT-LEVEL ONLY. No source code reading.
1. Parse task description from arguments
2. Detect polish scope:
| Signal | Pipeline Mode |
|--------|---------------|
| "scan", "audit", "check", "report", "analyze" | scan-only |
| "fix color", "fix typography", specific dimension keyword | targeted |
| "polish", "fix all", "full", "improve", "clean up" | full |
| Unclear | ask user |
3. Ask for missing parameters if scope unclear:
```
request_user_input({
questions: [
{ question: "What should I polish?", header: "Target", options: [
{ label: "URL", description: "Live page URL for Chrome DevTools analysis" },
{ label: "Component path", description: "Specific component files to polish" },
{ label: "Full site", description: "Scan and polish entire frontend" }
]},
{ question: "Polish mode?", header: "Mode", options: [
{ label: "Scan only", description: "Discover + diagnose, report only" },
{ label: "Targeted fix", description: "Fix specific dimensions" },
{ label: "Full polish", description: "Complete polish cycle" }
]}
]
})
```
4. Delegate to `@commands/analyze.md` -> output scope context
5. Record: pipeline_mode, target, complexity, dimension_filters
## Phase 2: Create Session + Initialize
1. Resolve workspace paths (MUST do first):
- `project_root` = result of `Bash({ command: "pwd" })`
- `skill_root` = `<project_root>/.codex/skills/team-ui-polish`
2. Generate session ID: `UIP-<slug>-<YYYY-MM-DD>`
3. Create session folder structure:
```
.workflow/.team/UIP-<slug>-<date>/scan/
.workflow/.team/UIP-<slug>-<date>/diagnosis/
.workflow/.team/UIP-<slug>-<date>/optimization/
.workflow/.team/UIP-<slug>-<date>/verification/
.workflow/.team/UIP-<slug>-<date>/evidence/
.workflow/.team/UIP-<slug>-<date>/wisdom/
.workflow/.team/UIP-<slug>-<date>/.msg/
```
4. Initialize `.msg/meta.json` via team_msg state_update with pipeline metadata
5. Write initial tasks.json:
```json
{
"session_id": "<id>",
"pipeline_mode": "<scan-only|targeted|full>",
"target": "<url|component-path|full_site>",
"created_at": "<ISO timestamp>",
"gc_rounds": 0,
"max_gc_rounds": 2,
"active_agents": {},
"tasks": {}
}
```
6. Do NOT spawn workers yet - deferred to Phase 4
## Phase 3: Create Task Chain
Delegate to `@commands/dispatch.md`. Task chains by mode:
| Mode | Task Chain |
|------|------------|
| scan-only | SCAN-001 -> DIAG-001 |
| targeted | SCAN-001 -> DIAG-001 -> OPT-001 -> VERIFY-001 |
| full | SCAN-001 -> DIAG-001 -> OPT-001 -> VERIFY-001 (GC loop if verify fails) |
## Phase 4: Spawn-and-Wait
Delegate to `@commands/monitor.md#handleSpawnNext`:
1. Find ready tasks (pending + deps resolved)
2. Spawn team_worker agents via spawn_agent, wait_agent for results
3. Output status summary
4. STOP
## Phase 5: Report + Completion Action
1. Read session state -> collect all results
2. List deliverables:
| Deliverable | Path |
|-------------|------|
| Scan Report | <session>/scan/scan-report.md |
| Diagnosis Report | <session>/diagnosis/diagnosis-report.md |
| Optimization Log | <session>/optimization/fix-log.md |
| Verification Report | <session>/verification/verify-report.md |
| Before/After Screenshots | <session>/evidence/*.png |
3. Calculate summary:
- `issues_found`: total from scan report
- `issues_fixed`: total from optimization log
- `issues_remaining`: issues_found - issues_fixed + regressions
- `before_score`: original scan score (out of 32)
- `after_score`: verification re-scan score (out of 32)
- `gc_rounds`: number of optimizer<->verifier iterations
4. Output pipeline summary with [coordinator] prefix
5. Execute completion action:
```
request_user_input({
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
{ label: "Archive & Clean", description: "Archive session and clean up resources" },
{ label: "Keep Active", description: "Keep session for follow-up work" },
{ label: "Export Results", description: "Export deliverables to specified location" }
]}]
})
```
## v4 Coordination Patterns
### Message Semantics
- **send_message**: Queue supplementary info to a running agent. Does NOT interrupt current processing. Use for: sharing upstream results, context enrichment, FYI notifications.
- **assign_task**: Assign new work and trigger processing. Use for: waking idle agents, redirecting work, requesting new output.
### Agent Lifecycle Management
- **list_agents({})**: Returns all running agents. Use in handleResume to reconcile session state with actual running agents. Use in handleComplete to verify clean shutdown.
- **Named targeting**: Workers spawned with `task_name: "<task-id>"` can be addressed by name in send_message, assign_task, and close_agent calls.
## Error Handling
| Error | Resolution |
|-------|------------|
| Task timeout | Log, mark failed, ask user to retry or skip |
| Worker crash | Reset task to pending, respawn worker |
| Dependency cycle | Detect, report to user, halt |
| Invalid scope | Reject with error, ask to clarify |
| Session corruption | Attempt recovery, fallback to manual reconciliation |
| GC loop stuck > 2 rounds | Escalate to user: accept / try one more / terminate |
| Chrome DevTools unavailable | Continue without screenshots, note in report |

View File

@@ -0,0 +1,164 @@
---
role: diagnostician
prefix: DIAG
inner_loop: false
message_types: [diag_complete, diag_progress, error]
---
# Root Cause Diagnostician
Deep-dive root cause analysis of discovered design problems. Classify severity, group systemic vs one-off issues, build fix dependency graph, and map each issue group to Impeccable fix strategies.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Scan report | <session>/scan/scan-report.md | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Fix strategies | specs/fix-strategies.md | Yes |
| Design standards | specs/design-standards.md | Yes |
1. Extract session path from task description
2. Read scan report: parse per-dimension scores, issue inventory, systemic patterns
3. Read specs/fix-strategies.md for issue-to-fix mapping
4. Read specs/design-standards.md for target state reference
## Phase 3: Root Cause Analysis
### Step 1: Issue Classification
For each issue in the scan report, classify:
| Classification | Definition | Example |
|---------------|------------|---------|
| Systemic | Affects whole project, single root cause creates many symptoms | "No design token system" causes 15 hard-coded color issues |
| One-off | Single component, isolated fix | Button missing hover state in one component |
### Step 2: Root Cause Grouping
Group issues by shared root cause. Common root cause patterns:
| Root Cause | Typical Symptoms |
|------------|-----------------|
| No design token system | Hard-coded colors, inconsistent spacing, no theme support |
| AI-generated template | Multiple AI slop tells (gradient text, glassmorphism, generic fonts) |
| No typography system | Muddy hierarchy, arbitrary font sizes, no modular scale |
| No spacing scale | Arbitrary spacing values, monotonous rhythm, no gap usage |
| No motion system | Random durations, bad easing, no reduced-motion |
| Missing state layer | No hover/focus/active/disabled/loading across components |
| No responsive strategy | Fixed widths, missing breakpoints, small mobile targets |
| No hierarchy design | Everything same weight, no squint test pass, size-only hierarchy |
### Step 3: Priority Assignment
For each root cause group:
| Priority | Criteria |
|----------|----------|
| P0 | Contains any blocking issue (WCAG AA failure, missing focus, horizontal scroll, no viewport meta) |
| P1 | Contains major issues (pure black/white, contrast near-fail, missing hover/loading) |
| P2 | Contains minor issues (no OKLCH, overused fonts, monotonous spacing) |
| P3 | Polish only (missing exit animation, no container queries, optical adjustments) |
### Step 4: Fix Strategy Mapping
For each root cause group, map to Impeccable fix strategy (from specs/fix-strategies.md):
| Root Cause | Fix Strategy | Effort |
|------------|-------------|--------|
| No token system | Create token file, tokenize all values | systemic, high |
| AI template aesthetic | Break templates, add intentional design | systemic, high |
| No type system | Define modular scale, apply across project | systemic, medium |
| No spacing scale | Define 4pt scale, replace arbitrary values | systemic, medium |
| No motion system | Create motion tokens, fix easing/duration | systemic, medium |
| Missing states | Add state CSS to each component | distributed, medium |
| No responsive | Add media queries, fix widths/targets | distributed, high |
| Individual issues | Component-level fixes | one-off, low |
### Step 5: Fix Dependency Graph
Build ordered dependency graph:
```
1. Design token system (if missing) -- everything else depends on this
2. Color fixes (pure black/white, contrast) -- visual foundation
3. Typography system -- content hierarchy
4. Spacing scale -- layout foundation
5. Anti-AI-slop cleanup -- requires tokens, colors, type to be in place
6. Motion system -- independent
7. Interaction states -- independent per component
8. Visual hierarchy -- requires typography + spacing
9. Responsive fixes -- last, tests everything together
```
Rules:
- Token system MUST come before individual token consumption fixes
- Color fixes before anti-slop (anti-slop fixes may adjust colors)
- Typography before hierarchy (hierarchy depends on type scale)
- Responsive fixes last (they validate all other fixes at different viewports)
## Phase 4: Validate Diagnosis Completeness
| Check | Pass Criteria |
|-------|---------------|
| All issues covered | Every issue from scan report appears in at least one root cause group |
| No orphan issues | No issues without a root cause group |
| Fix strategies assigned | Every root cause group has a fix strategy |
| Dependencies valid | Dependency graph is acyclic |
| Priority consistent | Group priority matches highest-severity issue in group |
Output: `<session>/diagnosis/diagnosis-report.md`
Report structure:
```markdown
# Diagnosis Report
## Summary
- Total issues: N (P0: X, P1: X, P2: X, P3: X)
- Root cause groups: N
- Systemic issues: N
- One-off issues: N
- Estimated effort: <low|medium|high>
## Root Cause Groups (by priority)
### [P0] <Root Cause Name>
- **Type**: systemic | one-off
- **Affected issues**: <count>
- **Affected files**: <file list>
- **Description**: <what is fundamentally wrong>
- **Fix strategy**: <from fix-strategies.md>
- **Effort**: <quick fix | medium | systemic change>
- **Dependencies**: <which other fixes must come first>
- **Issues in this group**:
| # | Location | Severity | Description |
|---|----------|----------|-------------|
| 1 | file:line | P0 | ... |
### [P1] <Root Cause Name>
...
## Fix Dependency Graph
<ordered list of fix phases>
## Recommended Fix Order
1. <fix phase 1>: <root cause groups to address>
2. <fix phase 2>: <root cause groups to address>
...
## Metadata
- Source: <session>/scan/scan-report.md
- Original score: X/32
- Timestamp: <ISO timestamp>
```
After writing the report, update session state:
```
mcp__ccw-tools__team_msg(session_id, role="diagnostician", type="diag_complete", content="Diagnosis complete. Root cause groups: N. Systemic: N. Fix phases: N.")
```
Then use `report_agent_job_result` to signal completion to coordinator:
```
report_agent_job_result({ result: "[diagnostician] DIAG-001 complete. Root cause groups: N (P0: X, P1: X, P2: X, P3: X). Systemic: N, One-off: N. Report: <session>/diagnosis/diagnosis-report.md" })
```

View File

@@ -0,0 +1,229 @@
---
role: optimizer
prefix: OPT
inner_loop: true
message_types: [opt_complete, opt_progress, error]
---
# UI Optimizer -- Targeted Fix Application
Apply targeted fixes following Impeccable design standards. Consumes diagnosis report and applies fixes in dependency order. Acts as Generator in the optimizer<->verifier Generator-Critic loop.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Scan report | <session>/scan/scan-report.md | Yes |
| Diagnosis report | <session>/diagnosis/diagnosis-report.md | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Fix strategies | specs/fix-strategies.md | Yes |
| Design standards | specs/design-standards.md | Yes |
| Verification feedback | <session>/verification/verify-report.md | Only for GC fix tasks |
1. Extract session path from task description
2. Read diagnosis report: parse root cause groups, fix dependency graph, recommended fix order
3. Read scan report: parse positive findings (things to preserve)
4. Read specs/fix-strategies.md and specs/design-standards.md for fix reference
5. Detect task type from subject: "OPT-001" -> initial optimization, "OPT-fix-*" -> GC fix round
6. If GC fix task: read verification feedback for specific regressions to fix
## Phase 3: Apply Fixes
Follow the fix dependency graph from diagnosis report. Apply fixes in order, one category at a time. After each category, self-validate before proceeding.
**CRITICAL**: Preserve positive findings from scan report. Do not break what already works.
---
### Fix Category 1: Anti-AI-Slop Fixes
Target: Root cause groups tagged with anti-patterns dimension.
| Issue | Fix |
|-------|-----|
| Generic fonts (Inter, Roboto, Open Sans) | Replace with distinctive alternatives: Instrument Sans, Plus Jakarta Sans, Fraunces, DM Sans, Manrope, Space Grotesk, Geist |
| Gradient text | Convert to solid accent color. Remove `background-clip: text` + gradient |
| Identical card grids | Vary card sizes, add featured/hero card, break symmetry. Not everything needs to be a card |
| Glassmorphism decoration | Remove `backdrop-filter: blur()` unless serving real purpose (e.g., overlays). Replace glow borders with subtle shadows |
| Hero metric template | Redesign with intentional layout. Vary metric sizes by importance. Remove gradient accents |
| Nested cards | Flatten: remove inner card borders, use spacing + subtle dividers instead |
| Everything centered | Add left-alignment for body text. Use asymmetric layouts. Vary alignment per section |
| All buttons primary | Create button hierarchy: 1 primary, ghost/outline for secondary, text links for tertiary |
| Same spacing everywhere | Introduce spacing rhythm: tighter within groups, generous between sections |
| Bounce/elastic easing | Replace with exponential curves: `cubic-bezier(0.25, 1, 0.5, 1)` (ease-out-quart) |
---
### Fix Category 2: Color Fixes
Target: Root cause groups tagged with color dimension.
| Issue | Fix |
|-------|-----|
| Pure black (#000) | Replace with tinted near-black: `oklch(0.15 0.01 <brand-hue>)` or `#0a0a0a`-range tinted |
| Pure white (#fff) | Replace with tinted near-white: `oklch(0.98 0.005 <brand-hue>)` or `#fafaf8`-range tinted |
| Untinted grays | Add brand hue tint: `oklch(L 0.005-0.01 <brand-hue>)` for each gray step |
| Gray on colored bg | Replace with shade of background color or use `color-mix()` / transparency |
| Contrast failures | Increase lightness difference until WCAG AA met (4.5:1 text, 3:1 large text, 3:1 UI) |
| No OKLCH | Convert key palette colors to `oklch()`. Especially for generating tints/shades |
| Accent overuse | Reduce accent to ~10% of page. Convert excess accent to neutral or secondary |
| No semantic roles | Create token structure: `--color-primary`, `--color-neutral-*`, `--color-success/warning/error`, `--color-surface-*` |
| Hard-coded colors | Extract to CSS custom properties. Create design token file if none exists |
---
### Fix Category 3: Typography Fixes
Target: Root cause groups tagged with typography dimension.
| Issue | Fix |
|-------|-----|
| Overused fonts | Replace with distinctive alternatives. Body: Plus Jakarta Sans, Instrument Sans, DM Sans. Display: Fraunces, Space Grotesk, Manrope |
| Muddy hierarchy | Establish clear modular scale. Remove intermediate sizes. Target: 5-7 distinct sizes |
| No modular scale | Define scale with ratio (1.25 major third, 1.333 perfect fourth, 1.5 perfect fifth). Base: 16px |
| Small body text | Set minimum `font-size: 1rem` (16px) for body. 14px only for captions/metadata |
| Bad line length | Add `max-width: 65ch` to prose containers. Min 45ch, max 75ch |
| Inconsistent line-height | Establish system: 1.5 for body, 1.2-1.3 for headings, 1.6-1.7 for small text |
| No fluid sizing | Add `clamp()` for h1-h3: e.g., `font-size: clamp(1.75rem, 1.2rem + 2vw, 3rem)` |
| Missing font-display | Add `font-display: swap` to all @font-face declarations |
---
### Fix Category 4: Spacing & Layout Fixes
Target: Root cause groups tagged with spacing dimension.
| Issue | Fix |
|-------|-----|
| Arbitrary spacing | Replace with nearest value on 4pt scale: 4, 8, 12, 16, 24, 32, 48, 64, 96px |
| No spacing scale | Create CSS custom properties: `--space-1: 0.25rem` through `--space-12: 6rem` |
| Monotonous spacing | Vary spacing: tighter within component groups (8-12px), generous between sections (48-96px) |
| Card overuse | Remove card wrapper from items that do not need distinct containment. Use spacing + dividers |
| Nested cards | Flatten inner cards. Remove inner borders. Use spacing or subtle background tint |
| Fixed widths | Replace `width: Npx` with `max-width` + `width: 100%` or grid/flex |
| Small touch targets | Set `min-height: 44px; min-width: 44px` on all interactive elements |
| Margin for siblings | Replace `margin-top/bottom` between siblings with `gap` on flex/grid parent |
---
### Fix Category 5: Motion Fixes
Target: Root cause groups tagged with motion dimension.
| Issue | Fix |
|-------|-----|
| Layout property animation | Replace `width/height/top/left/margin/padding` transitions with `transform` + `opacity` |
| Bad easing | Replace `ease`, `linear`, `ease-in-out` with `cubic-bezier(0.25, 1, 0.5, 1)` (ease-out-quart) |
| Bounce/elastic | Replace with exponential: `cubic-bezier(0.25, 1, 0.5, 1)` for enter, `cubic-bezier(0.5, 0, 0.75, 0)` for exit |
| No reduced-motion | Add: `@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }` |
| No motion tokens | Create: `--duration-instant: 100ms`, `--duration-fast: 150ms`, `--duration-normal: 250ms`, `--duration-slow: 400ms`, `--duration-entrance: 500ms` |
| Uncapped stagger | Cap at 10 items visible, total stagger <= 500ms. Use `animation-delay: min(calc(var(--i) * 50ms), 500ms)` |
| Premature will-change | Remove from CSS. Add via JS on `pointerenter`/`focusin`, remove on `animationend`/`transitionend` |
---
### Fix Category 6: Interaction State Fixes
Target: Root cause groups tagged with interaction dimension.
| Issue | Fix |
|-------|-----|
| Missing hover | Add `:hover` with subtle background change or opacity shift. Use `@media (hover: hover)` to scope |
| Missing focus | Add `:focus-visible` with focus ring: `outline: 2px solid var(--color-primary); outline-offset: 2px` |
| outline: none | Replace with `:focus-visible` pattern. Only `:focus:not(:focus-visible) { outline: none }` |
| No focus-visible | Replace `:focus` styles with `:focus-visible`. Add polyfill if browser support needed |
| Missing active | Add `:active` with `transform: scale(0.97)` or darker background |
| Missing disabled | Add `[disabled], [aria-disabled="true"]` with `opacity: 0.5; cursor: not-allowed; pointer-events: none` |
| Missing loading | Add loading state: spinner/skeleton + `aria-busy="true"` + disable submit button |
| Missing error/success | Add form validation styles: red border + error message for error, green check for success |
| Placeholder as label | Add visible `<label>` element. Keep placeholder as hint only. Use `aria-labelledby` if needed |
| Focus ring quality | Ensure: 2px solid accent, offset 2px, 3:1 contrast ratio against background |
---
### Fix Category 7: Visual Hierarchy Fixes
Target: Root cause groups tagged with hierarchy dimension.
| Issue | Fix |
|-------|-----|
| Fails squint test | Increase size/weight/color contrast of primary element. Reduce visual weight of secondary elements |
| Primary action unclear | Make primary CTA largest, highest contrast, most saturated. Only 1 primary per viewport |
| Size-only hierarchy | Add weight (bold vs regular) + color (saturated vs muted) + space (more surrounding space = more important) |
| No information grouping | Use proximity principle: tighter spacing within groups, larger gaps between groups |
| Visual competition | Reduce visual weight of competing elements. Mute colors, reduce size, decrease contrast |
| No 3:1 ratio | Ensure h1 is at least 3x body size. Each heading level should be 1.25-1.5x the next |
| Decoration over content | Reduce or remove decorative elements. Mute icon colors. Remove background decorations |
---
### Fix Category 8: Responsive Fixes
Target: Root cause groups tagged with responsive dimension.
| Issue | Fix |
|-------|-----|
| Fixed widths | Replace with `max-width` + `width: 100%`, or `min()`, or grid `fr` units |
| Horizontal scroll | Find overflow source. Add `overflow-x: hidden` on body only as last resort. Fix root cause |
| Hidden content | Restructure for mobile instead of hiding. Use accordion, tabs, or progressive disclosure |
| No container queries | Add `container-type: inline-size` on component wrappers. Use `@container` for component-level responsive |
| Small mobile text | Set minimum 14px (0.875rem) for all text on mobile. Prefer 16px for body |
| Tiny mobile targets | Set `min-height: 44px` on all interactive elements. Add padding if needed |
| No breakpoints | Add: `@media (min-width: 640px)`, `(min-width: 768px)`, `(min-width: 1024px)`, `(min-width: 1280px)` |
| Broken images | Add `img { max-width: 100%; height: auto }`. Use `object-fit` for fixed aspect ratios |
---
## Phase 4: Self-Validation & Output
1. After all fixes applied, validate:
| Check | Pass Criteria |
|-------|---------------|
| Code compiles | No syntax errors in modified files |
| Lint passes | No new lint errors introduced |
| No positive findings broken | Items from scan report "Positive Findings" section still intact |
| Fix log complete | Every applied fix documented |
2. Write fix log: `<session>/optimization/fix-log.md`
```markdown
# Optimization Fix Log
## Summary
- Fixes applied: N
- Files modified: N
- Categories addressed: <list>
- GC round: <1 | fix-N>
## Fixes Applied
### Category: <category name>
| # | File | Line | Before | After | Issue Ref |
|---|------|------|--------|-------|-----------|
| 1 | path/to/file.css | 42 | `color: #000` | `color: oklch(0.15 0.01 250)` | P1-Color-3 |
### Category: <next category>
...
## Files Modified
- `path/to/file.css`: <summary of changes>
- `path/to/file.tsx`: <summary of changes>
## Preserved (not modified)
- <positive findings that were intentionally kept>
## Metadata
- Source diagnosis: <session>/diagnosis/diagnosis-report.md
- Timestamp: <ISO timestamp>
```
3. Update session state and signal completion:
```
mcp__ccw-tools__team_msg(session_id, role="optimizer", type="opt_complete", content="Optimization complete. Fixes applied: N. Files modified: N. Categories: <list>.")
```
Then use `report_agent_job_result` to signal completion to coordinator:
```
report_agent_job_result({ result: "[optimizer] OPT-001 complete. Applied N fixes across N files. Categories: <list>. Log: <session>/optimization/fix-log.md" })
```

View File

@@ -0,0 +1,360 @@
---
role: scanner
prefix: SCAN
inner_loop: false
message_types: [scan_complete, scan_progress, error]
---
# UI Scanner -- 8-Dimension Design Audit
Scan existing UI against Impeccable's 8 audit dimensions to discover all design problems. This is the team's core diagnostic engine. Every issue found here drives the entire downstream pipeline.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Target files or URL | From task description | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Anti-patterns catalog | specs/anti-patterns.md | Yes |
| Design standards | specs/design-standards.md | Yes |
1. Extract session path and target from task description
2. Read specs/anti-patterns.md and specs/design-standards.md for reference criteria
3. Load target files based on target type:
- **URL target**: Use Chrome DevTools to navigate, take screenshots at 3 viewports:
- Mobile: `mcp__chrome-devtools__resize_page(width=375, height=812)` + screenshot
- Tablet: `mcp__chrome-devtools__resize_page(width=768, height=1024)` + screenshot
- Desktop: `mcp__chrome-devtools__resize_page(width=1440, height=900)` + screenshot
- Save to `<session>/evidence/before-mobile.png`, `before-tablet.png`, `before-desktop.png`
- **Component target**: Read CSS/SCSS, HTML, JS/TS/JSX/TSX files
- **Full site target**: Glob for all frontend source files (*.css, *.scss, *.tsx, *.jsx, *.html, *.vue, *.svelte)
4. Extract raw data for analysis:
- All color values (hex, rgb, hsl, oklch, named colors, CSS custom properties)
- All font declarations (font-family, font-size, font-weight, line-height)
- All spacing values (margin, padding, gap, inset)
- All animation/transition declarations
- All interactive pseudo-classes and state handling
5. If Chrome DevTools available: extract computed styles via `mcp__chrome-devtools__evaluate_script`
## Phase 3: 8-Dimension Scan
For each dimension, check every item in the checklist. Record each finding with:
- Location: file:line (or "screenshot: viewport" for visual-only issues)
- Severity: P0 (blocking) / P1 (major) / P2 (minor) / P3 (polish)
- Description: what is wrong and why it matters
- Evidence: the specific code or visual that triggers the finding
---
### Dimension 1: Anti-AI-Slop Detection (CRITICAL -- scan first)
**The AI Slop Test**: "If you showed this to someone and said 'AI made this,' would they believe you immediately? If yes, that is the problem."
Check for these AI-generated UI fingerprints:
| # | Pattern | What to Look For | Severity |
|---|---------|-------------------|----------|
| 1 | AI color palette | cyan-on-dark (#00d4ff, #06b6d4), purple-to-blue gradients, neon accents on dark backgrounds | P1 |
| 2 | Gradient text | `background-clip: text` + gradient on metrics, headings, or hero text for "impact" | P1 |
| 3 | Default dark mode | Dark background with glowing/neon accents as the default theme; avoids real design decisions | P2 |
| 4 | Glassmorphism everywhere | `backdrop-filter: blur()`, glass cards, glow borders (`box-shadow: 0 0 Xpx color`), used decoratively not functionally | P1 |
| 5 | Hero metric layout | Big number + small label + supporting stats in a row + gradient accent. The "AI dashboard" template | P2 |
| 6 | Identical card grids | Same-sized cards with icon + heading + body text repeated 3-6 times in a grid | P2 |
| 7 | Nested cards | Cards inside cards (`.card .card`, multiple layers of bordered containers) | P2 |
| 8 | Generic fonts | Inter, Roboto, Arial, Open Sans, Lato, Montserrat, system-ui used without intentional choice | P2 |
| 9 | Rounded rect + shadow | `border-radius: 8-16px` + `box-shadow: 0 1-4px 6-24px rgba(0,0,0,0.1)` on everything | P3 |
| 10 | Icon-above-heading | Large icons (24-48px) with rounded corners/background placed above every heading or card | P2 |
| 11 | One-side border accent | `border-left: 3-4px solid <accent>` or `border-top` as lazy accent on cards | P3 |
| 12 | Decorative sparklines | Tiny charts/graphs that look sophisticated but convey no actionable data | P2 |
| 13 | Bounce/elastic easing | `cubic-bezier(0.68, -0.55, 0.265, 1.55)` or spring animations. Dated, 2015 aesthetic | P2 |
| 14 | Redundant copy | Intro paragraphs that restate the heading. "Welcome to Dashboard. This dashboard shows..." | P3 |
| 15 | All buttons primary | Every button is filled/primary. No ghost buttons, text links, or secondary variants | P1 |
| 16 | Everything centered | `text-align: center` or `justify-content: center` on everything. No asymmetry | P2 |
| 17 | Same spacing everywhere | Identical margin/padding on all elements. No spacing rhythm or variation | P2 |
| 18 | Monospace as tech | Monospace fonts used for non-code content to appear "techy" | P3 |
| 19 | Modal overuse | Modals for confirmations, settings, forms -- when inline or drawer would work | P3 |
| 20 | Pure black/white | `#000000` or `#ffffff` without any tint toward brand hue | P1 |
**Scoring**:
- 0: AI slop gallery (5+ tells present)
- 1: Heavy AI influence (3-4 tells)
- 2: Some AI tells (1-2 noticeable)
- 3: Mostly clean (subtle traces only)
- 4: Distinctive (genuinely intentional design, zero AI tells)
---
### Dimension 2: Color Quality
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Pure black usage | `#000`, `#000000`, `rgb(0,0,0)` anywhere except borders/outlines | P1 |
| 2 | Pure white usage | `#fff`, `#ffffff`, `rgb(255,255,255)` for backgrounds without brand tint | P1 |
| 3 | Untinted grays | Gray values with chroma exactly 0 (pure gray). Should have chroma 0.005-0.01 toward brand hue | P2 |
| 4 | Gray on colored bg | Gray text (#666, #999, etc.) on colored backgrounds. Looks washed out. Use shade of background or transparency | P1 |
| 5 | WCAG AA contrast | Text contrast below 4.5:1 (normal text) or 3:1 (large text >= 18px/24px bold) | P0 |
| 6 | UI component contrast | Interactive component boundaries below 3:1 contrast against adjacent colors | P1 |
| 7 | No OKLCH | All colors in hex/rgb/hsl without oklch() for perceptual uniformity | P2 |
| 8 | Accent overuse | Accent color exceeds 10% of visual weight. Violates 60-30-10 rule (60% neutral, 30% secondary, 10% accent) | P2 |
| 9 | No semantic roles | Colors not organized into primary/neutral/semantic(success,warning,error)/surface layers | P2 |
| 10 | Hard-coded colors | Color values inline in components instead of CSS custom properties or design tokens | P2 |
| 11 | No dark/light tokens | Single-theme colors without alternate theme support | P3 |
**Scoring**:
- 0: Multiple contrast failures, pure black/white everywhere, no system
- 1: Contrast issues, hard-coded colors, no tokens
- 2: Basic contrast OK but no OKLCH, some hard-coded values
- 3: Good system with minor gaps (some untinted grays or missing tokens)
- 4: OKLCH-based, fully tokenized, WCAG AA+ compliant, proper 60-30-10
---
### Dimension 3: Typography Quality
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Overused fonts | Inter, Roboto, Open Sans, Lato, Montserrat, Arial without intentional justification | P2 |
| 2 | Muddy hierarchy | Too many close font sizes (e.g., 13/14/15/16/18). Should have clear steps | P1 |
| 3 | No modular scale | Font sizes without mathematical ratio (1.125, 1.2, 1.25, 1.333, 1.5, 1.618) | P2 |
| 4 | Small body text | Body/paragraph text below 16px (1rem) | P1 |
| 5 | Line length | Body text wider than 75ch or narrower than 45ch. Optimal: 65ch | P2 |
| 6 | Inconsistent line-height | Different line-heights without system. Should follow vertical rhythm | P2 |
| 7 | No fluid sizing | Headings without `clamp()` for responsive scaling. Fixed px that are too big on mobile or too small on desktop | P2 |
| 8 | Monospace misuse | Monospace fonts for non-code body content used as "tech" aesthetic | P3 |
| 9 | Missing font-display | No `font-display: swap` causing FOIT (flash of invisible text) | P2 |
| 10 | Too many font families | More than 2-3 font families in use (excluding monospace for code) | P2 |
| 11 | No fallback metrics | Custom fonts without `size-adjust`, `ascent-override` for CLS prevention | P3 |
**Scoring**:
- 0: Generic font, no scale, tiny text, no hierarchy
- 1: Overused font, muddy sizes, missing fluid sizing
- 2: Decent font choice but inconsistent scale or line-height
- 3: Good typography with minor gaps (missing clamp, slight inconsistencies)
- 4: Distinctive font, clear modular scale, fluid sizing, proper rhythm
---
### Dimension 4: Spacing & Layout Quality
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Arbitrary spacing | Spacing values outside a consistent scale (e.g., 7px, 13px, 22px, 37px) | P2 |
| 2 | No spacing scale | No evidence of 4pt base (4, 8, 12, 16, 24, 32, 48, 64, 96px) or similar system | P2 |
| 3 | Monotonous spacing | Same padding/margin value everywhere. No rhythm (tight groups + generous separations) | P2 |
| 4 | Card overuse | Everything wrapped in cards. Cards for single text items, cards for navigation, cards for everything | P2 |
| 5 | Nested cards | Cards inside cards. Multiple bordered containers creating visual noise | P1 |
| 6 | Fixed widths | Hard-coded pixel widths that break on different viewports | P1 |
| 7 | Small touch targets | Interactive elements below 44x44px (buttons, links, inputs on mobile) | P1 |
| 8 | Margin for siblings | Using `margin` between sibling elements instead of `gap` on parent | P3 |
| 9 | No optical adjustment | Purely mathematical centering without optical corrections (e.g., play button in circle) | P3 |
| 10 | No max-width on prose | Text containers without max-width causing ultra-wide line lengths | P2 |
**Scoring**:
- 0: Random spacing, nested cards, fixed widths, tiny touch targets
- 1: Some system but many arbitrary values, cards overused
- 2: Decent spacing but monotonous or missing rhythm
- 3: Good system with minor gaps (occasional arbitrary value)
- 4: Consistent scale, varied rhythm, gap usage, proper touch targets
---
### Dimension 5: Motion & Animation Quality
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Layout property animation | Animating `width`, `height`, `top`, `left`, `margin`, `padding` (causes layout thrashing) | P1 |
| 2 | Bad easing | Using `ease` (default), `linear`, or `ease-in-out` for UI transitions. Should use exponential curves | P2 |
| 3 | Bounce/elastic | `cubic-bezier(0.68, -0.55, 0.265, 1.55)` or similar bounce curves. Dated aesthetic | P2 |
| 4 | No reduced-motion | Missing `@media (prefers-reduced-motion: reduce)` query. Affects ~35% of adults over 40 | P0 |
| 5 | No motion tokens | No consistent duration/easing system. Random 200ms/300ms/0.5s values | P2 |
| 6 | Uncapped stagger | Stagger animation over 10 items or total duration > 500ms | P2 |
| 7 | Premature will-change | `will-change` set in CSS instead of activated on interaction (wastes GPU memory) | P3 |
| 8 | No exit animation | Elements appear with animation but disappear instantly | P3 |
| 9 | Slow feedback | Hover/focus/active feedback slower than 150ms | P2 |
| 10 | Animation on load | Heavy entrance animations on page load that delay content access | P2 |
**Scoring**:
- 0: Layout animations, no reduced-motion, bounce easing, no system
- 1: Some transform-based but bad easing, missing reduced-motion
- 2: Decent animations but no token system or missing reduced-motion
- 3: Good system with minor gaps (occasional bad easing, missing exit animation)
- 4: Transform+opacity only, exponential easing, reduced-motion, token system, proper stagger
---
### Dimension 6: Interaction States
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Missing hover | Interactive elements without `:hover` state (no pointer feedback) | P1 |
| 2 | Missing focus | Interactive elements without `:focus` state (keyboard users invisible) | P0 |
| 3 | outline: none | `outline: none` or `outline: 0` without replacement focus indicator | P0 |
| 4 | No focus-visible | Using `:focus` instead of `:focus-visible` (showing focus ring on mouse click) | P2 |
| 5 | Missing active | No `:active` / pressed state on buttons/links | P2 |
| 6 | Missing disabled | No visual distinction for disabled state, or `disabled` without opacity/cursor change | P2 |
| 7 | Missing loading | Async actions (form submit, API calls) without loading feedback | P1 |
| 8 | Missing error/success | Forms without error/success state indication | P1 |
| 9 | Placeholder as label | `placeholder` used as the only label for form inputs (disappears on focus) | P1 |
| 10 | No empty state | Lists/tables without empty state design (blank space when no data) | P2 |
| 11 | Focus ring quality | Focus ring not meeting 2px solid accent, offset 2px, 3:1 contrast spec | P2 |
**Scoring**:
- 0: No hover, no focus, outline:none everywhere, no loading states
- 1: Basic hover but missing focus/active, no loading states
- 2: Hover + focus exist but no focus-visible, missing some states
- 3: Most states present with minor gaps (missing empty state, imperfect focus ring)
- 4: All 8 states implemented, focus-visible, proper focus ring, loading/error/success/empty
---
### Dimension 7: Visual Hierarchy
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Fails squint test | When page is blurred/squinted, cannot identify 1st and 2nd most important elements | P1 |
| 2 | Primary action unclear | Cannot identify the primary action within 2 seconds of viewing | P1 |
| 3 | Size-only hierarchy | Hierarchy established only through font size, not combining size + weight + color + space | P2 |
| 4 | No information grouping | Related content not grouped by proximity. Equal spacing between related and unrelated items | P2 |
| 5 | Visual competition | Multiple elements competing for attention at the same visual weight | P1 |
| 6 | No 3:1 ratio | Less than 3:1 size ratio between major hierarchy levels (e.g., h1 vs body) | P2 |
| 7 | Decoration over content | Visual decorations (icons, borders, backgrounds) draw more attention than content | P2 |
| 8 | No progressive disclosure | All information shown at once. No layering of detail (summary -> detail on demand) | P3 |
**Scoring**:
- 0: Everything same visual weight, no clear action, fails squint test
- 1: Some size differences but no clear hierarchy system
- 2: Basic hierarchy via size but missing weight/color/space dimensions
- 3: Good hierarchy with minor issues (occasional visual competition)
- 4: Clear squint test pass, obvious primary action, multi-dimension hierarchy, progressive disclosure
---
### Dimension 8: Responsive Design
| # | Check | What to Look For | Severity |
|---|-------|-------------------|----------|
| 1 | Fixed widths | Hard-coded pixel widths that break below certain viewport sizes | P1 |
| 2 | Horizontal scroll | Content causing horizontal scrollbar on viewports >= 320px | P0 |
| 3 | Hidden content | Content hidden on mobile via `display:none` instead of being adapted/restructured | P2 |
| 4 | No container queries | Components that should adapt to container size still using viewport media queries only | P3 |
| 5 | Small mobile text | Text below 14px on mobile viewports (illegible without zoom) | P1 |
| 6 | Tiny mobile targets | Touch targets below 44x44px on mobile (frustrating to tap) | P1 |
| 7 | No breakpoints | Single layout for all viewports. No media queries or responsive grid | P1 |
| 8 | Broken images | Images that overflow or distort on narrow viewports (missing max-width:100%) | P1 |
| 9 | No viewport meta | Missing `<meta name="viewport" content="width=device-width, initial-scale=1">` | P0 |
| 10 | Desktop-first only | Only desktop layout works properly. Mobile is broken or unusable | P1 |
**Scoring**:
- 0: No responsive design, horizontal scroll, broken on mobile
- 1: Basic media queries but many breakage points
- 2: Decent mobile but some fixed widths or small targets
- 3: Good responsive with minor issues (missing container queries, occasional small target)
- 4: Fluid design, proper breakpoints, container queries, 44px targets, no overflow
---
### Dimension 9: Cognitive Load
Evaluate information processing burden per Impeccable's cognitive load principles.
| Check | Detection | Score Impact |
|-------|-----------|-------------|
| Information overload | >7 distinct data groups visible simultaneously without progressive disclosure | -1 per violation |
| Choice overload | >5 equally-weighted CTAs in one viewport | -1 |
| No progressive disclosure | All details shown at once, no expand/collapse or summary->detail | -1 |
| Redundant copy | Heading text repeated in body paragraph (>50% overlap) | -0.5 |
| Generic labels | "OK/Submit/Cancel" buttons without verb+object | -0.5 |
| Error without guidance | Error messages missing what+why+fix formula | -1 |
| Empty state without action | Data list shows "No data" without create/import guidance | -0.5 |
| No visual grouping | Related items not proximity-grouped or separated from unrelated | -1 |
### Dimension 10: Dark Mode Quality
Only score if dark mode exists. Skip and note "N/A -- no dark mode" if not present.
| Check | Detection | Score Impact |
|-------|-----------|-------------|
| Pure black background | #000 or rgb(0,0,0) as base background | -2 |
| Same font weights as light | No weight reduction in dark theme | -1 |
| Saturated accents on dark | Same chroma values as light theme (vibrating colors) | -1 |
| No surface hierarchy | All dark surfaces same lightness (flat, no depth) | -1 |
| Dangerous combinations | Gray text on colored bg, saturated red-green adjacent | -1 |
---
## Phase 4: Generate Scan Report
Output: `<session>/scan/scan-report.md`
Report structure:
```markdown
# UI Polish Scan Report
## Overall Score: X/36 (<rating-band>)
## Anti-Patterns Verdict (Dimension 1)
Score: X/4
<verdict summary -- this section comes FIRST as it is most important>
<list of detected AI slop tells>
## Per-Dimension Scores
| Dimension | Score | Key Finding |
|-----------|-------|-------------|
| 1. Anti-Patterns | X/4 | <one-line summary> |
| 2. Color Quality | X/4 | <one-line summary> |
| 3. Typography | X/4 | <one-line summary> |
| 4. Spacing/Layout | X/4 | <one-line summary> |
| 5. Motion | X/4 | <one-line summary> |
| 6. Interaction States | X/4 | <one-line summary> |
| 7. Visual Hierarchy | X/4 | <one-line summary> |
| 8. Responsive | X/4 | <one-line summary> |
| 9. Cognitive Load | X/4 | <one-line summary> |
| 10. Dark Mode | X/4 or N/A | <one-line summary> |
## Issue Inventory
### P0 -- Blocking
| # | Dimension | Location | Description |
|---|-----------|----------|-------------|
| 1 | ... | file:line | ... |
### P1 -- Major
...
### P2 -- Minor
...
### P3 -- Polish
...
## Patterns & Systemic Issues
<recurring problems that affect multiple locations>
## Positive Findings
<what works well -- important for optimizer to not break>
## Scan Metadata
- Target: <target>
- Files scanned: <count>
- Screenshots: <yes/no, viewports>
- Timestamp: <ISO timestamp>
```
**Rating Bands** (total out of 36, or 40 with dark mode):
- 32-36: Excellent (36-40 with dark mode)
- 25-31: Good (29-35 with dark mode)
- 18-24: Acceptable (22-28 with dark mode)
- 11-17: Poor (15-21 with dark mode)
- 0-10: Critical (0-14 with dark mode)
After writing the report, update session state:
```
mcp__ccw-tools__team_msg(session_id, role="scanner", type="scan_complete", content="Scan complete. Score: X/36. P0: N, P1: N, P2: N, P3: N issues found.")
```
Then use `report_agent_job_result` to signal completion to coordinator:
```
report_agent_job_result({ result: "[scanner] SCAN-001 complete. Score: X/36 (<rating-band>). Issues: P0=N P1=N P2=N P3=N. Report: <session>/scan/scan-report.md" })
```

View File

@@ -0,0 +1,142 @@
---
role: verifier
prefix: VERIFY
inner_loop: false
message_types: [verify_passed, verify_failed, fix_required, error]
---
# Verification & Regression Check
Before/after comparison verification. Re-scan fixed code against same 8 dimensions, calculate improvement, detect regressions. Acts as Critic in the optimizer<->verifier Generator-Critic loop.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Original scan report | <session>/scan/scan-report.md | Yes |
| Fix log | <session>/optimization/fix-log.md | Yes |
| .msg/meta.json | <session>/wisdom/.msg/meta.json | Yes |
| Anti-patterns catalog | specs/anti-patterns.md | Yes |
| Design standards | specs/design-standards.md | Yes |
| Scoring guide | specs/scoring-guide.md | Yes |
1. Extract session path from task description
2. Read original scan report: parse before-scores per dimension and issue inventory
3. Read fix log: parse all fixes applied and files modified
4. Read specs for scoring reference
## Phase 3: Verification
### Step 1: Re-scan Fixed Code
Apply the same 8-dimension scan as the scanner role (reference roles/scanner/role.md Phase 3) to the current state of files. Use identical checklist items and scoring criteria.
If Chrome DevTools available:
- Take screenshots at same 3 viewports (mobile 375px, tablet 768px, desktop 1440px)
- Save to `<session>/evidence/after-mobile.png`, `after-tablet.png`, `after-desktop.png`
### Step 2: Calculate Score Delta
For each dimension, compare before and after:
| Dimension | Before | After | Delta | Status |
|-----------|--------|-------|-------|--------|
| 1. Anti-Patterns | X/4 | Y/4 | +/-N | improved/same/regressed |
| 2. Color Quality | X/4 | Y/4 | +/-N | improved/same/regressed |
| 3. Typography | X/4 | Y/4 | +/-N | improved/same/regressed |
| 4. Spacing/Layout | X/4 | Y/4 | +/-N | improved/same/regressed |
| 5. Motion | X/4 | Y/4 | +/-N | improved/same/regressed |
| 6. Interaction States | X/4 | Y/4 | +/-N | improved/same/regressed |
| 7. Visual Hierarchy | X/4 | Y/4 | +/-N | improved/same/regressed |
| 8. Responsive | X/4 | Y/4 | +/-N | improved/same/regressed |
| **Total** | X/32 | Y/32 | +/-N | |
### Step 3: Regression Detection
Check for NEW issues not present in original scan report:
| Check | Method |
|-------|--------|
| New issues introduced | Compare current issue inventory against original. Any issue not in original = regression |
| Score dropped | Any dimension score lower than before = regression |
| Positive findings broken | Items from original "Positive Findings" no longer hold |
| Build broken | Modified files have syntax errors or lint failures |
Classify regressions:
- **Critical**: Score dropped in any dimension, WCAG AA violation introduced, build broken
- **Non-critical**: New minor issues introduced but overall score improved
### Step 4: Determine Signal
| Condition | Signal |
|-----------|--------|
| No regressions AND total score >= before score | `verify_passed` |
| Non-critical regressions AND total score improved | `verify_failed` (fixable) |
| Critical regressions OR total score dropped | `fix_required` (urgent) |
## Phase 4: Generate Verification Report
Output: `<session>/verification/verify-report.md`
```markdown
# Verification Report
## Verdict: <PASSED | FAILED | FIX REQUIRED>
## Score Comparison
| Dimension | Before | After | Delta |
|-----------|--------|-------|-------|
| 1. Anti-Patterns | X/4 | Y/4 | +N |
| 2. Color Quality | X/4 | Y/4 | +N |
| 3. Typography | X/4 | Y/4 | +N |
| 4. Spacing/Layout | X/4 | Y/4 | +N |
| 5. Motion | X/4 | Y/4 | +N |
| 6. Interaction States | X/4 | Y/4 | +N |
| 7. Visual Hierarchy | X/4 | Y/4 | +N |
| 8. Responsive | X/4 | Y/4 | +N |
| **Total** | **X/32** | **Y/32** | **+N** |
## Before Rating: <rating-band> -> After Rating: <rating-band>
## Regressions Found
<list of regressions with location, severity, description>
<or "None" if clean>
## Remaining Issues
<issues from original scan that were NOT fixed>
## Improvements
<per-dimension improvement details>
## Screenshots
- Before: <session>/evidence/before-*.png
- After: <session>/evidence/after-*.png
<or "Chrome DevTools not available" if no screenshots>
## Metadata
- Original scan: <session>/scan/scan-report.md
- Fix log: <session>/optimization/fix-log.md
- GC round: <round number>
- Timestamp: <ISO timestamp>
```
After writing the report, send signal-appropriate message:
**If verify_passed**:
```
mcp__ccw-tools__team_msg(session_id, role="verifier", type="verify_passed", content="Verification passed. Score: before X/32 -> after Y/32 (+N). No regressions.")
report_agent_job_result({ result: "[verifier] VERIFY-001 passed. Score: X/32 -> Y/32 (+N). No regressions. Report: <session>/verification/verify-report.md" })
```
**If verify_failed**:
```
mcp__ccw-tools__team_msg(session_id, role="verifier", type="verify_failed", content="Verification failed. N non-critical regressions found. Score: X/32 -> Y/32.")
report_agent_job_result({ result: "[verifier] VERIFY-001 failed. N regressions (non-critical). Score: X/32 -> Y/32. Report: <session>/verification/verify-report.md" })
```
**If fix_required**:
```
mcp__ccw-tools__team_msg(session_id, role="verifier", type="fix_required", content="Fix required. N critical regressions. Score dropped: X/32 -> Y/32.")
report_agent_job_result({ result: "[verifier] VERIFY-001 fix_required. N critical regressions. Score: X/32 -> Y/32 (DROPPED). Report: <session>/verification/verify-report.md" })
```

View File

@@ -0,0 +1,141 @@
# Anti-Pattern Catalog
Complete catalog of UI design anti-patterns from Impeccable's design audit knowledge. Used by scanner for detection and optimizer for remediation.
## The AI Slop Test
> "If you showed this to someone and said 'AI made this,' would they believe you immediately? If yes, that is the problem."
AI-generated UIs share recognizable fingerprints. These are not inherently bad techniques -- they become problems when used as defaults without intentional design decisions. The issue is not the technique itself but the lack of thought behind it.
## AI Slop Tells (20 Items)
### 1. AI Color Palette
**Pattern**: Cyan-on-dark (#00d4ff, #06b6d4), purple-to-blue gradients (#8b5cf6 to #3b82f6), neon accents on dark backgrounds.
**Why it is a tell**: Every AI model defaults to the same "futuristic" palette. It signals zero design intent.
**Detection**: Search for cyan/purple/neon values on dark backgrounds. Check if palette could be from any Tailwind dark template.
**Severity**: P1
### 2. Gradient Text for Impact
**Pattern**: `background-clip: text` + gradient applied to metrics, headings, or hero text.
**Why it is a tell**: AI uses gradient text as a crutch to make numbers and titles feel "premium." Real typography achieves emphasis through weight, size, and space.
**Detection**: Search for `background-clip: text` or `-webkit-background-clip: text`.
**Severity**: P1
### 3. Default Dark Mode with Glowing Accents
**Pattern**: Dark background (gray-900/950) as default with glowing/neon accent colors. No light mode offered or light mode is an afterthought.
**Why it is a tell**: Dark mode with glow effects requires no real color decisions. It hides contrast problems and creates false sophistication.
**Detection**: Check default theme. If dark with glow `box-shadow` or neon colors, flag it.
**Severity**: P2
### 4. Glassmorphism Everywhere
**Pattern**: `backdrop-filter: blur()`, glass cards, glow borders (`box-shadow: 0 0 Xpx <color>`), used decoratively on multiple components.
**Why it is a tell**: Glassmorphism is a valid technique for specific use cases (overlays, elevated surfaces). AI applies it everywhere as the default "modern" aesthetic.
**Detection**: Count instances of `backdrop-filter: blur`. If > 2 components use it without functional reason, flag.
**Severity**: P1
### 5. Hero Metric Layout
**Pattern**: Big number (32-48px) + small label underneath + supporting stats in a row + gradient accent or colored bar.
**Why it is a tell**: This is the universal "AI dashboard" template. Every AI-generated analytics page uses this exact layout.
**Detection**: Pattern match for large-number + small-label structures repeated in a metrics row/grid.
**Severity**: P2
### 6. Identical Card Grids
**Pattern**: Same-sized cards with icon + heading + body text repeated 3-6 times in a grid. Equal width, equal height, equal spacing.
**Why it is a tell**: Real content varies in importance. AI treats all items as equally important because it has no content strategy.
**Detection**: Grid of 3+ cards with identical structure and sizing. No featured/hero card.
**Severity**: P2
### 7. Nested Cards
**Pattern**: Cards inside cards. `.card > .card-body > .inner-card`. Multiple layers of bordered containers.
**Why it is a tell**: AI nests containers to create visual "depth." It actually creates noise and makes hierarchy unclear.
**Detection**: Search for elements with border/shadow inside elements with border/shadow. Two levels of containment.
**Severity**: P2
### 8. Generic Fonts
**Pattern**: Inter, Roboto, Arial, Open Sans, Lato, Montserrat, system-ui used as primary font without intentional choice.
**Why it is a tell**: These are defaults. AI picks them because they are safe. Safe means forgettable.
**Detection**: Check `font-family` declarations. If primary font is in the generic list, flag.
**Severity**: P2
### 9. Rounded Rectangles with Generic Drop Shadows
**Pattern**: `border-radius: 8-16px` combined with `box-shadow: 0 1-4px 6-24px rgba(0,0,0,0.05-0.15)` on every container.
**Why it is a tell**: The "safe shape." Every AI output uses this exact combination because it is never wrong -- but never distinctive either.
**Detection**: Count elements with both border-radius (8-16px range) and generic box-shadow. If > 5, flag.
**Severity**: P3
### 10. Large Icons Above Every Heading
**Pattern**: 24-48px icons with rounded corners or colored backgrounds placed above every heading or card title.
**Why it is a tell**: AI uses icons as visual filler. Real design uses icons sparingly where they aid comprehension.
**Detection**: Pattern match for icon elements directly above heading elements. If repeated 3+ times, flag.
**Severity**: P2
### 11. One-Side Border Accent
**Pattern**: `border-left: 3-4px solid <accent-color>` or `border-top` used as the primary accent technique on cards/containers.
**Why it is a tell**: Lazy accent. It is a shortcut to add "personality" without making real design decisions.
**Detection**: Search for `border-left: [2-5]px solid` or `border-top: [2-5]px solid` with accent colors.
**Severity**: P3
### 12. Decorative Sparklines
**Pattern**: Tiny charts, mini-graphs, or trend indicators that look sophisticated but convey no actionable data. Often in card corners.
**Why it is a tell**: AI adds charts to appear data-driven. If the chart has no axis labels, no values, and no interaction, it is decoration.
**Detection**: Small SVG/canvas charts (<100px) without labels, tooltips, or legends.
**Severity**: P2
### 13. Bounce/Elastic Easing
**Pattern**: `cubic-bezier(0.68, -0.55, 0.265, 1.55)`, spring animations, or any easing that overshoots.
**Why it is a tell**: Bounce easing was trendy circa 2015. AI still defaults to it for "playfulness." It feels dated and tacky in modern UI.
**Detection**: Search for cubic-bezier with negative values or spring keyword.
**Severity**: P2
### 14. Redundant Copy
**Pattern**: Intro paragraphs that restate the heading. "Welcome to your Dashboard. This is your dashboard where you can see..."
**Why it is a tell**: AI generates text to fill space. Real UX uses headings as the message and body for additional context only.
**Detection**: Compare heading text with first paragraph. If >50% word overlap, flag.
**Severity**: P3
### 15. All Buttons Primary
**Pattern**: Every button is filled/primary color. No ghost buttons, text links, outline buttons, or secondary variants.
**Why it is a tell**: AI makes everything important. Real design creates hierarchy: 1 primary, 1-2 secondary, rest tertiary.
**Detection**: Check button variants. If all buttons have same fill/color treatment, flag.
**Severity**: P1
### 16. Everything Centered
**Pattern**: `text-align: center` or `justify-content: center` / `align-items: center` on most content blocks including body text.
**Why it is a tell**: Centering is the safe choice. Real design uses left-alignment for readability, centering only for specific elements (headings, hero).
**Detection**: Count centered text blocks. If body text is centered, flag. If > 60% of content sections are centered, flag.
**Severity**: P2
### 17. Same Spacing Everywhere
**Pattern**: Identical padding/margin on all cards, sections, and components. No variation in spacing rhythm.
**Why it is a tell**: AI applies uniform spacing because it has no sense of content grouping or visual rhythm.
**Detection**: Extract all padding/margin values. If > 70% are the same value, flag.
**Severity**: P2
### 18. Monospace as Tech Aesthetic
**Pattern**: Monospace font (Fira Code, JetBrains Mono, Source Code Pro) used for non-code content to appear "techy."
**Why it is a tell**: AI equates monospace with "developer tool" aesthetic. Real design uses monospace only for actual code.
**Detection**: Monospace `font-family` on non-`<code>`, non-`<pre>` elements.
**Severity**: P3
### 19. Modal Overuse
**Pattern**: Modals for confirmations, settings changes, form entries, when inline editing, drawers, or expandable sections would work.
**Why it is a tell**: Modals are AI's default "interaction" pattern because they are self-contained. Real UX considers context loss and flow interruption.
**Detection**: Count modal/dialog components. If > 3 modals for non-critical actions, flag.
**Severity**: P3
### 20. Pure Black or Pure White
**Pattern**: `#000000` or `#ffffff` used as primary background/text colors without any tint.
**Why it is a tell**: Pure black and white create harsh contrast and feel sterile. Real design tints toward a brand hue.
**Detection**: Search for `#000`, `#000000`, `rgb(0,0,0)`, `#fff`, `#ffffff`, `rgb(255,255,255)` in styles.
**Severity**: P1
## Scoring Guide
| Score | Tells Present | Label |
|-------|---------------|-------|
| 0 | 5+ tells | AI Slop Gallery |
| 1 | 3-4 tells | Heavy AI Influence |
| 2 | 1-2 tells | Some AI Tells |
| 3 | Subtle traces only | Mostly Clean |
| 4 | Zero tells, distinctive | Genuinely Intentional |

View File

@@ -0,0 +1,356 @@
# Design Standards
Impeccable's positive design standards. These are the target state -- what good looks like. Used by scanner for scoring (how close to ideal) and optimizer as fix targets.
---
## Color
### Principles
- Use **OKLCH** for perceptually uniform palettes. Colors at the same lightness actually look the same lightness
- Tint neutrals toward brand hue (chroma 0.005-0.01). Never pure gray
- **60-30-10 rule**: 60% neutral, 30% secondary/supporting, 10% accent
- Semantic token hierarchy: primitive -> semantic -> component tokens
- Never pure black (`#000`) or pure white (`#fff`). Always tint
### Color Token Structure
```
--color-primary oklch(0.55 0.2 250)
--color-primary-hover oklch(0.50 0.22 250)
--color-primary-active oklch(0.45 0.22 250)
--color-neutral-50 oklch(0.98 0.005 250) /* near-white, brand tinted */
--color-neutral-100 oklch(0.95 0.005 250)
--color-neutral-200 oklch(0.90 0.007 250)
--color-neutral-300 oklch(0.80 0.007 250)
--color-neutral-400 oklch(0.65 0.008 250)
--color-neutral-500 oklch(0.50 0.008 250)
--color-neutral-600 oklch(0.40 0.008 250)
--color-neutral-700 oklch(0.30 0.008 250)
--color-neutral-800 oklch(0.20 0.010 250)
--color-neutral-900 oklch(0.13 0.010 250)
--color-neutral-950 oklch(0.08 0.010 250) /* near-black, brand tinted */
--color-success oklch(0.65 0.18 145)
--color-warning oklch(0.75 0.15 85)
--color-error oklch(0.55 0.22 25)
--color-info oklch(0.60 0.15 250)
--color-surface var(--color-neutral-50)
--color-surface-raised var(--color-neutral-100)
--color-surface-overlay var(--color-neutral-900 / 0.5)
--color-text-primary var(--color-neutral-900)
--color-text-secondary var(--color-neutral-600)
--color-text-muted var(--color-neutral-400)
```
### Contrast Requirements (WCAG AA)
- Normal text (<18px / <24px bold): 4.5:1 minimum
- Large text (>=18px / >=24px bold): 3:1 minimum
- UI components and graphical objects: 3:1 minimum
- Focus indicators: 3:1 against adjacent colors
### Text on Colored Backgrounds
- Never gray text on colored backgrounds (looks washed out)
- Use shade of the background color, or white/dark with transparency
- `color-mix(in oklch, var(--bg-color) 30%, black)` for text on colored surfaces
---
## Typography
### Font Selection
Avoid: Inter, Roboto, Open Sans, Lato, Montserrat, Arial (overused defaults).
Recommended alternatives by category:
- **Sans-serif body**: Instrument Sans, Plus Jakarta Sans, DM Sans, Geist, General Sans
- **Sans-serif display**: Space Grotesk, Manrope, Outfit, Satoshi, Clash Display
- **Serif display**: Fraunces, Playfair Display 2, Source Serif 4
- **Monospace (code only)**: Geist Mono, JetBrains Mono, Fira Code
### Modular Type Scale
Choose one ratio and apply consistently:
| Ratio | Name | Scale (base 16px) |
|-------|------|--------------------|
| 1.125 | Major Second | 16, 18, 20.25, 22.78, 25.63 |
| 1.200 | Minor Third | 16, 19.2, 23.04, 27.65, 33.18 |
| 1.250 | Major Third | 16, 20, 25, 31.25, 39.06 |
| 1.333 | Perfect Fourth | 16, 21.33, 28.43, 37.9, 50.52 |
| 1.500 | Perfect Fifth | 16, 24, 36, 54, 81 |
### Fluid Sizing
Use `clamp()` for display text:
```css
--text-xs: 0.75rem; /* 12px, fixed */
--text-sm: 0.875rem; /* 14px, fixed */
--text-base: 1rem; /* 16px, body */
--text-lg: 1.125rem; /* 18px */
--text-xl: clamp(1.25rem, 1.1rem + 0.5vw, 1.5rem); /* 20-24px */
--text-2xl: clamp(1.5rem, 1.2rem + 1vw, 2rem); /* 24-32px */
--text-3xl: clamp(1.875rem, 1.4rem + 1.5vw, 2.5rem); /* 30-40px */
--text-4xl: clamp(2.25rem, 1.5rem + 2.5vw, 3.5rem); /* 36-56px */
```
### Line Height & Spacing
- Body text: `line-height: 1.5` (24px at 16px base)
- Headings: `line-height: 1.2` (tighter)
- Small text / captions: `line-height: 1.6`
- Reading width: `max-width: 65ch` (range: 45-75ch)
### Loading
- `font-display: swap` on all custom fonts
- Provide `size-adjust`, `ascent-override`, `descent-override` on fallback for minimal CLS
---
## Spacing
### 4pt Base Scale
```css
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-24: 6rem; /* 96px */
```
### Rhythm
- **Tight**: 4-8px within component groups (e.g., label + input, icon + text)
- **Comfortable**: 16-24px between related items (e.g., list items, form fields)
- **Generous**: 48-96px between major sections (e.g., page sections, content blocks)
Monotonous spacing (same value everywhere) = no rhythm = boring. Vary spacing intentionally.
### Layout Principles
- Use `gap` instead of `margin` for sibling spacing
- Cards only when content is truly distinct and actionable. Not everything needs a card
- Flatten nested cards -- use spacing + subtle dividers instead
- Container queries (`@container`) for component-level responsive
- Touch targets: minimum 44x44px for all interactive elements
- Optical adjustments: visually center, not mathematically center (e.g., play button in circle needs right offset)
---
## Motion
### Property Rules
- **Animate ONLY**: `transform`, `opacity`, `clip-path`, `background-color`, `color`, `border-color`, `box-shadow`, `filter`
- **NEVER animate**: `width`, `height`, `top`, `left`, `right`, `bottom`, `margin`, `padding` (triggers layout)
### Easing
- **Default (ease-out-quart)**: `cubic-bezier(0.25, 1, 0.5, 1)` -- decelerates naturally
- **Enter (ease-out)**: `cubic-bezier(0, 0, 0.25, 1)` -- elements arrive and settle
- **Exit (ease-in)**: `cubic-bezier(0.5, 0, 0.75, 0)` -- elements accelerate away
- **NEVER**: `ease` (default), `linear` (mechanical), bounce/elastic (dated)
### Duration Scale
```css
--duration-instant: 100ms; /* tooltip show, ripple */
--duration-fast: 150ms; /* button hover, focus ring */
--duration-normal: 250ms; /* dropdown open, tab switch */
--duration-slow: 400ms; /* modal open, sidebar slide */
--duration-entrance: 500ms; /* page entrance, hero animation */
--duration-complex: 800ms; /* complex sequence, page transition */
```
- Exit = 75% of entrance duration
- Feedback (hover, active, focus): 100-150ms maximum
- State change: 200-300ms
- Layout change: 300-500ms
### Stagger
- Max visible items to stagger: 10
- Total stagger duration: max 500ms
- Formula: `animation-delay: calc(var(--index) * 50ms)`
- Cap: `animation-delay: min(calc(var(--index) * 50ms), 500ms)`
### Reduced Motion
**Required** -- affects ~35% of adults over 40:
```css
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
### will-change
- Do NOT set in CSS (wastes GPU memory permanently)
- Add via JS on `pointerenter` / `focusin`
- Remove on `animationend` / `transitionend`
---
## Interaction States
### The 8 Required States
Every interactive element must define:
| State | CSS | Visual Change |
|-------|-----|---------------|
| Default | -- | Base appearance |
| Hover | `:hover` (wrap in `@media(hover:hover)`) | Subtle background/opacity change |
| Focus | `:focus-visible` | Focus ring: 2px solid accent, offset 2px |
| Active | `:active` | Scale down (0.97) or darker background |
| Disabled | `[disabled], [aria-disabled="true"]` | Opacity 0.5, cursor not-allowed |
| Loading | `[aria-busy="true"]` | Spinner/skeleton, disable interaction |
| Error | `[aria-invalid="true"]` | Red border, error message below |
| Success | custom class/attribute | Green check, success message |
### Focus Ring Specification
```css
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
border-radius: inherit;
}
/* Only remove outline for mouse clicks */
:focus:not(:focus-visible) {
outline: none;
}
```
Focus ring contrast: 3:1 minimum against all adjacent colors.
### Form Labels
- Always provide visible `<label>` elements
- Placeholders are hints, NOT labels (they disappear)
- Use `aria-labelledby` or `aria-label` for icon-only buttons
- Error messages: `aria-describedby` linking input to error text
### Touch Targets
- Minimum: 44x44px (WCAG 2.5.5 AAA) / 24x24px (WCAG 2.5.8 AA minimum)
- Use padding to increase hit area without changing visual size
- Minimum 8px gap between adjacent targets
---
## Visual Hierarchy
### Squint Test
Blur the page (or squint). You should immediately identify:
1. The most important element (usually primary heading or CTA)
2. The second most important element
3. Clear groupings of related content
If everything looks the same when blurred, hierarchy has failed.
### Hierarchy Tools (use 2-3 together)
| Tool | Effect |
|------|--------|
| Size | Larger = more important. 3:1 ratio between major levels |
| Weight | Bold vs regular vs light. Maximum 2 weights per page |
| Color | Saturated vs muted. Primary color for emphasis |
| Space | More surrounding space = more important |
| Position | Top-left reads first (in LTR). Above fold > below fold |
| Contrast | High contrast = more important. Low contrast recedes |
### Primary Action Rule
- Only 1 primary CTA per viewport
- Primary: filled button, highest contrast, most saturated
- Secondary: outline/ghost button
- Tertiary: text link, no background
### Progressive Disclosure
- Show summary first, detail on demand
- Expandable sections, "show more," detail panels
- Do not dump all information at once
---
## Responsive Design
### Breakpoints
```css
/* Mobile first */
--bp-sm: 640px; /* Small tablets */
--bp-md: 768px; /* Tablets */
--bp-lg: 1024px; /* Laptops */
--bp-xl: 1280px; /* Desktops */
--bp-2xl: 1536px; /* Large screens */
```
### Fluid Design Principles
- Use `%`, `vw`, `fr`, `min()`, `max()`, `clamp()` instead of fixed `px` widths
- `max-width` instead of `width` for containers
- Grid with `fr` units for responsive layouts
- Container queries (`@container`) for component-level responsiveness
### Mobile Requirements
- Minimum text: 14px (0.875rem), prefer 16px for body
- Touch targets: 44x44px minimum
- No horizontal scroll at >= 320px viewport
- Must have `<meta name="viewport" content="width=device-width, initial-scale=1">`
- Images: `max-width: 100%; height: auto`
### Adapt, Don't Hide
- Content should be restructured for smaller screens, not hidden
- Stack horizontal layouts vertically
- Use accordion/tabs for complex content
- Simplify navigation (hamburger, bottom nav)
---
## UX Writing
### Button Labels
- NEVER: "OK", "Submit", "Yes", "No" (generic)
- ALWAYS: verb + object -- "Save changes", "Create account", "Delete message"
- Destructive: name the destruction + count -- "Delete 5 items"
### Error Messages
Formula: what happened + why + how to fix
- "Password must be 8+ characters with a number" not "Invalid password"
- Never blame user, never use codes alone
- Preserve user input on error
### Empty States
Acknowledge + explain value + provide action
- "No projects yet. Create your first project to start collaborating. [Create project]"
### Loading Text
- Specific: "Saving your draft..." not "Loading..."
- Multi-step: "Uploading (2 of 5 files)..."
### Consistency
- One term per concept (delete/remove -> pick one)
- Same icon for same action everywhere
---
## Dark Mode (when present)
### Rules
- NOT inverted light mode -- requires deliberate design
- **Surface hierarchy**: lighter surfaces = higher elevation
- Base: `oklch(0.10-0.15 0.01 <hue>)`
- Raised: `oklch(0.18-0.22 0.01 <hue>)`
- Overlay: `oklch(0.24-0.28 0.01 <hue>)`
- **Font weight**: reduce by 1 step (600->500, 500->400) -- light text on dark looks heavier
- **Accent colors**: desaturate -- reduce OKLCH chroma by 0.05-0.10 from light theme values
- Never: pure black `#000` background
### Dangerous Combinations
| Combination | Problem | Fix |
|-------------|---------|-----|
| Gray on colored bg | Washed out | Use shade of bg color or white with opacity |
| Red + Green adjacent | Color blindness | Add icons/patterns |
| Yellow on white | Invisible | Use dark amber |
| Thin light text on images | Unpredictable contrast | Text shadow or overlay |
| Saturated on dark | Visual vibration | Desaturate chroma |

View File

@@ -0,0 +1,235 @@
# Fix Strategies
Maps issue categories to Impeccable fix strategies. Used by diagnostician for fix planning and optimizer for implementation guidance.
## Strategy Index
| Issue Category | Fix Strategy | Impeccable Concept | Scope |
|----------------|-------------|-------------------|-------|
| AI slop aesthetic | De-template | normalize + critique | Systemic |
| Color problems | Colorize | colorize | Systemic / Per-file |
| Typography issues | Typeset | typeset | Systemic |
| Spacing/layout | Arrange | arrange | Systemic / Per-file |
| Animation issues | Animate | animate | Per-file |
| Missing states | Harden | harden + polish | Per-component |
| Visual noise | Simplify | quieter + distill | Per-component |
| Too bland/weak | Strengthen | bolder + delight | Per-component |
| Inconsistency | Normalize | normalize | Systemic |
| Final pass | Polish | polish | Per-component |
| Hierarchy issues | Clarify | distill + bolder | Per-page |
| Responsive issues | Adapt | adapt | Per-component |
---
## De-template (Anti-AI-Slop)
**When**: Anti-patterns dimension score 0-2 (AI slop or heavy AI influence)
**Strategy**:
1. Replace generic fonts with distinctive alternatives (see design-standards.md Typography)
2. Convert gradient text to solid accent colors with weight/size emphasis instead
3. Break identical card grids: vary sizes, add featured card, introduce asymmetry
4. Remove decorative glassmorphism (keep functional like overlays)
5. Redesign hero metrics with intentional hierarchy, not template layout
6. Flatten nested cards into single-level with spacing
7. Add left-alignment for body text, centering only for specific hero elements
8. Create button hierarchy: 1 primary, ghost secondary, text tertiary
9. Introduce spacing rhythm (tight within groups, generous between sections)
10. Replace bounce easing with exponential curves
**Dependency**: Requires Colorize and Typeset to be planned (often executed together).
---
## Colorize
**When**: Color dimension score 0-2 or any P0/P1 color issues
**Strategy**:
1. **Token foundation** (if no tokens exist):
- Create CSS custom property file with full neutral scale (50-950)
- Define primary, semantic (success/warning/error/info), and surface tokens
- All neutrals tinted toward brand hue (OKLCH chroma 0.005-0.01)
2. **Pure black/white removal**:
- `#000` -> `oklch(0.08-0.15 0.01 <hue>)` (near-black, brand tinted)
- `#fff` -> `oklch(0.97-0.99 0.005 <hue>)` (near-white, brand tinted)
3. **Gray tinting**:
- Convert all pure grays to brand-tinted variants
- Add chroma 0.005-0.01 at brand hue
4. **Contrast fixes**:
- Measure each text/background pair
- Adjust lightness until WCAG AA met (4.5:1 normal, 3:1 large)
5. **OKLCH conversion**:
- Convert key palette colors from hex/hsl to oklch
- Generate tint/shade scales in OKLCH for perceptual uniformity
6. **60-30-10 enforcement**:
- Audit accent color usage, reduce to ~10%
- Ensure neutral dominates at ~60%
**Dependency**: Should run before De-template (anti-slop fixes may need new colors).
---
## Typeset
**When**: Typography dimension score 0-2 or muddy hierarchy
**Strategy**:
1. **Font replacement**: Swap generic fonts for distinctive alternatives
- Body: Plus Jakarta Sans, Instrument Sans, DM Sans, Geist
- Display: Space Grotesk, Manrope, Fraunces
2. **Scale establishment**: Choose modular ratio (1.25 or 1.333 recommended), generate size scale
3. **Fluid sizing**: Add `clamp()` for h1-h3 display sizes
4. **Line length**: Add `max-width: 65ch` to prose containers
5. **Vertical rhythm**: Set line-height system (1.5 body, 1.2 headings)
6. **Font loading**: Add `font-display: swap` to all @font-face
**Dependency**: Run before Clarify (hierarchy depends on type scale).
---
## Arrange
**When**: Spacing dimension score 0-2 or arbitrary spacing values
**Strategy**:
1. **Scale creation**: Define 4pt base scale as CSS custom properties
2. **Value replacement**: Map arbitrary values to nearest scale value
3. **Rhythm introduction**: Tight (4-8px) within groups, comfortable (16-24px) between items, generous (48-96px) between sections
4. **Card flattening**: Remove nested cards, replace with spacing + subtle dividers
5. **Gap conversion**: Replace margin between siblings with gap on flex/grid parent
6. **Touch targets**: Ensure all interactive elements are 44x44px minimum
**Dependency**: Independent, but benefits from Colorize tokens being in place.
---
## Animate
**When**: Motion dimension score 0-2 or layout property animations
**Strategy**:
1. **Property fix**: Replace layout animations (width/height/margin/padding) with transform+opacity
2. **Easing fix**: Replace ease/linear/bounce with exponential curves
3. **Reduced-motion**: Add `@media (prefers-reduced-motion: reduce)` global rule
4. **Token system**: Create duration + easing custom properties
5. **Stagger cap**: Cap stagger at 10 items, 500ms total
6. **will-change**: Remove from CSS, document JS activation pattern
**Dependency**: Independent.
---
## Harden
**When**: Interaction states dimension score 0-2 or missing critical states
**Strategy**:
1. **Hover**: Add `:hover` with subtle visual change, wrap in `@media(hover:hover)`
2. **Focus**: Add `:focus-visible` with 2px solid accent ring, offset 2px
3. **Active**: Add `:active` with scale(0.97) or darker background
4. **Disabled**: Add `[disabled]` with opacity 0.5, cursor not-allowed
5. **Loading**: Add aria-busy pattern with spinner/skeleton
6. **Error/Success**: Add form validation visual states
7. **Focus ring**: Ensure 3:1 contrast against all adjacent colors
8. **Labels**: Replace placeholder-as-label with visible `<label>` elements
9. **Touch targets**: Pad interactive elements to 44px minimum
**Dependency**: Requires Colorize tokens for consistent state colors.
---
## Simplify (quieter + distill)
**When**: Visual noise, too many decorations, competing elements
**Strategy**:
1. Remove decorative elements that do not aid comprehension
2. Mute icon colors (reduce saturation/opacity)
3. Remove background decorations and unnecessary borders
4. Reduce shadow intensity
5. Simplify card borders (remove or lighten)
6. Remove sparkline decorations without data value
**Dependency**: Independent.
---
## Strengthen (bolder + delight)
**When**: Too bland, everything same weight, no emphasis
**Strategy**:
1. Increase primary element size by 1.5-2x
2. Add color saturation to primary CTA
3. Increase weight contrast (bold primary, regular secondary)
4. Add subtle micro-interactions (hover lift, active press)
5. Introduce one distinctive element (asymmetric layout, unexpected color, custom illustration)
**Dependency**: Requires Typeset and Colorize to be in place.
---
## Clarify (hierarchy)
**When**: Visual hierarchy dimension score 0-2 or fails squint test
**Strategy**:
1. Identify primary element, increase to 3:1 ratio over body
2. Use 2-3 hierarchy tools together (size + weight + color)
3. Group related content with proximity (smaller gaps within, larger between)
4. Reduce visual weight of competing secondary elements
5. Ensure only 1 primary CTA per viewport
6. Add progressive disclosure where appropriate
**Dependency**: Requires Typeset (size hierarchy) and Colorize (color hierarchy).
---
## Adapt (responsive)
**When**: Responsive dimension score 0-2 or broken mobile experience
**Strategy**:
1. Replace fixed widths with fluid (%, vw, fr, min/max/clamp)
2. Add missing breakpoints (640, 768, 1024, 1280px)
3. Fix overflow (horizontal scroll causes)
4. Fix mobile text sizes (minimum 14px)
5. Fix touch targets (minimum 44px)
6. Add container queries for component-level responsive
7. Restructure hidden content (adapt, don't hide)
8. Add viewport meta tag if missing
**Dependency**: Run last -- tests all other fixes at different viewports.
---
## Fix Order (Default)
When applying all strategies in a full polish cycle:
```
Phase 1: Foundation
1. Colorize (token system + color fixes)
2. Typeset (font + scale + fluid sizing)
3. Arrange (spacing scale + layout)
Phase 2: Aesthetic
4. De-template (anti-AI-slop cleanup)
5. Simplify or Strengthen (as needed)
Phase 3: Interaction
6. Animate (motion system)
7. Harden (interaction states)
Phase 4: Structure
8. Clarify (visual hierarchy)
Phase 5: Validation
9. Adapt (responsive -- tests everything)
```

View File

@@ -0,0 +1,81 @@
# Pipeline Definitions
UI polish pipeline modes and task registry.
## Pipeline Modes
| Mode | Description | Task Count |
|------|-------------|------------|
| scan-only | Discover + diagnose, report only | 2 tasks |
| targeted | Fix specific dimensions: scan -> diagnose -> optimize -> verify | 4 tasks |
| full | Complete polish cycle with GC loop on verify failure | 4 tasks + GC |
## Scan-Only Pipeline Task Registry
| Task ID | Role | blockedBy | Description |
|---------|------|-----------|-------------|
| SCAN-001 | scanner | [] | 8-dimension UI audit against Impeccable design standards |
| DIAG-001 | diagnostician | [SCAN-001] | Root cause analysis, severity classification, fix dependency graph |
## Targeted Pipeline Task Registry
| Task ID | Role | blockedBy | Description |
|---------|------|-----------|-------------|
| SCAN-001 | scanner | [] | 8-dimension UI audit (filtered to target dimensions) |
| DIAG-001 | diagnostician | [SCAN-001] | Root cause analysis for targeted dimensions |
| OPT-001 | optimizer | [DIAG-001] | Apply targeted fixes per Impeccable standards |
| VERIFY-001 | verifier | [OPT-001] | Before/after comparison, regression check |
## Full Pipeline Task Registry
| Task ID | Role | blockedBy | Description |
|---------|------|-----------|-------------|
| SCAN-001 | scanner | [] | Full 8-dimension UI audit |
| DIAG-001 | diagnostician | [SCAN-001] | Complete root cause analysis with fix dependency graph |
| OPT-001 | optimizer | [DIAG-001] | Apply all fixes in dependency order |
| VERIFY-001 | verifier | [OPT-001] | Verification with GC loop trigger |
## GC Loop (Full Mode Only)
| Checkpoint | Task | Condition | Action |
|------------|------|-----------|--------|
| VERIFY completes | VERIFY-* | verify_passed (no regressions, score >= before) | Pipeline complete |
| VERIFY completes | VERIFY-* | verify_failed (non-critical regressions) | gc_rounds < 2 -> create OPT-fix task |
| VERIFY completes | VERIFY-* | fix_required (critical regressions or score drop) | gc_rounds < 2 -> create OPT-fix task (CRITICAL) |
| VERIFY completes | VERIFY-* | gc_rounds >= 2 | Escalate to user |
### GC Fix Tasks (dynamically created)
| Task ID | Role | blockedBy | Description |
|---------|------|-----------|-------------|
| OPT-fix-1 | optimizer | [VERIFY-001] | Fix regressions from round 1 verification |
| VERIFY-002 | verifier | [OPT-fix-1] | Re-verify after round 1 fixes |
| OPT-fix-2 | optimizer | [VERIFY-002] | Fix regressions from round 2 verification (if needed) |
| VERIFY-003 | verifier | [OPT-fix-2] | Final re-verify (max round) |
## Collaboration Patterns
| Pattern | Roles | Description |
|---------|-------|-------------|
| CP-1 Linear Pipeline | All | Base sequential flow: scan -> diagnose -> optimize -> verify |
| CP-2 Review-Fix (GC) | optimizer <-> verifier | Generator-Critic loop, max 2 rounds |
## Spawn Rules
| Mode | Behavior |
|------|----------|
| scan-only | Sequential: SCAN-001 then DIAG-001 |
| targeted | Sequential: SCAN -> DIAG -> OPT -> VERIFY |
| full | Sequential: SCAN -> DIAG -> OPT -> VERIFY, then GC loop if verify triggers |
All modes use sequential spawning (one task at a time) since each task depends on the previous.
## Output Artifacts
| Task | Output Path |
|------|-------------|
| SCAN-001 | <session>/scan/scan-report.md |
| DIAG-001 | <session>/diagnosis/diagnosis-report.md |
| OPT-001 / OPT-fix-* | <session>/optimization/fix-log.md + modified source files |
| VERIFY-001 / VERIFY-* | <session>/verification/verify-report.md |
| Screenshots (if DevTools) | <session>/evidence/*.png |

View File

@@ -0,0 +1,162 @@
# Scoring Guide
How to score each dimension consistently. Used by scanner for initial audit and verifier for re-assessment.
## Rating Bands (Total Score out of 36)
| Range | Rating | Description |
|-------|--------|-------------|
| 32-36 | Excellent | Distinctive, intentional design. Minimal or zero issues |
| 25-31 | Good | Solid design with minor polish opportunities |
| 18-24 | Acceptable | Functional but significant design work needed |
| 11-17 | Poor | Major overhaul required across multiple dimensions |
| 0-10 | Critical | AI slop gallery or fundamentally broken design |
## Per-Dimension Scoring (0-4)
### General Rubric
| Score | Criteria |
|-------|----------|
| 0 | Completely failing. Multiple major violations. Fundamental problems |
| 1 | Major gaps. 3-4 violations. Some effort but insufficient |
| 2 | Partial effort. 1-2 noticeable issues. Functional but not good |
| 3 | Mostly clean. Subtle issues only. Good with minor polish needed |
| 4 | Excellent. Genuinely distinctive/intentional. Meets all standards |
### Dimension 1: Anti-AI-Slop Detection
| Score | Criteria |
|-------|----------|
| 0 | 5+ AI slop tells present. Looks immediately AI-generated |
| 1 | 3-4 AI slop tells. Heavy AI influence obvious |
| 2 | 1-2 noticeable AI tells. Some templated elements |
| 3 | Subtle traces only. Mostly intentional design choices |
| 4 | Zero AI tells. Genuinely distinctive aesthetic. Would never guess AI-made |
### Dimension 2: Color Quality
| Score | Criteria |
|-------|----------|
| 0 | Multiple WCAG AA failures, pure black/white everywhere, hard-coded colors, no system |
| 1 | Some contrast issues, hard-coded colors, no token system, pure grays |
| 2 | Basic contrast OK, some OKLCH or tokens, but gaps (untinted grays, missing semantic colors) |
| 3 | Good color system with minor gaps (a few hard-coded values, imperfect 60-30-10) |
| 4 | OKLCH-based, fully tokenized, WCAG AA+ compliant, proper 60-30-10, semantic roles defined |
### Dimension 3: Typography Quality
| Score | Criteria |
|-------|----------|
| 0 | Generic font, no scale, body text <16px, no hierarchy |
| 1 | Overused font, muddy sizes (many close values), missing fluid sizing |
| 2 | Decent font choice but inconsistent scale or line-height issues |
| 3 | Good typography with minor gaps (missing clamp, slight rhythm inconsistencies) |
| 4 | Distinctive font, clear modular scale, fluid sizing, proper vertical rhythm, max-width on prose |
### Dimension 4: Spacing & Layout Quality
| Score | Criteria |
|-------|----------|
| 0 | Random spacing, nested cards, fixed widths, tiny touch targets |
| 1 | Some spacing pattern but many arbitrary values, cards overused |
| 2 | Decent spacing but monotonous rhythm or occasional arbitrary values |
| 3 | Good spacing system with minor gaps (occasional non-scale value, mostly gap usage) |
| 4 | Consistent scale, varied rhythm, gap for siblings, proper touch targets, no card nesting |
### Dimension 5: Motion & Animation Quality
| Score | Criteria |
|-------|----------|
| 0 | Layout animations, no reduced-motion, bounce easing, no system |
| 1 | Some transform-based but bad easing, missing reduced-motion |
| 2 | Decent animations but no token system or still missing reduced-motion |
| 3 | Good system with minor gaps (occasional ease default, missing exit animation) |
| 4 | Transform+opacity only, exponential easing, reduced-motion query, duration tokens, proper stagger |
### Dimension 6: Interaction States
| Score | Criteria |
|-------|----------|
| 0 | No hover, no focus, outline:none without replacement, no loading states |
| 1 | Basic hover but missing focus/active on many elements, no loading states |
| 2 | Hover + focus exist but no focus-visible, missing some states (disabled, error, empty) |
| 3 | Most states present with minor gaps (imperfect focus ring, missing empty state) |
| 4 | All 8 states implemented, focus-visible, proper focus ring, loading/error/success/empty states |
### Dimension 7: Visual Hierarchy
| Score | Criteria |
|-------|----------|
| 0 | Everything same visual weight, no clear primary action, fails squint test completely |
| 1 | Some size differences but no clear hierarchy system, multiple competing primary actions |
| 2 | Basic hierarchy via size but missing weight/color/space dimensions |
| 3 | Good hierarchy with minor issues (occasional visual competition, could be stronger) |
| 4 | Clear squint test pass, obvious primary action, multi-dimension hierarchy, progressive disclosure |
### Dimension 8: Responsive Design
| Score | Criteria |
|-------|----------|
| 0 | No responsive design, horizontal scroll, completely broken on mobile |
| 1 | Basic media queries but many breakage points, some fixed widths |
| 2 | Decent mobile but some fixed widths, small targets, or missing breakpoints |
| 3 | Good responsive with minor issues (missing container queries, occasional small target) |
| 4 | Fluid design, proper breakpoints, container queries, 44px targets, no overflow, adapted content |
### Dimension 9: Cognitive Load & UX Writing
| Score | Criteria |
|-------|----------|
| 0 | Information overload everywhere, no grouping, generic labels, useless error messages |
| 1 | Some grouping but >7 data groups visible, many generic labels, errors without fix guidance |
| 2 | Decent grouping but missing progressive disclosure, some generic buttons, partial error messages |
| 3 | Good information architecture with minor issues (occasional generic label, one missing empty state) |
| 4 | Clear progressive disclosure, verb+object labels, what+why+fix errors, guided empty states, proper grouping |
### Dimension 10: Dark Mode Quality (Conditional)
Only scored if dark mode exists. If no dark mode, this dimension is excluded from total.
| Score | Criteria |
|-------|----------|
| 0 | Pure black bg, no surface hierarchy, saturated colors vibrating, dangerous combos |
| 1 | Some dark surfaces but flat (same lightness), still using light-mode font weights |
| 2 | Basic surface hierarchy but still saturated accents or missing font weight reduction |
| 3 | Good dark mode with minor issues (occasional pure black, one dangerous combo) |
| 4 | Proper surface hierarchy (lighter=higher), desaturated accents, reduced font weights, tinted dark bg |
When dark mode exists: total out of 40, bands shift +4. When no dark mode: total out of 36.
---
## Severity Mapping
| Severity | Definition | Score Correlation | Action |
|----------|-----------|-------------------|--------|
| P0 Blocking | Prevents use or violates law/standard. WCAG AA failure, missing focus, horizontal scroll on mobile, no viewport meta | Any dimension at 0 | Fix immediately, blocks release |
| P1 Major | Significant UX harm or near-violation. Pure black/white, missing hover, all buttons primary, muddy hierarchy | Any dimension at 1 | Fix before release |
| P2 Minor | Annoyance with workaround. No OKLCH, overused fonts, monotonous spacing, no container queries | Any dimension at 2 | Fix in next polish pass |
| P3 Polish | Nice-to-fix, minimal user impact. Missing exit animation, optical adjustments, font fallback metrics | Dimension at 3 with minor issues | Fix when convenient |
---
## Scoring Process
1. For each dimension, go through every checklist item in the scanner audit
2. Count the number and severity of violations found
3. Apply the dimension-specific rubric to assign 0-4
4. Sum all 8 dimensions for total (0-32)
5. Apply rating band
### Tie-Breaking Rules
- If between two scores, the presence of any P0 issue in that dimension rounds down
- If between two scores with no P0, consider the count of P1 issues
- When in doubt, score lower (conservative) -- it is better to fix something unnecessary than miss something important
### Verification Scoring
When verifier re-scores after optimization:
- Use identical checklist and rubric as original scan
- Score independently (do not adjust based on "how much improved")
- Report both absolute score and delta from original
- Flag any dimension where score decreased (regression)

View File

@@ -0,0 +1,73 @@
{
"team_name": "ui-polish",
"team_display_name": "UI Polish",
"description": "Auto-discover and fix UI design issues using Impeccable design standards",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Pipeline orchestration, scope assessment, GC loop management",
"message_types": ["task_unblocked", "gc_checkpoint", "fix_required", "error", "shutdown"]
},
"scanner": {
"task_prefix": "SCAN",
"responsibility": "8-dimension UI audit using Impeccable design standards",
"message_types": ["scan_complete", "scan_progress", "error"]
},
"diagnostician": {
"task_prefix": "DIAG",
"responsibility": "Root cause analysis, severity classification, fix prioritization",
"message_types": ["diag_complete", "diag_progress", "error"]
},
"optimizer": {
"task_prefix": "OPT",
"responsibility": "Apply targeted fixes following Impeccable design standards",
"message_types": ["opt_complete", "opt_progress", "error"]
},
"verifier": {
"task_prefix": "VERIFY",
"responsibility": "Before/after comparison, regression detection",
"message_types": ["verify_passed", "verify_failed", "fix_required", "error"]
}
},
"pipelines": {
"scan-only": {
"description": "Discover + diagnose, no fixes (report only)",
"task_chain": ["SCAN-001", "DIAG-001"],
"complexity": "low"
},
"targeted": {
"description": "Fix specific dimensions only",
"task_chain": ["SCAN-001", "DIAG-001", "OPT-001", "VERIFY-001"],
"complexity": "medium"
},
"full": {
"description": "Complete polish cycle with GC loop",
"task_chain": ["SCAN-001", "DIAG-001", "OPT-001", "VERIFY-001"],
"gc_loop": true,
"complexity": "high"
}
},
"innovation_patterns": {
"generator_critic": {
"generator": "optimizer",
"critic": "verifier",
"max_rounds": 2,
"convergence": "verify.regressions === 0 && verify.score_delta >= 0",
"escalation": "Coordinator intervenes after max rounds"
}
},
"session_dirs": {
"base": ".workflow/.team/UIP-{slug}-{YYYY-MM-DD}/",
"scan": "scan/",
"diagnosis": "diagnosis/",
"optimization": "optimization/",
"verification": "verification/",
"evidence": "evidence/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,319 @@
---
name: team-visual-a11y
description: Unified team skill for visual accessibility QA. OKLCH color contrast, typography readability, focus management, WCAG AA/AAA audit at rendered level. Uses team-worker agent architecture. Triggers on "team visual a11y", "accessibility audit", "visual a11y".
allowed-tools: spawn_agent(*), wait_agent(*), send_message(*), assign_task(*), close_agent(*), list_agents(*), report_agent_job_result(*), request_user_input(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*), mcp__ccw-tools__read_file(*), mcp__ccw-tools__write_file(*), mcp__ccw-tools__edit_file(*), mcp__ccw-tools__team_msg(*), mcp__chrome-devtools__evaluate_script(*), mcp__chrome-devtools__take_screenshot(*), mcp__chrome-devtools__emulate(*), mcp__chrome-devtools__lighthouse_audit(*), mcp__chrome-devtools__navigate_page(*), mcp__chrome-devtools__resize_page(*)
---
# Team Visual Accessibility
Deep visual accessibility QA: OKLCH-based perceptual color contrast, typography readability at all viewports, focus-visible completeness, WCAG AA/AAA audit at rendered level. Built on **team-worker agent architecture** -- all worker roles share a single agent definition with role-specific Phase 2-4 loaded from `roles/<role>/role.md`.
## Architecture
```
Skill(skill="team-visual-a11y", args="task description")
|
SKILL.md (this file) = Router
|
+--------------+--------------+
| |
no --role flag --role <name>
| |
Coordinator Worker
roles/coordinator/role.md roles/<name>/role.md
|
+-- analyze -> dispatch -> spawn workers -> STOP
|
+-------+-------+-------+
v v v |
[3 auditors spawn in PARALLEL] |
color-auditor typo-auditor focus-auditor
| | |
+---+---+---+---+
v
remediation-planner
|
v
fix-implementer (inner_loop)
|
v
[re-audit: color + focus in PARALLEL]
```
## Role Registry
| Role | Path | Prefix | Inner Loop |
|------|------|--------|------------|
| coordinator | [roles/coordinator/role.md](roles/coordinator/role.md) | -- | -- |
| color-auditor | [roles/color-auditor/role.md](roles/color-auditor/role.md) | COLOR-* | false |
| typo-auditor | [roles/typo-auditor/role.md](roles/typo-auditor/role.md) | TYPO-* | false |
| focus-auditor | [roles/focus-auditor/role.md](roles/focus-auditor/role.md) | FOCUS-* | false |
| remediation-planner | [roles/remediation-planner/role.md](roles/remediation-planner/role.md) | REMED-* | false |
| fix-implementer | [roles/fix-implementer/role.md](roles/fix-implementer/role.md) | FIX-* | true |
## Role Router
Parse `$ARGUMENTS`:
- Has `--role <name>` -> Read `roles/<name>/role.md`, execute Phase 2-4
- No `--role` -> `roles/coordinator/role.md`, execute entry router
## Delegation Lock
**Coordinator is a PURE ORCHESTRATOR. It coordinates, it does NOT do.**
Before calling ANY tool, apply this check:
| Tool Call | Verdict | Reason |
|-----------|---------|--------|
| `spawn_agent`, `wait_agent`, `close_agent`, `send_message`, `assign_task` | ALLOWED | Orchestration |
| `list_agents` | ALLOWED | Agent health check |
| `request_user_input` | ALLOWED | User interaction |
| `mcp__ccw-tools__team_msg` | ALLOWED | Message bus |
| `Read/Write` on `.workflow/.team/` files | ALLOWED | Session state |
| `Read` on `roles/`, `commands/`, `specs/` | ALLOWED | Loading own instructions |
| `Read/Grep/Glob` on project source code | BLOCKED | Delegate to worker |
| `Edit` on any file outside `.workflow/` | BLOCKED | Delegate to worker |
| `Bash("ccw cli ...")` | BLOCKED | Only workers call CLI |
| `Bash` running build/test/lint commands | BLOCKED | Delegate to worker |
**If a tool call is BLOCKED**: STOP. Create a task, spawn a worker.
**No exceptions for "simple" tasks.** Even a single-file read-and-report MUST go through spawn_agent.
---
## Shared Constants
- **Session prefix**: `VA`
- **Session path**: `.workflow/.team/VA-<slug>-<date>/`
- **team_name**: `visual-a11y`
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
- **Max GC rounds**: 2
## Worker Spawn Template
Coordinator spawns workers using this template:
```
spawn_agent({
agent_type: "team_worker",
task_name: "<task-id>",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: <role>
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
requirement: <task-description>
inner_loop: <true|false>
Read role_spec file (<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: <task-id>
title: <task-title>
description: <task-description>
pipeline_phase: <pipeline-phase>` },
{ type: "text", text: `## Upstream Context
<prev_context>` }
]
})
```
### Parallel Fan-in Spawn (3 Auditors)
The 3 auditors run in parallel. Spawn all 3, then wait for all 3:
```javascript
// Spawn 3 auditors in parallel
spawn_agent({
agent_type: "team_worker",
task_name: "COLOR-001",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: color-auditor
role_spec: ${skillRoot}/roles/color-auditor/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${colorTaskDescription}
inner_loop: false
Read role_spec file to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: COLOR-001
title: OKLCH Color Contrast Audit
description: ${colorTaskDescription}
pipeline_phase: audit` }
]
})
spawn_agent({
agent_type: "team_worker",
task_name: "TYPO-001",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: typo-auditor
role_spec: ${skillRoot}/roles/typo-auditor/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${typoTaskDescription}
inner_loop: false
Read role_spec file to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: TYPO-001
title: Typography Readability Audit
description: ${typoTaskDescription}
pipeline_phase: audit` }
]
})
spawn_agent({
agent_type: "team_worker",
task_name: "FOCUS-001",
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: focus-auditor
role_spec: ${skillRoot}/roles/focus-auditor/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${focusTaskDescription}
inner_loop: false
Read role_spec file to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: FOCUS-001
title: Focus & Keyboard Accessibility Audit
description: ${focusTaskDescription}
pipeline_phase: audit` }
]
})
// Wait for ALL 3 auditors to complete
wait_agent({ targets: ["COLOR-001", "TYPO-001", "FOCUS-001"], timeout_ms: 900000 })
// Close all 3
close_agent({ target: "COLOR-001" })
close_agent({ target: "TYPO-001" })
close_agent({ target: "FOCUS-001" })
// Then spawn remediation-planner with all 3 audit results as upstream context
```
After spawning, use `wait_agent({ targets: [...], timeout_ms: 900000 })` to collect results, then `close_agent({ target })` each worker.
### Model Selection Guide
Visual accessibility is a precision pipeline where auditors need thorough analysis and fix-implementer needs careful code changes.
| Role | reasoning_effort | Rationale |
|------|-------------------|-----------|
| color-auditor | high | OKLCH calculations, contrast ratio precision |
| typo-auditor | high | Multi-breakpoint analysis, clamp() validation |
| focus-auditor | high | ARIA patterns, keyboard navigation completeness |
| remediation-planner | high | Synthesize 3 audit reports into actionable plan |
| fix-implementer | medium | Implementation follows defined remediation plan |
### Audit-to-Remediation Context Flow
All 3 audit findings must reach remediation-planner via coordinator's upstream context:
```
// After COLOR-001 + TYPO-001 + FOCUS-001 all complete, coordinator sends findings to planner
spawn_agent({
agent_type: "team_worker",
task_name: "REMED-001",
fork_context: false,
items: [
...,
{ type: "text", text: `## Upstream Context
Color audit: <session>/audits/color/color-audit-001.md
Typography audit: <session>/audits/typography/typo-audit-001.md
Focus audit: <session>/audits/focus/focus-audit-001.md` }
]
})
```
## User Commands
| Command | Action |
|---------|--------|
| `check` / `status` | View execution status graph |
| `resume` / `continue` | Advance to next step |
## Specs Reference
- [specs/pipelines.md](specs/pipelines.md) -- Pipeline definitions and task registry
- [specs/oklch-standards.md](specs/oklch-standards.md) -- OKLCH color accessibility rules
- [specs/wcag-matrix.md](specs/wcag-matrix.md) -- WCAG 2.1 criteria matrix
- [specs/typography-scale.md](specs/typography-scale.md) -- Typography accessibility rules
- [specs/focus-patterns.md](specs/focus-patterns.md) -- Focus management patterns
## Session Directory
```
.workflow/.team/VA-<slug>-<date>/
+-- .msg/
| +-- messages.jsonl # Team message bus
| +-- meta.json # Pipeline config + GC state
+-- audits/
| +-- color/ # Color auditor output
| | +-- color-audit-001.md
| +-- typography/ # Typography auditor output
| | +-- typo-audit-001.md
| +-- focus/ # Focus auditor output
| +-- focus-audit-001.md
+-- remediation/ # Remediation planner output
| +-- remediation-plan.md
+-- fixes/ # Fix implementer output
| +-- fix-summary-001.md
+-- re-audit/ # Re-audit output (GC loop)
| +-- color-audit-002.md
| +-- focus-audit-002.md
+-- evidence/ # Screenshots, traces
```
## v4 Agent Coordination
### Message Semantics
| Intent | API | Example |
|--------|-----|---------|
| Queue supplementary info (don't interrupt) | `send_message` | Send audit findings to running remediation-planner |
| Assign new work from reviewed plan | `assign_task` | Assign FIX task after remediation plan ready |
| Check running agents | `list_agents` | Verify agent health during resume |
### Agent Health Check
Use `list_agents({})` in handleResume and handleComplete:
```
// Reconcile session state with actual running agents
const running = list_agents({})
// Compare with tasks.json active tasks
// Reset orphaned tasks (in_progress but agent gone) to pending
```
### Named Agent Targeting
Workers are spawned with `task_name: "<task-id>"` enabling direct addressing:
- `send_message({ target: "REMED-001", items: [...] })` -- send additional audit findings to remediation-planner
- `assign_task({ target: "FIX-001", items: [...] })` -- assign implementation from remediation plan
- `close_agent({ target: "COLOR-001" })` -- cleanup after color audit
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown command | Error with available command list |
| Role not found | Error with role registry |
| Session corruption | Attempt recovery, fallback to manual |
| Fast-advance conflict | Coordinator reconciles on next callback |
| Completion action fails | Default to Keep Active |
| GC loop stuck > 2 rounds | Escalate to user: accept / retry / terminate |
| Chrome DevTools unavailable | Degrade to static analysis only |

View File

@@ -0,0 +1,178 @@
---
role: color-auditor
prefix: COLOR
inner_loop: false
message_types: [state_update]
---
# Color Accessibility Auditor
OKLCH-based perceptual color contrast analysis. Extract all color values, calculate WCAG 2.1 and APCA contrast ratios, assess OKLCH lightness/chroma ranges, simulate color blindness conditions. Produce detailed color audit report with pass/fail per combination.
## Phase 2: Context & Environment Detection
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| Target (URL or file paths) | From task description CONTEXT | Yes |
| WCAG level (AA/AAA) | From task description CONTEXT | Yes |
| .msg/meta.json | <session>/.msg/meta.json | No |
| Previous audit (re-audit) | <session>/audits/color/color-audit-*.md | Only for COLOR-002+ |
1. Extract session path, target, and WCAG level from task description
2. Determine audit type from subject: COLOR-001 -> initial audit, COLOR-002+ -> re-audit (verification)
3. Identify target:
- URL -> use Chrome DevTools for rendered colors (navigate_page, evaluate_script)
- File paths -> read CSS/SCSS/Tailwind config files directly
- Full site -> enumerate stylesheets from HTML entry points
4. For re-audit: read previous audit report and fix summary for comparison baseline
## Phase 3: Color Audit Execution
### Step 1: Color Extraction
Extract all color values from target:
**Static analysis** (always):
- Glob for CSS/SCSS/Tailwind files -> extract color definitions
- Parse CSS custom properties (--color-*), class colors, inline styles
- Normalize all formats to OKLCH for perceptual comparison:
- `#hex` -> sRGB -> OKLCH
- `rgb()/rgba()` -> OKLCH
- `hsl()/hsla()` -> OKLCH
- `oklch()` -> direct
- Record source location (file:line) for each color
**Runtime analysis** (if Chrome DevTools available):
- `mcp__chrome-devtools__navigate_page({ url: "<target-url>" })`
- `mcp__chrome-devtools__evaluate_script({ expression: "..." })` with getComputedStyle to extract rendered colors from key elements (body, headings, links, buttons, inputs)
- `mcp__chrome-devtools__take_screenshot({})` for visual evidence -> save to `<session>/evidence/`
### Step 2: Contrast Ratio Calculation
For each text/background color combination:
**WCAG 2.1 Contrast Ratios**:
- Calculate relative luminance: `L = 0.2126*R + 0.7152*G + 0.0722*B` (linearized sRGB)
- Contrast ratio: `(L1 + 0.05) / (L2 + 0.05)` where L1 > L2
- Thresholds:
| Text Type | AA | AAA |
|-----------|-----|-----|
| Normal text (< 18pt / < 14pt bold) | >= 4.5:1 | >= 7:1 |
| Large text (>= 18pt / >= 14pt bold) | >= 3:1 | >= 4.5:1 |
| Non-text (UI components, icons) | >= 3:1 | >= 3:1 |
**APCA Contrast (Lc values)**:
- Calculate APCA Lc using OKLCH lightness difference
- Thresholds:
| Use Case | Minimum Lc |
|----------|-----------|
| Body text (16px) | >= 60 |
| Large text (24px+) | >= 45 |
| Non-text elements | >= 30 |
| Placeholder/disabled | >= 15 |
### Step 3: OKLCH Lightness Analysis
Verify OKLCH lightness ranges per specs/oklch-standards.md:
| Element | Expected L Range | Flag If |
|---------|-----------------|---------|
| Dark text on light bg | L <= 40% | L > 40% (too light for text) |
| Light background | L >= 90% | L < 90% (too dark for bg) |
| Accent colors | L 50-65% | Outside range |
| Disabled/muted text | L 55-70% | Outside range |
Check chroma values:
- Text colors: C near 0 (achromatic) unless intentional accent
- Vibrant accents: C 0.2-0.25, max 1-2 per palette
### Step 4: Color Blindness Simulation
Assess color distinguishability under:
- **Protanopia** (red-blind): Check red/green pairs still distinguishable
- **Deuteranopia** (green-blind): Check green/red pairs
- **Tritanopia** (blue-blind): Check blue/yellow pairs
Flag combinations that rely solely on color difference without shape/text/pattern alternatives.
### Step 5: Dark Mode Parity
If dark mode exists (media query or data-attribute):
- Verify all color combinations also pass in dark mode
- Check that OKLCH lightness relationships invert properly
- Flag combinations that pass in one mode but fail in the other
### Dark Mode Audit (if dark mode exists)
| Check | Requirement | Method |
|-------|-------------|--------|
| No pure black background | Base bg uses tinted dark (oklch L >= 0.10, chroma >= 0.005) | evaluate_script: getComputedStyle check |
| Surface hierarchy | Higher elevation = lighter surface (at least 3 distinct levels) | Screenshot comparison |
| Font weight reduction | Dark theme reduces weight by 1 step vs light (600->500, 500->400) | Compare computed font-weight |
| Accent desaturation | Dark theme accents have lower OKLCH chroma than light (by 0.03-0.10) | Compare computed colors |
| Dangerous combos | No gray text on colored backgrounds, no red-green only indicators | Visual + computed color analysis |
| All contrast ratios met | WCAG AA requirements must pass in BOTH light and dark themes | Lighthouse audit both themes |
## Phase 4: Report Generation & Output
1. Write audit report to `<session>/audits/color/color-audit-{NNN}.md` (or `<session>/re-audit/color-audit-{NNN}.md` for re-audits):
```markdown
# Color Accessibility Audit - {NNN}
[color-auditor]
## Summary
- **Total color combinations tested**: {count}
- **Pass**: {pass_count} | **Fail**: {fail_count}
- **WCAG Level**: {AA|AAA}
- **Critical issues**: {count}
- **High issues**: {count}
## Color Palette (OKLCH)
| Name | Value | L% | C | H | Source |
|------|-------|----|---|---|--------|
| ... | oklch(X% Y Z) | X | Y | Z | file:line |
## Contrast Results
| Foreground | Background | WCAG Ratio | Pass/Fail | APCA Lc | Pass/Fail | Type |
|-----------|-----------|------------|-----------|---------|-----------|------|
| ... | ... | X.X:1 | PASS/FAIL | XX | PASS/FAIL | normal/large |
## OKLCH Lightness Issues
| Element | Current L | Expected Range | Status |
|---------|----------|---------------|--------|
| ... | X% | Y-Z% | PASS/FAIL |
## Color Blindness Assessment
| Combination | Protanopia | Deuteranopia | Tritanopia | Alt indicator |
|------------|-----------|-------------|-----------|--------------|
| ... | safe/risk | safe/risk | safe/risk | yes/no |
## Dark Mode Parity
| Combination | Light Mode | Dark Mode | Status |
|------------|-----------|----------|--------|
| ... | PASS/FAIL | PASS/FAIL | PASS/FAIL |
## Issues (by severity)
### Critical
- ...
### High
- ...
### Medium
- ...
```
2. For re-audit (COLOR-002+), add before/after comparison section:
```markdown
## Before/After Comparison
| Combination | Before (ratio) | After (ratio) | Status |
|------------|----------------|---------------|--------|
| ... | X.X:1 FAIL | Y.Y:1 PASS | FIXED |
```
3. Update `<session>/.msg/meta.json` under `color-auditor` namespace:
- Read existing -> merge `{ "color-auditor": { audit_id, total_combinations, pass_count, fail_count, critical_count, high_count, timestamp } }` -> write back

View File

@@ -0,0 +1,72 @@
# Analyze Task
Parse user task -> detect accessibility audit scope -> determine target -> select pipeline mode.
**CONSTRAINT**: Text-level analysis only. NO source code reading, NO codebase exploration.
## Signal Detection
| Keywords | Capability | Pipeline Hint |
|----------|------------|---------------|
| color, contrast, oklch, palette, hue | color audit | audit-only or full |
| typography, font, line-height, clamp, readability | typography audit | audit-only or full |
| focus, tab, keyboard, aria, skip-link, focus-visible | focus audit | audit-only or full |
| wcag, a11y, accessibility, compliance | full audit | audit-only or full |
| fix, remediate, implement, correct | fix cycle | full |
| audit only, assessment, review, check | audit only | audit-only |
## Target Detection
| Signal | Target Type |
|--------|-------------|
| URL (http/https) | rendered-page |
| File path (.tsx, .vue, .html, .css) | component-source |
| "full site", "all pages", "entire app" | full-site |
| Component name without path | component-source (search needed) |
| Unclear | ask user |
## Mode Determination
| Signal | Pipeline Mode |
|--------|---------------|
| "audit only", "no fixes", "assessment", "review" | audit-only |
| "full", "fix", "remediate", "complete cycle" | full |
| Single audit domain (color OR typography OR focus only) | audit-only |
| Unclear | ask user |
## WCAG Level Detection
| Signal | Level |
|--------|-------|
| "AA" or default | AA |
| "AAA", "enhanced", "strict" | AAA |
## Complexity Scoring
| Factor | Points |
|--------|--------|
| Single component | +1 |
| Multiple components | +2 |
| Full site | +3 |
| Rendered page (Chrome DevTools) | +1 |
| AAA level requested | +1 |
| Fix cycle included | +1 |
Results: 1-2 Low, 3-4 Medium, 5+ High
## Output
Write scope context to coordinator memory:
```json
{
"pipeline_mode": "<audit-only|full>",
"target": {
"type": "<rendered-page|component-source|full-site>",
"value": "<URL or file path or 'all'>"
},
"wcag_level": "<AA|AAA>",
"scope": "<description>",
"complexity": { "score": 0, "level": "Low|Medium|High" },
"chrome_devtools": true
}
```

View File

@@ -0,0 +1,188 @@
# Command: Dispatch
Create the visual accessibility task chain with correct dependencies and structured task descriptions. Supports audit-only and full pipeline modes.
## Phase 2: Context Loading
| Input | Source | Required |
|-------|--------|----------|
| User requirement | From coordinator Phase 1 | Yes |
| Session folder | From coordinator Phase 2 | Yes |
| Pipeline mode | From session tasks.json `pipeline_mode` | Yes |
| Target info | From session tasks.json `target` | Yes |
1. Load user requirement and scope from tasks.json
2. Load pipeline stage definitions from specs/pipelines.md
3. Read `pipeline_mode` and `target` from tasks.json
## Phase 3: Task Chain Creation (Mode-Branched)
### Task Description Template
Every task is added to tasks.json with structured format:
```json
{
"<TASK-ID>": {
"title": "<task title>",
"description": "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>\nTASK:\n - <step 1: specific action>\n - <step 2: specific action>\n - <step 3: specific action>\nCONTEXT:\n - Session: <session-folder>\n - Target: <URL or file path>\n - WCAG Level: <AA|AAA>\n - Upstream artifacts: <artifact-1>, <artifact-2>\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <deliverable path> + <quality criteria>\nCONSTRAINTS: <scope limits, focus areas>",
"role": "<role-name>",
"prefix": "<PREFIX>",
"deps": ["<dependency-list>"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
### Mode Router
| Mode | Action |
|------|--------|
| `audit-only` | Create 4 tasks: [COLOR-001 + TYPO-001 + FOCUS-001] parallel -> REMED-001 |
| `full` | Create 7 tasks: [COLOR-001 + TYPO-001 + FOCUS-001] -> REMED-001 -> FIX-001 -> [COLOR-002 + FOCUS-002] |
---
### Audit-Only Pipeline Task Chain
**COLOR-001** (color-auditor):
```json
{
"COLOR-001": {
"title": "OKLCH Color Contrast Audit",
"description": "PURPOSE: OKLCH color contrast audit for all color combinations | Success: Complete color audit with WCAG 2.1 + APCA contrast ratios and color blindness assessment\nTASK:\n - Extract all color values (OKLCH, HSL, RGB, hex) from stylesheets\n - Calculate WCAG 2.1 contrast ratios for all text/background combinations\n - Calculate APCA Lc values for body and large text\n - Assess OKLCH lightness ranges for text and backgrounds\n - Simulate color blindness (protanopia, deuteranopia, tritanopia)\n - Check dark mode color parity if applicable\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/audits/color/color-audit-001.md | Pass/fail per color combination\nCONSTRAINTS: Read-only analysis | Use Chrome DevTools for computed styles when available",
"role": "color-auditor",
"prefix": "COLOR",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**TYPO-001** (typo-auditor):
```json
{
"TYPO-001": {
"title": "Typography Readability Audit",
"description": "PURPOSE: Typography readability audit across all viewports | Success: Complete typography audit with size, line-height, reading width at each breakpoint\nTASK:\n - Audit font sizes at each breakpoint (320px, 768px, 1024px, 1400px)\n - Validate minimum body text >= 16px on mobile\n - Check line-height ratios (body 1.5-1.75, headings 1.1-1.3)\n - Validate clamp() functions for responsive scaling\n - Measure reading width (45-75 characters per line)\n - Assess font loading strategy (font-display values)\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/audits/typography/typo-audit-001.md | Breakpoint-by-breakpoint report\nCONSTRAINTS: Read-only analysis | Screenshot at multiple viewports if Chrome DevTools available",
"role": "typo-auditor",
"prefix": "TYPO",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**FOCUS-001** (focus-auditor):
```json
{
"FOCUS-001": {
"title": "Focus & Keyboard Accessibility Audit",
"description": "PURPOSE: Focus management and keyboard accessibility audit | Success: Complete focus audit with tab order, indicator visibility, ARIA coverage\nTASK:\n - Audit tab order for logical sequence and no tab traps\n - Check focus indicator visibility (outline >= 2px, contrast >= 3:1)\n - Verify :focus-visible usage for keyboard vs mouse distinction\n - Check skip link presence and functionality\n - Audit focus traps in modals/dialogs (Tab cycles, Escape dismisses)\n - Verify ARIA live regions for dynamic content\n - Check ARIA roles and states on interactive elements\n - Validate keyboard operability (Enter/Space, Arrow keys)\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/audits/focus/focus-audit-001.md | Element-by-element focus report\nCONSTRAINTS: Read-only analysis | Tab through elements if Chrome DevTools available",
"role": "focus-auditor",
"prefix": "FOCUS",
"deps": [],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**CRITICAL**: COLOR-001, TYPO-001, FOCUS-001 have NO deps -- they run in PARALLEL.
**REMED-001** (remediation-planner):
```json
{
"REMED-001": {
"title": "Prioritized Remediation Plan",
"description": "PURPOSE: Synthesize all 3 audit findings into prioritized remediation plan | Success: Complete remediation plan with severity ranking, code-level fix guidance, WCAG criterion mapping\nTASK:\n - Read color, typography, and focus audit reports\n - Merge and deduplicate findings\n - Prioritize by severity (Critical > High > Medium > Low)\n - Group by file/component for efficient fixing\n - Provide code-level fix guidance (specific CSS/HTML changes)\n - Map each fix to WCAG success criterion\n - Estimate effort per fix\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Upstream artifacts: audits/color/color-audit-001.md, audits/typography/typo-audit-001.md, audits/focus/focus-audit-001.md\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/remediation/remediation-plan.md | All critical/high issues addressed\nCONSTRAINTS: Read-only synthesis | No code modifications",
"role": "remediation-planner",
"prefix": "REMED",
"deps": ["COLOR-001", "TYPO-001", "FOCUS-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
---
### Full Pipeline Task Chain
Same as audit-only (COLOR-001, TYPO-001, FOCUS-001, REMED-001), plus:
**FIX-001** (fix-implementer):
```json
{
"FIX-001": {
"title": "Implement Accessibility Fixes",
"description": "PURPOSE: Implement accessibility fixes from remediation plan | Success: All critical and high severity issues fixed with passing contrast ratios and ARIA validation\nTASK:\n - Read remediation plan for prioritized fix list\n - Apply OKLCH color corrections for contrast compliance\n - Add/fix focus styles (outline, outline-offset, :focus-visible)\n - Add missing ARIA attributes (role, aria-label, aria-live, aria-expanded)\n - Add reduced-motion media queries where needed\n - Fix typography (clamp(), line-height, max-width for reading)\n - Add skip link if missing\n - Apply fixes in priority order (critical first)\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Upstream artifacts: remediation/remediation-plan.md\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: Modified source files + <session>/fixes/fix-summary-001.md | All critical/high fixes applied\nCONSTRAINTS: Modify only files identified in remediation plan | Preserve existing functionality",
"role": "fix-implementer",
"prefix": "FIX",
"deps": ["REMED-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**COLOR-002** (color-auditor):
```json
{
"COLOR-002": {
"title": "Re-audit Color Contrast After Fixes",
"description": "PURPOSE: Re-audit color contrast after fixes applied | Success: All color combinations pass WCAG target level\nTASK:\n - Re-extract all color values from modified stylesheets\n - Re-calculate WCAG 2.1 contrast ratios\n - Re-calculate APCA Lc values\n - Compare before/after for each fixed combination\n - Verify no regressions in unfixed combinations\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Upstream artifacts: fixes/fix-summary-001.md, audits/color/color-audit-001.md\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/re-audit/color-audit-002.md | Before/after comparison with pass/fail\nCONSTRAINTS: Read-only verification | Focus on fixed items + regression check",
"role": "color-auditor",
"prefix": "COLOR",
"deps": ["FIX-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**FOCUS-002** (focus-auditor):
```json
{
"FOCUS-002": {
"title": "Re-audit Focus Management After Fixes",
"description": "PURPOSE: Re-audit focus management after fixes applied | Success: All focus indicators visible with correct ARIA attributes\nTASK:\n - Re-audit tab order after DOM changes\n - Verify focus indicator fixes (outline, contrast)\n - Check new ARIA attributes are valid\n - Verify skip link implementation\n - Test keyboard operability of fixed elements\n - Compare before/after for each fixed element\nCONTEXT:\n - Session: <session-folder>\n - Target: <target>\n - WCAG Level: <level>\n - Upstream artifacts: fixes/fix-summary-001.md, audits/focus/focus-audit-001.md\n - Shared memory: <session>/.msg/meta.json\nEXPECTED: <session>/re-audit/focus-audit-002.md | Before/after comparison with pass/fail\nCONSTRAINTS: Read-only verification | Focus on fixed items + regression check",
"role": "focus-auditor",
"prefix": "FOCUS",
"deps": ["FIX-001"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
**CRITICAL**: COLOR-002 and FOCUS-002 both blocked only by FIX-001 -- they run in PARALLEL after fixes.
---
## Phase 4: Validation
Verify task chain integrity:
| Check | Method | Expected |
|-------|--------|----------|
| Task count correct | tasks.json count | audit-only: 4, full: 7 |
| Dependencies correct | Trace dependency graph | Acyclic, correct deps |
| No circular dependencies | Trace dependency graph | Acyclic |
| 3 audit tasks have NO deps | Pattern check | COLOR-001, TYPO-001, FOCUS-001 are parallel |
| REMED-001 blocked by all 3 | Check deps | [COLOR-001, TYPO-001, FOCUS-001] |
| Task IDs use correct prefixes | Pattern check | COLOR/TYPO/FOCUS/REMED/FIX |
| Structured descriptions complete | Each has PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS | All present |
If validation fails, fix the specific task and re-validate.

View File

@@ -0,0 +1,281 @@
# Monitor Pipeline
Synchronous pipeline coordination using spawn_agent + wait_agent.
## Constants
- WORKER_AGENT: team_worker
- MAX_GC_ROUNDS: 2
## Handler Router
| Source | Handler |
|--------|---------|
| "capability_gap" | handleAdapt |
| "check" or "status" | handleCheck |
| "resume" or "continue" | handleResume |
| All tasks completed | handleComplete |
| Default | handleSpawnNext |
## handleCallback
Worker completed (wait_agent returns). Process and advance.
1. Determine role from completed task prefix:
| Task Prefix | Role |
|-------------|------|
| `COLOR-*` | color-auditor |
| `TYPO-*` | typo-auditor |
| `FOCUS-*` | focus-auditor |
| `REMED-*` | remediation-planner |
| `FIX-*` | fix-implementer |
2. Mark task completed in tasks.json: `state.tasks[taskId].status = 'completed'`
3. Record completion in session state
4. Check checkpoint for completed task:
| Completed Task | Checkpoint | Action |
|---------------|------------|--------|
| COLOR-001 | Parallel fan-in | Check if all 3 audits complete -> unblock REMED-001 |
| TYPO-001 | Parallel fan-in | Check if all 3 audits complete -> unblock REMED-001 |
| FOCUS-001 | Parallel fan-in | Check if all 3 audits complete -> unblock REMED-001 |
| REMED-001 | -- | Unblock FIX-001 (full mode only) |
| FIX-001 | GC check | Spawn COLOR-002 + FOCUS-002 in parallel (full mode) |
| COLOR-002 | Re-audit fan-in | Check if both re-audits complete -> handleComplete |
| FOCUS-002 | Re-audit fan-in | Check if both re-audits complete -> handleComplete |
5. **Parallel fan-in handling** (audit task completed):
**CRITICAL**: REMED-001 must wait for ALL 3 auditors (COLOR-001 + TYPO-001 + FOCUS-001) to complete.
Since all 3 are spawned together and waited on together:
```javascript
// Spawn all 3 auditors
spawn_agent({ agent_type: "team_worker", task_name: "COLOR-001", ... })
spawn_agent({ agent_type: "team_worker", task_name: "TYPO-001", ... })
spawn_agent({ agent_type: "team_worker", task_name: "FOCUS-001", ... })
// Wait for ALL 3 to complete
wait_agent({ targets: ["COLOR-001", "TYPO-001", "FOCUS-001"], timeout_ms: 900000 })
// Close all 3
close_agent({ target: "COLOR-001" })
close_agent({ target: "TYPO-001" })
close_agent({ target: "FOCUS-001" })
// Mark all 3 completed in tasks.json
// Then spawn REMED-001
```
6. **GC loop handling** (full mode, after FIX-001 completes):
Spawn COLOR-002 + FOCUS-002 in parallel, wait for both:
```javascript
spawn_agent({ agent_type: "team_worker", task_name: "COLOR-002", ... })
spawn_agent({ agent_type: "team_worker", task_name: "FOCUS-002", ... })
wait_agent({ targets: ["COLOR-002", "FOCUS-002"], timeout_ms: 900000 })
close_agent({ target: "COLOR-002" })
close_agent({ target: "FOCUS-002" })
```
Read re-audit results:
| Signal | Condition | Action |
|--------|-----------|--------|
| All pass | No critical/high issues remaining | GC converged -> handleComplete |
| Issues remain | Critical/high issues found | gc_rounds < max -> create FIX-002 + re-audit tasks |
| Any | gc_rounds >= max | Escalate to user |
**GC Fix Task Creation** (when re-audit finds issues):
```json
{
"FIX-002": {
"title": "Address remaining issues from re-audit",
"description": "PURPOSE: Address remaining issues from re-audit | Success: All critical/high issues resolved\nTASK:\n - Parse re-audit reports for remaining issues\n - Apply targeted fixes for color and focus issues\nCONTEXT:\n - Session: <session-folder>\n - Upstream artifacts: re-audit/color-audit-002.md, re-audit/focus-audit-002.md",
"role": "fix-implementer",
"prefix": "FIX",
"deps": ["COLOR-002", "FOCUS-002"],
"status": "pending",
"findings": "",
"error": ""
}
}
```
Then create new re-audit tasks with deps on FIX-002. Increment gc_rounds.
**GC Escalation Options** (when max rounds exceeded):
1. Accept current state - acknowledge remaining issues
2. Try one more round
3. Terminate
7. -> handleSpawnNext
## handleCheck
Read-only status report from tasks.json, then STOP.
```
Pipeline Status (<pipeline-mode>):
[DONE] COLOR-001 (color-auditor) -> audits/color/color-audit-001.md
[DONE] TYPO-001 (typo-auditor) -> audits/typography/typo-audit-001.md
[RUN] FOCUS-001 (focus-auditor) -> auditing focus...
[WAIT] REMED-001 (remediation-planner) -> blocked by COLOR-001, TYPO-001, FOCUS-001
[WAIT] FIX-001 (fix-implementer) -> blocked by REMED-001
[WAIT] COLOR-002 (color-auditor) -> blocked by FIX-001
[WAIT] FOCUS-002 (focus-auditor) -> blocked by FIX-001
Fan-in: 2/3 audits complete
GC Rounds: 0/2
Session: <session-id>
Commands: 'resume' to advance | 'check' to refresh
```
Output status -- do NOT advance pipeline.
## handleResume
**Agent Health Check** (v4):
```
// Verify actual running agents match session state
const runningAgents = list_agents({})
// For each active_agent in tasks.json:
// - If agent NOT in runningAgents -> agent crashed
// - Reset that task to pending, remove from active_agents
// This prevents stale agent references from blocking the pipeline
```
1. Audit tasks.json for inconsistencies:
- Tasks stuck in "in_progress" -> reset to "pending"
- Tasks with completed deps but still "pending" -> include in spawn list
2. -> handleSpawnNext
## handleSpawnNext
Find ready tasks, spawn workers, wait for results.
1. Read tasks.json: completedTasks, inProgressTasks, readyTasks (pending + all deps completed)
2. No ready + work in progress -> report waiting, STOP
3. No ready + nothing in progress -> handleComplete
4. Has ready -> for each:
a. Check inner loop role with active worker -> skip (worker picks up)
b. Update task status to in_progress in tasks.json
c. team_msg log -> task_unblocked
d. Spawn team_worker:
```javascript
// 1) Update status in tasks.json
state.tasks[taskId].status = 'in_progress'
// 2) Spawn worker
const agentId = spawn_agent({
agent_type: "team_worker",
task_name: taskId, // e.g., "COLOR-001" -- enables named targeting
fork_context: false,
items: [
{ type: "text", text: `## Role Assignment
role: ${role}
role_spec: ${skillRoot}/roles/${role}/role.md
session: ${sessionFolder}
session_id: ${sessionId}
requirement: ${taskDescription}
inner_loop: ${innerLoop}
Read role_spec file to load Phase 2-4 domain instructions.` },
{ type: "text", text: `## Task Context
task_id: ${taskId}
title: ${taskTitle}
description: ${taskDescription}
pipeline_phase: ${pipelinePhase}` },
{ type: "text", text: `## Upstream Context
${upstreamContext}` }
]
})
// 3) Track agent
state.active_agents[taskId] = { agentId, role, started_at: now }
// 4) Wait for completion -- use task_name for stable targeting (v4)
const waitResult = wait_agent({ targets: [taskId], timeout_ms: 900000 })
if (waitResult.timed_out) {
state.tasks[taskId].status = 'timed_out'
close_agent({ target: taskId })
delete state.active_agents[taskId]
} else {
// 5) Collect results and update tasks.json
state.tasks[taskId].status = 'completed'
close_agent({ target: taskId }) // Use task_name, not agentId
delete state.active_agents[taskId]
}
```
**Parallel spawn rules by mode**:
| Mode | Scenario | Spawn Behavior |
|------|----------|---------------|
| audit-only | Initial | Spawn COLOR-001 + TYPO-001 + FOCUS-001 in parallel, wait_agent for all 3 |
| audit-only | After 3 audits complete | Spawn REMED-001 |
| full | Initial | Spawn COLOR-001 + TYPO-001 + FOCUS-001 in parallel, wait_agent for all 3 |
| full | After 3 audits complete | Spawn REMED-001 |
| full | After REMED-001 | Spawn FIX-001 |
| full | After FIX-001 | Spawn COLOR-002 + FOCUS-002 in parallel, wait_agent for both |
| full (GC) | After re-audit fan-in | If issues: spawn FIX-002, then new re-audits |
**Cross-Agent Supplementary Context** (v4):
When spawning workers in a later pipeline phase, send upstream results as supplementary context to already-running workers:
```
// Example: Send audit results to running remediation-planner
send_message({
target: "<running-agent-task-name>",
items: [{ type: "text", text: `## Supplementary Context\n${upstreamFindings}` }]
})
// Note: send_message queues info without interrupting the agent's current work
```
Use `send_message` (not `assign_task`) for supplementary info that enriches but doesn't redirect the agent's current task.
5. Update tasks.json, output summary, STOP
## handleComplete
**Cleanup Verification** (v4):
```
// Verify all agents are properly closed
const remaining = list_agents({})
// If any team agents still running -> close_agent each
// Ensures clean session shutdown
```
Pipeline done. Generate report and completion action.
**Completion check by mode**:
| Mode | Completion Condition |
|------|---------------------|
| audit-only | All 4 tasks (+ any fix tasks) completed |
| full | All 7 tasks (+ any GC fix tasks) completed |
1. If any tasks not completed -> handleSpawnNext
2. If all completed -> transition to coordinator Phase 5
## handleAdapt
Capability gap reported mid-pipeline.
1. Parse gap description
2. Check if existing role covers it -> redirect
3. Role count < 6 -> generate dynamic role spec
4. Create new task in tasks.json, spawn worker
5. Role count >= 6 -> merge or pause
## Fast-Advance Reconciliation
On every coordinator wake:
1. Read tasks.json for completed tasks
2. Sync active_agents with actual state
3. No duplicate spawns

View File

@@ -0,0 +1,213 @@
# Coordinator Role
Visual Accessibility Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages parallel fan-in (3 auditors), remediation synthesis, fix implementation, and optional re-audit GC loop.
## Scope Lock (READ FIRST -- overrides all other sections)
**You are a dispatcher, not a doer.** Your ONLY outputs are:
- Session state files (`.workflow/.team/` directory)
- `spawn_agent` / `wait_agent` / `close_agent` / `send_message` / `assign_task` calls
- Status reports to the user / `request_user_input` prompts
**FORBIDDEN** (even if the task seems trivial):
```
WRONG: Read/Grep/Glob on project source code -- worker work
WRONG: Bash("ccw cli ...") -- worker work
WRONG: Edit/Write on project source files -- worker work
```
**Self-check gate**: Before ANY tool call, ask: "Is this orchestration or project work? If project work -> STOP -> spawn worker."
---
## Identity
- **Name**: coordinator | **Tag**: [coordinator]
- **Responsibility**: Analyze scope -> Create session -> Dispatch tasks -> Monitor progress -> Report results
## Boundaries
### MUST
- All output (team_msg, logs) must carry `[coordinator]` identifier
- Use `team_worker` agent type for all worker spawns (NOT `general-purpose`)
- Dispatch tasks with proper dependency chains and deps in tasks.json
- Spawn COLOR-001, TYPO-001, FOCUS-001 in PARALLEL (no deps between them)
- Monitor worker progress via wait_agent and process results
- Handle Generator-Critic loops with max 2 iterations
- Maintain session state persistence (tasks.json)
- **Always proceed through full Phase 1-5 workflow, never skip to direct execution**
- Use `send_message` for supplementary context (non-interrupting) and `assign_task` for triggering new work
- Use `list_agents` for session resume health checks and cleanup verification
### MUST NOT
- Implement domain logic (auditing, planning, fixing) -- workers handle this
- Spawn workers without creating tasks first
- Skip sync points when configured
- Force-advance pipeline past failed audit
- Modify source code or design artifacts directly -- delegate to workers
- Omit `[coordinator]` identifier in any output
- Call CLI tools (ccw cli) -- only workers use CLI
## Command Execution Protocol
When coordinator needs to execute a command (analyze, dispatch, monitor):
1. Read `commands/<command>.md`
2. Follow the workflow defined in the command
3. Commands are inline execution guides, NOT separate agents
4. Execute synchronously, complete before proceeding
## Entry Router
| Detection | Condition | Handler |
|-----------|-----------|---------|
| Status check | Args contain "check" or "status" | -> handleCheck (monitor.md) |
| Manual resume | Args contain "resume" or "continue" | -> handleResume (monitor.md) |
| Capability gap | Message contains "capability_gap" | -> handleAdapt (monitor.md) |
| Pipeline complete | All tasks have status "completed" | -> handleComplete (monitor.md) |
| Interrupted session | Active/paused session exists in .workflow/.team/VA-* | -> Phase 0 |
| New session | None of above | -> Phase 1 |
For check/resume/adapt/complete: load `@commands/monitor.md`, execute matched handler, STOP.
## Phase 0: Session Resume Check
1. Scan `.workflow/.team/VA-*/tasks.json` for active/paused sessions
2. No sessions -> Phase 1
3. Single session -> reconcile (read tasks.json, reset in_progress->pending, kick first ready task)
4. Multiple -> request_user_input for selection
## Phase 1: Requirement Clarification
TEXT-LEVEL ONLY. No source code reading.
1. Parse task description from arguments
2. Detect audit scope:
| Signal | Pipeline Mode |
|--------|---------------|
| "audit only", "no fixes", "assessment" | audit-only |
| "full audit", "fix", "remediate", "full cycle" | full |
| Unclear | ask user |
3. Ask for missing parameters if scope unclear:
```
request_user_input({
questions: [
{ question: "Accessibility audit scope?", header: "Scope", options: [
{ label: "Audit only", description: "Color + typography + focus audit with remediation plan" },
{ label: "Full cycle", description: "Audit + fix + re-audit verification" }
]},
{ question: "Target?", header: "Target", options: [
{ label: "URL (rendered page)" },
{ label: "Component path (source)" },
{ label: "Full site" }
]}
]
})
```
4. Delegate to `@commands/analyze.md` -> output scope context
5. Record: pipeline_mode, target, wcag_level
## Phase 2: Create Session + Initialize
1. Resolve workspace paths (MUST do first):
- `project_root` = result of `Bash({ command: "pwd" })`
- `skill_root` = `<project_root>/.codex/skills/team-visual-a11y`
2. Generate session ID: `VA-<slug>-<YYYY-MM-DD>`
3. Create session folder structure:
```
.workflow/.team/VA-<slug>-<date>/audits/color/
.workflow/.team/VA-<slug>-<date>/audits/typography/
.workflow/.team/VA-<slug>-<date>/audits/focus/
.workflow/.team/VA-<slug>-<date>/remediation/
.workflow/.team/VA-<slug>-<date>/fixes/
.workflow/.team/VA-<slug>-<date>/re-audit/
.workflow/.team/VA-<slug>-<date>/evidence/
.workflow/.team/VA-<slug>-<date>/.msg/
```
4. Initialize `.msg/meta.json` via team_msg state_update with pipeline metadata
5. Write initial tasks.json:
```json
{
"session_id": "<id>",
"pipeline_mode": "<audit-only|full>",
"target": "<target>",
"wcag_level": "<AA|AAA>",
"created_at": "<ISO timestamp>",
"gc_rounds": 0,
"max_gc_rounds": 2,
"active_agents": {},
"tasks": {}
}
```
6. Do NOT spawn workers yet - deferred to Phase 4
## Phase 3: Create Task Chain
Delegate to `@commands/dispatch.md`. Task chains by mode:
| Mode | Task Chain |
|------|------------|
| audit-only | [COLOR-001 + TYPO-001 + FOCUS-001 parallel] -> REMED-001 |
| full | [COLOR-001 + TYPO-001 + FOCUS-001 parallel] -> REMED-001 -> FIX-001 -> [COLOR-002 + FOCUS-002 parallel] |
## Phase 4: Spawn-and-Wait
**CRITICAL**: Spawn COLOR-001, TYPO-001, FOCUS-001 in PARALLEL (all 3 have NO deps).
Delegate to `@commands/monitor.md#handleSpawnNext`:
1. Find ready tasks (pending + deps resolved)
2. Spawn team_worker agents via spawn_agent, wait_agent for results
3. Output status summary
4. STOP
## Phase 5: Report + Completion Action
1. Read session state -> collect all results
2. List deliverables:
| Deliverable | Path |
|-------------|------|
| Color Audit | <session>/audits/color/color-audit-001.md |
| Typography Audit | <session>/audits/typography/typo-audit-001.md |
| Focus Audit | <session>/audits/focus/focus-audit-001.md |
| Remediation Plan | <session>/remediation/remediation-plan.md |
| Fix Summary | <session>/fixes/fix-summary-001.md (full mode) |
| Re-audit Color | <session>/re-audit/color-audit-002.md (full mode) |
| Re-audit Focus | <session>/re-audit/focus-audit-002.md (full mode) |
| Evidence | <session>/evidence/*.png (if Chrome DevTools used) |
3. Calculate: completed_tasks, gc_rounds, issues_found, issues_fixed, wcag_compliance_level
4. Output pipeline summary with [coordinator] prefix
5. Execute completion action:
```
request_user_input({
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
{ label: "Archive & Clean", description: "Archive session and clean up resources" },
{ label: "Keep Active", description: "Keep session for follow-up work" },
{ label: "Export Results", description: "Export deliverables to specified location" }
]}]
})
```
## v4 Coordination Patterns
### Message Semantics
- **send_message**: Queue supplementary info to a running agent. Does NOT interrupt current processing. Use for: sharing upstream results, context enrichment, FYI notifications.
- **assign_task**: Assign new work and trigger processing. Use for: waking idle agents, redirecting work, requesting new output.
### Agent Lifecycle Management
- **list_agents({})**: Returns all running agents. Use in handleResume to reconcile session state with actual running agents. Use in handleComplete to verify clean shutdown.
- **Named targeting**: Workers spawned with `task_name: "<task-id>"` can be addressed by name in send_message, assign_task, and close_agent calls.
## Error Handling
| Error | Resolution |
|-------|------------|
| Task timeout | Log, mark failed, ask user to retry or skip |
| Worker crash | Reset task to pending, respawn worker |
| Dependency cycle | Detect, report to user, halt |
| Invalid scope | Reject with error, ask to clarify |
| Session corruption | Attempt recovery, fallback to manual reconciliation |
| GC loop stuck > 2 rounds | Escalate to user: accept / try one more / terminate |
| Chrome DevTools unavailable | Mark in meta.json, auditors degrade to static analysis |

View File

@@ -0,0 +1,246 @@
---
role: fix-implementer
prefix: FIX
inner_loop: true
message_types: [state_update]
---
# Accessibility Fix Implementer
Implement accessibility fixes from the remediation plan. OKLCH color corrections, focus styles, ARIA attributes, reduced-motion queries, typography adjustments. Apply fixes in priority order (critical first) and self-validate results.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| Remediation plan | <session>/remediation/remediation-plan.md | Yes |
| Color audit report | <session>/audits/color/color-audit-001.md | Yes |
| Focus audit report | <session>/audits/focus/focus-audit-001.md | Yes |
| Typography audit report | <session>/audits/typography/typo-audit-001.md | Yes |
| .msg/meta.json | <session>/.msg/meta.json | Yes |
| Re-audit reports (GC loop) | <session>/re-audit/*.md | Only for FIX-002+ |
1. Extract session path from task description
2. Read remediation plan -- this is the primary work instruction
3. Parse priority matrix for ordered fix list
4. Read audit reports for detailed context on each issue
5. For FIX-002+ (GC loop): read re-audit reports for remaining issues
## Phase 3: Fix Implementation
Apply fixes in priority order: Critical -> High -> Medium -> Low.
### Category 1: OKLCH Color Corrections
**Goal**: Adjust OKLCH lightness/chroma to meet contrast requirements.
**Process**:
1. Read remediation plan for specific color changes needed
2. Locate CSS custom properties or color definitions in source files
3. Apply lightness adjustments:
- Text too light -> decrease L% (e.g., L 55% -> L 35%)
- Background too dark -> increase L% (e.g., L 80% -> L 92%)
- Maintain hue (H) and adjust chroma (C) minimally
4. Verify new contrast ratios meet WCAG target
5. If dark mode exists, apply corresponding adjustments
**Example**:
```css
/* Before: contrast 3.2:1 */
--color-text: oklch(55% 0 0);
--color-bg: oklch(98% 0 0);
/* After: contrast 7.2:1 (AAA) */
--color-text: oklch(25% 0 0);
--color-bg: oklch(98% 0 0);
```
### Category 2: Focus Styles
**Goal**: Add visible, high-contrast focus indicators for keyboard users.
**Process**:
1. Add `:focus-visible` rules per specs/focus-patterns.md:
```css
:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
:focus:not(:focus-visible) {
outline: none;
}
```
2. Remove bare `outline: none` or `outline: 0` that suppress focus without alternative
3. Verify focus indicator contrast >= 3:1 against adjacent colors
4. Add consistent focus style across all interactive elements
### Category 3: ARIA Attributes
**Goal**: Add missing ARIA roles, states, and properties.
**Process**:
1. Add `role` attributes where semantic HTML is not used:
- `<div onclick>` -> add `role="button"` and `tabindex="0"`
- Custom widgets -> appropriate ARIA role
2. Add state attributes:
- Toggle buttons: `aria-pressed="true|false"`
- Expandable: `aria-expanded="true|false"`, `aria-controls="panel-id"`
- Dialogs: `role="dialog"`, `aria-modal="true"`, `aria-labelledby="title-id"`
3. Add labels:
- `aria-label` for icon-only buttons
- `aria-labelledby` for dialogs and sections
- `aria-describedby` for form error messages
4. Add live regions:
- Status messages: `aria-live="polite"`
- Error messages: `aria-live="assertive"`
### Category 4: Reduced-Motion Queries
**Goal**: Respect user's motion preferences.
**Process**:
1. Wrap animations and transitions in media query:
```css
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
2. Or per-element: disable specific animations while keeping layout
3. Ensure no content is lost when motion is reduced
### Category 5: Typography Adjustments
**Goal**: Fix font sizes, line heights, and reading widths.
**Process**:
1. Replace fixed font sizes with responsive clamp():
```css
body { font-size: clamp(1rem, 1vw + 0.875rem, 1.25rem); }
```
2. Fix line-height to acceptable ranges:
```css
body { line-height: 1.625; }
h1, h2, h3 { line-height: 1.2; }
```
3. Add max-width for reading containers:
```css
.content { max-width: 70ch; }
```
### Category 6: Skip Link
**Goal**: Add skip-to-main-content link if missing.
**Process** (per specs/focus-patterns.md):
1. Add as first child of `<body>`:
```html
<a href="#main" class="skip-link">Skip to main content</a>
```
2. Add CSS:
```css
.skip-link {
position: absolute;
left: -9999px;
top: auto;
}
.skip-link:focus {
position: fixed;
left: 16px;
top: 16px;
z-index: 9999;
background: var(--color-paper, #fff);
color: var(--color-ink, #000);
padding: 8px 16px;
border-radius: 4px;
text-decoration: underline;
}
```
3. Ensure main content has `id="main"` (or equivalent target)
### Category 7: Focus Trap for Modals
**Goal**: Implement proper focus management in dialogs.
**Process** (per specs/focus-patterns.md):
1. On dialog open:
- Store `document.activeElement` as return target
- Move focus to first focusable element within dialog
2. Trap Tab/Shift+Tab within dialog:
- Collect all focusable elements within dialog
- On Tab at last element -> focus first element
- On Shift+Tab at first element -> focus last element
3. On Escape -> close dialog, restore focus to stored element
4. Set `aria-modal="true"` on dialog container
5. Optional: set `inert` on background content
## Phase 4: Self-Validation & Output
1. Validate each fix category:
| Category | Validation Method |
|----------|------------------|
| Color | Recalculate contrast ratios for changed colors, verify >= target |
| Focus | Search for :focus-visible rules, verify no bare outline:none |
| ARIA | Check all dialogs have role+aria-modal, all buttons have labels |
| Motion | Verify prefers-reduced-motion media query exists |
| Typography | Check clamp() minimum >= 1rem, line-height in range |
| Skip link | Verify skip link element exists, CSS hides then shows on focus |
| Focus trap | Verify dialog has focus management code |
2. Write fix summary to `<session>/fixes/fix-summary-{NNN}.md`:
```markdown
# Fix Summary - {NNN}
[fix-implementer]
## Overview
- **Total fixes applied**: {count}
- **Critical fixed**: {count}
- **High fixed**: {count}
- **Medium fixed**: {count}
- **Files modified**: {count}
## Fixes Applied
### Fix 1: Color contrast (Critical, WCAG 1.4.3)
- **File**: `src/styles/globals.css:12`
- **Before**: `--color-text: oklch(55% 0 0)` (contrast 3.2:1)
- **After**: `--color-text: oklch(25% 0 0)` (contrast 7.2:1)
- **Validated**: PASS
### Fix 2: Focus indicators (High, WCAG 2.4.7)
- **File**: `src/styles/globals.css:45`
- **Before**: No :focus-visible rules
- **After**: Added :focus-visible with 2px outline
- **Validated**: PASS
...
## Files Modified
| File | Changes |
|------|---------|
| src/styles/globals.css | Color adjustments, focus styles, reduced-motion |
| src/components/Modal.tsx | Focus trap, ARIA attributes |
| src/app/layout.tsx | Skip link |
## Remaining Issues
- {Any medium/low issues not addressed in this round}
## Verification Status
- [ ] Color contrast: {n}/{total} passing
- [ ] Focus indicators: {n}/{total} visible
- [ ] ARIA coverage: {n}/{total} complete
- [ ] Typography: {n}/{total} compliant
```
3. Update `<session>/.msg/meta.json` under `fix-implementer` namespace:
- Read existing -> merge `{ "fix-implementer": { fix_id, total_fixes, critical_fixed, high_fixed, medium_fixed, files_modified, timestamp } }` -> write back

View File

@@ -0,0 +1,222 @@
---
role: focus-auditor
prefix: FOCUS
inner_loop: false
message_types: [state_update]
---
# Focus & Keyboard Accessibility Auditor
Focus-visible completeness audit. Tab order, focus indicator visibility (3:1 contrast), skip link, focus traps, ARIA live regions, keyboard operability. Produce detailed focus audit report with element-by-element analysis.
## Phase 2: Context & Environment Detection
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| Target (URL or file paths) | From task description CONTEXT | Yes |
| WCAG level (AA/AAA) | From task description CONTEXT | Yes |
| .msg/meta.json | <session>/.msg/meta.json | No |
| Previous audit (re-audit) | <session>/audits/focus/focus-audit-*.md | Only for FOCUS-002+ |
1. Extract session path, target, and WCAG level from task description
2. Determine audit type from subject: FOCUS-001 -> initial audit, FOCUS-002+ -> re-audit (verification)
3. Identify target:
- URL -> use Chrome DevTools for interactive focus testing
- File paths -> read HTML/JSX/Vue/Svelte files for interactive elements
- Full site -> enumerate pages from navigation/routes
4. For re-audit: read previous audit report and fix summary for comparison baseline
5. Read focus patterns from specs/focus-patterns.md for reference
## Phase 3: Focus Audit Execution
### Step 1: Interactive Element Inventory
**Static analysis** (always):
- Glob for HTML/JSX/TSX/Vue/Svelte files
- Extract all interactive elements:
- Native focusable: `<a href>`, `<button>`, `<input>`, `<select>`, `<textarea>`, `<details>`
- Custom focusable: elements with `tabindex`, `role="button"`, `role="link"`, `role="tab"`, etc.
- Modals/dialogs: `role="dialog"`, `role="alertdialog"`, `<dialog>`
- Dynamic content areas: `aria-live`, `role="status"`, `role="alert"`
- Record source location (file:line) and context for each element
**Runtime analysis** (if Chrome DevTools available):
- `mcp__chrome-devtools__navigate_page({ url: "<target-url>" })`
- `mcp__chrome-devtools__evaluate_script({ expression: "..." })` to:
- Enumerate all focusable elements in DOM order
- Check `tabindex` values (0, -1, positive)
- Detect focus traps (elements that prevent Tab from escaping)
### Step 2: Tab Order Audit
| Check | Criterion | Standard |
|-------|-----------|----------|
| Logical sequence | Tab order follows visual/reading order | WCAG 2.4.3 |
| No positive tabindex | `tabindex > 0` is an anti-pattern | Best practice |
| No tab traps | Tab can escape all containers (except modals) | WCAG 2.1.2 |
| Skip link first | First focusable element is skip-to-content link | WCAG 2.4.1 |
| All interactive reachable | Every interactive element reachable via Tab | WCAG 2.1.1 |
Flag:
- `tabindex > 0` (disrupts natural tab order)
- `tabindex="-1"` on elements that should be focusable
- Missing `tabindex="0"` on custom interactive elements
- `outline: none` or `outline: 0` without alternative focus indicator
### Step 3: Focus Indicator Visibility
Per specs/focus-patterns.md:
| Check | Requirement | Standard |
|-------|-------------|----------|
| Outline present | At least 2px outline on :focus-visible | WCAG 2.4.7 |
| Outline contrast | >= 3:1 against adjacent colors | WCAG 2.4.11 |
| :focus-visible used | Keyboard focus distinct from mouse click | Best practice |
| Not obscured | Focus indicator not hidden by overlays, sticky headers | WCAG 2.4.11 |
| Consistent style | Same focus style across similar elements | Best practice |
**CSS analysis**:
- Search for `:focus`, `:focus-visible`, `:focus-within` rules
- Check for `outline: none` / `outline: 0` without alternative (box-shadow, border)
- Verify `:focus:not(:focus-visible) { outline: none; }` pattern (mouse click suppression)
- Calculate focus indicator contrast against adjacent background
### Step 4: Skip Link Audit
| Check | Requirement |
|-------|-------------|
| Exists | `<a href="#main">` or similar as first focusable element |
| Visually hidden until focus | `position: absolute; left: -9999px` pattern |
| Visible on focus | Repositions on `:focus` to visible area |
| Target exists | `#main` or target ID exists in DOM |
| Functional | Focus moves to main content on activation |
### Step 5: Focus Trap Audit (Modals/Dialogs)
Per specs/focus-patterns.md:
| Check | Requirement | Standard |
|-------|-------------|----------|
| Focus moves to dialog | On open, focus moves to first focusable or dialog itself | ARIA Practices |
| Tab cycles within | Tab/Shift+Tab stay within dialog focusable elements | ARIA Practices |
| Escape closes | Escape key closes dialog | ARIA Practices |
| Focus restores | On close, focus returns to trigger element | ARIA Practices |
| Background inert | Background content not focusable while dialog open | Best practice |
| Scroll lock | Background scroll locked while dialog open | Best practice |
### Step 6: ARIA Audit
| Element Type | Required ARIA | Standard |
|-------------|--------------|----------|
| Buttons | `role="button"` (if not `<button>`), `aria-pressed` (toggle), `aria-expanded` (disclosure) | WCAG 4.1.2 |
| Dialogs | `role="dialog"`, `aria-modal="true"`, `aria-labelledby` | ARIA Practices |
| Navigation | `role="navigation"` (if not `<nav>`), `aria-label` for multiple nav regions | WCAG 4.1.2 |
| Live regions | `aria-live="polite"` (status), `aria-live="assertive"` (errors) | WCAG 4.1.3 |
| Forms | `aria-required`, `aria-invalid`, `aria-describedby` for errors | WCAG 4.1.2 |
| Tabs | `role="tablist"`, `role="tab"`, `role="tabpanel"`, `aria-selected` | ARIA Practices |
| Accordions | `aria-expanded`, `aria-controls` | ARIA Practices |
### Step 7: Keyboard Operability
| Element | Expected Keys | Standard |
|---------|--------------|----------|
| Links/buttons | Enter activates | WCAG 2.1.1 |
| Buttons | Space activates | WCAG 2.1.1 |
| Checkboxes | Space toggles | WCAG 2.1.1 |
| Radio groups | Arrow keys navigate within group | ARIA Practices |
| Tabs | Arrow keys switch tabs, Tab moves to panel | ARIA Practices |
| Menus | Arrow keys navigate, Enter selects, Escape closes | ARIA Practices |
| Sliders | Arrow keys adjust value | ARIA Practices |
### Input Method Awareness
| Check | Requirement |
|-------|-------------|
| Hover guard | `:hover` styles wrapped in `@media(hover:hover)` -- touch devices don't hover |
| Pointer detection | `@media(pointer:coarse)` used for larger touch targets (48px+) |
| Focus-visible distinction | `:focus-visible` for keyboard only, not mouse clicks |
| Touch target sizing | All interactive elements >= 44x44px on `pointer:coarse` devices |
### Step 8: Target Size (WCAG 2.5.8)
| Check | Requirement | Standard |
|-------|-------------|----------|
| Interactive elements | Minimum 24x24px CSS pixels | WCAG 2.5.8 AA |
| Inline links | Exempt if within text paragraph | Exception |
| Spacing | At least 24px between targets OR targets themselves >= 24px | WCAG 2.5.8 |
## Phase 4: Report Generation & Output
1. Write audit report to `<session>/audits/focus/focus-audit-{NNN}.md` (or `<session>/re-audit/focus-audit-{NNN}.md` for re-audits):
```markdown
# Focus & Keyboard Accessibility Audit - {NNN}
[focus-auditor]
## Summary
- **Total interactive elements**: {count}
- **Pass**: {pass_count} | **Fail**: {fail_count}
- **WCAG Level**: {AA|AAA}
- **Critical issues**: {count}
- **High issues**: {count}
## Tab Order
| # | Element | Type | tabindex | Logical | Status |
|---|---------|------|----------|---------|--------|
| 1 | Skip link | <a> | 0 | Yes | PASS |
| 2 | Logo link | <a> | 0 | Yes | PASS |
| ... | ... | ... | ... | ... | ... |
## Focus Indicators
| Element | :focus-visible | Outline | Contrast | Obscured | Status |
|---------|---------------|---------|----------|----------|--------|
| ... | yes/no | Xpx solid | X:1 | no | PASS/FAIL |
## Skip Link
| Check | Status | Details |
|-------|--------|---------|
| Exists | PASS/FAIL | ... |
| Hidden until focus | PASS/FAIL | ... |
| Target exists | PASS/FAIL | ... |
## Focus Traps (Modals/Dialogs)
| Dialog | Focus on open | Tab cycles | Escape closes | Focus restores | Status |
|--------|-------------|-----------|--------------|---------------|--------|
| ... | yes/no | yes/no | yes/no | yes/no | PASS/FAIL |
## ARIA Coverage
| Element | Role | Label | States | Status |
|---------|------|-------|--------|--------|
| ... | ... | ... | ... | PASS/FAIL |
## Keyboard Operability
| Element | Enter | Space | Arrows | Escape | Status |
|---------|-------|-------|--------|--------|--------|
| ... | yes/no | yes/no | n/a | n/a | PASS/FAIL |
## Target Size
| Element | Size | Min 24x24 | Status |
|---------|------|----------|--------|
| ... | WxH | yes/no | PASS/FAIL |
## Issues (by severity)
### Critical
- ...
### High
- ...
### Medium
- ...
```
2. For re-audit (FOCUS-002+), add before/after comparison section:
```markdown
## Before/After Comparison
| Element | Before | After | Status |
|---------|--------|-------|--------|
| ... | FAIL (no outline) | PASS (2px solid) | FIXED |
```
3. Update `<session>/.msg/meta.json` under `focus-auditor` namespace:
- Read existing -> merge `{ "focus-auditor": { audit_id, total_elements, pass_count, fail_count, critical_count, high_count, skip_link_present, focus_traps_valid, timestamp } }` -> write back

View File

@@ -0,0 +1,206 @@
---
role: remediation-planner
prefix: REMED
inner_loop: false
message_types: [state_update]
---
# Remediation Planner
Synthesize findings from all 3 audit reports (color, typography, focus) into a prioritized remediation plan with code-level fix guidance. Map each issue to WCAG success criterion, estimate effort, and group by file/component for efficient fixing.
## Phase 2: Context & Artifact Loading
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| Color audit report | <session>/audits/color/color-audit-001.md | Yes |
| Typography audit report | <session>/audits/typography/typo-audit-001.md | Yes |
| Focus audit report | <session>/audits/focus/focus-audit-001.md | Yes |
| WCAG level (AA/AAA) | From task description CONTEXT | Yes |
| .msg/meta.json | <session>/.msg/meta.json | Yes |
1. Extract session path and WCAG level from task description
2. Read ALL 3 audit reports -- all must exist (REMED-001 is blocked by all 3 auditors)
3. Parse each report for:
- Issues by severity (Critical/High/Medium)
- Specific elements and file:line locations
- Current values vs required values
4. Read meta.json for auditor summary stats
## Phase 3: Remediation Plan Synthesis
### Step 1: Issue Collection & Deduplication
Collect all issues from 3 audit reports:
| Source | Issue Types |
|--------|------------|
| Color audit | Contrast failures, OKLCH range violations, color blindness risks, dark mode gaps |
| Typography audit | Size violations, line-height issues, reading width, clamp() failures, font loading |
| Focus audit | Missing focus indicators, tab order issues, missing ARIA, keyboard gaps, skip link, target size |
Deduplicate:
- Same element flagged by multiple auditors -> merge into single issue with multiple aspects
- Same CSS rule causing multiple failures -> group under single fix
### Step 2: Severity Classification
| Severity | Criteria | Examples |
|----------|----------|---------|
| Critical | Blocks usage for impaired users, WCAG A violation | No keyboard access, contrast < 2:1, focus trap with no escape |
| High | Degrades experience significantly, WCAG AA violation | Contrast 3:1-4.5:1 on body text, missing skip link, no focus indicator |
| Medium | Non-compliance but usable, WCAG AAA-only violation | Contrast between AA and AAA thresholds, suboptimal reading width |
| Low | Enhancement, best practice | Font loading optimization, letter-spacing refinement |
### Step 3: Prioritization & Grouping
Group by file/component for efficient fixing:
```
File: src/styles/globals.css
[CRITICAL] Color: --text-primary contrast 3.2:1 (need 4.5:1) -> WCAG 1.4.3
[HIGH] Focus: No :focus-visible on buttons -> WCAG 2.4.7
[MEDIUM] Typography: line-height 1.4 on body (need 1.5) -> WCAG 1.4.12
File: src/components/Modal.tsx
[CRITICAL] Focus: No focus trap in modal -> WCAG 2.1.2
[HIGH] ARIA: Missing aria-modal="true" -> WCAG 4.1.2
```
Priority order within each file: Critical -> High -> Medium -> Low.
### Step 4: Code-Level Fix Guidance
For each issue, provide specific fix:
**Color fixes**:
```css
/* Before: contrast 3.2:1 */
--text-primary: oklch(55% 0 0);
/* After: contrast 5.1:1 -- adjust lightness down */
--text-primary: oklch(35% 0 0);
```
**Focus fixes**:
```css
/* Add :focus-visible to interactive elements */
button:focus-visible,
a:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
button:focus:not(:focus-visible) {
outline: none;
}
```
**ARIA fixes**:
```html
<!-- Before -->
<div class="modal">
<!-- After -->
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="modal-title">
```
**Typography fixes**:
```css
/* Before: fixed font-size */
body { font-size: 14px; }
/* After: responsive with floor */
body { font-size: clamp(1rem, 1vw + 0.875rem, 1.25rem); line-height: 1.625; }
```
### Step 5: Effort Estimation
| Effort | Criteria |
|--------|----------|
| Trivial (< 5 min) | Single CSS property change (contrast, outline) |
| Small (5-15 min) | Multiple CSS changes in one file, add ARIA attributes |
| Medium (15-60 min) | Focus trap implementation, skip link, keyboard navigation |
| Large (1-4 hours) | Responsive typography overhaul, dark mode color parity |
### Step 6: WCAG Criterion Mapping
Map every issue to specific WCAG success criterion:
| Issue Domain | Common Criteria |
|-------------|----------------|
| Color contrast | 1.4.3 (AA), 1.4.6 (AAA), 1.4.11 (non-text) |
| Typography | 1.4.4 (resize), 1.4.12 (text spacing) |
| Focus indicators | 2.4.7 (visible), 2.4.11 (not obscured) |
| Keyboard | 2.1.1 (keyboard), 2.1.2 (no trap) |
| Tab order | 2.4.3 (focus order) |
| Skip link | 2.4.1 (bypass blocks) |
| ARIA | 4.1.2 (name/role/value) |
| Target size | 2.5.8 (target size) |
| Live regions | 4.1.3 (status messages) |
## Phase 4: Validation & Output
1. Validate plan completeness:
| Check | Requirement |
|-------|-------------|
| All critical issues addressed | Every critical issue has a fix |
| All high issues addressed | Every high issue has a fix |
| File grouping complete | Every fix maps to specific file:line |
| WCAG mapping complete | Every fix maps to WCAG criterion |
| No orphan issues | Every audit issue appears in plan |
2. Write remediation plan to `<session>/remediation/remediation-plan.md`:
```markdown
# Remediation Plan
[remediation-planner]
## Executive Summary
- **Total issues**: {count} (Critical: {n}, High: {n}, Medium: {n}, Low: {n})
- **Files affected**: {count}
- **Estimated total effort**: {hours}
- **WCAG target**: {AA|AAA}
## Priority Matrix
| # | Severity | Domain | WCAG | File | Issue | Fix | Effort |
|---|----------|--------|------|------|-------|-----|--------|
| 1 | Critical | Color | 1.4.3 | globals.css:12 | Contrast 3.2:1 | L 55% -> 35% | Trivial |
| 2 | Critical | Focus | 2.1.2 | Modal.tsx:45 | No focus trap | Add trap logic | Medium |
| ... | ... | ... | ... | ... | ... | ... | ... |
## Fixes by File
### `src/styles/globals.css`
#### Fix 1: Color contrast (Critical, WCAG 1.4.3)
- **Current**: `--text-primary: oklch(55% 0 0);` (contrast 3.2:1)
- **Target**: `--text-primary: oklch(35% 0 0);` (contrast 5.1:1)
- **Effort**: Trivial
#### Fix 2: Focus indicators (High, WCAG 2.4.7)
- **Current**: No :focus-visible rules
- **Target**: Add :focus-visible with 2px outline
- **Effort**: Small
### `src/components/Modal.tsx`
#### Fix 3: Focus trap (Critical, WCAG 2.1.2)
- **Current**: No focus management
- **Target**: Implement focus trap (store activeElement, cycle Tab, Escape to close)
- **Effort**: Medium
## Implementation Order
1. All Critical fixes (blocks usage)
2. All High fixes (degrades experience)
3. Medium fixes (non-compliance)
4. Low fixes (enhancements)
## Verification Checklist
- [ ] All color combinations pass WCAG {level} contrast
- [ ] All interactive elements have visible focus indicators
- [ ] Tab order is logical with no traps (except modals)
- [ ] Skip link present and functional
- [ ] All ARIA roles and states correct
- [ ] Typography meets minimum sizes at all breakpoints
```
3. Update `<session>/.msg/meta.json` under `remediation-planner` namespace:
- Read existing -> merge `{ "remediation-planner": { total_issues, critical, high, medium, low, files_affected, estimated_effort, timestamp } }` -> write back

View File

@@ -0,0 +1,185 @@
---
role: typo-auditor
prefix: TYPO
inner_loop: false
message_types: [state_update]
---
# Typography Readability Auditor
Typography accessibility audit across all viewports. Font sizes at breakpoints, line-height ratios, clamp() validation, reading width measurement, font loading strategy assessment. Produce detailed typography report with breakpoint-by-breakpoint analysis.
## Phase 2: Context & Environment Detection
| Input | Source | Required |
|-------|--------|----------|
| Task description | From task subject/description | Yes |
| Session path | Extracted from task description | Yes |
| Target (URL or file paths) | From task description CONTEXT | Yes |
| WCAG level (AA/AAA) | From task description CONTEXT | Yes |
| .msg/meta.json | <session>/.msg/meta.json | No |
1. Extract session path, target, and WCAG level from task description
2. Identify target:
- URL -> use Chrome DevTools for rendered typography (navigate_page, resize_page, screenshot)
- File paths -> read CSS/SCSS files directly for typography definitions
- Full site -> enumerate stylesheets from HTML entry points
3. Read typography standards from specs/typography-scale.md for reference thresholds
## Phase 3: Typography Audit Execution
### Step 1: Typography Definition Extraction
**Static analysis** (always):
- Glob for CSS/SCSS/Tailwind files -> extract typography definitions
- Extract: font-family, font-size, line-height, letter-spacing, font-weight, font-display
- Parse clamp() functions: `clamp(min, preferred, max)` -> validate min/max bounds
- Parse @media queries for responsive breakpoints
- Record source location (file:line) for each rule
**Runtime analysis** (if Chrome DevTools available):
- Navigate to target URL
- For each breakpoint (320px, 768px, 1024px, 1400px):
- `mcp__chrome-devtools__resize_page({ width: <breakpoint>, height: 900 })`
- `mcp__chrome-devtools__evaluate_script({ expression: "..." })` to measure:
- Computed font-size on body, headings (h1-h6), paragraphs, captions
- Computed line-height on same elements
- Container width and character count per line
- `mcp__chrome-devtools__take_screenshot({})` -> save to `<session>/evidence/typo-{breakpoint}px.png`
### Step 2: Font Size Audit
| Breakpoint | Element | Minimum Size | Standard |
|-----------|---------|-------------|----------|
| 320px (mobile) | Body text | 16px | WCAG 1.4.4 |
| 320px (mobile) | Small/caption | 14px | Best practice |
| 768px (tablet) | Body text | 16px | WCAG 1.4.4 |
| 1024px (desktop) | Body text | 16px | WCAG 1.4.4 |
| 1400px (wide) | Body text | 16px | WCAG 1.4.4 |
**clamp() validation**:
- Minimum value >= 14px (absolute floor)
- Maximum value reasonable for element type (headings: max ~72px, body: max ~20px)
- Preferred value uses viewport unit (vw) for fluid scaling
- Check: `clamp(min, preferred, max)` where min >= 14px for any text
**200% zoom check** (WCAG 1.4.4):
- At 200% zoom, no content should be clipped or lost
- Text should reflow without horizontal scrolling
### Step 3: Line Height Audit
| Element Type | Expected Range | Standard |
|-------------|---------------|----------|
| Body text | 1.5 - 1.75 | WCAG 1.4.12, readability |
| Headings | 1.1 - 1.3 | Visual impact |
| Code blocks | 1.5 - 1.7 | Scanning readability |
| Buttons/labels | 1.2 - 1.5 | UI element |
Check for unitless line-height (preferred over px/em for inheritance).
### Step 4: Letter Spacing Audit
| Element Type | Expected Range | Standard |
|-------------|---------------|----------|
| Display headings | -0.02em to 0 | Tight for visual |
| Body text | 0 (default) | Normal |
| Uppercase labels | 0.05em - 0.1em | Legibility |
| Monospace code | 0.08em - 0.15em | Wide for scanning |
**WCAG 1.4.12 override test**: Text must remain readable when user overrides:
- Line height to at least 1.5x font size
- Letter spacing to at least 0.12em
- Word spacing to at least 0.16em
### Step 5: Reading Width Audit
Measure characters per line for body text containers:
| Metric | Optimal | Acceptable | Flag |
|--------|---------|-----------|------|
| Characters per line | 66ch | 45-75ch | < 45 or > 75 |
| Max container width | 65ch-75ch | Up to 900px | > 900px without column |
Check: `max-width` or `width` on body text containers.
### Step 6: Font Loading Strategy
| Property | Good | Acceptable | Poor |
|----------|------|-----------|------|
| Body font | `font-display: swap` | `font-display: fallback` | `font-display: block` or missing |
| Display font | `font-display: optional` | `font-display: swap` | `font-display: block` |
| Preload | Critical fonts preloaded | Some preloaded | None preloaded |
| Fallback stack | System font fallback defined | Generic fallback | No fallback |
Check for FOUT (Flash of Unstyled Text) / FOIT (Flash of Invisible Text) risks.
## Phase 4: Report Generation & Output
1. Write audit report to `<session>/audits/typography/typo-audit-{NNN}.md`:
```markdown
# Typography Accessibility Audit - {NNN}
[typo-auditor]
## Summary
- **Total typography rules audited**: {count}
- **Pass**: {pass_count} | **Fail**: {fail_count}
- **WCAG Level**: {AA|AAA}
- **Critical issues**: {count}
- **High issues**: {count}
## Font Size by Breakpoint
| Breakpoint | Element | Computed Size | Min Required | Status |
|-----------|---------|--------------|-------------|--------|
| 320px | body | Xpx | 16px | PASS/FAIL |
| 320px | h1 | Xpx | -- | OK |
| ... | ... | ... | ... | ... |
## clamp() Validation
| Rule | clamp() Value | Min | Max | Status |
|------|--------------|-----|-----|--------|
| .body | clamp(1rem, 2vw, 1.25rem) | 16px | 20px | PASS/FAIL |
| ... | ... | ... | ... | ... |
## Line Height Audit
| Element | Current | Expected Range | Status |
|---------|---------|---------------|--------|
| body | 1.6 | 1.5-1.75 | PASS |
| h1 | 1.2 | 1.1-1.3 | PASS |
| ... | ... | ... | ... |
## Letter Spacing Audit
| Element | Current | Expected Range | Status |
|---------|---------|---------------|--------|
| ... | ... | ... | ... |
## Reading Width
| Container | Width | Chars/Line | Optimal (45-75) | Status |
|-----------|-------|-----------|-----------------|--------|
| .content | 700px | ~68ch | Yes | PASS |
| ... | ... | ... | ... | ... |
## Font Loading
| Font | font-display | Preload | Fallback | Status |
|------|-------------|---------|----------|--------|
| ... | swap | yes/no | system | PASS/FAIL |
## Text Spacing Override Test (WCAG 1.4.12)
| Override | Applied | Content Readable | Status |
|---------|---------|-----------------|--------|
| line-height: 1.5x | Yes | Yes/No | PASS/FAIL |
| letter-spacing: 0.12em | Yes | Yes/No | PASS/FAIL |
| word-spacing: 0.16em | Yes | Yes/No | PASS/FAIL |
## Issues (by severity)
### Critical
- ...
### High
- ...
### Medium
- ...
```
2. Update `<session>/.msg/meta.json` under `typo-auditor` namespace:
- Read existing -> merge `{ "typo-auditor": { audit_id, total_rules, pass_count, fail_count, critical_count, high_count, breakpoints_tested, timestamp } }` -> write back

View File

@@ -0,0 +1,325 @@
# Focus Management Patterns
Reference guide for focus indicator styles, skip links, focus traps, and ARIA patterns. Used by focus-auditor and fix-implementer roles.
## Focus Indicator Style
### Recommended Pattern
```css
/* Keyboard focus: visible outline */
:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
/* Mouse click: no outline */
:focus:not(:focus-visible) {
outline: none;
}
```
### Requirements
| Property | Minimum | Rationale |
|----------|---------|-----------|
| outline-width | 2px | Visibility at distance |
| outline-style | solid | Consistent rendering |
| outline-offset | 2px | Separation from element edge |
| Contrast vs adjacent | >= 3:1 | WCAG 2.4.11 |
### Anti-Patterns (Do NOT)
```css
/* BAD: Removes all focus indicators */
*:focus { outline: none; }
/* BAD: Removes focus without alternative */
button:focus { outline: 0; }
/* BAD: Only uses box-shadow (invisible in high contrast mode) */
:focus-visible { outline: none; box-shadow: 0 0 0 2px blue; }
```
### Correct Alternative Indicator
```css
/* If not using outline, MUST provide visible alternative */
:focus-visible {
outline: 2px solid transparent; /* For Windows high contrast mode */
box-shadow: 0 0 0 2px var(--color-accent);
}
```
## Skip Link
### HTML
```html
<body>
<a href="#main" class="skip-link">Skip to main content</a>
<!-- navigation, header, etc. -->
<main id="main" tabindex="-1">
<!-- main content -->
</main>
</body>
```
### CSS
```css
.skip-link {
position: absolute;
left: -9999px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
z-index: -1;
}
.skip-link:focus {
position: fixed;
left: 16px;
top: 16px;
width: auto;
height: auto;
overflow: visible;
z-index: 9999;
background: var(--color-paper, #fff);
color: var(--color-ink, #000);
padding: 8px 16px;
border: 2px solid var(--color-ink, #000);
border-radius: 4px;
font-size: 1rem;
text-decoration: underline;
}
```
### Requirements
| Check | Requirement |
|-------|-------------|
| Position | First focusable element in DOM |
| Default state | Visually hidden (not display:none or visibility:hidden) |
| Focus state | Visible, fixed position, high z-index |
| Target | Points to main content area with valid ID |
| Contrast | Link text meets 4.5:1 contrast against background |
## Focus Trap (Modals/Dialogs)
### Implementation Pattern
```javascript
function trapFocus(dialog) {
const focusableSelector = [
'a[href]', 'button:not([disabled])', 'input:not([disabled])',
'select:not([disabled])', 'textarea:not([disabled])',
'[tabindex]:not([tabindex="-1"])'
].join(', ');
const focusableElements = dialog.querySelectorAll(focusableSelector);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
// Store trigger for focus restore
const trigger = document.activeElement;
// Move focus to first element
firstFocusable.focus();
dialog.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeDialog(dialog);
trigger.focus(); // Restore focus
return;
}
if (e.key !== 'Tab') return;
if (e.shiftKey) {
// Shift+Tab at first element -> wrap to last
if (document.activeElement === firstFocusable) {
e.preventDefault();
lastFocusable.focus();
}
} else {
// Tab at last element -> wrap to first
if (document.activeElement === lastFocusable) {
e.preventDefault();
firstFocusable.focus();
}
}
});
}
```
### Dialog HTML Pattern
```html
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
<h2 id="dialog-title">Dialog Title</h2>
<div class="dialog-content">
<!-- content -->
</div>
<div class="dialog-actions">
<button type="button">Cancel</button>
<button type="button">Confirm</button>
</div>
</div>
```
### Requirements
| Step | Action | Detail |
|------|--------|--------|
| Open | Store trigger | `const trigger = document.activeElement` |
| Open | Move focus | Focus first focusable element in dialog |
| Open | Lock background | `document.body.style.overflow = 'hidden'` or `inert` attribute |
| Open | Set ARIA | `aria-modal="true"` on dialog |
| Tab | Cycle within | Tab/Shift+Tab wrap within dialog focusable elements |
| Escape | Close + restore | Close dialog, restore focus to trigger |
| Close | Unlock background | Remove scroll lock / inert |
## ARIA Patterns
### Button Patterns
```html
<!-- Standard button -->
<button type="button">Save</button>
<!-- Icon-only button (needs aria-label) -->
<button type="button" aria-label="Close dialog">
<svg><!-- X icon --></svg>
</button>
<!-- Toggle button -->
<button type="button" aria-pressed="false">Bold</button>
<!-- Disclosure button -->
<button type="button" aria-expanded="false" aria-controls="panel-1">
Show details
</button>
<div id="panel-1" hidden>Details content</div>
```
### Dialog Pattern
```html
<div role="dialog" aria-modal="true" aria-labelledby="dlg-title" aria-describedby="dlg-desc">
<h2 id="dlg-title">Confirm Action</h2>
<p id="dlg-desc">Are you sure you want to proceed?</p>
<button type="button">Cancel</button>
<button type="button">Confirm</button>
</div>
```
### Live Region Patterns
```html
<!-- Status updates (polite) -->
<div role="status" aria-live="polite">
3 items in cart
</div>
<!-- Error messages (assertive) -->
<div role="alert" aria-live="assertive">
Email address is invalid
</div>
<!-- Log/chat (polite, additions only) -->
<div role="log" aria-live="polite" aria-relevant="additions">
<!-- new messages appended here -->
</div>
```
### Navigation Pattern
```html
<!-- Primary navigation -->
<nav aria-label="Primary">
<ul role="menubar">
<li role="none"><a role="menuitem" href="/">Home</a></li>
<li role="none"><a role="menuitem" href="/about">About</a></li>
</ul>
</nav>
<!-- Breadcrumb -->
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li aria-current="page">Widget</li>
</ol>
</nav>
```
### Tab Pattern
```html
<div role="tablist" aria-label="Settings">
<button role="tab" aria-selected="true" aria-controls="panel-general" id="tab-general">
General
</button>
<button role="tab" aria-selected="false" aria-controls="panel-security" id="tab-security" tabindex="-1">
Security
</button>
</div>
<div role="tabpanel" id="panel-general" aria-labelledby="tab-general">
General settings content
</div>
<div role="tabpanel" id="panel-security" aria-labelledby="tab-security" hidden>
Security settings content
</div>
```
**Keyboard**: Arrow Left/Right to switch tabs, Tab to move into panel content.
### Form Error Pattern
```html
<label for="email">Email</label>
<input
type="email"
id="email"
aria-required="true"
aria-invalid="true"
aria-describedby="email-error"
>
<div id="email-error" role="alert">
Please enter a valid email address
</div>
```
## Keyboard Navigation Reference
| Component | Key | Action |
|-----------|-----|--------|
| Link | Enter | Activate |
| Button | Enter, Space | Activate |
| Checkbox | Space | Toggle |
| Radio group | Arrow Up/Down | Select previous/next |
| Tab list | Arrow Left/Right | Switch tab |
| Menu | Arrow Up/Down | Navigate items |
| Menu | Enter | Select item |
| Menu | Escape | Close menu |
| Dialog | Escape | Close dialog |
| Slider | Arrow Left/Right | Decrease/increase |
| Combobox | Arrow Down | Open dropdown |
| Combobox | Enter | Select highlighted |
| Combobox | Escape | Close dropdown |
| Tree | Arrow Up/Down | Navigate siblings |
| Tree | Arrow Right | Expand / enter child |
| Tree | Arrow Left | Collapse / go to parent |
## Target Size Reference
| Standard | Minimum Size | Notes |
|----------|-------------|-------|
| WCAG 2.5.8 (AA) | 24x24px CSS pixels | Or adequate spacing between targets |
| WCAG 2.5.5 (AAA) | 44x44px CSS pixels | Recommended for touch interfaces |
| Apple HIG | 44x44pt | iOS touch targets |
| Material Design | 48x48dp | Android touch targets |
**Exceptions**: Inline links within text, browser default controls, essential fixed-size elements.

View File

@@ -0,0 +1,130 @@
# OKLCH Color Accessibility Standards
Reference guide for OKLCH-based perceptual color analysis. Used by color-auditor and fix-implementer roles.
## OKLCH Basics
```
oklch(Lightness% Chroma Hue)
```
- **Lightness (L)**: 0% (black) to 100% (white) -- perceptually uniform
- **Chroma (C)**: 0 (achromatic/gray) to ~0.37 (maximum saturation) -- perceptual colorfulness
- **Hue (H)**: 0-360 degrees -- color wheel angle
OKLCH is perceptually uniform: equal numeric changes produce equal perceived changes, unlike HSL/RGB.
## Lightness Guidelines
| Element | L Range | Rationale |
|---------|---------|-----------|
| Dark text on light background | L <= 40% | Ensures sufficient contrast against light surfaces |
| Light background for text | L >= 90% | Provides clean reading surface |
| Accent colors (interactive) | L 50-65% | Vibrant but readable |
| Disabled/muted elements | L 55-70% | Intentionally reduced contrast (with care) |
| Dark mode text | L >= 85% | Light text on dark background |
| Dark mode background | L <= 20% | Dark surface for light text |
## Chroma Guidelines
| Use Case | C Range | Notes |
|----------|---------|-------|
| Neutral/text colors | C = 0 | Pure achromatic for maximum readability |
| Subtle warm/cool tint | C = 0.005-0.02 | Adds warmth without color distraction |
| Standard accent | C = 0.1-0.15 | Good balance of color and readability |
| Vibrant accent | C = 0.2-0.25 | Use sparingly, max 1-2 per palette |
| Maximum saturation | C > 0.25 | Avoid for text; OK for decorative only |
## Impeccable Palette Reference
```css
/* Neutrals */
--color-ink: oklch(10% 0 0); /* Primary text */
--color-paper: oklch(98% 0 0); /* Primary background */
--color-cream: oklch(96% 0.005 350); /* Warm background variant */
--color-charcoal: oklch(25% 0 0); /* Secondary text */
--color-ash: oklch(55% 0 0); /* Muted/disabled text */
--color-mist: oklch(92% 0 0); /* Border/divider */
/* Accent */
--color-accent: oklch(60% 0.25 350); /* Primary action */
--color-accent-hover: oklch(52% 0.25 350); /* Hover state (darker) */
```
### Palette Analysis
| Name | L | C | H | Role | Contrast vs paper (98%) |
|------|---|---|---|------|------------------------|
| ink | 10% | 0 | 0 | Body text | ~15.4:1 (AAA) |
| charcoal | 25% | 0 | 0 | Secondary text | ~9.5:1 (AAA) |
| ash | 55% | 0 | 0 | Muted text | ~3.8:1 (AA large only) |
| accent | 60% | 0.25 | 350 | Interactive | ~3.4:1 (large text / non-text only) |
| accent-hover | 52% | 0.25 | 350 | Hover state | ~4.6:1 (AA) |
## Contrast Verification Methods
### WCAG 2.1 Contrast Ratio
Formula: `(L1 + 0.05) / (L2 + 0.05)` where L1, L2 are relative luminances (L1 > L2).
Convert OKLCH -> sRGB -> linear RGB -> relative luminance:
`L_rel = 0.2126 * R_linear + 0.7152 * G_linear + 0.0722 * B_linear`
| Text Type | AA | AAA |
|-----------|-----|-----|
| Normal text (< 18pt / < 14pt bold) | >= 4.5:1 | >= 7:1 |
| Large text (>= 18pt / >= 14pt bold) | >= 3:1 | >= 4.5:1 |
| Non-text (UI components, icons) | >= 3:1 | >= 3:1 |
### APCA Contrast (Advanced)
APCA (Accessible Perceptual Contrast Algorithm) uses OKLCH lightness for perceptual accuracy.
Lc (Lightness contrast) values:
| Use Case | Minimum Lc | Description |
|----------|-----------|-------------|
| Body text (14-16px) | >= 75 | Primary reading content |
| Content text (18px) | >= 60 | Secondary content |
| Large text (24px+) | >= 45 | Headings, display |
| Non-text elements | >= 30 | Icons, borders, focus indicators |
| Placeholder/disabled | >= 15 | Intentionally muted |
### Focus Indicator Contrast
Focus indicators must have >= 3:1 contrast against adjacent colors:
- Outline color vs element background
- Outline color vs surrounding page background
- Both must pass
## Color Blindness Reference
### Confusion Lines
| Type | Prevalence | Confuses | Safe Alternatives |
|------|-----------|----------|-------------------|
| Protanopia (red-blind) | ~1% male | Red/green, red/brown | Use blue/orange, add patterns |
| Deuteranopia (green-blind) | ~5% male | Green/red, green/brown | Use blue/orange, add patterns |
| Tritanopia (blue-blind) | ~0.01% | Blue/yellow | Use red/green pairs (opposite) |
| Achromatopsia (no color) | ~0.003% | All chromatic | Rely on lightness difference only |
### Safe Color Pairs
Always ensure information is not conveyed by color alone. Safe strategies:
- Use lightness difference (>= 40% L difference)
- Add text labels, icons, or patterns alongside color
- Use blue + orange (safe for most color blindness types)
- Avoid red-only or green-only indicators
## Dark Mode Color Mapping
When converting light mode to dark mode:
| Light Mode | Dark Mode | Rule |
|-----------|----------|------|
| Text L <= 40% | Text L >= 85% | Invert lightness range |
| Background L >= 90% | Background L <= 20% | Invert lightness range |
| Accent L 50-65% | Accent L 60-75% | Slight lightness increase |
| Border L ~92% | Border L ~25% | Invert proportionally |
Maintain same hue and similar chroma; adjust lightness to preserve contrast ratios.

View File

@@ -0,0 +1,98 @@
# Pipeline Definitions
Visual accessibility pipeline modes and task registry.
## Pipeline Modes
| Mode | Description | Task Count |
|------|-------------|------------|
| audit-only | 3 parallel auditors -> remediation plan | 4 tasks |
| full | 3 parallel auditors -> remediation -> fix -> 2 parallel re-auditors | 7 tasks |
## Audit-Only Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| COLOR-001 | color-auditor | [] | OKLCH color contrast audit: WCAG 2.1 + APCA ratios, color blindness simulation |
| TYPO-001 | typo-auditor | [] | Typography readability: font size at breakpoints, line-height, reading width |
| FOCUS-001 | focus-auditor | [] | Focus management: tab order, indicators, skip link, ARIA, keyboard |
| REMED-001 | remediation-planner | [COLOR-001, TYPO-001, FOCUS-001] | Prioritized remediation plan with code-level fixes |
**CRITICAL**: COLOR-001, TYPO-001, FOCUS-001 have NO deps -- they run in PARALLEL.
## Full Pipeline Task Registry
| Task ID | Role | deps | Description |
|---------|------|------|-------------|
| COLOR-001 | color-auditor | [] | OKLCH color contrast audit (initial) |
| TYPO-001 | typo-auditor | [] | Typography readability audit |
| FOCUS-001 | focus-auditor | [] | Focus management audit (initial) |
| REMED-001 | remediation-planner | [COLOR-001, TYPO-001, FOCUS-001] | Prioritized remediation plan |
| FIX-001 | fix-implementer | [REMED-001] | Implement a11y fixes from remediation plan |
| COLOR-002 | color-auditor | [FIX-001] | Re-audit color contrast after fixes |
| FOCUS-002 | focus-auditor | [FIX-001] | Re-audit focus management after fixes |
**CRITICAL**: COLOR-002 and FOCUS-002 both blocked only by FIX-001 -- they run in PARALLEL.
## Dependency Graphs
### Audit-Only
```
COLOR-001 --+
|
TYPO-001 --+--> REMED-001
|
FOCUS-001 --+
```
### Full
```
COLOR-001 --+
|
TYPO-001 --+--> REMED-001 --> FIX-001 --+--> COLOR-002
| |
FOCUS-001 --+ +--> FOCUS-002
```
## Fan-In Points
| Point | Waiting For | Gate Task | Action |
|-------|------------|-----------|--------|
| Audit fan-in | COLOR-001 + TYPO-001 + FOCUS-001 (all 3) | REMED-001 | Unblock REMED-001 when all 3 complete |
| Re-audit fan-in | COLOR-002 + FOCUS-002 (both) | Pipeline complete | Check GC convergence |
## GC Loop Behavior (Full Mode)
After re-audit fan-in (COLOR-002 + FOCUS-002 both complete):
| Signal | Condition | Action |
|--------|-----------|--------|
| All pass | 0 critical + 0 high issues remaining | GC converged -> pipeline complete |
| Issues remain | Critical or high issues found | gc_rounds < 2 -> create FIX-002 + re-audit tasks |
| Max rounds | gc_rounds >= 2 | Escalate to user: accept / try one more / terminate |
## Parallel Spawn Rules
| Mode | Scenario | Spawn Behavior |
|------|----------|---------------|
| audit-only | Initial | Spawn COLOR-001 + TYPO-001 + FOCUS-001 in parallel |
| audit-only | After 3 audits | Spawn REMED-001 |
| full | Initial | Spawn COLOR-001 + TYPO-001 + FOCUS-001 in parallel |
| full | After 3 audits | Spawn REMED-001 |
| full | After REMED-001 | Spawn FIX-001 |
| full | After FIX-001 | Spawn COLOR-002 + FOCUS-002 in parallel |
| full (GC) | After re-audit fan-in | If issues: spawn FIX-002, then new re-audits |
## Output Artifacts
| Task | Output Path |
|------|-------------|
| COLOR-001 | <session>/audits/color/color-audit-001.md |
| TYPO-001 | <session>/audits/typography/typo-audit-001.md |
| FOCUS-001 | <session>/audits/focus/focus-audit-001.md |
| REMED-001 | <session>/remediation/remediation-plan.md |
| FIX-001 | Modified source files + <session>/fixes/fix-summary-001.md |
| COLOR-002 | <session>/re-audit/color-audit-002.md |
| FOCUS-002 | <session>/re-audit/focus-audit-002.md |

View File

@@ -0,0 +1,109 @@
{
"team_name": "visual-a11y",
"team_display_name": "Visual Accessibility",
"description": "Visual accessibility QA team with parallel auditors, remediation planning, and fix implementation with re-audit verification",
"version": "1.0.0",
"roles": {
"coordinator": {
"task_prefix": null,
"responsibility": "Scope assessment (page/component/full site), pipeline orchestration, parallel fan-in coordination",
"message_types": ["task_unblocked", "fan_in_complete", "gc_check", "error", "shutdown"]
},
"color-auditor": {
"task_prefix": "COLOR",
"responsibility": "OKLCH lightness/chroma analysis, contrast ratio (WCAG 2.1 + APCA), color blindness simulation",
"message_types": ["audit_complete", "audit_progress", "error"]
},
"typo-auditor": {
"task_prefix": "TYPO",
"responsibility": "Typography readability: font size at breakpoints, line-height ratios, clamp() validation, reading width",
"message_types": ["audit_complete", "audit_progress", "error"]
},
"focus-auditor": {
"task_prefix": "FOCUS",
"responsibility": "Focus-visible completeness: tab-order, focus indicator visibility, skip-link, focus traps, ARIA live regions",
"message_types": ["audit_complete", "audit_progress", "error"]
},
"remediation-planner": {
"task_prefix": "REMED",
"responsibility": "Synthesize audit findings into prioritized remediation plan with code-level fix guidance",
"message_types": ["plan_ready", "plan_progress", "error"]
},
"fix-implementer": {
"task_prefix": "FIX",
"inner_loop": true,
"responsibility": "Implement a11y fixes: OKLCH color corrections, focus styles, ARIA attributes, reduced-motion queries",
"message_types": ["fix_complete", "fix_progress", "error"]
}
},
"pipelines": {
"audit-only": {
"description": "3 parallel auditors -> remediation plan",
"task_chain": [
"COLOR-001 || TYPO-001 || FOCUS-001",
"REMED-001"
],
"fan_in_points": ["REMED-001"],
"complexity": "medium"
},
"full": {
"description": "3 parallel auditors -> remediation -> fix -> 2 parallel re-auditors",
"task_chain": [
"COLOR-001 || TYPO-001 || FOCUS-001",
"REMED-001",
"FIX-001",
"COLOR-002 || FOCUS-002"
],
"fan_in_points": ["REMED-001"],
"gc_points": ["COLOR-002", "FOCUS-002"],
"complexity": "high"
}
},
"innovation_patterns": {
"parallel_fan_in": {
"pattern": "CP-3",
"description": "3 auditors run simultaneously, remediation waits for all 3",
"fan_in_count": 3,
"fan_in_roles": ["color-auditor", "typo-auditor", "focus-auditor"],
"gate_task": "REMED-001"
},
"generator_critic": {
"pattern": "CP-2",
"generator": "fix-implementer",
"critic": ["color-auditor", "focus-auditor"],
"max_rounds": 2,
"convergence": "re-audit finds 0 critical and 0 high issues",
"escalation": "Coordinator intervenes after max rounds"
},
"shared_memory": {
"file": ".msg/meta.json",
"fields": {
"color-auditor": ["total_combinations", "pass_count", "fail_count", "critical_count"],
"typo-auditor": ["total_rules", "pass_count", "fail_count", "breakpoints_tested"],
"focus-auditor": ["total_elements", "pass_count", "fail_count", "skip_link_present"],
"remediation-planner": ["total_issues", "critical", "high", "medium", "low"],
"fix-implementer": ["total_fixes", "critical_fixed", "high_fixed", "files_modified"]
}
},
"chrome_devtools": {
"description": "Chrome DevTools integration for rendered verification",
"tools": ["evaluate_script", "take_screenshot", "navigate_page", "resize_page", "emulate", "lighthouse_audit"],
"degradation": "If unavailable, degrade to static analysis only"
}
},
"session_dirs": {
"base": ".workflow/.team/VA-{slug}-{YYYY-MM-DD}/",
"color_audit": "audits/color/",
"typo_audit": "audits/typography/",
"focus_audit": "audits/focus/",
"remediation": "remediation/",
"fixes": "fixes/",
"re_audit": "re-audit/",
"evidence": "evidence/",
"messages": ".workflow/.team-msg/{team-name}/"
}
}

View File

@@ -0,0 +1,165 @@
# Typography Accessibility Standards
Reference guide for typography readability analysis. Used by typo-auditor and fix-implementer roles.
## Font Stack Hierarchy
| Purpose | Category | Example | Usage |
|---------|----------|---------|-------|
| Display | Serif | Cormorant Garamond, Georgia, serif | Headings, hero text |
| Body | Sans-serif | Instrument Sans, Inter, system-ui, sans-serif | Paragraphs, UI text |
| Mono | Monospace | Space Grotesk, Fira Code, monospace | Code blocks, labels |
### System Font Stack (Fallback)
```css
--font-body: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-mono: ui-monospace, "Cascadia Code", "Fira Code", Menlo, monospace;
```
## Responsive Size Scale
### clamp() Formula Pattern
```css
/* clamp(minimum, preferred, maximum) */
/* preferred = slope * 100vw + intercept */
/* slope = (max - min) / (max-viewport - min-viewport) */
```
### Recommended Scale
| Element | clamp() Value | Min (320px) | Max (1400px) | WCAG |
|---------|--------------|-------------|-------------|------|
| Hero | `clamp(2.5rem, 7vw, 4.5rem)` | 40px | 72px | -- |
| Section title | `clamp(1.75rem, 4vw, 2.5rem)` | 28px | 40px | -- |
| H1 | `clamp(2rem, 5vw, 3rem)` | 32px | 48px | -- |
| H2 | `clamp(1.5rem, 3vw, 2.25rem)` | 24px | 36px | -- |
| H3 | `clamp(1.25rem, 2vw, 1.75rem)` | 20px | 28px | -- |
| Body | `clamp(1rem, 1vw + 0.875rem, 1.25rem)` | 16px | 20px | 1.4.4 |
| Small/caption | 14px (fixed floor) | 14px | 14px | 1.4.4 |
### Absolute Minimums
| Element | Minimum | Rationale |
|---------|---------|-----------|
| Body text | 16px | WCAG 1.4.4 baseline readability |
| Small text / caption | 14px | Absolute floor for legibility |
| Interactive labels | 14px | Touch/click target readability |
**Never**: Set body text below 14px at any viewport width.
## Line Height Scale
| Element Type | Range | Optimal | Rationale |
|-------------|-------|---------|-----------|
| Body text | 1.5 - 1.75 | 1.625 | WCAG 1.4.12, optimal readability |
| Headings | 1.1 - 1.3 | 1.2 | Tight for visual impact, still readable |
| Code blocks | 1.5 - 1.7 | 1.6 | Generous for scanning |
| Buttons/labels | 1.2 - 1.5 | 1.3 | Compact UI element |
| Lists | 1.4 - 1.6 | 1.5 | Slightly tighter than body |
### Line Height Rules
- Use unitless values (not px or em) for proper inheritance
- `line-height: 1.5` (unitless) is preferred over `line-height: 24px` (fixed)
- WCAG 1.4.12 requires text to remain readable at 1.5x font-size line-height
## Letter Spacing Scale
| Element Type | Range | Optimal | Notes |
|-------------|-------|---------|-------|
| Display headings | -0.02em to 0 | -0.015em | Tight for visual weight |
| Body text | 0 (default) | 0 | Browser default is optimal |
| Uppercase labels | 0.05em - 0.1em | 0.08em | Open for legibility |
| Monospace code | 0.08em - 0.15em | 0.1em | Wide for character distinction |
| Small caps | 0.05em - 0.08em | 0.06em | Slight opening |
### WCAG 1.4.12 Override Requirements
Content must remain readable when user applies:
- Letter spacing: 0.12em
- Word spacing: 0.16em
- These overrides should not cause content overflow or overlap
## Reading Width
| Metric | Optimal | Acceptable | Flag |
|--------|---------|-----------|------|
| Characters per line | 66ch | 45-75ch | < 45 (too narrow) or > 75 (too wide) |
| Container max-width | 65ch | 60ch-75ch | > 80ch |
| Content column width | Up to 900px | Up to 1000px | > 1000px without columns |
### Implementation
```css
/* Preferred: ch-based */
.content { max-width: 70ch; }
/* Alternative: px-based */
.content { max-width: 700px; }
/* With centering */
.content {
max-width: 70ch;
margin-inline: auto;
padding-inline: 1rem;
}
```
## Font Loading Strategy
### font-display Values
| Value | Behavior | Recommended For |
|-------|----------|----------------|
| `swap` | Show fallback immediately, swap when loaded | Body text |
| `optional` | Show fallback, swap only if already cached | Display/decorative fonts |
| `fallback` | Brief invisible period (~100ms), then fallback | Important fonts |
| `block` | Invisible text up to 3s | Avoid for body text |
| `auto` | Browser decides | Avoid (unpredictable) |
### Best Practices
```css
/* Body font: swap for immediate readability */
@font-face {
font-family: "Body Font";
src: url("body.woff2") format("woff2");
font-display: swap;
}
/* Display font: optional to prevent layout shift */
@font-face {
font-family: "Display Font";
src: url("display.woff2") format("woff2");
font-display: optional;
}
```
### Preloading Critical Fonts
```html
<link rel="preload" href="/fonts/body.woff2" as="font" type="font/woff2" crossorigin>
```
### Fallback Stack Requirements
- Every custom font must have a system fallback
- Fallback should have similar metrics (x-height, width) to minimize layout shift
- Use `size-adjust`, `ascent-override`, `descent-override` for metric matching
## Responsive Typography Checklist
| # | Check | Standard | Method |
|---|-------|----------|--------|
| 1 | Body text >= 16px at 320px | WCAG 1.4.4 | Computed style at mobile viewport |
| 2 | No text below 14px at any viewport | Best practice | Search for font-size values |
| 3 | clamp() min >= 14px | Best practice | Parse clamp() functions |
| 4 | Line-height unitless | Best practice | Search for px/em line-height |
| 5 | Body line-height 1.5-1.75 | WCAG 1.4.12 | Computed style check |
| 6 | Reading width 45-75ch | Best practice | Measure container + font size |
| 7 | font-display: swap on body | Best practice | Parse @font-face rules |
| 8 | System fallback defined | Best practice | Parse font-family stacks |
| 9 | 200% zoom no overflow | WCAG 1.4.4 | Zoom test |
| 10 | Text spacing override safe | WCAG 1.4.12 | Apply overrides, check layout |

View File

@@ -0,0 +1,133 @@
# WCAG 2.1 Criteria Matrix
Reference matrix for visual accessibility audit. Maps WCAG success criteria to audit methods and responsible roles.
## Criteria Covered by This Team
| Criterion | Level | Automated | Manual | Check Method | Primary Role |
|-----------|-------|-----------|--------|-------------|-------------|
| 1.4.3 Contrast (Minimum) | AA | Yes | - | Color ratio calculation (4.5:1 normal, 3:1 large) | color-auditor |
| 1.4.6 Contrast (Enhanced) | AAA | Yes | - | Color ratio calculation (7:1 normal, 4.5:1 large) | color-auditor |
| 1.4.11 Non-text Contrast | AA | Partial | Yes | UI component border/fill contrast >= 3:1 | color-auditor |
| 1.4.4 Resize Text | AA | Yes | - | 200% zoom, no content loss | typo-auditor |
| 1.4.12 Text Spacing | AA | Partial | Yes | Override line-height 1.5x, letter-spacing 0.12em, word-spacing 0.16em | typo-auditor |
| 2.1.1 Keyboard | A | Partial | Yes | Tab through all interactive elements | focus-auditor |
| 2.1.2 No Keyboard Trap | A | - | Yes | Tab can escape all contexts (except intentional traps with Escape) | focus-auditor |
| 2.4.1 Bypass Blocks | A | Yes | - | Skip link present and functional | focus-auditor |
| 2.4.3 Focus Order | A | - | Yes | Logical tab sequence | focus-auditor |
| 2.4.7 Focus Visible | AA | Partial | Yes | Visible focus indicator on all interactive elements | focus-auditor |
| 2.4.11 Focus Not Obscured (Min) | AA | - | Yes | Focus indicator not hidden by overlays, sticky headers | focus-auditor |
| 2.5.8 Target Size (Minimum) | AA | Yes | - | Minimum 24x24px CSS pixel touch targets | focus-auditor |
| 4.1.2 Name, Role, Value | A | Yes | - | ARIA roles, labels, and states on interactive elements | focus-auditor |
| 4.1.3 Status Messages | AA | Partial | Yes | aria-live regions for dynamic status updates | focus-auditor |
## Audit Method Legend
| Method | Description |
|--------|-------------|
| Automated | Can be verified programmatically (CSS parsing, contrast calculation) |
| Manual | Requires human judgment or runtime interaction |
| Partial | Automated detection of presence, manual verification of correctness |
## Criterion Details
### 1.4.3 Contrast (Minimum) - AA
**Requirement**: Text and images of text have a contrast ratio of at least 4.5:1 (3:1 for large text).
**Large text definition**: >= 18pt (24px) or >= 14pt bold (18.66px bold).
**Exceptions**: Decorative text, logos, inactive UI components.
**Check**: Extract foreground/background colors -> calculate contrast ratio -> compare against threshold.
### 1.4.6 Contrast (Enhanced) - AAA
**Requirement**: Text has contrast ratio of at least 7:1 (4.5:1 for large text).
**Check**: Same as 1.4.3 but with higher thresholds.
### 1.4.11 Non-text Contrast - AA
**Requirement**: UI components and graphical objects have at least 3:1 contrast against adjacent colors.
**Applies to**: Buttons, inputs, icons, focus indicators, charts, custom controls.
**Check**: Extract border/fill colors of UI components -> calculate contrast against background.
### 1.4.4 Resize Text - AA
**Requirement**: Text can be resized up to 200% without loss of content or functionality.
**Check**: Zoom to 200% -> verify no horizontal scrolling, no content clipping, no overlap.
### 1.4.12 Text Spacing - AA
**Requirement**: Content must remain readable when user overrides:
- Line height to 1.5x font size
- Paragraph spacing to 2x font size
- Letter spacing to 0.12x font size
- Word spacing to 0.16x font size
**Check**: Apply overrides via JavaScript/CSS -> verify no content loss or overlap.
### 2.1.1 Keyboard - A
**Requirement**: All functionality available via keyboard (Enter, Space, Tab, Arrow keys, Escape).
**Check**: Tab to every interactive element -> activate with Enter/Space -> navigate composites with Arrows.
### 2.1.2 No Keyboard Trap - A
**Requirement**: Keyboard focus can be moved away from any component using standard keys.
**Exception**: Modal dialogs that trap focus intentionally (must have Escape to exit).
**Check**: Tab forward and backward through all elements -> verify escape from all containers.
### 2.4.1 Bypass Blocks - A
**Requirement**: Mechanism to bypass repeated content blocks (skip links, landmarks, headings).
**Check**: Verify skip link as first focusable element, target exists, focus moves correctly.
### 2.4.3 Focus Order - A
**Requirement**: Focus order preserves meaning and operability (logical sequence).
**Check**: Tab through page -> verify order matches visual/reading order.
### 2.4.7 Focus Visible - AA
**Requirement**: Keyboard focus indicator is visible on all interactive elements.
**Check**: Tab to each element -> verify visible outline/border/shadow change.
### 2.4.11 Focus Not Obscured (Minimum) - AA
**Requirement**: Focused element is not entirely hidden by other content (sticky headers, overlays, banners).
**Check**: Tab through elements near sticky/fixed positioned elements -> verify focus indicator partially visible.
### 2.5.8 Target Size (Minimum) - AA
**Requirement**: Interactive targets are at least 24x24 CSS pixels, or have adequate spacing.
**Exceptions**: Inline links within text, user agent default controls, essential presentation.
**Check**: Measure interactive element dimensions -> verify >= 24x24px or adequate spacing.
### 4.1.2 Name, Role, Value - A
**Requirement**: All UI components have accessible name, role, and state programmatically determined.
**Check**: Verify interactive elements have:
- Accessible name (text content, aria-label, aria-labelledby)
- Appropriate role (native HTML or ARIA role)
- Current state (aria-expanded, aria-pressed, aria-selected, aria-checked)
### 4.1.3 Status Messages - AA
**Requirement**: Status messages can be programmatically determined through role or properties without receiving focus.
**Check**: Verify dynamic content updates use `aria-live` or appropriate roles (`status`, `alert`, `log`).