agency-web/app/components/motion.ts

38 lines
1.7 KiB
TypeScript

/**
* Shared motion personality — Emil Kowalski craft methodology.
*
* One cohesive easing/spring vocabulary used across the whole page so every
* interaction feels like it belongs to the same product. Springs (not raw
* mouse-tracking) drive ALL decorative/pointer motion so it has momentum and
* feels alive; bezier curves drive everything choreographed.
*/
import type { Transition } from "motion/react";
/* Custom bezier curves (mirror globals.css tokens). */
export const EASE_OUT = [0.23, 1, 0.32, 1] as const; // entrances / settle
export const EASE_IN_OUT = [0.77, 0, 0.175, 1] as const; // on-screen movement
export const EASE_DRAWER = [0.32, 0.72, 0, 1] as const; // panels / accordions
/* Springs — soft & momentum-rich so motion has life, never mechanical. */
export const SPRING = {
/* magnetic buttons / pointer pull — loose, lively, slight overshoot */
magnetic: { stiffness: 150, damping: 13, mass: 0.7 } satisfies Transition,
/* 3D card tilt — heavier so it floats and settles, never snaps */
tilt: { stiffness: 110, damping: 14, mass: 0.9 } satisfies Transition,
/* cursor ring — trails the pointer with visible lag (the "alive" feel) */
cursorRing: { stiffness: 220, damping: 24, mass: 0.7 } satisfies Transition,
/* cursor dot — tighter so it leads, ring chases it */
cursorDot: { stiffness: 600, damping: 34, mass: 0.5 } satisfies Transition,
/* generic decorative drift */
soft: { stiffness: 120, damping: 18, mass: 0.8 } satisfies Transition,
} as const;
/* Asymmetric enter/exit: deliberate in (ease-out), snappy out. */
export const ENTER = (duration = 0.9): Transition => ({
duration,
ease: EASE_OUT,
});
export const EXIT = (duration = 0.22): Transition => ({
duration,
ease: EASE_OUT,
});