Animation and Keyframe Generation

1. Keyframe Mixins and Animation Libraries

Pattern Technique Output Use Case
Keyframe Mixin @mixin with @keyframes Reusable animations Common effects
Animation Shorthand Single-line animation setup Quick application Simple animations
Animation Library Pre-built animation set Ready-to-use effects Rapid development
Prefix Handling Vendor prefix automation Cross-browser support Legacy browsers
Composable Animations Combine multiple effects Complex movements Rich interactions

Example: Basic keyframe animation mixins

// Reusable keyframe mixin
@mixin keyframes($name) {
  @keyframes #{$name} {
    @content;
  }
}

// Usage - Fade in animation
@include keyframes(fadeIn) {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

// Slide in from left
@include keyframes(slideInLeft) {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

// Bounce effect
@include keyframes(bounce) {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-30px);
  }
  60% {
    transform: translateY(-15px);
  }
}

// Apply animation
.element {
  animation: fadeIn 0.5s ease-out;
}

.slide {
  animation: slideInLeft 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.bouncing {
  animation: bounce 1s infinite;
}

Example: Animation library with mixin helpers

// Animation application mixin
@mixin animate(
  $name,
  $duration: 0.3s,
  $timing: ease,
  $delay: 0s,
  $iteration: 1,
  $direction: normal,
  $fill: both
) {
  animation-name: $name;
  animation-duration: $duration;
  animation-timing-function: $timing;
  animation-delay: $delay;
  animation-iteration-count: $iteration;
  animation-direction: $direction;
  animation-fill-mode: $fill;
}

// Shorthand animation
@mixin anim($name, $duration: 0.3s, $timing: ease) {
  animation: $name $duration $timing;
}

// Fade animations
@include keyframes(fadeIn) {
  from { opacity: 0; }
  to { opacity: 1; }
}

@include keyframes(fadeOut) {
  from { opacity: 1; }
  to { opacity: 0; }
}

@include keyframes(fadeInUp) {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@include keyframes(fadeInDown) {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

// Scale animations
@include keyframes(zoomIn) {
  from {
    opacity: 0;
    transform: scale(0.3);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@include keyframes(pulse) {
  0%, 100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.05);
  }
}

// Rotation animations
@include keyframes(rotate) {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@include keyframes(shake) {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); }
  20%, 40%, 60%, 80% { transform: translateX(10px); }
}

// Usage
.modal {
  @include animate(fadeInUp, 0.4s, cubic-bezier(0.4, 0, 0.2, 1));
}

.loader {
  @include anim(rotate, 1s, linear);
  animation-iteration-count: infinite;
}

.error-message {
  @include anim(shake, 0.5s, ease-in-out);
}

Example: Advanced animation library patterns

// Configurable entrance animations
@mixin entrance-animation(
  $name,
  $from-opacity: 0,
  $from-transform: translateY(20px),
  $to-opacity: 1,
  $to-transform: translateY(0)
) {
  @include keyframes($name) {
    from {
      opacity: $from-opacity;
      transform: $from-transform;
    }
    to {
      opacity: $to-opacity;
      transform: $to-transform;
    }
  }
}

// Generate entrance variations
@include entrance-animation('enterFromBottom', 0, translateY(50px));
@include entrance-animation('enterFromTop', 0, translateY(-50px));
@include entrance-animation('enterFromLeft', 0, translateX(-50px));
@include entrance-animation('enterFromRight', 0, translateX(50px));

// Attention seekers
@include keyframes(heartbeat) {
  0%, 100% {
    transform: scale(1);
  }
  10%, 30% {
    transform: scale(0.9);
  }
  20%, 40% {
    transform: scale(1.1);
  }
}

@include keyframes(wiggle) {
  0%, 100% { transform: rotate(0deg); }
  25% { transform: rotate(-5deg); }
  75% { transform: rotate(5deg); }
}

@include keyframes(flash) {
  0%, 50%, 100% { opacity: 1; }
  25%, 75% { opacity: 0; }
}

// Loading animations
@include keyframes(spin) {
  to { transform: rotate(360deg); }
}

@include keyframes(dots) {
  0%, 20% { content: '.'; }
  40% { content: '..'; }
  60%, 100% { content: '...'; }
}

// Utility mixin for animation delays
@mixin stagger-animation($base-delay: 0.1s, $count: 5) {
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      animation-delay: $base-delay * ($i - 1);
    }
  }
}

