The shared duration tokens had been stretched to slow the pulses down, which also slowed every panel and dock animation and left `motion.ts` out of step with the CSS. Both are back to 200/300 ms, and the pulses use a new `--duration-pulse` (500 ms): a message arriving is a signal, not a state change, and it is the only thing here that should linger. The edge pulse read its own 300 ms constant, so it now takes the token through `motion.ts` and the two sides cannot drift again. The code editor also expands: the same node panel fills the content region beside the sidebar, the canvas chrome steps aside rather than floating on top, and the settings above the editor keep a readable width.
77 lines
2.8 KiB
TypeScript
77 lines
2.8 KiB
TypeScript
/**
|
|
* Shared motion presets (Fluksio design system).
|
|
*
|
|
* Pure data: variants and transitions consumed by `motion/react` components
|
|
* across the app. Mirrors the `--ease-*` / `--duration-*` timing tokens defined
|
|
* in `index.css`, so CSS transitions and JS animations stay in sync.
|
|
*
|
|
* This file is duplicated verbatim in `app` and `index` (the shadcn model,
|
|
* see ../../DESIGN.md / the root DESIGN-GUIDELINES.md). Keep the two copies
|
|
* identical; `make design-check` at the workspace root verifies it.
|
|
*
|
|
* Reduced motion: wrap each app root in `<MotionConfig reducedMotion="user">` so
|
|
* transform/layout animations are disabled automatically when the OS requests it.
|
|
*/
|
|
import type { Transition, Variants } from "motion/react"
|
|
|
|
/** Easing curves, mirroring the `--ease-*` tokens. */
|
|
export const easeEmphasized: [number, number, number, number] = [0.2, 0, 0, 1]
|
|
export const easeStandard: [number, number, number, number] = [0.4, 0, 0.2, 1]
|
|
|
|
/** Durations in seconds, mirroring the `--duration-*` tokens (ms). */
|
|
export const duration = {
|
|
fast: 0.15,
|
|
base: 0.2,
|
|
slow: 0.3,
|
|
/** One-shot feedback, not a state change. See `--duration-pulse`. */
|
|
pulse: 0.5,
|
|
} as const
|
|
|
|
export const transitions = {
|
|
/** Enter / expressive moves (decelerate). */
|
|
emphasized: { duration: duration.base, ease: easeEmphasized },
|
|
/** Neutral state changes. */
|
|
standard: { duration: duration.base, ease: easeStandard },
|
|
/** Springy, for hover tilt / direct-manipulation feedback. */
|
|
spring: { type: "spring", stiffness: 250, damping: 20, mass: 0.5 },
|
|
} satisfies Record<string, Transition>
|
|
|
|
const exitFast: Transition = { duration: duration.fast, ease: easeStandard }
|
|
|
|
/** Opacity fade. */
|
|
export const fadeIn: Variants = {
|
|
hidden: { opacity: 0 },
|
|
visible: { opacity: 1, transition: transitions.standard },
|
|
exit: { opacity: 0, transition: exitFast },
|
|
}
|
|
|
|
/** Fade + subtle scale: popovers, dialogs, floating panels. */
|
|
export const scaleIn: Variants = {
|
|
hidden: { opacity: 0, scale: 0.96 },
|
|
visible: { opacity: 1, scale: 1, transition: transitions.emphasized },
|
|
exit: { opacity: 0, scale: 0.96, transition: exitFast },
|
|
}
|
|
|
|
/** Fade + rise: list/grid items, toolbars, content blocks. */
|
|
export const slideUp: Variants = {
|
|
hidden: { opacity: 0, y: 8 },
|
|
visible: { opacity: 1, y: 0, transition: transitions.emphasized },
|
|
exit: { opacity: 0, y: 8, transition: exitFast },
|
|
}
|
|
|
|
/** Dialog / drawer scrim. */
|
|
export const overlayFade: Variants = {
|
|
hidden: { opacity: 0 },
|
|
visible: { opacity: 1, transition: exitFast },
|
|
exit: { opacity: 0, transition: exitFast },
|
|
}
|
|
|
|
/**
|
|
* Stagger container for lists/grids. Children animate with `slideUp` / `fadeIn`
|
|
* via `variants` inheritance (set the same `initial`/`animate` state names).
|
|
*/
|
|
export const listStagger: Variants = {
|
|
hidden: {},
|
|
visible: { transition: { staggerChildren: 0.05, delayChildren: 0.02 } },
|
|
}
|