arc-motion
Skill7 starsChanged 10 months agoMITView on GitHub
Natural arc motion paths following gravity and momentum. Disney's principle that organic motion follows curved trajectories. Use for object movement, drag-release, toss gestures, and any physics-affected animation.
In this repository87 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- motion-designSkill
- 3d-transformsSkill
- accessibilitySkill
- android-nativeSkill
- animation-recipesSkill
- anticipationSkill
- 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
Files
Arc Motion Paths
Living things and physical objects move in arcs, not straight lines. Gravity, momentum, and inertia create curved trajectories that feel natural.
Core Principle
Objects in motion follow parabolic arcs due to gravity and momentum.
Linear Motion: A ------------------> B (robotic, mechanical)
Arc Motion: A ~~~~~~~~~~~~~~~> B (natural, organic)
^
apex of arcToken Reference
Load from: tokens/motion-path.tokens.json
| Token | Path | Use Case |
arc-subtle | M0,0 Q25,10 50,0 | Small movements, icons |
arc-medium | M0,0 Q50,30 100,0 | Standard travel, cards |
arc-large | M0,0 Q75,50 150,0 | Dramatic motion, hero |
arc-throw | M0,0 Q100,80 200,20 | Toss, dismiss gestures |
arc-drop | M0,0 Q10,50 50,100 | Gravity drop |
arc-rise | M0,100 Q40,50 50,0 | Upward against gravity |
When to Use Arcs vs Linear
Use Arc Motion For:
- Physical objects - Cards, images, icons moving through space
- Drag-and-drop release - Object thrown by user
- Dismiss gestures - Swipe-away, toss-to-delete
- Gravity-affected motion - Drops, rises, bounces
- Organic/character animation - Limbs, eyes, living things
Use Linear Motion For:
- UI feedback - Progress bars, loading indicators
- State changes - Toggle switches, checkboxes
- Direct manipulation - While user is actively dragging
- Mechanical/robotic motion - Intentionally artificial
Implementation Presets
CSS offset-path
/* Native CSS Motion Path */
.arc-motion {
offset-path: path('M0,0 Q50,30 100,0');
animation: follow-arc 500ms var(--ease-standard) forwards;
}
@keyframes follow-arc {
from { offset-distance: 0%; }
to { offset-distance: 100%; }
}
/* Throw/dismiss arc */
.toss-dismiss {
offset-path: path('M0,0 Q100,80 200,20');
animation: toss 400ms cubic-bezier(0.2, 0, 0.4, 1) forwards;
}
@keyframes toss {
from {
offset-distance: 0%;
opacity: 1;
}
to {
offset-distance: 100%;
opacity: 0;
}
}GSAP MotionPathPlugin
import { gsap } from 'gsap';
import { MotionPathPlugin } from 'gsap/MotionPathPlugin';
import tokens from '../tokens/motion-path.tokens.json';
gsap.registerPlugin(MotionPathPlugin);
// Basic arc motion
gsap.to('.element', {
motionPath: {
path: tokens['motion-path']['arc-medium'].$value,
align: 'self',
alignOrigin: [0.5, 0.5]
},
duration: 0.5,
ease: 'power2.inOut'
});
// Throw gesture with physics
function throwElement(element, velocity, angle) {
const radians = angle * (Math.PI / 180);
const distance = velocity * 0.5; // Simplified physics
// Calculate parabolic path points
const endX = Math.cos(radians) * distance;
const endY = Math.sin(radians) * distance + 100; // Gravity pulls down
const apexX = endX * 0.4;
const apexY = Math.min(Math.sin(radians) * distance * 0.6, -50); // Arc peak
const path = `M0,0 Q${apexX},${apexY} ${endX},${endY}`;
return gsap.to(element, {
motionPath: { path, align: 'self' },
duration: 0.6,
ease: 'power1.out',
opacity: 0
});
}
// Gravity drop
function dropWithGravity(element, height = 200) {
return gsap.to(element, {
motionPath: {
path: `M0,0 Q10,${height * 0.5} 50,${height}`,
align: 'self'
},
duration: 0.4,
ease: 'power2.in' // Accelerating (gravity)
});
}Framer Motion
import { motion, useAnimation } from 'framer-motion';
// Arc motion using keyframes
const arcVariants = {
initial: { x: 0, y: 0 },
arcMove: {
x: [0, 25, 50, 75, 100],
y: [0, -15, -30, -15, 0], // Parabolic y values
transition: {
duration: 0.5,
ease: 'easeInOut',
times: [0, 0.25, 0.5, 0.75, 1]
}
},
throwAway: {
x: [0, 50, 100, 150, 200],
y: [0, -40, -60, -40, 20],
opacity: [1, 1, 1, 0.5, 0],
transition: {
duration: 0.4,
ease: [0.2, 0, 0.4, 1]
}
}
};
export const ArcMotionElement = () => (
<motion.div
variants={arcVariants}
initial="initial"
animate="arcMove"
/>
);
// Physics-based arc with useSpring
import { useSpring, animated } from '@react-spring/web';
export const PhysicsArc = ({ isThrown }) => {
const props = useSpring({
x: isThrown ? 200 : 0,
y: isThrown ? 50 : 0,
config: { tension: 200, friction: 20, mass: 1 }
});
// Add gravity effect to y
const gravityY = useSpring({
y: isThrown ? 100 : 0,
config: { tension: 100, friction: 10 }
});
return (
<animated.div
style={{
x: props.x,
y: props.y.to((y) => y + gravityY.y.get())
}}
/>
);
};Remotion
import { useCurrentFrame, interpolate } from 'remotion';
import tokens from '../tokens/motion-path.tokens.json';
interface ArcMotionProps {
startFrame: number;
endFrame: number;
start: { x: number; y: number };
end: { x: number; y: number };
arcHeight?: number;
children: React.ReactNode;
}
export const ArcMotion: React.FC<ArcMotionProps> = ({
startFrame,
endFrame,
start,
end,
arcHeight = 50,
children
}) => {
const frame = useCurrentFrame();
const progress = interpolate(
frame,
[startFrame, endFrame],
[0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
// Linear interpolation for X (horizontal motion)
const x = interpolate(progress, [0, 1], [start.x, end.x]);
// Parabolic arc for Y (gravity simulation)
// y = start.y + (end.y - start.y) * progress - arcHeight * sin(progress * PI)
const linearY = start.y + (end.y - start.y) * progress;
const arcOffset = arcHeight * Math.sin(progress * Math.PI);
const y = linearY - arcOffset; // Subtract because negative Y is up
return (
<div style={{ transform: `translate(${x}px, ${y}px)` }}>
{children}
</div>
);
};
// Gravity-affected drop with acceleration
export const GravityDrop: React.FC<{
startFrame: number;
dropHeight: number;
children: React.ReactNode;
}> = ({ startFrame, dropHeight, children }) => {
const frame = useCurrentFrame();
const gravity = tokens['gravity-simulation']['earth-gravity'].$value.acceleration;
// Use accelerating easing to simulate gravity
const progress = interpolate(
frame,
[startFrame, startFrame + 20], // ~0.67s at 30fps
[0, 1],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
// Quadratic easing (acceleration) for gravity
const easedProgress = progress * progress;
const y = easedProgress * dropHeight;
return (
<div style={{ transform: `translateY(${y}px)` }}>
{children}
</div>
);
};
// Throw with velocity and angle
export const ThrowMotion: React.FC<{
startFrame: number;
velocity: number;
angle: number; // degrees
children: React.ReactNode;
}> = ({ startFrame, velocity, angle, children }) => {
const frame = useCurrentFrame();
const radians = (angle * Math.PI) / 180;
const gravity = 980; // pixels/s^2
const fps = 30;
const t = (frame - startFrame) / fps; // time in seconds
if (t < 0) {
return <div>{children}</div>;
}
// Projectile motion equations
const vx = velocity * Math.cos(radians);
const vy = velocity * Math.sin(radians);
const x = vx * t;
const y = vy * t + 0.5 * gravity * t * t; // gravity pulls down
return (
<div style={{ transform: `translate(${x}px, ${y}px)` }}>
{children}
</div>
);
};Physics Reference
Parabolic Arc Formula
x(t) = x0 + vx * t
y(t) = y0 + vy * t + 0.5 * g * t^2
Where:
- x0, y0 = starting position
- vx, vy = initial velocity components
- g = gravity (9.8 m/s^2 or ~980 px/s^2)
- t = timeSimplified Quadratic Bezier
For a simple arc from (0,0) to (100,0) with height h:
Control point: (50, -h)
Path: M0,0 Q50,-h 100,0Accessibility
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// Reduced motion: use linear fade instead of arc
const animation = prefersReducedMotion
? { opacity: [1, 0], x: [0, 100] }
: { /* full arc path */ };Common Mistakes
- Linear for physical objects - Real objects don't move in straight lines
- Arc for UI state changes - Toggles and checkmarks should be linear
- Wrong arc direction - Upward motion should fight gravity (decelerate at top)
- Ignoring momentum - Objects continue moving after release
- Same arc for all sizes - Larger distances need larger arcs
Related Skills
- anticipation - Anticipation affects the starting trajectory of arc paths
- follow-through - Objects continue along arc trajectory after primary action
- squash-stretch - Objects stretch along their arc trajectory direction
- exaggeration - Exaggeration affects arc height and trajectory drama
- secondary-action - Secondary elements may follow their own arc trajectories
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.

