import { keyframes } from '@vanilla-extract/css'; /** * Autumn overlay keyframes. Every animation touches ONLY `transform` and * `opacity` so the compositor can run them on the GPU without triggering * layout or paint. keyframes() returns the generated animation-name string, * which is applied inline in Autumn.tsx. * * Motion philosophy: warm, slow, cozy. Leaves tumble and rotate as they fall * with a per-leaf sway decoupled on a wrapper; sun shafts breathe; dust motes * drift up through the light; the whole frame has a barely-there warm pulse. */ /** * A leaf falls from above to below the viewport while continuously rotating. * A single tall translateY serves every leaf — per-leaf duration/delay/scale * create the parallax variety. Horizontal travel is intentionally small here * because the real lateral motion comes from the sway wrapper below. */ export const animLeafFall = keyframes({ '0%': { transform: 'translate3d(0, -12vh, 0) rotate(-30deg)', opacity: '0' }, '8%': { opacity: '1' }, '50%': { transform: 'translate3d(10px, 50vh, 0) rotate(200deg)' }, '92%': { opacity: '0.85' }, '100%': { transform: 'translate3d(-6px, 114vh, 0) rotate(430deg)', opacity: '0' }, }); /** * Lateral sway applied to a leaf's wrapper so the descent reads as wind * catching the blade. Decoupled from the fall so the two compose into an * organic, non-repeating-looking path. */ export const animLeafSway = keyframes({ '0%': { transform: 'translate3d(0, 0, 0)' }, '50%': { transform: 'translate3d(34px, 0, 0)' }, '100%': { transform: 'translate3d(0, 0, 0)' }, }); /** * A second flutter on the leaf's inner shape: a gentle skew/scale wobble that * mimics the blade catching air as it spins. Cheap, transform-only. */ export const animLeafFlutter = keyframes({ '0%': { transform: 'rotate(-8deg) scaleX(1)' }, '50%': { transform: 'rotate(8deg) scaleX(0.82)' }, '100%': { transform: 'rotate(-8deg) scaleX(1)' }, }); /** * Low-sun light shaft: a long soft beam slowly slides and breathes. Uses * translateX + opacity (never background-position) so it stays on the * compositor. Scale on Y makes the beam subtly elongate as it brightens. */ export const animSunShaft = keyframes({ '0%': { transform: 'translate3d(-4%, 0, 0) scaleY(1)', opacity: '0.4' }, '50%': { transform: 'translate3d(4%, 0, 0) scaleY(1.06)', opacity: '0.75' }, '100%': { transform: 'translate3d(-4%, 0, 0) scaleY(1)', opacity: '0.4' }, }); /** * Dust / pollen mote: a tiny speck drifts upward through the light, swaying, * pulsing softly in brightness as it catches the sun. transform + opacity. */ export const animMoteDrift = keyframes({ '0%': { transform: 'translate3d(0, 0, 0) scale(0.7)', opacity: '0' }, '15%': { opacity: '0.85' }, '40%': { transform: 'translate3d(16px, -30vh, 0) scale(1)' }, '70%': { transform: 'translate3d(-12px, -58vh, 0) scale(0.85)', opacity: '0.6' }, '90%': { opacity: '0.2' }, '100%': { transform: 'translate3d(10px, -84vh, 0) scale(0.6)', opacity: '0' }, }); /** * Independent twinkle for motes — a brightness flicker layered on the drift so * specks shimmer as if turning in the light. Opacity only. */ export const animMoteTwinkle = keyframes({ '0%': { opacity: '0.5' }, '50%': { opacity: '1' }, '100%': { opacity: '0.5' }, }); /** * Barely-there breathing of the warm vignette frame so the static tint feels * alive without any distracting motion. Opacity only. */ export const animEmberPulse = keyframes({ '0%': { opacity: '0.82' }, '50%': { opacity: '1' }, '100%': { opacity: '0.82' }, });