// Usage
.list-item {
  @include anim(fadeInUp, 0.4s, ease-out);
  @include stagger-animation(0.1s, 10);
}

2. Dynamic Animation Generation with Maps

Technique Data Structure Benefit Use Case
Map-based Config Animation properties map Centralized settings Consistent animations
Loop Generation @each over animation map Auto-generate variants Multiple animations
Timing Presets Easing function map Reusable timing Brand consistency
Duration Scale Speed multiplier map Consistent timing Animation speeds
State Animations State-to-animation map Logical mapping UI state changes

Example: Map-based animation system

// Animation configuration map
$animations: (
  'fade-in': (
    from: (opacity: 0),
    to: (opacity: 1),
    duration: 0.3s,
    timing: ease-out
  ),
  'slide-up': (
    from: (opacity: 0, transform: translateY(20px)),
    to: (opacity: 1, transform: translateY(0)),
    duration: 0.4s,
    timing: cubic-bezier(0.4, 0, 0.2, 1)
  ),
  'scale-in': (
    from: (opacity: 0, transform: scale(0.8)),
    to: (opacity: 1, transform: scale(1)),
    duration: 0.35s,
    timing: cubic-bezier(0.34, 1.56, 0.64, 1)
  ),
  'rotate-in': (
    from: (opacity: 0, transform: rotate(-180deg) scale(0.5)),
    to: (opacity: 1, transform: rotate(0deg) scale(1)),
    duration: 0.6s,
    timing: ease-out
  )
);

// Generate keyframes from map
@each $name, $config in $animations {
  @include keyframes($name) {
    from {
      @each $prop, $value in map-get($config, from) {
        #{$prop}: $value;
      }
    }
    to {
      @each $prop, $value in map-get($config, to) {
        #{$prop}: $value;
      }
    }
  }
  
  // Generate utility class
  .animate-#{$name} {
    animation: $name 
      map-get($config, duration)
      map-get($config, timing);
  }
}

// Output:
// @keyframes fade-in { ... }
// .animate-fade-in { animation: fade-in 0.3s ease-out; }
// @keyframes slide-up { ... }
// .animate-slide-up { animation: slide-up 0.4s cubic-bezier(...); }
// etc.

Example: Timing function and duration scales

// Easing function library
$easings: (
  'linear': linear,
  'ease': ease,
  'ease-in': ease-in,
  'ease-out': ease-out,
  'ease-in-out': ease-in-out,
  'ease-in-quad': cubic-bezier(0.55, 0.085, 0.68, 0.53),
  'ease-out-quad': cubic-bezier(0.25, 0.46, 0.45, 0.94),
  'ease-in-cubic': cubic-bezier(0.55, 0.055, 0.675, 0.19),
  'ease-out-cubic': cubic-bezier(0.215, 0.61, 0.355, 1),
  'ease-in-quart': cubic-bezier(0.895, 0.03, 0.685, 0.22),
  'ease-out-quart': cubic-bezier(0.165, 0.84, 0.44, 1),
  'ease-in-back': cubic-bezier(0.6, -0.28, 0.735, 0.045),
  'ease-out-back': cubic-bezier(0.175, 0.885, 0.32, 1.275),
  'ease-in-out-back': cubic-bezier(0.68, -0.55, 0.265, 1.55)
);

// Duration scale
$durations: (
  'instant': 0.1s,
  'fast': 0.2s,
  'normal': 0.3s,
  'slow': 0.5s,
  'slower': 0.8s,
  'slowest': 1.2s
);

// Helper function to get easing
@function ease($name) {
  @return map-get($easings, $name);
}

// Helper function to get duration
@function duration($name) {
  @return map-get($durations, $name);
}

// Animation mixin using presets
@mixin preset-animate($name, $duration-key: 'normal', $easing-key: 'ease-out') {
  animation: $name duration($duration-key) ease($easing-key);
}

