/** 行业常用缓动曲线(Duolingo / Material / 手游 Modal 规范) */ /** 入场:cubic-bezier(0, 0, 0.2, 1) — 快启慢收 */ export function easeEnter(t: number): number { return cubicBezierY(t, 0, 0, 0.2, 1); } /** 退场:cubic-bezier(0.4, 0, 1, 1) — 快出 */ export function easeExit(t: number): number { return cubicBezierY(t, 0.4, 0, 1, 1); } /** 庆祝 overshoot:cubic-bezier(0.34, 1.56, 0.64, 1) — Duolingo 奖励弹入 */ export function easeCelebrate(t: number): number { return cubicBezierY(t, 0.34, 1.56, 0.64, 1); } /** 标准双向往返:cubic-bezier(0.4, 0, 0.2, 1) */ export function easeStandard(t: number): number { return cubicBezierY(t, 0.4, 0, 0.2, 1); } function cubicBezierY(t: number, x1: number, y1: number, x2: number, y2: number): number { if (t <= 0) return 0; if (t >= 1) return 1; let lo = 0; let hi = 1; for (let i = 0; i < 10; i++) { const mid = (lo + hi) * 0.5; if (bezier(x1, x2, mid) < t) lo = mid; else hi = mid; } const u = (lo + hi) * 0.5; return bezier(y1, y2, u); } function bezier(a: number, b: number, t: number): number { const inv = 1 - t; return 3 * inv * inv * t * a + 3 * inv * t * t * b + t * t * t; }