interaction-design

安装量: 263
排名: #8014

安装

npx skills add https://github.com/wshobson/agents --skill interaction-design
Interaction Design
Create engaging, intuitive interactions through motion, feedback, and thoughtful state transitions that enhance usability and delight users.
When to Use This Skill
Adding microinteractions to enhance user feedback
Implementing smooth page and component transitions
Designing loading states and skeleton screens
Creating gesture-based interactions
Building notification and toast systems
Implementing drag-and-drop interfaces
Adding scroll-triggered animations
Designing hover and focus states
Core Principles
1. Purposeful Motion
Motion should communicate, not decorate:
Feedback
Confirm user actions occurred
Orientation
Show where elements come from/go to
Focus
Direct attention to important changes
Continuity
Maintain context during transitions
2. Timing Guidelines
Duration
Use Case
100-150ms
Micro-feedback (hovers, clicks)
200-300ms
Small transitions (toggles, dropdowns)
300-500ms
Medium transitions (modals, page changes)
500ms+
Complex choreographed animations
3. Easing Functions
/ Common easings /
--ease-out
:
cubic-bezier
(
0.16
,
1
,
0.3
,
1
)
;
/ Decelerate - entering /
--ease-in
:
cubic-bezier
(
0.55
,
0
,
1
,
0.45
)
;
/ Accelerate - exiting /
--ease-in-out
:
cubic-bezier
(
0.65
,
0
,
0.35
,
1
)
;
/ Both - moving between /
--spring
:
cubic-bezier
(
0.34
,
1.56
,
0.64
,
1
)
;
/ Overshoot - playful /
Quick Start: Button Microinteraction
import
{
motion
}
from
"framer-motion"
;
export
function
InteractiveButton
(
{
children
,
onClick
}
)
{
return
(
<
motion.button
onClick
=
{
onClick
}
whileHover
=
{
{
scale
:
1.02
}
}
whileTap
=
{
{
scale
:
0.98
}
}
transition
=
{
{
type
:
"spring"
,
stiffness
:
400
,
damping
:
17
}
}
className
=
"
px-4 py-2 bg-blue-600 text-white rounded-lg
"
>
{
children
}
</
motion.button
>
)
;
}
Interaction Patterns
1. Loading States
Skeleton Screens
Preserve layout while loading
function
CardSkeleton
(
)
{
return
(
<
div
className
=
"
animate-pulse
"
>
<
div
className
=
"
h-48 bg-gray-200 rounded-lg
"
/>
<
div
className
=
"
mt-4 h-4 bg-gray-200 rounded w-3/4
"
/>
<
div
className
=
"
mt-2 h-4 bg-gray-200 rounded w-1/2
"
/>
</
div
>
)
;
}
Progress Indicators
Show determinate progress
function
ProgressBar
(
{
progress
}
:
{
progress
:
number
}
)
{
return
(
<
div
className
=
"
h-2 bg-gray-200 rounded-full overflow-hidden
"
>
<
motion.div
className
=
"
h-full bg-blue-600
"
initial
=
{
{
width
:
0
}
}
animate
=
{
{
width
:
`
${
progress
}
%
`
}
}
transition
=
{
{
ease
:
"easeOut"
}
}
/>
</
div
>
)
;
}
2. State Transitions
Toggle with smooth transition
:
function
Toggle
(
{
checked
,
onChange
}
)
{
return
(
<
button
role
=
"
switch
"
aria-checked
=
{
checked
}
onClick
=
{
(
)
=>
onChange
(
!
checked
)
}
className
=
{
`
relative w-12 h-6 rounded-full transition-colors duration-200
${
checked
?
"bg-blue-600"
:
"bg-gray-300"
}
`
}
>
<
motion.span
className
=
"
absolute top-1 left-1 w-4 h-4 bg-white rounded-full shadow
"
animate
=
{
{
x
:
checked
?
24
:
0
}
}
transition
=
{
{
type
:
"spring"
,
stiffness
:
500
,
damping
:
30
}
}
/>
</
button
>
)
;
}
3. Page Transitions
Framer Motion layout animations
:
import
{
AnimatePresence
,
motion
}
from
"framer-motion"
;
function
PageTransition
(
{
children
,
key
}
)
{
return
(
<
AnimatePresence
mode
=
"
wait
"
>
<
motion.div
key
=
{
key
}
initial
=
{
{
opacity
:
0
,
y
:
20
}
}
animate
=
{
{
opacity
:
1
,
y
:
0
}
}
exit
=
{
{
opacity
:
0
,
y
:
-
20
}
}
transition
=
{
{
duration
:
0.3
}
}
>
{
children
}
</
motion.div
>
</
AnimatePresence
>
)
;
}
4. Feedback Patterns
Ripple effect on click
:
function
RippleButton
(
{
children
,
onClick
}
)
{
const
[
ripples
,
setRipples
]
=
useState
(
[
]
)
;
const
handleClick
=
(
e
)
=>
{
const
rect
=
e
.
currentTarget
.
getBoundingClientRect
(
)
;
const
ripple
=
{
x
:
e
.
clientX
-
rect
.
left
,
y
:
e
.
clientY
-
rect
.
top
,
id
:
Date
.
now
(
)
,
}
;
setRipples
(
(
prev
)
=>
[
...
prev
,
ripple
]
)
;
setTimeout
(
(
)
=>
{
setRipples
(
(
prev
)
=>
prev
.
filter
(
(
r
)
=>
r
.
id
!==
ripple
.
id
)
)
;
}
,
600
)
;
onClick
?.
(
e
)
;
}
;
return
(
<
button
onClick
=
{
handleClick
}
className
=
"
relative overflow-hidden
"
>
{
children
}
{
ripples
.
map
(
(
ripple
)
=>
(
<
span
key
=
{
ripple
.
id
}
className
=
"
absolute bg-white/30 rounded-full animate-ripple
"
style
=
{
{
left
:
ripple
.
x
,
top
:
ripple
.
y
}
}
/>
)
)
}
</
button
>
)
;
}
5. Gesture Interactions
Swipe to dismiss
:
function
SwipeCard
(
{
children
,
onDismiss
}
)
{
return
(
<
motion.div
drag
=
"
x
"
dragConstraints
=
{
{
left
:
0
,
right
:
0
}
}
onDragEnd
=
{
(
_
,
info
)
=>
{
if
(
Math
.
abs
(
info
.
offset
.
x
)
>
100
)
{
onDismiss
(
)
;
}
}
}
className
=
"
cursor-grab active:cursor-grabbing
"
>
{
children
}
</
motion.div
>
)
;
}
CSS Animation Patterns
Keyframe Animations
@keyframes
fadeIn
{
from
{
opacity
:
0
;
transform
:
translateY
(
10
px
)
;
}
to
{
opacity
:
1
;
transform
:
translateY
(
0
)
;
}
}
@keyframes
pulse
{
0%
,
100%
{
opacity
:
1
;
}
50%
{
opacity
:
0.5
;
}
}
@keyframes
spin
{
to
{
transform
:
rotate
(
360
deg
)
;
}
}
.animate-fadeIn
{
animation
:
fadeIn
0.3
s
ease-out
;
}
.animate-pulse
{
animation
:
pulse
2
s
ease-in-out infinite
;
}
.animate-spin
{
animation
:
spin
1
s
linear infinite
;
}
CSS Transitions
.card
{
transition
:
transform
0.2
s
ease-out
,
box-shadow
0.2
s
ease-out
;
}
.card
:hover
{
transform
:
translateY
(
-4
px
)
;
box-shadow
:
0
12
px
24
px
rgba
(
0
,
0
,
0
,
0.1
)
;
}
Accessibility Considerations
/ Respect user motion preferences /
@media
(
prefers-reduced-motion
:
reduce
)
{
*
,
*
::before
,
*
::after
{
animation-duration
:
0.01
ms
!important
;
animation-iteration-count
:
1
!important
;
transition-duration
:
0.01
ms
!important
;
}
}
function
AnimatedComponent
(
)
{
const
prefersReducedMotion
=
window
.
matchMedia
(
"(prefers-reduced-motion: reduce)"
,
)
.
matches
;
return
(
<
motion.div
animate
=
{
{
opacity
:
1
}
}
transition
=
{
{
duration
:
prefersReducedMotion
?
0
:
0.3
}
}
/>
)
;
}
Best Practices
Performance First
Use
transform
and
opacity
for smooth 60fps
Reduce Motion Support
Always respect
prefers-reduced-motion
Consistent Timing
Use a timing scale across the app
Natural Physics
Prefer spring animations over linear
Interruptible
Allow users to cancel long animations
Progressive Enhancement
Work without JS animations
Test on Devices
Performance varies significantly
Common Issues
Janky Animations
Avoid animating
width
,
height
,
top
,
left
Over-animation
Too much motion causes fatigue
Blocking Interactions
Never prevent user input during animations
Memory Leaks
Clean up animation listeners on unmount
Flash of Content
Use will-change sparingly for optimization
返回排行榜