diff --git a/web/src/lib/components/welcome/WelcomeCard.svelte b/web/src/lib/components/welcome/WelcomeCard.svelte index 6b30d51d1..5f5234372 100644 --- a/web/src/lib/components/welcome/WelcomeCard.svelte +++ b/web/src/lib/components/welcome/WelcomeCard.svelte @@ -27,7 +27,12 @@ import ArrowRight from "$icon/arrow-right"; import Check from "$icon/check"; import Button from "$lib/components/ui/Button.svelte"; - import { EXIT_DURATION, PANE_DURATION, PANE_EASING, paneEasing } from "$lib/motion/spring"; + import { + CROSSFADE_DURATION, + CROSSFADE_EASING, + crossfadeEasing, + EXIT_DURATION + } from "$lib/motion/spring"; import Steps from "./Steps.svelte"; import { LAST_STEP, WELCOME_STEPS, WELCOME_TOTAL } from "./steps"; @@ -64,8 +69,8 @@ const DISTANCE = 22; const enter = $derived( prefersReducedMotion.current - ? { duration: PANE_DURATION, easing: paneEasing } - : { x: direction * DISTANCE, duration: PANE_DURATION, easing: paneEasing } + ? { duration: CROSSFADE_DURATION, easing: crossfadeEasing } + : { x: direction * DISTANCE, duration: CROSSFADE_DURATION, easing: crossfadeEasing } ); const leave = $derived( prefersReducedMotion.current @@ -77,7 +82,9 @@ `Step ${index + 1} of ${WELCOME_TOTAL}: ${WELCOME_STEPS[index].label}`; const mobileLabelTransition = $derived( - prefersReducedMotion.current ? "" : `transition: opacity ${PANE_DURATION}ms ${PANE_EASING};` + prefersReducedMotion.current + ? "" + : `transition: opacity ${CROSSFADE_DURATION}ms ${CROSSFADE_EASING};` ); let height = $state(null); @@ -89,7 +96,7 @@ const heightTransition = $derived( mounted && !prefersReducedMotion.current - ? `transition: height ${PANE_DURATION}ms ${PANE_EASING};` + ? `transition: height ${CROSSFADE_DURATION}ms ${CROSSFADE_EASING};` : "" ); diff --git a/web/src/lib/motion/spring.ts b/web/src/lib/motion/spring.ts index b9be190f2..62cc7b098 100644 --- a/web/src/lib/motion/spring.ts +++ b/web/src/lib/motion/spring.ts @@ -38,12 +38,13 @@ export const RAIL_DURATION = 400; export const railEasing = springEasing(520, 40, 0.5, RAIL_DURATION); export const RAIL_EASING = cssLinear(railEasing); -/** step panes and the card height that follows them. interior's crossfade spring - (260/34/0.8) settles in 659ms, so it is rescaled at a constant zeta to land - inside the 300ms budget without changing its shape. */ -export const PANE_DURATION = 280; -export const paneEasing = springEasing(1438, 80, 0.8, PANE_DURATION); -export const PANE_EASING = cssLinear(paneEasing); +/** interior's crossfade spring (260/34/0.8) — step panes, the card height that + follows them, and anything swapping one face for another. it settles in + 659ms, so it is rescaled at a constant zeta to land inside the 300ms budget + without changing its shape. */ +export const CROSSFADE_DURATION = 280; +export const crossfadeEasing = springEasing(1438, 80, 0.8, CROSSFADE_DURATION); +export const CROSSFADE_EASING = cssLinear(crossfadeEasing); /** the tick/cross arriving in a step's status cell — interior.dev's POP */ export const POP_DURATION = 300; @@ -53,3 +54,7 @@ export const POP_EASING = cssLinear(popEasing, 40); /** leaving is shorter and closer in, matching ui/Modal */ export const EXIT_DURATION = 140; export const EXIT_EASING = "cubic-bezier(0.4, 0, 1, 1)"; + +/** a stroke drawing itself on, interior's DRAW */ +export const DRAW_DURATION = 260; +export const DRAW_EASING = "cubic-bezier(0.23, 1, 0.32, 1)";