feat(createPerspectiveManager): create perspective manager to work with perspective, moving objects along the z axis

This commit is contained in:
Ilia Mashkov
2026-02-15 23:02:49 +03:00
parent 9e74a2c2c6
commit 4fdc99a15a

View File

@@ -0,0 +1,130 @@
import { Spring } from 'svelte/motion';
export interface PerspectiveConfig {
/**
* How many px to move back per level
*/
depthStep?: number;
/**
* Scale reduction per level
*/
scaleStep?: number;
/**
* Blur amount per level
*/
blurStep?: number;
/**
* Opacity reduction per level
*/
opacityStep?: number;
/**
* Parallax intensity per level
*/
parallaxIntensity?: number;
/**
* Horizontal offset for each plan (x-axis positioning)
* Positive = right, Negative = left
*/
horizontalOffset?: number;
/**
* Layout mode: 'center' (default) or 'split' for Swiss-style side-by-side
*/
layoutMode?: 'center' | 'split';
}
/**
* Manages perspective state with a simple boolean flag.
*
* Drastically simplified from the complex camera/index system.
* Just manages whether content is in "back" or "front" state.
*
* @example
* ```typescript
* const perspective = createPerspectiveManager({
* depthStep: 100,
* scaleStep: 0.5,
* blurStep: 4,
* });
*
* // Toggle back/front
* perspective.toggle();
*
* // Check state
* const isBack = perspective.isBack; // reactive boolean
* ```
*/
export class PerspectiveManager {
/**
* Spring for smooth back/front transitions
*/
spring = new Spring(0, {
stiffness: 0.2,
damping: 0.8,
});
/**
* Reactive boolean: true when in back position (blurred, scaled down)
*/
isBack = $derived(this.spring.current > 0.5);
/**
* Reactive boolean: true when in front position (fully visible, interactive)
*/
isFront = $derived(this.spring.current < 0.5);
/**
* Configuration values for style computation
*/
private config: Required<PerspectiveConfig>;
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 (0) and back (1) positions.
* Smooth spring animation handles the transition.
*/
toggle = () => {
const target = this.spring.current < 0.5 ? 1 : 0;
this.spring.target = target;
};
/**
* Force to back position
*/
setBack = () => {
this.spring.target = 1;
};
/**
* Force to front position
*/
setFront = () => {
this.spring.target = 0;
};
/**
* Get configuration for style computation
* @internal
*/
getConfig = () => this.config;
}
/**
* Factory function to create a PerspectiveManager instance.
*
* @param config - Configuration options
* @returns Configured PerspectiveManager instance
*/
export function createPerspectiveManager(config: PerspectiveConfig = {}) {
return new PerspectiveManager(config);
}