mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-03-30 20:21:09 +08:00
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:
220
.codex/skills/team-interactive-craft/SKILL.md
Normal file
220
.codex/skills/team-interactive-craft/SKILL.md
Normal 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 |
|
||||||
159
.codex/skills/team-interactive-craft/roles/a11y-tester/role.md
Normal file
159
.codex/skills/team-interactive-craft/roles/a11y-tester/role.md
Normal 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
|
||||||
216
.codex/skills/team-interactive-craft/roles/builder/role.md
Normal file
216
.codex/skills/team-interactive-craft/roles/builder/role.md
Normal 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
|
||||||
@@ -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" }
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
209
.codex/skills/team-interactive-craft/roles/coordinator/role.md
Normal file
209
.codex/skills/team-interactive-craft/roles/coordinator/role.md
Normal 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 |
|
||||||
@@ -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
|
||||||
131
.codex/skills/team-interactive-craft/roles/researcher/role.md
Normal file
131
.codex/skills/team-interactive-craft/roles/researcher/role.md
Normal 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
|
||||||
@@ -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
|
||||||
85
.codex/skills/team-interactive-craft/specs/pipelines.md
Normal file
85
.codex/skills/team-interactive-craft/specs/pipelines.md
Normal 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 |
|
||||||
105
.codex/skills/team-interactive-craft/specs/team-config.json
Normal file
105
.codex/skills/team-interactive-craft/specs/team-config.json
Normal 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}/"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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/` |
|
||||||
222
.codex/skills/team-motion-design/SKILL.md
Normal file
222
.codex/skills/team-motion-design/SKILL.md
Normal 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 |
|
||||||
194
.codex/skills/team-motion-design/roles/animator/role.md
Normal file
194
.codex/skills/team-motion-design/roles/animator/role.md
Normal 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
|
||||||
164
.codex/skills/team-motion-design/roles/choreographer/role.md
Normal file
164
.codex/skills/team-motion-design/roles/choreographer/role.md
Normal 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
|
||||||
@@ -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" }
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
210
.codex/skills/team-motion-design/roles/coordinator/role.md
Normal file
210
.codex/skills/team-motion-design/roles/coordinator/role.md
Normal 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 |
|
||||||
115
.codex/skills/team-motion-design/roles/motion-researcher/role.md
Normal file
115
.codex/skills/team-motion-design/roles/motion-researcher/role.md
Normal 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
|
||||||
175
.codex/skills/team-motion-design/roles/motion-tester/role.md
Normal file
175
.codex/skills/team-motion-design/roles/motion-tester/role.md
Normal 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
|
||||||
114
.codex/skills/team-motion-design/specs/gpu-constraints.md
Normal file
114
.codex/skills/team-motion-design/specs/gpu-constraints.md
Normal 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
|
||||||
|
```
|
||||||
128
.codex/skills/team-motion-design/specs/motion-tokens.md
Normal file
128
.codex/skills/team-motion-design/specs/motion-tokens.md
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
74
.codex/skills/team-motion-design/specs/pipelines.md
Normal file
74
.codex/skills/team-motion-design/specs/pipelines.md
Normal 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 |
|
||||||
129
.codex/skills/team-motion-design/specs/reduced-motion.md
Normal file
129
.codex/skills/team-motion-design/specs/reduced-motion.md
Normal 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)
|
||||||
99
.codex/skills/team-motion-design/specs/team-config.json
Normal file
99
.codex/skills/team-motion-design/specs/team-config.json
Normal 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}/"
|
||||||
|
}
|
||||||
|
}
|
||||||
218
.codex/skills/team-ui-polish/SKILL.md
Normal file
218
.codex/skills/team-ui-polish/SKILL.md
Normal 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 |
|
||||||
@@ -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" }
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
213
.codex/skills/team-ui-polish/roles/coordinator/role.md
Normal file
213
.codex/skills/team-ui-polish/roles/coordinator/role.md
Normal 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 |
|
||||||
164
.codex/skills/team-ui-polish/roles/diagnostician/role.md
Normal file
164
.codex/skills/team-ui-polish/roles/diagnostician/role.md
Normal 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" })
|
||||||
|
```
|
||||||
229
.codex/skills/team-ui-polish/roles/optimizer/role.md
Normal file
229
.codex/skills/team-ui-polish/roles/optimizer/role.md
Normal 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" })
|
||||||
|
```
|
||||||
360
.codex/skills/team-ui-polish/roles/scanner/role.md
Normal file
360
.codex/skills/team-ui-polish/roles/scanner/role.md
Normal 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" })
|
||||||
|
```
|
||||||
142
.codex/skills/team-ui-polish/roles/verifier/role.md
Normal file
142
.codex/skills/team-ui-polish/roles/verifier/role.md
Normal 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" })
|
||||||
|
```
|
||||||
141
.codex/skills/team-ui-polish/specs/anti-patterns.md
Normal file
141
.codex/skills/team-ui-polish/specs/anti-patterns.md
Normal 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 |
|
||||||
356
.codex/skills/team-ui-polish/specs/design-standards.md
Normal file
356
.codex/skills/team-ui-polish/specs/design-standards.md
Normal 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 |
|
||||||
235
.codex/skills/team-ui-polish/specs/fix-strategies.md
Normal file
235
.codex/skills/team-ui-polish/specs/fix-strategies.md
Normal 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)
|
||||||
|
```
|
||||||
81
.codex/skills/team-ui-polish/specs/pipelines.md
Normal file
81
.codex/skills/team-ui-polish/specs/pipelines.md
Normal 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 |
|
||||||
162
.codex/skills/team-ui-polish/specs/scoring-guide.md
Normal file
162
.codex/skills/team-ui-polish/specs/scoring-guide.md
Normal 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)
|
||||||
73
.codex/skills/team-ui-polish/specs/team-config.json
Normal file
73
.codex/skills/team-ui-polish/specs/team-config.json
Normal 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}/"
|
||||||
|
}
|
||||||
|
}
|
||||||
319
.codex/skills/team-visual-a11y/SKILL.md
Normal file
319
.codex/skills/team-visual-a11y/SKILL.md
Normal 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 |
|
||||||
178
.codex/skills/team-visual-a11y/roles/color-auditor/role.md
Normal file
178
.codex/skills/team-visual-a11y/roles/color-auditor/role.md
Normal 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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
213
.codex/skills/team-visual-a11y/roles/coordinator/role.md
Normal file
213
.codex/skills/team-visual-a11y/roles/coordinator/role.md
Normal 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 |
|
||||||
246
.codex/skills/team-visual-a11y/roles/fix-implementer/role.md
Normal file
246
.codex/skills/team-visual-a11y/roles/fix-implementer/role.md
Normal 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
|
||||||
222
.codex/skills/team-visual-a11y/roles/focus-auditor/role.md
Normal file
222
.codex/skills/team-visual-a11y/roles/focus-auditor/role.md
Normal 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
|
||||||
206
.codex/skills/team-visual-a11y/roles/remediation-planner/role.md
Normal file
206
.codex/skills/team-visual-a11y/roles/remediation-planner/role.md
Normal 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
|
||||||
185
.codex/skills/team-visual-a11y/roles/typo-auditor/role.md
Normal file
185
.codex/skills/team-visual-a11y/roles/typo-auditor/role.md
Normal 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
|
||||||
325
.codex/skills/team-visual-a11y/specs/focus-patterns.md
Normal file
325
.codex/skills/team-visual-a11y/specs/focus-patterns.md
Normal 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.
|
||||||
130
.codex/skills/team-visual-a11y/specs/oklch-standards.md
Normal file
130
.codex/skills/team-visual-a11y/specs/oklch-standards.md
Normal 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.
|
||||||
98
.codex/skills/team-visual-a11y/specs/pipelines.md
Normal file
98
.codex/skills/team-visual-a11y/specs/pipelines.md
Normal 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 |
|
||||||
109
.codex/skills/team-visual-a11y/specs/team-config.json
Normal file
109
.codex/skills/team-visual-a11y/specs/team-config.json
Normal 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}/"
|
||||||
|
}
|
||||||
|
}
|
||||||
165
.codex/skills/team-visual-a11y/specs/typography-scale.md
Normal file
165
.codex/skills/team-visual-a11y/specs/typography-scale.md
Normal 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 |
|
||||||
133
.codex/skills/team-visual-a11y/specs/wcag-matrix.md
Normal file
133
.codex/skills/team-visual-a11y/specs/wcag-matrix.md
Normal 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`).
|
||||||
Reference in New Issue
Block a user