// Generate timing utility classes
@each $name, $value in $easings {
  .ease-#{$name} {
    animation-timing-function: $value;
  }
}

@each $name, $value in $durations {
  .duration-#{$name} {
    animation-duration: $value;
  }
}

// Usage
.modal {
  @include preset-animate(fadeIn, 'normal', 'ease-out-back');
}

.notification {
  animation: slideInRight duration('fast') ease('ease-out-quad');
}

// HTML usage:
// <div class="animate-fade-in duration-slow ease-ease-out-back">

Example: Complex animation sequences with maps

// Multi-step animation configuration
$complex-animations: (
  'loading-pulse': (
    steps: (
      0: (transform: scale(1), opacity: 1),
      50: (transform: scale(1.2), opacity: 0.7),
      100: (transform: scale(1), opacity: 1)
    ),
    duration: 1.5s,
    timing: ease-in-out,
    iteration: infinite
  ),
  'success-check': (
    steps: (
      0: (transform: scale(0) rotate(0deg), opacity: 0),
      50: (transform: scale(1.2) rotate(360deg), opacity: 1),
      100: (transform: scale(1) rotate(360deg), opacity: 1)
    ),
    duration: 0.6s,
    timing: cubic-bezier(0.68, -0.55, 0.265, 1.55),
    iteration: 1
  ),
  'error-shake': (
    steps: (
      0: (transform: translateX(0)),
      10: (transform: translateX(-10px)),
      20: (transform: translateX(10px)),
      30: (transform: translateX(-10px)),
      40: (transform: translateX(10px)),
      50: (transform: translateX(-10px)),
      60: (transform: translateX(10px)),
      70: (transform: translateX(-10px)),
      80: (transform: translateX(10px)),
      90: (transform: translateX(-10px)),
      100: (transform: translateX(0))
    ),
    duration: 0.8s,
    timing: ease,
    iteration: 1
  )
);

// Generate complex keyframes
@each $name, $config in $complex-animations {
  @include keyframes($name) {
    @each $percent, $properties in map-get($config, steps) {
      #{$percent}% {
        @each $prop, $value in $properties {
          #{$prop}: $value;
        }
      }
    }
  }
  
  .#{$name} {
    animation-name: $name;
    animation-duration: map-get($config, duration);
    animation-timing-function: map-get($config, timing);
    animation-iteration-count: map-get($config, iteration);
  }
}

3. CSS Transition Mixins and Timing Functions

Mixin Properties Use Case Example
transition Single property transition Simple effects Button hover
transitions Multiple properties Complex changes Card expand
transition-all All properties Quick prototyping Theme changes
Custom easing Cubic bezier curves Brand feel Material Design
Hardware acceleration transform, opacity Performance Smooth animations

Example: Transition utility mixins

// Single property transition
@mixin transition($property, $duration: 0.3s, $timing: ease, $delay: 0s) {
  transition: $property $duration $timing $delay;
}

// Multiple property transitions
@mixin transitions($transitions...) {
  transition: $transitions;
}

// Transition all properties
@mixin transition-all($duration: 0.3s, $timing: ease) {
  transition: all $duration $timing;
}

// No transition
@mixin no-transition {
  transition: none !important;
}

// Hardware-accelerated properties only
@mixin hw-transition($duration: 0.3s, $timing: ease) {
  transition: transform $duration $timing,
              opacity $duration $timing;
}

// Usage examples
.button {
  @include transition(background-color, 0.2s, ease-out);
  
  &:hover {
    background-color: darken(#1976d2, 10%);
  }
}

.card {
  @include transitions(
    transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.3s ease-out,
    background-color 0.2s ease
  );
  
  &:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0,0,0,0.2);
  }
}

.modal {
  @include hw-transition(0.4s, cubic-bezier(0.4, 0, 0.2, 1));
}

// Disable transitions for reduced motion
@media (prefers-reduced-motion: reduce) {
  * {
    @include no-transition;
    animation-duration: 0.01ms !important;
  }
}

Example: Timing function library with presets

