188 lines
4.8 KiB
TypeScript
188 lines
4.8 KiB
TypeScript
/**
|
|
* 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
|
|
* <script lang="ts">
|
|
* import { createPerspectiveManager } from '$shared/lib/helpers';
|
|
*
|
|
* const perspective = createPerspectiveManager({
|
|
* depthStep: 100,
|
|
* scaleStep: 0.5,
|
|
* blurStep: 4
|
|
* });
|
|
* </script>
|
|
*
|
|
* <div
|
|
* style="transform: scale({perspective.isBack ? 0.5 : 1});
|
|
* filter: blur({perspective.isBack ? 4 : 0}px)"
|
|
* >
|
|
* <button on:click={perspective.toggle}>Toggle View</button>
|
|
* </div>
|
|
* ```
|
|
*/
|
|
|
|
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<PerspectiveConfig>;
|
|
|
|
/**
|
|
* 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);
|
|
}
|