
Team Motion Design
- 15 installs
- 2.1k repo stars
- Updated June 18, 2026
- catlog22/claude-code-workflow
Support for team-motion-design
About
Provides workflow support for team-motion-design. Solo builders use this to streamline development.
- team-motion-design
Team Motion Design by the numbers
- 15 all-time installs (skills.sh)
- Ranked #2,109 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/catlog22/claude-code-workflow --skill team-motion-designAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 15 |
|---|---|
| repo stars | ★ 2.1k |
| Last updated | June 18, 2026 |
| Repository | catlog22/claude-code-workflow ↗ |
What it does
Support for team-motion-design
Files
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-testerRole Registry
| Role | Path | Prefix | Inner Loop |
|---|---|---|---|
| coordinator | roles/coordinator/role.md | -- | -- |
| motion-researcher | roles/motion-researcher/role.md | MRESEARCH-* | false |
| choreographer | roles/choreographer/role.md | CHOREO-* | false |
| animator | roles/animator/role.md | ANIM-* | true |
| motion-tester | roles/motion-tester/role.md | MTEST-* | false |
Role Router
Parse $ARGUMENTS:
- Has
--role <name>-> Readroles/<name>/role.md, execute Phase 2-4 - No
--role->@roles/coordinator/role.md, execute entry router
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:
Agent({
subagent_type: "team-worker",
description: "Spawn <role> worker for <task-id>",
team_name: "motion-design",
name: "<role>",
run_in_background: true,
prompt: `## Role Assignment
role: <role>
role_spec: <skill_root>/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
team_name: motion-design
requirement: <task-description>
inner_loop: <true|false>
## Progress Milestones
session_id: <session-id>
Report progress via team_msg at natural phase boundaries (context loaded -> core work done -> verification).
Report blockers immediately via team_msg type="blocker".
Report completion via team_msg type="task_complete" after final SendMessage.
Read role_spec file (@<skill_root>/roles/<role>/role.md) to load Phase 2-4 domain instructions.
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
})User Commands
| Command | Action |
|---|---|
check / status | View execution status graph |
resume / continue | Advance to next step |
Specs Reference
- specs/pipelines.md -- Pipeline definitions and task registry
- specs/motion-tokens.md -- Animation token schema
- specs/gpu-constraints.md -- Compositor-only animation rules
- 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 knowledgeError 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 |
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`:
: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, opacityon 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):
// 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:
.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
pointerdownnotclick(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->opacityon overlay- Reduce will-change elements to max 3-4 simultaneous
- Add missing prefers-reduced-motion overrides
- Signal
animation_revisioninstead ofanimation_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
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.05sto0.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
{
"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
# 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 movementTransition 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
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:
{
"pipeline_mode": "<tokens|component|page>",
"scope": "<description>",
"framework": "<detected-framework>",
"complexity": { "score": 0, "level": "Low|Medium|High" }
}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 session.json pipeline | Yes |
| Framework config | From session.json framework | Yes |
1. Load user requirement and motion scope from session.json 2. Load pipeline stage definitions from specs/pipelines.md 3. Read pipeline and framework from session.json
Phase 3: Task Chain Creation (Mode-Branched)
Task Description Template
Every task description uses structured format:
TaskCreate({
subject: "<TASK-ID>",
description: "PURPOSE: <what this task achieves> | Success: <measurable completion criteria>
TASK:
- <step 1: specific action>
- <step 2: specific action>
- <step 3: specific action>
CONTEXT:
- Session: <session-folder>
- Scope: <motion-scope>
- Framework: <framework>
- Upstream artifacts: <artifact-1>, <artifact-2>
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <deliverable path> + <quality criteria>
CONSTRAINTS: <scope limits, focus areas>"
})
TaskUpdate({ taskId: "<TASK-ID>", addBlockedBy: [<dependency-list>], owner: "<role>" })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):
TaskCreate({
subject: "MRESEARCH-001",
description: "PURPOSE: Audit existing animations, measure performance baseline, catalog easing patterns | Success: 3 research artifacts produced with valid data
TASK:
- Scan codebase for existing CSS @keyframes, transitions, JS animation code
- Measure paint/composite costs via Chrome DevTools performance traces (if available)
- Catalog existing easing functions and timing patterns
- Identify properties being animated (safe vs unsafe for compositor)
CONTEXT:
- Session: <session-folder>
- Scope: <motion-scope>
- Framework: <framework>
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <session>/research/*.json | All 3 research files with valid JSON
CONSTRAINTS: Read-only analysis | Focus on existing animation patterns"
})
TaskUpdate({ taskId: "MRESEARCH-001", owner: "motion-researcher" })CHOREO-001 (choreographer):
TaskCreate({
subject: "CHOREO-001",
description: "PURPOSE: Design animation token system with easing functions, duration scale, stagger formulas | Success: Complete motion-tokens.json with all token categories
TASK:
- Define easing functions (ease-out, ease-in-out, ease-spring) as cubic-bezier values
- Define duration scale (fast, base, slow, slower, slowest)
- Define stagger formula with base delay and increment
- Define reduced-motion fallback tokens
- Reference specs/motion-tokens.md for token schema
CONTEXT:
- Session: <session-folder>
- Scope: <motion-scope>
- Framework: <framework>
- Upstream artifacts: research/*.json
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <session>/choreography/motion-tokens.json | Complete token system
CONSTRAINTS: Follow motion-tokens.md schema | All tokens must have reduced-motion fallback"
})
TaskUpdate({ taskId: "CHOREO-001", addBlockedBy: ["MRESEARCH-001"], owner: "choreographer" })ANIM-001 (animator):
TaskCreate({
subject: "ANIM-001",
description: "PURPOSE: Implement CSS custom properties and utility classes from motion tokens | Success: Production-ready CSS with token consumption and reduced-motion overrides
TASK:
- Generate CSS custom properties from motion-tokens.json
- Create utility animation classes consuming tokens
- Add prefers-reduced-motion media query overrides
- Ensure compositor-only properties (transform, opacity) per specs/gpu-constraints.md
CONTEXT:
- Session: <session-folder>
- Scope: <motion-scope>
- Framework: <framework>
- Upstream artifacts: choreography/motion-tokens.json
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <session>/animations/keyframes/*.css | Token CSS + utility classes + reduced-motion
CONSTRAINTS: Compositor-only animations | No layout-triggering properties | will-change budget"
})
TaskUpdate({ taskId: "ANIM-001", addBlockedBy: ["CHOREO-001"], owner: "animator" })MTEST-001 (motion-tester):
TaskCreate({
subject: "MTEST-001",
description: "PURPOSE: Verify animation performance and accessibility compliance | Success: 60fps confirmed, no layout thrashing, reduced-motion present
TASK:
- Start Chrome DevTools performance trace (if available)
- Verify compositor-only animations (no paint/layout triggers)
- Check will-change usage (not excessive, max 3-4 elements)
- Validate prefers-reduced-motion @media query presence
- Static code analysis as fallback if Chrome DevTools unavailable
CONTEXT:
- Session: <session-folder>
- Scope: <motion-scope>
- Framework: <framework>
- Upstream artifacts: animations/keyframes/*.css, choreography/motion-tokens.json
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <session>/testing/reports/perf-report-001.md | Performance validation report
CONSTRAINTS: Target 60fps | Flag any layout-triggering properties"
})
TaskUpdate({ taskId: "MTEST-001", addBlockedBy: ["ANIM-001"], owner: "motion-tester" })---
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_requiredsignal
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:
TaskCreate({
subject: "ANIM-<NNN>",
description: "PURPOSE: Implement animations for <section-name> | Success: Scroll-triggered reveals with 60fps performance
TASK:
- Implement IntersectionObserver-based scroll triggers for <section-name>
- Apply staggered entry animations with calculated delays
- Add scroll-linked parallax (if specified in choreography)
- Ensure prefers-reduced-motion fallback
CONTEXT:
- Session: <session-folder>
- Section: <section-name>
- Upstream artifacts: choreography/sequences/<section>.md, choreography/motion-tokens.json
- Shared memory: <session>/wisdom/.msg/meta.json
EXPECTED: <session>/animations/keyframes/<section>.css + orchestrators/<section>.js
CONSTRAINTS: Compositor-only | will-change budget | Follow motion-tokens"
})
TaskUpdate({ taskId: "ANIM-<NNN>", addBlockedBy: ["CHOREO-001"], owner: "animator" })MTEST-001: Blocked by all ANIM tasks. Full page performance validation.
---
Phase 4: Validation
Verify task chain integrity:
| Check | Method | Expected |
|---|---|---|
| Task count correct | TaskList count | tokens: 4, component: 4, page: 4+N |
| Dependencies correct | Trace dependency graph | Acyclic, correct blockedBy |
| 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.
Monitor Pipeline
Event-driven pipeline coordination. Beat model: coordinator wake -> process -> spawn -> STOP.
Constants
- SPAWN_MODE: background
- ONE_STEP_PER_INVOCATION: true
- FAST_ADVANCE_AWARE: true
- WORKER_AGENT: team-worker
- MAX_GC_ROUNDS: 2
Handler Router
| Source | Handler |
|---|---|
| Message contains [motion-researcher], [choreographer], [animator], [motion-tester] | handleCallback |
| "capability_gap" | handleAdapt |
| "check" or "status" | handleCheck |
| "resume" or "continue" | handleResume |
| All tasks completed | handleComplete |
| Default | handleSpawnNext |
handleCallback
Worker completed. Process and advance.
1. Parse message to identify role and task ID:
| Message Pattern | Role |
|---|---|
[motion-researcher] or MRESEARCH-* | motion-researcher |
[choreographer] or CHOREO-* | choreographer |
[animator] or ANIM-* | animator |
[motion-tester] or MTEST-* | motion-tester |
2. Mark task completed: TaskUpdate({ taskId: "<task-id>", 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 message: 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:
TaskCreate({ subject: "ANIM-fix-<round>",
description: "PURPOSE: Address performance issues from motion-tester report | Success: All critical perf issues resolved
TASK:
- Parse performance report for specific issues (layout thrashing, unsafe properties, excessive will-change)
- Replace layout-triggering properties with compositor-only alternatives
- Optimize will-change usage
- Verify reduced-motion fallback completeness
CONTEXT:
- Session: <session-folder>
- Upstream artifacts: testing/reports/perf-report-<NNN>.md" })
TaskUpdate({ taskId: "ANIM-fix-<round>", owner: "animator" })Then create new MTEST task blocked by 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, then STOP.
Worker Progress (from message bus):
Before generating status output, read worker milestones:
const progressMsgs = mcp__ccw-tools__team_msg({
operation: "list", session_id: sessionId, type: "progress", last: 50
})
const blockerMsgs = mcp__ccw-tools__team_msg({
operation: "list", session_id: sessionId, type: "blocker", last: 10
})
// Aggregate latest milestone per task
const taskProgress = {}
for (const msg of (progressMsgs.result?.messages || [])) {
const tid = msg.data?.task_id
if (tid && (!taskProgress[tid] || msg.ts > taskProgress[tid].ts)) {
taskProgress[tid] = { phase: msg.data.phase, pct: msg.data.progress_pct, ts: msg.ts }
}
}Include in status output:
- Per-worker latest milestone (phase + progress_pct) next to task status
- Active blockers section (if any blockerMsgs found)
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 refreshOutput status -- do NOT advance pipeline.
handleResume
1. Audit task list for inconsistencies:
- Tasks stuck in "in_progress" -> reset to "pending"
- Tasks with completed blockers but still "pending" -> include in spawn list
2. -> handleSpawnNext
handleSpawnNext
Find ready tasks, spawn workers, STOP.
1. Collect: completedSubjects, inProgressSubjects, readySubjects (pending + all blockedBy 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. TaskUpdate -> in_progress c. team_msg log -> task_unblocked d. Spawn team-worker:
Agent({
subagent_type: "team-worker",
description: "Spawn <role> worker for <task-id>",
team_name: "motion-design",
name: "<role>",
run_in_background: true,
prompt: `## Role Assignment
role: <role>
role_spec: ~ or <project>/.claude/skills/team-motion-design/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
team_name: motion-design
requirement: <task-description>
inner_loop: <true|false>
## Progress Milestones
session_id: <session-id>
Report progress via team_msg at natural phase boundaries (context loaded -> core work done -> verification).
Report blockers immediately via team_msg type="blocker".
Report completion via team_msg type="task_complete" after final SendMessage.
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).`
})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 (CP-3 Fan-out) |
| page | After all ANIM complete | Spawn MTEST-001 |
5. Add to active_workers, update session, output summary, STOP
handleComplete
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, spawn worker 5. Role count >= 5 -> merge or pause
Fast-Advance Reconciliation
On every coordinator wake: 1. Read team_msg entries with type="fast_advance" 2. Sync active_workers with spawned successors 3. No duplicate spawns
Coordinator Role
Motion Design Team coordinator. Orchestrate pipeline: analyze -> dispatch -> spawn -> monitor -> report. Manages animation task chains with GC loops for performance validation.
Identity
- Name: coordinator | Tag: [coordinator]
- Responsibility: Analyze task -> Create team -> Dispatch tasks -> Monitor progress -> Report results
Boundaries
MUST
- All output (SendMessage, team_msg, logs) must carry
[coordinator]identifier - Use
team-workeragent type for all worker spawns (NOTgeneral-purpose) - Dispatch tasks with proper dependency chains and blockedBy
- Monitor worker progress via message bus and route messages
- Handle Generator-Critic loops with max 2 iterations
- Maintain session state persistence
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
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 |
|---|---|---|
| Worker callback | Message contains [motion-researcher], [choreographer], [animator], [motion-tester] | -> handleCallback (monitor.md) |
| 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 callback/check/resume/adapt/complete: load @commands/monitor.md, execute matched handler, STOP.
Phase 0: Session Resume Check
1. Scan .workflow/.team/MD-*/.msg/meta.json for active/paused sessions 2. No sessions -> Phase 1 3. Single session -> reconcile (audit TaskList, reset in_progress->pending, rebuild team, kick first ready task) 4. Multiple -> AskUserQuestion 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:
AskUserQuestion({
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 Team + Initialize Session
1. Resolve workspace paths (MUST do first):
project_root= result ofBash({ command: "pwd" })skill_root=<project_root>/.claude/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. TeamCreate(team_name="motion-design") 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-Stop
Delegate to @commands/monitor.md#handleSpawnNext: 1. Find ready tasks (pending + blockedBy resolved) 2. Spawn team-worker agents (see SKILL.md Spawn Template) 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:
AskUserQuestion({
questions: [{ question: "Pipeline complete. What next?", header: "Completion", options: [
{ label: "Archive & Clean", description: "Archive session and clean up team resources" },
{ label: "Keep Active", description: "Keep session for follow-up work" },
{ label: "Export Results", description: "Export deliverables to specified location" }
]}]
})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 |
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
{
"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
{
"_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
{
"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
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)opacityfilter(blur, brightness, contrast)backdrop-filter
UNSAFE (trigger layout/paint):
width,height,top,left,right,bottommargin,padding,borderfont-size,color,background-colorbox-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/offsetWidthread followed by style write followed by readgetBoundingClientRect()interleaved with style mutationsgetComputedStyle()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:
# 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] Description2. 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
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
/* 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;
}// JS: add before, remove after
element.style.willChange = 'transform';
element.addEventListener('transitionend', () => {
element.style.willChange = 'auto';
}, { once: true });Layer Promotion
transform: translateZ(0)orwill-change: transformpromotes 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 panelMotion 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-outis the default for most animations (content reveals, transitions)ease-in-outfor reversible state changes (expand/collapse, toggle)ease-springsparingly for emphasis (new item added, attention-grabbing)- Never use
ease-inalone (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
: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
/* 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
{
"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"
}
}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 | blockedBy | 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 | blockedBy | 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 | blockedBy | 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 |
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
@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)
.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
.parallax-element {
transform: translateY(calc(var(--scroll-y) * 0.5));
}
@media (prefers-reduced-motion: reduce) {
.parallax-element {
transform: none !important;
}
}JavaScript Detection
// 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)
{
"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}/"
}
}