// Timing function presets
$timing-functions: (
  // Standard
  'linear': linear,
  'ease': ease,
  'ease-in': ease-in,
  'ease-out': ease-out,
  'ease-in-out': ease-in-out,
  
  // Material Design
  'material-standard': cubic-bezier(0.4, 0, 0.2, 1),
  'material-decelerate': cubic-bezier(0, 0, 0.2, 1),
  'material-accelerate': cubic-bezier(0.4, 0, 1, 1),
  'material-sharp': cubic-bezier(0.4, 0, 0.6, 1),
  
  // Expressive
  'bounce': cubic-bezier(0.68, -0.55, 0.265, 1.55),
  'elastic': cubic-bezier(0.68, -0.6, 0.32, 1.6),
  'overshoot': cubic-bezier(0.175, 0.885, 0.32, 1.275),
  
  // Smooth
  'smooth': cubic-bezier(0.25, 0.1, 0.25, 1),
  'smooth-in': cubic-bezier(0.42, 0, 1, 1),
  'smooth-out': cubic-bezier(0, 0, 0.58, 1),
  'smooth-in-out': cubic-bezier(0.42, 0, 0.58, 1)
);

// Get timing function
@function timing($name) {
  @if map-has-key($timing-functions, $name) {
    @return map-get($timing-functions, $name);
  }
  @warn "Timing function '#{$name}' not found.";
  @return ease;
}

// Transition with preset timing
@mixin t($property, $duration: 0.3s, $timing-name: 'ease-out', $delay: 0s) {
  transition: $property $duration timing($timing-name) $delay;
}

// Generate timing utility classes
@each $name, $function in $timing-functions {
  .timing-#{$name} {
    transition-timing-function: $function;
  }
}

// Usage
.button {
  @include t(all, 0.2s, 'material-standard');
}

.dropdown {
  @include t(opacity, 0.15s, 'material-decelerate');
  @include t(transform, 0.3s, 'material-decelerate');
}

.notification {
  transition: transform 0.4s timing('bounce'),
              opacity 0.3s timing('ease-out');
}

Example: Advanced transition patterns

// Stagger transition delays
@mixin stagger-transition(
  $property: all,
  $duration: 0.3s,
  $timing: ease-out,
  $base-delay: 0.05s,
  $count: 10
) {
  transition: $property $duration $timing;
  
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      transition-delay: $base-delay * ($i - 1);
    }
  }
}

// Conditional transitions (only specific properties)
@mixin transition-props($props, $duration: 0.3s, $timing: ease) {
  $transition-list: ();
  
  @each $prop in $props {
    $transition-list: append($transition-list, $prop $duration $timing, comma);
  }
  
  transition: $transition-list;
}

// Safe transitions (avoid layout thrashing)
@mixin safe-transition($duration: 0.3s, $timing: ease) {
  // Only transition properties that don't trigger layout
  transition: transform $duration $timing,
              opacity $duration $timing,
              color $duration $timing,
              background-color $duration $timing,
              border-color $duration $timing,
              box-shadow $duration $timing;
}

// Transition with will-change optimization
@mixin optimized-transition($property, $duration: 0.3s, $timing: ease) {
  will-change: $property;
  transition: $property $duration $timing;
  
  &:hover,
  &:focus {
    will-change: auto;
  }
}

// Usage
.list-item {
  @include stagger-transition(transform, 0.3s, ease-out, 0.05s, 20);
}

.card {
  @include transition-props((transform, box-shadow), 0.3s, ease-out);
}

.menu-item {
  @include safe-transition(0.2s, ease-out);
}

.hero-image {
  @include optimized-transition(transform, 0.6s, ease-out);
}

4. Transform Function Utilities

Transform Function Use Case Performance
translate translateX/Y/Z Movement GPU accelerated Fast
scale scaleX/Y/Z Zoom effects GPU accelerated Fast
rotate rotateX/Y/Z Rotation GPU accelerated Fast
skew skewX/Y Distortion GPU accelerated Fast
3D transforms translate3d, etc. Depth effects Hardware accelerated Fast

Example: Transform utility mixins

