agentleFS
soilmasssoilmass/motion-design-agent/skills/consequence/SKILL.md

consequence

Skill7 starsChanged 10 months agoMITView on GitHub

Cause-effect animation chain patterns. Use when one animation should trigger another - ripple effects, cascading updates, direct consequences from user actions. Handles propagation timing, intensity decay, and multi-target choreography.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Min intensity: Stop when < 0.1

    line 401
  2. Distinctive:

    Boundary stop: Stop at container edges

    line 402

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Consequence

Design cause-effect relationships between animations. When one motion causes another, consequence patterns ensure the chain feels connected, meaningful, and physically plausible.

Standards Reference

StandardDocumentation
W3C DTCGdesigntokens.org
Material Design 3m3.material.io/styles/motion
Disney PrinciplesFollow-through, secondary action

Quick Reference

Load from: tokens/consequence.tokens.json

Chain Types

TypeDelayTargetsIntensityExample
direct0ms1100%button → modal
ripple30ms/stepmultiple-15%/stepcard → neighbors
cascade50ms/stepsequential85%submit → validate → success
echo200ms130%notification → reminder pulse
branch0msparallel70% eachsubmit → (loading + disable)
convergentwaitsmergemax of inputs(valid + verified) → enable

Selection Guide

How does the consequence relate to the cause?

├── Single, immediate result
│   └── DIRECT chain
│       └── e.g., click button → open modal
│
├── Spreading outward from source
│   └── RIPPLE chain
│       └── e.g., select card → nearby cards react
│
├── Sequential steps, each triggering next
│   └── CASCADE chain
│       └── e.g., submit → validate → transform → success
│
├── Delayed callback to original
│   └── ECHO chain
│       └── e.g., notification arrives → subtle pulse later
│
├── One cause, multiple parallel effects
│   └── BRANCH chain
│       └── e.g., submit → (show loading + disable button + scroll)
│
└── Multiple causes required for effect
    └── CONVERGENT chain
        └── e.g., (all fields valid + captcha passed) → enable submit

Chain Patterns

Direct Chain

Immediate, single-target consequence.

Use case: User action → immediate response

// Button click → Modal open
const directChain = {
  trigger: { element: '.btn', event: 'click' },
  consequence: {
    element: '.modal',
    type: 'direct',
    delay: 0,
    animation: {
      opacity: { from: 0, to: 1 },
      scale: { from: 0.9, to: 1 },
      duration: 300,
      easing: 'emphasized-decelerate'
    }
  }
};

// GSAP implementation
document.querySelector('.btn').addEventListener('click', () => {
  gsap.fromTo('.modal',
    { opacity: 0, scale: 0.9 },
    { opacity: 1, scale: 1, duration: 0.3, ease: 'power2.out' }
  );
});

Framer Motion:

const [isOpen, setIsOpen] = useState(false);

// Direct: button click → modal visibility
<motion.button onClick={() => setIsOpen(true)}>
  Open
</motion.button>

<AnimatePresence>
  {isOpen && (
    <motion.div
      initial={{ opacity: 0, scale: 0.9 }}
      animate={{ opacity: 1, scale: 1 }}
      exit={{ opacity: 0, scale: 0.9 }}
      transition={{ duration: 0.3 }}
    >
      Modal Content
    </motion.div>
  )}
</AnimatePresence>

Ripple Chain

Radiating outward from source point.

Use case: Selection affecting neighbors, touch feedback

// Card select → nearby cards react
function rippleChain(sourceElement, targets) {
  const sourceRect = sourceElement.getBoundingClientRect();
  const sourceCenter = {
    x: sourceRect.left + sourceRect.width / 2,
    y: sourceRect.top + sourceRect.height / 2
  };

  targets.forEach(target => {
    const targetRect = target.getBoundingClientRect();
    const distance = Math.hypot(
      targetRect.left + targetRect.width/2 - sourceCenter.x,
      targetRect.top + targetRect.height/2 - sourceCenter.y
    );

    const delay = distance * 0.001; // 30ms per 30px
    const intensity = Math.max(0.1, 1 - (distance * 0.0015)); // Decay

    gsap.to(target, {
      scale: 1 + (0.05 * intensity),
      opacity: 0.8 + (0.2 * intensity),
      duration: 0.2,
      delay: delay,
      ease: 'power2.out',
      yoyo: true,
      repeat: 1
    });
  });
}

GSAP with stagger:

gsap.from('.grid-item:not(.selected)', {
  scale: 0.98,
  opacity: 0.7,
  duration: 0.25,
  stagger: {
    each: 0.03,
    from: document.querySelector('.selected'),
    grid: 'auto'
  },
  ease: 'power2.out'
});

Cascade Chain

Sequential chain where each step triggers the next.

Use case: Form submission, multi-step processes

// Submit → validate → transform → success
const cascadeChain = gsap.timeline();

// Step 1: Button press feedback
cascadeChain.to('.submit-btn', {
  scale: 0.95,
  duration: 0.1,
  ease: 'power2.in'
});

