/** * 3D perspective animation state manager * * Manages smooth transitions between "front" (interactive) and "back" (background) * visual states using Svelte springs. Used for creating depth-based UI effects * like settings panels, modal transitions, and spatial navigation. * * @example * ```svelte * * *
* *
* ``` */ import { Spring } from 'svelte/motion'; /** * Configuration options for perspective effects */ export interface PerspectiveConfig { /** * Z-axis translation per level in pixels */ depthStep?: number; /** * Scale reduction per level (0-1) */ scaleStep?: number; /** * Blur amount per level in pixels */ blurStep?: number; /** * Opacity reduction per level (0-1) */ opacityStep?: number; /** * Parallax movement intensity per level */ parallaxIntensity?: number; /** * Horizontal offset - positive for right, negative for left */ horizontalOffset?: number; /** * Layout mode: 'center' for centered, 'split' for side-by-side */ layoutMode?: 'center' | 'split'; } /** * Manages perspective state with spring-based transitions * * Simplified from a complex camera system to just track back/front state. * The spring value animates between 0 (front) and 1 (back) for smooth * visual transitions of scale, blur, opacity, and position. * * @example * ```ts * const perspective = createPerspectiveManager({ * depthStep: 100, * scaleStep: 0.5, * blurStep: 4 * }); * * // Check state (reactive) * console.log(perspective.isBack); // false * * // Toggle with animation * perspective.toggle(); // Smoothly animates to back position * * // Direct control * perspective.setBack(); // Go to back * perspective.setFront(); // Go to front * ``` */ export class PerspectiveManager { /** * Spring animation state * Animates between 0 (front) and 1 (back) with configurable physics */ spring = new Spring(0, { stiffness: 0.2, damping: 0.8, }); /** * Reactive state: true when in back position * * Content should appear blurred, scaled down, and less interactive * when this is true. Derived from spring value > 0.5. */ isBack = $derived(this.spring.current > 0.5); /** * Reactive state: true when in front position * * Content should be fully visible, sharp, and interactive * when this is true. Derived from spring value < 0.5. */ isFront = $derived(this.spring.current < 0.5); /** * Internal configuration with defaults applied */ private config: Required; /** * Creates a new perspective manager * @param config - Configuration for visual effects */ constructor(config: PerspectiveConfig = {}) { this.config = { depthStep: config.depthStep ?? 100, scaleStep: config.scaleStep ?? 0.5, blurStep: config.blurStep ?? 4, opacityStep: config.opacityStep ?? 0.5, parallaxIntensity: config.parallaxIntensity ?? 0, horizontalOffset: config.horizontalOffset ?? 0, layoutMode: config.layoutMode ?? 'center', }; } /** * Toggle between front and back positions * * Uses spring animation for smooth transition. Toggles based on * current state - if spring < 0.5 goes to 1, otherwise goes to 0. */ toggle = () => { const target = this.spring.current < 0.5 ? 1 : 0; this.spring.target = target; }; /** * Force to back position (blurred, scaled down) */ setBack = () => { this.spring.target = 1; }; /** * Force to front position (fully visible, interactive) */ setFront = () => { this.spring.target = 0; }; /** * Get current configuration * @internal Used by components to compute styles */ getConfig = () => this.config; } /** * Factory function to create a perspective manager * * @param config - Configuration options for visual effects * @returns Configured PerspectiveManager instance * * @example * ```ts * const perspective = createPerspectiveManager({ * scaleStep: 0.6, * blurStep: 8, * layoutMode: 'split' * }); * ``` */ export function createPerspectiveManager(config: PerspectiveConfig = {}) { return new PerspectiveManager(config); }