/** * [INPUT]: 无运行时依赖(纯数据:Framer Motion 的 Apple 级 spring 配置与 variant 预设) * [OUTPUT]: 对外提供 SPRING 预设、APPLE_EASE* 曲线、VIEWPORT,及 variant: * fadeInUp / scaleIn / staggerContainer / staggerItem / slideInLeft / slideInRight / * hoverLift / tapScale / modalOverlay / modalContent / pageTransition * [POS]: lib 的动效契约层(单一真相源),被 components/landing/*、pages/*、App 路由过渡共用 * [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md */ // ─────────────────────────────────────────────────────────────────────────── // Apple 风格 spring 预设:弹簧起势 + 阻尼落定 + 质量惯性(禁 linear、禁无阻尼弹跳) // ─────────────────────────────────────────────────────────────────────────── export const SPRING = { snappy: { type: 'spring', stiffness: 400, damping: 30 }, // 微交互(按钮/卡片 hover)~200ms gentle: { type: 'spring', stiffness: 300, damping: 35 }, // 柔和过渡(面板/模态)~350ms bouncy: { type: 'spring', stiffness: 500, damping: 25, mass: 0.8 }, // 弹性强调(成功反馈)~300ms smooth: { type: 'spring', stiffness: 200, damping: 40, mass: 1.2 }, // 优雅落定(页面/大元素)~500ms inertia: { type: 'spring', stiffness: 150, damping: 20, mass: 0.5 }, // 惯性滑动(列表/轮播) } // 非 spring 场景的 Apple 缓动曲线(退场、透明度等) export const APPLE_EASE = [0.25, 0.1, 0.25, 1.0] // iOS 标准 export const APPLE_EASE_OUT = [0.22, 1, 0.36, 1] // iOS 弹出 export const APPLE_DECELERATE = [0, 0, 0.2, 1] // iOS 减速 // whileInView 触发:进入视口一次、提前 100px 预触发 export const VIEWPORT = { once: true, margin: '-100px' } // ─────────────────────────────────────────────────────────────────────────── // 进场 variant(spring 物理,自然起势 + 阻尼落定) // ─────────────────────────────────────────────────────────────────────────── export const fadeInUp = { hidden: { opacity: 0, y: 24 }, visible: { opacity: 1, y: 0, transition: SPRING.gentle }, } export const scaleIn = { hidden: { opacity: 0, scale: 0.9 }, visible: { opacity: 1, scale: 1, transition: { type: 'spring', stiffness: 400, damping: 25 } }, } export const staggerContainer = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.06, delayChildren: 0.1 } }, } export const staggerItem = { hidden: { opacity: 0, y: 20 }, visible: { opacity: 1, y: 0, transition: { type: 'spring', stiffness: 350, damping: 30 } }, } export const slideInLeft = { hidden: { opacity: 0, x: -30 }, visible: { opacity: 1, x: 0, transition: SPRING.gentle }, } export const slideInRight = { hidden: { opacity: 0, x: 30 }, visible: { opacity: 1, x: 0, transition: SPRING.gentle }, } // ─────────────────────────────────────────────────────────────────────────── // 交互 variant(hover / tap)——只动 transform,阴影交给 index.css 微拟物体系 // ─────────────────────────────────────────────────────────────────────────── export const hoverLift = { rest: { scale: 1, y: 0 }, hover: { scale: 1.02, y: -4, transition: SPRING.snappy }, } export const tapScale = { rest: { scale: 1 }, pressed: { scale: 0.96, transition: { type: 'spring', stiffness: 500, damping: 30 } }, } // ─────────────────────────────────────────────────────────────────────────── // 模态 / 路由(进场 spring,退场短 duration) // ─────────────────────────────────────────────────────────────────────────── export const modalOverlay = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { duration: 0.2 } }, exit: { opacity: 0, transition: { duration: 0.15 } }, } export const modalContent = { hidden: { opacity: 0, scale: 0.95, y: 20 }, visible: { opacity: 1, scale: 1, y: 0, transition: SPRING.gentle }, exit: { opacity: 0, scale: 0.95, transition: { duration: 0.15 } }, } // 页面路由过渡:用 y 位移(避免整页 x 横移触发水平滚动条 / 破坏 sticky 页头) export const pageTransition = { initial: { opacity: 0, y: 12 }, animate: { opacity: 1, y: 0, transition: { type: 'spring', stiffness: 260, damping: 40 } }, exit: { opacity: 0, y: -8, transition: { duration: 0.2, ease: APPLE_EASE } }, }