anticipation
Skill7 starsChanged 10 months agoMITView on GitHub
Disney's principle of preparation before action - the wind-up that makes motion feel intentional. Use when elements need clear directional cues, dramatic reveals, or physically believable movement.
In this repository87 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- motion-designSkill
- 3d-transformsSkill
- accessibilitySkill
- android-nativeSkill
- animation-recipesSkill
- arc-motionSkill
- attention-choreographySkill
- attentionSkill
- audio-reactiveSkill
- blurSkill
- brand-animationSkill
- cameraSkill
- characterSkill
- choice-resolutionSkill
- cinematicSkill
- code-generationSkill
- colorSkill
- component-animationsSkill
- compositingSkill
- consequenceSkill
- container-transformSkill
- css-advancedSkill
- data-visualizationSkill
- depthSkill
- distortionSkill
- dramaturgySkill
- durationSkill
- easingSkill
- emotional-journeySkill
- emotion-mappingSkill
- emotion-selectionSkill
- empty-statesSkill
- entrance-patternsSkill
- exaggerationSkill
- exit-patternsSkill
- exportSkill
- figma-integrationSkill
- follow-throughSkill
- frame-timingSkill
- gesture-motionSkill
- glow-shadowSkill
- intentSkill
- ios-nativeSkill
- loading-statesSkill
- loopingSkill
- lottieSkill
- masksSkill
- microstateSkill
- morphingSkill
- motion-auditSkill
- motion-blurSkill
- motion-principlesSkill
- motion-specsSkill
- narrative-arcSkill
- notificationsSkill
- onboardingSkill
- opacitySkill
- orchestratorSkill
- particlesSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 3 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
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
- Distinctive: line 455
Too long anticipation: - Should be 15-25% of total, not 50%
- Distinctive: line 456
Wrong direction: - Must be opposite to main action
- Distinctive: line 458
Overuse: - Not every action needs anticipation
≈ “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.
Files
Anticipation
The preparatory movement that precedes the main action. Like a pitcher's wind-up or a jumper's crouch, anticipation signals intent and builds energy.
Core Principle
Movement in the opposite direction before the main action creates expectation and makes motion feel intentional.
Without anticipation: -------> (sudden, jarring)
With anticipation: <-- -------> (prepared, natural)
^
wind-up phaseToken Reference
Load from: tokens/anticipation.tokens.json
| Token | Duration | Scale | Offset | Use Case |
micro | 50ms | 0.98 | -2px | Toggles, micro-interactions |
small | 80ms | 0.95 | -5px | Buttons, icons |
medium | 120ms | 0.90 | -10px | Cards, modals |
dramatic | 200ms | 0.85 | -20px | Hero moments, reveals |
extreme | 300ms | 0.75 | -40px | Cartoon, gaming |
Timing Ratios
Anticipation should be 15-25% of total animation duration:
| Total Duration | Anticipation | Main Action |
| 200ms | 30-50ms | 150-170ms |
| 300ms | 45-75ms | 225-255ms |
| 500ms | 75-125ms | 375-425ms |
Direction Rules
Anticipation direction = opposite of main action
| Main Action | Anticipation |
| Move right | Pull left |
| Move up | Dip down |
| Scale up | Shrink first |
| Rotate clockwise | Counter-rotate |
Implementation Presets
CSS
/* Button with anticipation */
.button-anticipate {
transition: transform 200ms var(--ease-standard);
}
.button-anticipate:active {
animation: anticipate-press 200ms ease-out;
}
@keyframes anticipate-press {
0% { transform: scale(1); }
30% { transform: scale(0.95) translateY(2px); } /* Wind-up */
100% { transform: scale(1.05); } /* Action */
}
/* Slide-in with anticipation */
@keyframes slide-in-anticipate {
0% {
transform: translateX(-100%);
opacity: 0;
}
15% {
transform: translateX(-110%); /* Pull back further */
opacity: 0.5;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
/* Pop-in with scale anticipation */
@keyframes pop-in-anticipate {
0% {
transform: scale(0);
opacity: 0;
}
20% {
transform: scale(0.85); /* Compress before pop */
opacity: 0.8;
}
50% {
transform: scale(1.1); /* Overshoot */
opacity: 1;
}
100% {
transform: scale(1);
}
}GSAP
import { gsap } from 'gsap';
import tokens from '../tokens/anticipation.tokens.json';
// Anticipation utility function
function withAnticipation(element, mainAction, intensity = 'small') {
const { duration, scale, offsetY } = tokens.anticipation[intensity].$value;
const anticipationMs = parseInt(duration);
const tl = gsap.timeline();
// Anticipation phase (opposite direction)
tl.to(element, {
scale: scale,
y: -parseInt(offsetY), // Negative because offsetY is already negative
duration: anticipationMs / 1000,
ease: 'power2.out'
});
// Main action
tl.add(mainAction);
return tl;
}
// Button press with anticipation
function pressButton(button) {
return withAnticipation(
button,
gsap.to(button, {
scale: 1.05,
y: 0,
duration: 0.15,
ease: 'back.out(2)'
}),
'small'
);
}
// Dramatic reveal with anticipation
function revealElement(element) {
const { scale, offsetY } = tokens.anticipation.dramatic.$value;
return gsap.timeline()
// Start hidden
.set(element, { opacity: 0, scale: 0.5, y: 50 })
// Anticipation - pull back
.to(element, {
opacity: 0.7,
scale: scale,
y: 50 - parseInt(offsetY),
duration: 0.2,
ease: 'power1.out'
})
// Main reveal - burst forward
.to(element, {
opacity: 1,
scale: 1.1,
y: -20,
duration: 0.3,
ease: 'back.out(1.7)'
})
// Settle
.to(element, {
scale: 1,
y: 0,
duration: 0.2,
ease: 'power2.out'
});
}
// Jump animation with crouch anticipation
function jumpAnimation(element, height = 100) {
return gsap.timeline()
// Crouch (anticipation)
.to(element, {
scaleY: 0.8,
scaleX: 1.1,
y: 10,
duration: 0.15,
ease: 'power2.out'
})
// Jump up (main action)
.to(element, {
scaleY: 1.2,
scaleX: 0.9,
y: -height,
duration: 0.25,
ease: 'power2.out'
})
// Fall down
.to(element, {
y: 0,
duration: 0.2,
ease: 'power2.in'
})
// Land squash
.to(element, {
scaleY: 0.85,
scaleX: 1.1,
duration: 0.1,
ease: 'power3.out'
})
// Recover
.to(element, {
scaleY: 1,
scaleX: 1,
duration: 0.15,
ease: 'elastic.out(1, 0.5)'
});
}Framer Motion
import { motion, useAnimation } from 'framer-motion';
import tokens from '../tokens/anticipation.tokens.json';
// Anticipation variants
const anticipationVariants = {
initial: { scale: 1, y: 0 },
anticipate: (intensity: string = 'small') => {
const { scale, offsetY } = tokens.anticipation[intensity].$value;
return {
scale: scale,
y: parseInt(offsetY),
transition: { duration: 0.08, ease: 'easeOut' }
};
},
action: {
scale: 1.05,
y: 0,
transition: {
type: 'spring',
stiffness: 400,
damping: 15
}
},
rest: {
scale: 1,
y: 0,
transition: { duration: 0.15 }
}
};
export const AnticipatedButton: React.FC<{ children: React.ReactNode }> = ({
children
}) => {
const controls = useAnimation();
const handlePress = async () => {
await controls.start('anticipate');
await controls.start('action');
await controls.start('rest');
};
return (
<motion.button
variants={anticipationVariants}
animate={controls}
onTapStart={handlePress}
custom="small"
>
{children}
</motion.button>
);
};
// Pop-in with anticipation
const popInVariants = {
hidden: {
scale: 0,
opacity: 0
},
anticipate: {
scale: 0.85,
opacity: 0.8,
transition: { duration: 0.1 }
},
visible: {
scale: [0.85, 1.1, 1],
opacity: 1,
transition: {
scale: {
times: [0, 0.6, 1],
duration: 0.3,
ease: 'easeOut'
}
}
}
};
export const PopInElement: React.FC<{ children: React.ReactNode }> = ({
children
}) => (
<motion.div
variants={popInVariants}
initial="hidden"
animate={['anticipate', 'visible']}
>
{children}
</motion.div>
);Remotion
import { useCurrentFrame, interpolate, spring } from 'remotion';
import tokens from '../tokens/anticipation.tokens.json';
interface AnticipationProps {
actionFrame: number;
anticipationFrames?: number;
intensity: 'micro' | 'small' | 'medium' | 'dramatic';
children: React.ReactNode;
}
export const WithAnticipation: React.FC<AnticipationProps> = ({
actionFrame,
anticipationFrames = 6,
intensity = 'small',
children
}) => {
const frame = useCurrentFrame();
const { scale: targetScale, offsetY } = tokens.anticipation[intensity].$value;
const offset = parseInt(offsetY);
const anticipationStart = actionFrame - anticipationFrames;
// Anticipation phase: ease into wind-up position
const anticipationProgress = interpolate(
frame,
[anticipationStart, actionFrame - 1],
[0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
// Main action phase: spring back
const actionProgress = spring({
frame: frame - actionFrame,
fps: 30,
config: { damping: 12, stiffness: 200, mass: 1 }
});
// Calculate current values
let scale: number;
let y: number;
if (frame < actionFrame) {
// During anticipation
scale = interpolate(anticipationProgress, [0, 0.7, 1], [1, targetScale, targetScale]);
y = interpolate(anticipationProgress, [0, 0.7, 1], [0, offset, offset]);
} else {
// During/after action
scale = interpolate(actionProgress, [0, 1], [targetScale, 1]);
y = interpolate(actionProgress, [0, 1], [offset, 0]);
}
return (
<div style={{
transform: `scale(${scale}) translateY(${y}px)`,
transformOrigin: 'center bottom'
}}>
{children}
</div>
);
};
// Jump anticipation (crouch before jump)
export const JumpAnticipation: React.FC<{
jumpFrame: number;
jumpHeight: number;
children: React.ReactNode;
}> = ({ jumpFrame, jumpHeight, children }) => {
const frame = useCurrentFrame();
const crouchFrames = 5;
const crouchStart = jumpFrame - crouchFrames;
// Crouch phase
const crouchProgress = interpolate(
frame,
[crouchStart, jumpFrame],
[0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
// Jump phase
const jumpDuration = 15; // frames
const jumpProgress = interpolate(
frame,
[jumpFrame, jumpFrame + jumpDuration / 2, jumpFrame + jumpDuration],
[0, 1, 0],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
const scaleY = frame < jumpFrame
? interpolate(crouchProgress, [0, 1], [1, 0.8])
: interpolate(jumpProgress, [0, 0.5, 1], [0.8, 1.15, 1]);
const y = frame < jumpFrame
? interpolate(crouchProgress, [0, 1], [0, 10])
: interpolate(jumpProgress, [0, 0.5, 1], [10, -jumpHeight, 0]);
return (
<div style={{
transform: `scaleY(${scaleY}) scaleX(${1/scaleY}) translateY(${y}px)`,
transformOrigin: 'center bottom'
}}>
{children}
</div>
);
};Brand Attitude Mapping
| Brand | Anticipation Level | Character |
| Luxury | micro | Elegant, restrained |
| Enterprise | micro-small | Professional, efficient |
| Consumer | small-medium | Friendly, clear |
| Gaming | medium-dramatic | Energetic, impactful |
| Kids | dramatic-extreme | Playful, exaggerated |
Accessibility
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// Skip anticipation for reduced motion
const animation = prefersReducedMotion
? { opacity: [0, 1] } // Direct fade
: { /* full anticipation sequence */ };Common Mistakes
- Too long anticipation - Should be 15-25% of total, not 50%
- Wrong direction - Must be opposite to main action
- No settle - Motion feels abrupt without recovery phase
- Overuse - Not every action needs anticipation
- Same intensity everywhere - Match to brand and context
Related Skills
- squash-stretch - Anticipation often includes a slight squash before the main action
- follow-through - The settling phase after main action completes the anticipation cycle
- exaggeration - Determines intensity of the anticipation wind-up
- arc-motion - Anticipation affects the starting trajectory of arc paths
- secondary-action - Supporting elements may have their own micro-anticipations
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
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.