// Center with transform
@mixin center-transform {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

// Center horizontally
@mixin center-x {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

// Center vertically
@mixin center-y {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

// Hardware acceleration hint
@mixin hardware-accelerate {
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
}

// 3D card flip
@mixin card-flip($duration: 0.6s) {
  transform-style: preserve-3d;
  transition: transform $duration;
  
  .front,
  .back {
    backface-visibility: hidden;
    position: absolute;
    width: 100%;
    height: 100%;
  }
  
  .back {
    transform: rotateY(180deg);
  }
  
  &.flipped {
    transform: rotateY(180deg);
  }
}

// Parallax effect
@mixin parallax($speed: 0.5) {
  transform: translateY(calc(var(--scroll) * #{$speed}px));
}

// Usage
.modal-content {
  @include center-transform;
}

.dropdown-menu {
  @include center-x;
  top: 100%;
}

.card {
  @include hardware-accelerate;
  
  &:hover {
    transform: translateY(-4px) translateZ(0);
  }
}

.flip-card {
  @include card-flip(0.6s);
}

.parallax-bg {
  @include parallax(0.3);
}

Example: Complex transform combinations

// Transform builder function
@function build-transform($transforms...) {
  $result: '';
  
  @each $transform in $transforms {
    $result: $result + ' ' + $transform;
  }
  
  @return unquote($result);
}

// Common transform combinations
@mixin lift($distance: 8px, $scale: 1.02) {
  transform: translateY(-#{$distance}) scale($scale);
}

@mixin push($distance: 2px) {
  transform: translateY($distance) scale(0.98);
}

@mixin swing {
  transform-origin: top center;
  @include keyframes(swing) {
    20% { transform: rotate(15deg); }
    40% { transform: rotate(-10deg); }
    60% { transform: rotate(5deg); }
    80% { transform: rotate(-5deg); }
    100% { transform: rotate(0deg); }
  }
}

@mixin wobble {
  @include keyframes(wobble) {
    0%, 100% { transform: translateX(0) rotate(0); }
    15% { transform: translateX(-25px) rotate(-5deg); }
    30% { transform: translateX(20px) rotate(3deg); }
    45% { transform: translateX(-15px) rotate(-3deg); }
    60% { transform: translateX(10px) rotate(2deg); }
    75% { transform: translateX(-5px) rotate(-1deg); }
  }
}

// 3D transforms
@mixin rotate-3d($x: 0, $y: 1, $z: 0, $angle: 45deg) {
  transform: rotate3d($x, $y, $z, $angle);
}

@mixin flip-horizontal {
  transform: scaleX(-1);
}

@mixin flip-vertical {
  transform: scaleY(-1);
}

// Perspective helper
@mixin perspective($distance: 1000px) {
  perspective: $distance;
  perspective-origin: center;
}

// Usage
.card {
  transition: transform 0.3s ease-out;
  
  &:hover {
    @include lift(10px, 1.05);
  }
  
  &:active {
    @include push(4px);
  }
}

.badge {
  animation: swing 1s ease-in-out;
}

.container-3d {
  @include perspective(1200px);
  
  .item {
    @include rotate-3d(1, 0, 0, 15deg);
  }
}

.mirrored {
  @include flip-horizontal;
}

Example: Transform animation sequences

// Entrance animations with transforms
@mixin slide-enter($from: left, $distance: 100%, $duration: 0.4s) {
  @if $from == left {
    @include keyframes(slideEnterLeft) {
      from { transform: translateX(-#{$distance}); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
    animation: slideEnterLeft $duration ease-out;
  } @else if $from == right {
    @include keyframes(slideEnterRight) {
      from { transform: translateX($distance); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
    animation: slideEnterRight $duration ease-out;
  } @else if $from == top {
    @include keyframes(slideEnterTop) {
      from { transform: translateY(-#{$distance}); opacity: 0; }
      to { transform: translateY(0); opacity: 1; }
    }
    animation: slideEnterTop $duration ease-out;
  } @else if $from == bottom {
    @include keyframes(slideEnterBottom) {
      from { transform: translateY($distance); opacity: 0; }
      to { transform: translateY(0); opacity: 1; }
    }
    animation: slideEnterBottom $duration ease-out;
  }
}

// Scale entrance
@mixin scale-enter($from: 0.8, $duration: 0.3s, $timing: ease-out) {
  @include keyframes(scaleEnter) {
    from {
      transform: scale($from);
      opacity: 0;
    }
    to {
      transform: scale(1);
      opacity: 1;
    }
  }
  animation: scaleEnter $duration $timing;
}

// Rotate entrance
@mixin rotate-enter($degrees: 90deg, $duration: 0.5s) {
  @include keyframes(rotateEnter) {
    from {
      transform: rotate($degrees) scale(0.5);
      opacity: 0;
    }
    to {
      transform: rotate(0deg) scale(1);
      opacity: 1;
    }
  }
  animation: rotateEnter $duration cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

// Usage
.sidebar {
  @include slide-enter(left, 300px, 0.4s);
}

.modal {
  @include scale-enter(0.7, 0.3s, cubic-bezier(0.34, 1.56, 0.64, 1));
}

.notification {
  @include rotate-enter(180deg, 0.6s);
}

5. Animation State Management

State CSS Property Control Use Case
Play/Pause animation-play-state paused/running User control
Direction animation-direction normal/reverse/alternate Reversible animations
Fill Mode animation-fill-mode forwards/backwards/both End state retention
Iteration animation-iteration-count number/infinite Looping control
Delay animation-delay Time value Sequence timing

Example: Animation state control mixins

// Pause animation on hover
@mixin pause-on-hover {
  &:hover {
    animation-play-state: paused;
  }
}

// Play animation on hover
@mixin play-on-hover($name, $duration: 1s, $timing: ease) {
  animation: $name $duration $timing paused;
  
  &:hover {
    animation-play-state: running;
  }
}

// Reverse on second hover
@mixin reverse-on-second-hover($name, $duration: 0.5s) {
  animation: $name $duration ease-out;
  animation-fill-mode: both;
  
  &.reversed {
    animation-direction: reverse;
  }
}

// Animation with state classes
@mixin stateful-animation(
  $name,
  $duration: 0.5s,
  $timing: ease
) {
  animation: $name $duration $timing;
  animation-fill-mode: both;
  animation-play-state: paused;
  
  &.playing {
    animation-play-state: running;
  }
  
  &.reverse {
    animation-direction: reverse;
  }
  
  &.loop {
    animation-iteration-count: infinite;
  }
}

// Sequential animations
@mixin sequence($animations...) {
  $total-duration: 0s;
  
  @each $anim in $animations {
    $name: nth($anim, 1);
    $duration: nth($anim, 2);
    $delay: $total-duration;
    
    &.step-#{index($animations, $anim)} {
      animation: $name $duration ease-out $delay;
      animation-fill-mode: both;
    }
    
    $total-duration: $total-duration + $duration;
  }
}

// Usage
.spinner {
  @include pause-on-hover;
}

.icon {
  @include play-on-hover(bounce, 0.6s, ease-in-out);
}

.menu {
  @include stateful-animation(slideDown, 0.4s, ease-out);
}

// JavaScript adds/removes classes:
// element.classList.add('playing');
// element.classList.add('reverse');
// element.classList.add('loop');

Example: Animation orchestration

// Chain animations using animation-delay
@mixin animation-chain($animations) {
  $total-delay: 0s;
  $all-animations: ();
  
  @each $name, $duration in $animations {
    $all-animations: append(
      $all-animations,
      $name $duration ease-out $total-delay both,
      comma
    );
    $total-delay: $total-delay + $duration;
  }
  
  animation: $all-animations;
}

// Staggered group animation
@mixin stagger-group(
  $animation,
  $duration: 0.3s,
  $delay: 0.1s,
  $count: 10
) {
  animation: $animation $duration ease-out;
  animation-fill-mode: both;
  
  @for $i from 1 through $count {
    &:nth-child(#{$i}) {
      animation-delay: ($i - 1) * $delay;
    }
  }
}

// Coordinated entrance
@mixin coordinated-entrance($children-map) {
  @each $selector, $config in $children-map {
    #{$selector} {
      animation: map-get($config, animation)
                 map-get($config, duration)
                 map-get($config, timing)
                 map-get($config, delay);
      animation-fill-mode: both;
    }
  }
}

// Usage - Chain multiple animations
.logo {
  @include animation-chain((
    fadeIn: 0.5s,
    slideUp: 0.4s,
    bounce: 0.6s
  ));
}

// Staggered list items
.nav-item {
  @include stagger-group(fadeInLeft, 0.4s, 0.08s, 8);
}

// Coordinated page entrance
.hero {
  @include coordinated-entrance((
    '.hero-title': (
      animation: fadeInUp,
      duration: 0.6s,
      timing: ease-out,
      delay: 0.2s
    ),
    '.hero-subtitle': (
      animation: fadeInUp,
      duration: 0.6s,
      timing: ease-out,
      delay: 0.4s
    ),
    '.hero-cta': (
      animation: scaleIn,
      duration: 0.5s,
      timing: cubic-bezier(0.68, -0.55, 0.265, 1.55),
      delay: 0.8s
    )
  ));
}

Example: Event-driven animation states

// Loading state animations
@mixin loading-state($animation: pulse) {
  &.loading {
    animation: $animation 1.5s ease-in-out infinite;
    pointer-events: none;
    
    & > * {
      opacity: 0.6;
    }
  }
}

// Success/error state transitions
@mixin result-states {
  transition: all 0.3s ease-out;
  
  &.success {
    animation: successPulse 0.6s ease-out;
    background-color: #4caf50;
    color: white;
  }
  
  &.error {
    animation: errorShake 0.5s ease-in-out;
    background-color: #f44336;
    color: white;
  }
}

// Define state animations
@include keyframes(successPulse) {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@include keyframes(errorShake) {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-8px); }
  20%, 40%, 60%, 80% { transform: translateX(8px); }
}

// Focus/blur animations
@mixin focus-animation($scale: 1.02) {
  transition: transform 0.2s ease-out;
  
  &:focus {
    transform: scale($scale);
    outline: 2px solid #2196f3;
    outline-offset: 2px;
  }
}

// Hover intent (delayed hover)
@mixin hover-intent($delay: 0.3s) {
  &:hover {
    animation: hoverIntent $delay ease-out;
    animation-fill-mode: forwards;
  }
  
  @include keyframes(hoverIntent) {
    from { opacity: 1; }
    to { opacity: 1; transform: translateY(-4px); }
  }
}

// Usage
.submit-button {
  @include loading-state(rotate);
  @include result-states;
}

.input-field {
  @include focus-animation(1.02);
}

.card {
  @include hover-intent(0.2s);
}

6. Performance-optimized Animation Patterns

Technique Implementation Benefit Impact
GPU Acceleration transform, opacity only 60fps animations Smooth performance
will-change Hint to browser Pre-optimization Faster start
contain Isolation hint Limit repaints Better performance
Reduced Motion prefers-reduced-motion Accessibility Better UX
Layer Promotion translateZ(0) Own composite layer Isolated rendering

Example: GPU-accelerated animations

// Force GPU acceleration
@mixin gpu-accelerate {
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
  will-change: transform;
}

// Performant transform animation
@mixin performant-transform($property: transform, $duration: 0.3s) {
  @include gpu-accelerate;
  transition: $property $duration cubic-bezier(0.4, 0, 0.2, 1);
}

// Only animate GPU-friendly properties
@mixin gpu-animation {
  // ✅ GOOD: transform and opacity (GPU accelerated)
  transition: transform 0.3s ease-out,
              opacity 0.3s ease-out;
  
  // ❌ AVOID: width, height, top, left (trigger layout)
  // transition: width 0.3s, height 0.3s, top 0.3s;
}

// Layer promotion for animations
@mixin promote-layer {
  will-change: transform, opacity;
  
  // Remove after animation
  &.animated {
    will-change: auto;
  }
}

// Composite layer for smooth animations
@mixin composite-layer {
  // Create new stacking context
  position: relative;
  z-index: 0;
  
  // Promote to own layer
  transform: translateZ(0);
  
  // Contain paint and layout
  contain: layout paint;
}

// Usage
.smooth-card {
  @include performant-transform(transform, 0.4s);
  
  &:hover {
    transform: translateY(-8px) scale(1.02);
  }
}

.modal {
  @include composite-layer;
  @include gpu-animation;
}

Example: Accessibility and reduced motion

// Respect user's motion preferences
@mixin respect-motion-preference {
  @media (prefers-reduced-motion: reduce) {
    animation: none !important;
    transition: none !important;
  }
}

// Safe animation (automatically disabled for reduced motion)
@mixin safe-animate(
  $name,
  $duration: 0.3s,
  $timing: ease,
  $fallback-transition: opacity 0.1s
) {
  animation: $name $duration $timing;
  
  @media (prefers-reduced-motion: reduce) {
    animation: none;
    transition: $fallback-transition;
  }
}

// Crossfade instead of movement
@mixin reduced-motion-friendly($normal-anim, $reduced-anim: fadeIn) {
  animation: $normal-anim;
  
  @media (prefers-reduced-motion: reduce) {
    animation: $reduced-anim 0.2s ease-out;
  }
}

// Conditional animation
@mixin motion-safe($animation, $duration: 0.3s) {
  @media (prefers-reduced-motion: no-preference) {
    animation: $animation $duration ease-out;
  }
}

// Global reduced motion reset
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

// Usage
.card {
  @include safe-animate(slideInUp, 0.4s, ease-out, opacity 0.2s);
}

.notification {
  @include reduced-motion-friendly(slideInRight, fadeIn);
}

.hero {
  @include motion-safe(fadeInUp, 0.6s);
}

Example: Performance monitoring and optimization

// Optimized animation helper
@mixin optimized-animation(
  $name,
  $duration: 0.3s,
  $timing: ease-out,
  $will-change-props: transform opacity
) {
  // Enable will-change before animation
  will-change: $will-change-props;
  animation: $name $duration $timing;
  
  // Cleanup after animation
  animation-fill-mode: both;
}

// Debounced animation (prevent too-frequent triggers)
@mixin debounced-animation($name, $duration: 0.3s, $delay: 0.1s) {
  animation: $name $duration ease-out;
  animation-delay: $delay;
  animation-fill-mode: both;
}

// Budget-aware animations (simple on low-end devices)
@mixin progressive-animation(
  $simple-animation,
  $complex-animation,
  $duration: 0.4s
) {
  // Default: simple animation
  animation: $simple-animation $duration ease-out;
  
  // Enhanced on powerful devices (no standard query yet, pseudo-code)
  @supports (backdrop-filter: blur(10px)) {
    animation: $complex-animation $duration cubic-bezier(0.68, -0.55, 0.265, 1.55);
  }
}

// Limit animation complexity based on number of elements
@mixin scale-animation-complexity($threshold: 20) {
  animation: complexAnimation 0.6s ease-out;
  
  // Simplify if many elements
  &:nth-child(n + #{$threshold}) {
    animation: simpleAnimation 0.3s ease-out;
  }
}

// Container-based performance hints
@mixin contained-animation {
  // Limit repaints to element
  contain: layout style paint;
  
  // Isolate rendering
  isolation: isolate;
  
  // Create stacking context
  position: relative;
  z-index: 0;
}

// Usage
.hero-image {
  @include optimized-animation(zoomIn, 0.8s, ease-out, transform opacity);
}

.tooltip {
  @include debounced-animation(fadeIn, 0.2s, 0.3s);
}

.product-card {
  @include progressive-animation(fadeIn, rotateInWithBounce, 0.5s);
}

.animated-list-item {
  @include scale-animation-complexity(50);
}

.animation-container {
  @include contained-animation;
}

Animation Best Practices

  • Use transform and opacity: GPU-accelerated properties for 60fps animations
  • Avoid layout thrashing: Don't animate width, height, top, left, margin, padding
  • will-change sparingly: Use only when needed, remove after animation
  • Respect reduced motion: Always provide @media (prefers-reduced-motion) fallbacks
  • Keep it short: Animations under 500ms feel snappier; avoid long durations
  • Ease-out for entrances: ease-in for exits, ease-in-out for transitions
  • Stagger for groups: Use delays for sequential animations in lists
  • Hardware acceleration: Use translateZ(0) for smooth performance
Note: Always test animations on lower-end devices. Use transform and opacity exclusively for 60fps performance. Provide meaningful motion with prefers-reduced-motion support for accessibility.