Add live show player playback and effects
This commit is contained in:
107
resources/js/guest/lib/liveShowEffects.ts
Normal file
107
resources/js/guest/lib/liveShowEffects.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
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),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user