// Step 2: Validation visual (50ms delay between steps)
cascadeChain.to('.form-fields', {
  borderColor: '#4CAF50',
  stagger: 0.05,
  duration: 0.2
}, '+=0.05');

// Step 3: Button transforms
cascadeChain.to('.submit-btn', {
  backgroundColor: '#4CAF50',
  width: 50,
  borderRadius: 25,
  duration: 0.3,
  ease: 'power2.inOut'
}, '+=0.05');

// Step 4: Success checkmark
cascadeChain.to('.checkmark', {
  scale: 1,
  opacity: 1,
  duration: 0.25,
  ease: 'back.out(2)'
}, '+=0.05');

Framer Motion with orchestration:

const cascadeVariants = {
  hidden: {},
  visible: {
    transition: {
      staggerChildren: 0.05,
      delayChildren: 0
    }
  }
};

const stepVariants = {
  hidden: { opacity: 0, y: 10 },
  visible: {
    opacity: 1,
    y: 0,
    transition: { duration: 0.2 }
  }
};

Echo Chain

Delayed repetition at reduced intensity.

Use case: Reminder pulses, attention maintenance

// Notification → echo pulse after 200ms
function echoChain(element) {
  // Primary animation
  gsap.fromTo(element,
    { scale: 0.8, opacity: 0 },
    { scale: 1, opacity: 1, duration: 0.3, ease: 'back.out(2)' }
  );

  // Echo at 30% intensity after 200ms
  gsap.to(element, {
    scale: 1.05,
    boxShadow: '0 0 20px rgba(33, 150, 243, 0.3)',
    duration: 0.4,
    delay: 0.2 + 0.3, // After primary + 200ms gap
    ease: 'power2.inOut',
    yoyo: true,
    repeat: 1
  });
}

Branch Chain

Single trigger, multiple parallel consequences.

Use case: Form submit, state changes with multiple effects

// Submit → (loading + disable inputs + scroll to top)
function branchChain() {
  const branches = [];

  // Branch 1: Show loading
  branches.push(
    gsap.to('.loading-spinner', {
      opacity: 1,
      rotation: 360,
      duration: 0.3
    })
  );

  // Branch 2: Disable inputs
  branches.push(
    gsap.to('.form-input', {
      opacity: 0.5,
      pointerEvents: 'none',
      duration: 0.2
    })
  );

  // Branch 3: Scroll to top
  branches.push(
    gsap.to(window, {
      scrollTo: 0,
      duration: 0.4
    })
  );

  // All branches execute in parallel
  return Promise.all(branches);
}

Framer Motion parallel:

const branchVariants = {
  idle: {},
  loading: {
    transition: { staggerChildren: 0 } // Parallel, no stagger
  }
};

const spinnerVariants = {
  idle: { opacity: 0 },
  loading: { opacity: 1, rotate: 360 }
};

const inputVariants = {
  idle: { opacity: 1 },
  loading: { opacity: 0.5 }
};

Convergent Chain

Multiple causes combine to trigger consequence.

Use case: Multi-condition validation, compound events

// (email valid + password valid + captcha passed) → enable submit
const conditions = {
  emailValid: false,
  passwordValid: false,
  captchaPassed: false
};

function checkConvergence() {
  const allMet = Object.values(conditions).every(Boolean);

  if (allMet) {
    gsap.to('.submit-btn', {
      opacity: 1,
      scale: 1,
      pointerEvents: 'auto',
      duration: 0.3,
      ease: 'power2.out'
    });
  }
}

// Each condition updates and checks
function setCondition(key, value) {
  conditions[key] = value;
  checkConvergence();
}

Propagation Timing

TimingValueUse
instant0msSame frame
linked16msNext frame, perceptually connected
followup100msClear follow-up
delayed300msBuilds anticipation
deferred600msSeparate moment

Intensity Profiles

ProfileMultiplierUse
preserve1.0Full intensity maintained
amplify1.3Consequence > cause
diminish0.6Consequence < cause
transformmappedIntensity maps to different property

Spatial Propagation

// Radial propagation
const radialConfig = {
  origin: 'center',
  spread: 'circular',
  delayPerUnit: 30 // ms per distance unit
};

// Calculate delay based on distance from origin
function getRadialDelay(element, origin) {
  const distance = getDistance(element, origin);
  return distance * radialConfig.delayPerUnit / 1000;
}

Termination Rules

  • Max depth: 5 steps maximum
  • Min intensity: Stop when < 0.1
  • Boundary stop: Stop at container edges

Reduced Motion

For prefers-reduced-motion: reduce:

Chain TypeReduced Alternative
rippleInstant state change
cascadeSingle combined transition
echoSkip echo
branchSimultaneous fade

Cross-References

  • See sequencing/ for stagger patterns
  • See narrative-arc/ for chain timing within story phases
  • See intent/ for consequence purpose
  • See follow-through/ for Disney principle connection

References

  • references/chain-patterns.md — Detailed chain configurations

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.