/**
* 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);
}