import type { MotionProps, Transition } from 'framer-motion'; import { IOS_EASE, IOS_EASE_SOFT } from './motion'; import type { LiveShowEffectPreset } from '../services/liveShowApi'; export type LiveShowEffectSpec = { frame: MotionProps; flash?: MotionProps; }; function clamp(value: number, min: number, max: number): number { return Math.min(max, Math.max(min, value)); } function resolveIntensity(intensity: number): number { const safe = Number.isFinite(intensity) ? intensity : 70; return clamp(safe / 100, 0, 1); } function buildTransition(duration: number, ease: Transition['ease']): Transition { return { duration, ease, }; } export function resolveLiveShowEffect( preset: LiveShowEffectPreset, intensity: number, reducedMotion: boolean ): LiveShowEffectSpec { const strength = reducedMotion ? 0 : resolveIntensity(intensity); const baseDuration = reducedMotion ? 0.2 : clamp(0.9 - strength * 0.35, 0.45, 1); const exitDuration = reducedMotion ? 0.15 : clamp(baseDuration * 0.6, 0.25, 0.6); if (reducedMotion) { return { frame: { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0, transition: buildTransition(exitDuration, IOS_EASE_SOFT) }, transition: buildTransition(baseDuration, IOS_EASE_SOFT), }, }; } switch (preset) { case 'shutter_flash': { const scale = 1 + strength * 0.05; return { frame: { initial: { opacity: 0, scale, y: 12 * strength }, animate: { opacity: 1, scale: 1, y: 0 }, exit: { opacity: 0, scale: 0.98, transition: buildTransition(exitDuration, IOS_EASE) }, transition: buildTransition(baseDuration, IOS_EASE), }, flash: { initial: { opacity: 0 }, animate: { opacity: [0, 0.85, 0], transition: { duration: 0.5, times: [0, 0.2, 1] } }, }, }; } case 'polaroid_toss': { const rotation = 3 + strength * 5; return { frame: { initial: { opacity: 0, rotate: -rotation, scale: 0.9 }, animate: { opacity: 1, rotate: 0, scale: 1 }, exit: { opacity: 0, rotate: rotation * 0.5, scale: 0.98, transition: buildTransition(exitDuration, IOS_EASE) }, transition: buildTransition(baseDuration, IOS_EASE), }, }; } case 'parallax_glide': { const scale = 1 + strength * 0.06; return { frame: { initial: { opacity: 0, scale, y: 24 * strength }, animate: { opacity: 1, scale: 1, y: 0 }, exit: { opacity: 0, scale: 1.02, transition: buildTransition(exitDuration, IOS_EASE_SOFT) }, transition: buildTransition(baseDuration + 0.2, IOS_EASE_SOFT), }, }; } case 'light_effects': { return { frame: { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0, transition: buildTransition(exitDuration, IOS_EASE_SOFT) }, transition: buildTransition(baseDuration * 0.8, IOS_EASE_SOFT), }, }; } case 'film_cut': default: { const scale = 1 + strength * 0.03; return { frame: { initial: { opacity: 0, scale }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.99, transition: buildTransition(exitDuration, IOS_EASE) }, transition: buildTransition(baseDuration, IOS_EASE), }, }; } } }