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