learn and share notes on atproto (wip) 馃
malfestio.stormlightlabs.org/
readability
solid
axum
atproto
srs
1import type { Options as MotionOptions } from "solid-motionone";
2import { motion } from "./design-tokens";
3
4/** Spring animation config for natural bounce */
5export const springConfig = { stiffness: 300, damping: 24 };
6
7/** Standard easing for UI animations */
8export const easeOut = [0.22, 1, 0.36, 1] as const;
9
10/** Bounce easing for playful animations */
11export const easeBounce = [0.34, 1.56, 0.64, 1] as const;
12
13/** Fade in animation */
14export const fadeIn: MotionOptions = {
15 initial: { opacity: 0 },
16 animate: { opacity: 1 },
17 transition: { duration: motion.duration.fast / 1000, easing: easeOut },
18};
19
20/** Fade in while sliding up 20px */
21export const fadeInUp: MotionOptions = {
22 initial: { opacity: 0, y: 20 },
23 animate: { opacity: 1, y: 0 },
24 transition: { duration: motion.duration.normal / 1000, easing: easeOut },
25};
26
27/** Slide in from right */
28export const slideInRight: MotionOptions = {
29 initial: { opacity: 0, x: 20 },
30 animate: { opacity: 1, x: 0 },
31 transition: { duration: motion.duration.normal / 1000, easing: easeOut },
32};
33
34/** Slide in from left */
35export const slideInLeft: MotionOptions = {
36 initial: { opacity: 0, x: -20 },
37 animate: { opacity: 1, x: 0 },
38 transition: { duration: motion.duration.slow / 1000, easing: easeOut },
39};
40
41/** Slide in from bottom */
42export const slideInUp: MotionOptions = {
43 initial: { opacity: 0, y: 10 },
44 animate: { opacity: 1, y: 0 },
45 transition: { duration: motion.duration.fast / 1000, easing: easeOut },
46};
47
48/** Scale in (pop) */
49export const scaleIn: MotionOptions = {
50 initial: { opacity: 0, scale: 0.95 },
51 animate: { opacity: 1, scale: 1 },
52 transition: { duration: motion.duration.fast / 1000, easing: easeOut },
53};
54
55/** Scale in with bounce effect */
56export const scaleInBounce: MotionOptions = {
57 initial: { opacity: 0, scale: 0.8 },
58 animate: { opacity: 1, scale: 1 },
59 transition: { duration: motion.duration.slow / 1000, easing: easeBounce },
60};
61
62/** Fade out animation */
63export const fadeOut: MotionOptions = {
64 initial: { opacity: 1 },
65 animate: { opacity: 0 },
66 transition: { duration: motion.duration.fast / 1000 },
67};
68
69/** Fade out while sliding down */
70export const fadeOutDown: MotionOptions = {
71 initial: { opacity: 1, y: 0 },
72 animate: { opacity: 0, y: 20 },
73 transition: { duration: motion.duration.fast / 1000 },
74};
75
76/** Scale out */
77export const scaleOut: MotionOptions = {
78 initial: { opacity: 1, scale: 1 },
79 animate: { opacity: 0, scale: 0.95 },
80 transition: { duration: motion.duration.fast / 1000 },
81};
82
83/** Quick scale out to zero */
84export const scaleOutFast: MotionOptions = {
85 initial: { opacity: 1, scale: 1 },
86 animate: { opacity: 0, scale: 0 },
87 transition: { duration: motion.duration.instant / 1000 },
88};
89
90/** Slide out left (for card dismissal) */
91export const slideOutLeft: MotionOptions = {
92 initial: { opacity: 1, x: 0 },
93 animate: { opacity: 0, x: -100 },
94 transition: { duration: motion.duration.normal / 1000, easing: easeOut },
95};
96
97/** Slide out right */
98export const slideOutRight: MotionOptions = {
99 initial: { opacity: 1, x: 0 },
100 animate: { opacity: 0, x: 100 },
101 transition: { duration: motion.duration.normal / 1000, easing: easeOut },
102};
103
104/** Card flip animation (3D) */
105export const cardFlip: MotionOptions = {
106 initial: { rotateY: 0 },
107 animate: { rotateY: 180 },
108 transition: { duration: 0.4, easing: easeOut },
109};
110
111/** Bounce in (for success feedback) */
112export const bounceIn: MotionOptions = {
113 initial: { opacity: 0, scale: 0.8 },
114 animate: { opacity: 1, scale: 1 },
115 transition: { duration: motion.duration.slow / 1000, easing: easeBounce },
116};
117
118/** Button press feedback - scale down slightly */
119export const pressDown: MotionOptions = {
120 initial: { scale: 1 },
121 animate: { scale: 0.97 },
122 transition: { duration: motion.duration.instant / 1000 },
123};
124
125/** Modal backdrop fade animation */
126export const modalBackdrop: MotionOptions = {
127 initial: { opacity: 0 },
128 animate: { opacity: 1 },
129 exit: { opacity: 0 },
130 transition: { duration: motion.duration.normal / 1000 },
131};
132
133/** Modal content scale + fade animation */
134export const modalContent: MotionOptions = {
135 initial: { opacity: 0, scale: 0.9 },
136 animate: { opacity: 1, scale: 1 },
137 exit: { opacity: 0, scale: 0.9 },
138 transition: { duration: motion.duration.slow / 1000, easing: easeOut },
139};
140
141/** Stagger delay for list items */
142export const staggerDelay = (index: number, baseDelay = 0.05) => index * baseDelay;
143
144/**
145 * Create staggered animation options for a list of items
146 */
147export const createStaggeredList = (
148 count: number,
149 baseAnimation: MotionOptions = fadeInUp,
150 staggerMs = 50,
151): MotionOptions[] => {
152 return Array.from(
153 { length: count },
154 (_, index) => ({
155 ...baseAnimation,
156 transition: { ...baseAnimation.transition, delay: (index * staggerMs) / 1000 },
157 }),
158 );
159};
160
161/** CSS class names for keyframe animations */
162export const cssAnimations = {
163 pulse: "animate-pulse",
164 shimmer: "animate-shimmer",
165 breathe: "animate-breathe",
166} as const;