02b2ce8109
Same treatment as the seasonal themes: split the 502-line chatBackground.ts Record into one premium module per background under lotus/backgrounds/ (each exposes a tuned dark + light ChatBgVariants), one Opus agent per background against a shared brief. chatBackground.ts now assembles DARK/LIGHT from the modules; getChatBg is unchanged. Carbon + Aurora are kept inline as-is (user favorites); none stays the empty layer. Every redesign: layered oklch palettes, seamless tiling with worked-out tile math (integer-multiple periods; edge-wrapping inline-SVG data-URIs for circuit/hexgrid/waves/herringbone/chevron/tactical), independently-tuned dark+light (not a recolor), and low "felt-not-read" opacity so chat text stays WCAG-AA legible. The 5 animated backgrounds (rain, star drift, grid pulse, aurora flow, fireflies) each colocate a vanilla-extract keyframe .css.ts, animate only background-position for a jump-free loop, and — since getChatBg strips animation for reduced-motion — render a finished static frame too. Redesigned: blueprint, stars, topographic, herringbone, crosshatch, chevron, polka, triangles, plaid, tactical, circuit, hexgrid, waves, neon, anim-rain, anim-stars, anim-pulse, anim-aurora, anim-fireflies. Gates: tsc clean, ESLint clean, Prettier clean, build OK, 551 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
46 lines
2.4 KiB
TypeScript
46 lines
2.4 KiB
TypeScript
import { keyframes } from '@vanilla-extract/css';
|
|
|
|
// Fireflies — a slow, gentle PAN of sparse glowing motes across a warm summer
|
|
// dusk. The scene in animFireflies.ts stacks these background layers:
|
|
// 1. large bright motes — tile 227x227, brightest core+halo, drifts FASTEST
|
|
// 2. medium motes — tile 293x293, dimmer, medium drift
|
|
// 3. tiny far sparks — tile 179x179, faintest, drifts SLOWEST (small step)
|
|
// 4. center vignette (100% 100%) — STATIC
|
|
// 5. warm dusk wash A (100% 100%) — STATIC
|
|
// 6. warm dusk wash B (100% 100%) — STATIC
|
|
//
|
|
// Seamless drift: the single `animation` shorthand shares ONE duration across all
|
|
// layers, so the differing apparent speeds come purely from how FAR each layer
|
|
// travels. For a jump-free loop every mote layer must translate by an EXACT
|
|
// integer multiple of its own tile period in BOTH axes, so the mote re-entering
|
|
// at the wrap is identical to the one that left. Each layer moves exactly one
|
|
// full tile:
|
|
// large : -227 / -227 (1 x 227)
|
|
// medium: -293 / -293 (1 x 293) — bigger tile, same 1-tile move => SLOWER look
|
|
// far : -179 / -179 (1 x 179) — smallest tile, damped by low opacity so it
|
|
// reads as the calm distant layer
|
|
// Because tile sizes differ, one shared 1-tile translation yields three distinct
|
|
// apparent speeds — the wandering-firefly parallax — while every layer lands back
|
|
// on an identical phase at 100% for a perfectly seamless repeat.
|
|
//
|
|
// The diagonal component (both x and y shift) makes motes feel like they wander
|
|
// through the meadow rather than slide flatly. The three static layers (vignette
|
|
// and the two dusk washes) are pinned at '0 0' every frame so the warm ambient
|
|
// glow and the calm reading center never move under the text.
|
|
//
|
|
// The '0%' frame MUST match the static backgroundPosition authored in
|
|
// animFireflies.ts, so when getChatBg STRIPS this animation for
|
|
// prefers-reduced-motion the finished scene of glowing motes shows without a jump.
|
|
export const firefliesDrift = keyframes({
|
|
'0%': {
|
|
// large, medium, far, vignette, wash A, wash B
|
|
backgroundPosition: '0 0, 83px 47px, 131px 101px, 0 0, 0 0, 0 0',
|
|
},
|
|
'100%': {
|
|
// large: 0-227 / 0-227
|
|
// medium: 83-293 / 47-293
|
|
// far: 131-179 / 101-179
|
|
backgroundPosition: '-227px -227px, -210px -246px, -48px -78px, 0 0, 0 0, 0 0',
|
|
},
|
|
});
|