40 lines
2.0 KiB
TypeScript
40 lines
2.0 KiB
TypeScript
|
|
import { keyframes } from '@vanilla-extract/css';
|
||
|
|
|
||
|
|
// Star Drift — a slow, serene PAN of a deep-space starfield with real parallax.
|
||
|
|
//
|
||
|
|
// The starfield in animStars.ts stacks six background layers:
|
||
|
|
// 1. near stars — tile 137x137, brighter, drifts FASTEST
|
||
|
|
// 2. mid stars — tile 191x191, medium
|
||
|
|
// 3. far dust — tile 233x233, dimmest, drifts SLOWEST
|
||
|
|
// 4. center vignette (100% 100%) — STATIC
|
||
|
|
// 5. nebula wash A (100% 100%) — STATIC
|
||
|
|
// 6. nebula wash B (100% 100%) — STATIC
|
||
|
|
//
|
||
|
|
// Seamless parallax: the single `animation` shorthand shares ONE duration across
|
||
|
|
// all layers, so speed differences are produced purely by how FAR each layer
|
||
|
|
// travels in the keyframe. For a perfectly seamless loop each star layer must
|
||
|
|
// translate by an EXACT integer multiple of its own tile period, so the pixel
|
||
|
|
// re-entering at the wrap is identical to the one that left. We move:
|
||
|
|
// near : -274px = 2 x 137 (two tiles -> fastest apparent drift)
|
||
|
|
// mid : -191px = 1 x 191 (one tile -> medium)
|
||
|
|
// far : -233px = 1 x 233 (one tile, but larger tile => slowest apparent)
|
||
|
|
// so near/mid/far read as three depths sliding past each other, yet every layer
|
||
|
|
// lands back on an identical phase at 100% for a jump-free repeat.
|
||
|
|
//
|
||
|
|
// A diagonal component (both x and y shift) makes the drift feel like gentle
|
||
|
|
// motion through space rather than a flat slide. The static layers are pinned at
|
||
|
|
// '0 0' every frame so the vignette and nebula never move under the text.
|
||
|
|
//
|
||
|
|
// The start frame ('0%') MUST match the static backgroundPosition authored in
|
||
|
|
// animStars.ts, so that when getChatBg STRIPS this animation for
|
||
|
|
// prefers-reduced-motion the finished starfield shows without a jump.
|
||
|
|
export const starDrift = keyframes({
|
||
|
|
'0%': {
|
||
|
|
backgroundPosition: '0 0, 61px 43px, 113px 97px, 0 0, 0 0, 0 0',
|
||
|
|
},
|
||
|
|
'100%': {
|
||
|
|
// near: -274/-274 (2 tiles), mid: 61-191/43-191, far: 113-233/97-233
|
||
|
|
backgroundPosition: '-274px -274px, -130px -148px, -120px -136px, 0 0, 0 0, 0 0',
|
||
|
|
},
|
||
|
|
});
|