Foundations
Motion
ScaffoldedMotion tokens describe how things move across every TpGroup surface. Durations and easing are defined once, exported to every platform, and honoured whether the consumer is React Native Reanimated, CSS transitions, iOS UIView animation, Android MotionLayout, or a Lottie file in After Effects.
Duration scale
| Token | Value | Use |
|---|---|---|
| motion.duration.instant | 0ms | Skip animation — used when reduce-motion is active |
| motion.duration.fast | 150ms | Micro-interactions — ripples, toggles, pressed states |
| motion.duration.base | 250ms | Default UI transitions — hover, focus, simple reveals |
| motion.duration.slow | 400ms | Surface moves — modals, sheets, route transitions |
| motion.duration.slower | 600ms | Choreographed sequences — onboarding, brand moments |
Easing
| Token | Curve | Use |
|---|---|---|
| motion.easing.standard | cubic-bezier(0.2, 0, 0, 1) | In-place moves — color, opacity, simple transforms |
| motion.easing.decelerate | cubic-bezier(0, 0, 0, 1) | Enter — element arrives on screen |
| motion.easing.accelerate | cubic-bezier(0.3, 0, 1, 1) | Exit — element leaves the screen |
Live demo
Applied CSS: transition: left 250ms var(--motion-easing-standard)
Reduce motion
Every TpGroup product must respect the operating-system reduce-motion preference. When active, durations collapse to motion.duration.instant and non-essential animations are suppressed entirely. Essential feedback (focus rings, toggle state changes) remains visible but without animation.
Your OS has reduce-motion disabled — this showcase animates at full speed.
This demo reads the live prefers-reduced-motion media query — no user toggle needed.
Per-platform mapping
| Token | Web (CSS) | iOS (UIView / SwiftUI) | Android (MotionLayout / Compose) | Windows (XAML Storyboard) | Lottie / After Effects |
|---|---|---|---|---|---|
| motion.duration.base | transition-duration: 250ms | UIView.animate(withDuration: 0.25) / .animation(.easeInOut(duration: 0.25)) | motionDurationMedium1 (250ms) / tween(durationMillis = 250) | Duration="0:0:0.25" | 15 frames @ 60fps (250ms) |
| motion.easing.standard | cubic-bezier(0.2, 0, 0, 1) | UIView.AnimationOptions.curveEaseInOut / timingCurve | FastOutSlowInEasing / CubicBezierEasing(0.2f, 0f, 0f, 1f) | KeySpline="0.2,0 0,1" | Easing expression (0.2, 0, 0, 1) |
| motion.easing.decelerate | cubic-bezier(0, 0, 0, 1) | .animation(.easeOut) | LinearOutSlowInEasing | KeySpline="0,0 0,1" | Ease Out curve |