stylization

برای هر برند، یک زبان حرکتی منسجم با presetهای حرفه‌ای بسازید.

این skill مجموعه‌ای از presetهای موشن برای سبک‌های vintage، minimalist، brutalist، organic، playful، elegant، glitch، retro-game و cinematic ارائه می‌دهد. پارامترهای timing، easing، bounce، wobble، grain، flicker و distortion را برای ساخت یک زبان حرکتی یکپارچه تنظیم می‌کند.

با استفاده از tokens/stylization.tokens.json می‌توانید این سبک‌ها را در CSS، JavaScript، Framer Motion و Remotion پیاده‌سازی کنید. راهنمای انتخاب سبک، نمونه‌کد آماده، پشتیبانی از prefers-reduced-motion و ارجاع به استانداردهایی مثل W3C Design Tokens و Material Design 3، این skill را برای پروژه‌های برندمحور و رابط‌های متحرک کاربردی می‌کند.

چه چیزی می‌گیرید

  • presetهای آماده برای ۹ سبک حرکتی و هنری متفاوت
  • پارامترهای منسجم برای duration، easing، spring، overshoot و شدت افکت
  • نمونه‌کدهای CSS، JavaScript، Framer Motion و Remotion
  • راهنمای انتخاب سبک بر اساس حال‌وهوا، برند و نوع محصول
  • الگوهای دسترس‌پذیر برای کاهش یا حذف حرکت با `prefers-reduced-motion`

برای چه کاری خوب است

  • طراحان و توسعه‌دهندگانی که برای یک محصول دیجیتال زبان حرکتی برندمحور می‌سازند
  • پروژه‌هایی که به انیمیشن‌های themed، هویت بصری متحرک یا انتقال‌های هماهنگ نیاز دارند
  • ساخت رابط‌های playful، glitch، retro، مینیمال یا سینمایی در وب و ویدیو

برای چه کاری نیست

  • پروژه‌هایی که فقط به یک انیمیشن ساده و بدون سبک بصری مشخص نیاز دارند
  • تحلیل UX motion یا طراحی کامل interaction بدون اجرای فنی
  • افکت‌های پیچیده تخصصی که به سیستم‌های جداگانه برای particle، distortion یا physics نیاز دارند

دربارهٔ این اسکیل

Stylization

Cohesive artistic motion styles for themed animation systems.

Standards Reference

StandardDocumentation
W3C DTCGdesigntokens.org
Material Design 3m3.material.io/styles/motion
IBM Carbon Motioncarbondesignsystem.com/guidelines/motion
Apple HIGdeveloper.apple.com/design/human-interface-guidelines/motion

Quick Reference

Load from: tokens/stylization.tokens.json

Style Presets

StyleFeelKey Characteristics
vintageNostalgicFilm grain, flicker, low fps
minimalistCleanDeliberate, precise, no overshoot
brutalistBoldFast, linear, jarring steps
organicNaturalNoise, wobble, variance
playfulFunBouncy, squash-stretch
elegantRefinedSlow, blurred, choreographed
glitchDigitalOffset, slicing, chromatic
retro-game8-bitStepped, pixelated
cinematicFilmicMotion blur, letterbox

Selection Guide

What's the brand/mood?
│
├── NOSTALGIC/RETRO
│   ├── Film/photo → vintage (sepia, grain, flicker)
│   ├── 8-bit games → retro-game (stepped, pixelated)
│   └── Digital errors → glitch (offset, chromatic)
│
├── PROFESSIONAL/CORPORATE
│   ├── Clean/modern → minimalist (precise, deliberate)
│   ├── Luxury/premium → elegant (slow, refined)
│   └── Bold/statement → brutalist (fast, linear)
│
├── CREATIVE/EXPRESSIVE
│   ├── Natural/organic → organic (noise, wobble)
│   ├── Fun/energetic → playful (bouncy, squash)
│   └── Dramatic/epic → cinematic (motion blur, slow)
│
└── TECHNICAL/DIGITAL
    ├── Glitch art → glitch (offset, slicing)
    ├── Cyberpunk → glitch + brutalist
    └── Sci-fi → cinematic + minimalist

Patterns

Vintage Style

Retro film aesthetic with grain and flicker.

CSS + JavaScript:

.vintage-container {
  position: relative;
  filter: sepia(0.6) contrast(1.1); /* {motion.stylization.vintage.sepia} */
}

/* Film grain overlay */
.vintage-container::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: url('grain.png');
  opacity: 0.15; /* {motion.stylization.vintage.film-grain} */
  pointer-events: none;
  animation: grain 0.5s steps(4) infinite;
}

/* Vignette */
.vintage-container::after {
  content: '';
  position: absolute;
  inset: 0;
  box-shadow: inset 0 0 100px rgba(0,0,0,0.3); /* {motion.stylization.vintage.vignette} */
  pointer-events: none;
}

@keyframes grain {
  0%, 100% { transform: translate(0, 0); }
  25% { transform: translate(-2%, 2%); }
  50% { transform: translate(2%, -2%); }
  75% { transform: translate(-2%, -2%); }
}

/* Flicker effect */
@keyframes flicker {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.95; } /* {motion.stylization.vintage.flicker-intensity} */
}

.vintage-flicker {
  animation: flicker 0.1s infinite;
}

JavaScript (low framerate simulation):

// Simulate 12fps vintage film
function vintageAnimate(element, props, duration) {
  const fps = 12; // {motion.stylization.vintage.frame-rate}
  const frameTime = 1000 / fps;
  const totalFrames = Math.ceil((duration / 1000) * fps);

  let frame = 0;

  function tick() {
    const progress = frame / totalFrames;

    // Apply interpolated values
    for (const [prop, value] of Object.entries(props)) {
      const current = value.from + (value.to - value.from) * progress;
      element.style[prop] = typeof value.unit === 'string'
        ? `${current}${value.unit}`
        : current;
    }

    frame++;
    if (frame <= totalFrames) {
      setTimeout(tick, frameTime);
    }
  }

  tick();
}

Minimalist Style

Clean, precise motion with deliberate pacing.

Framer Motion:

const minimalistTransition = {
  duration: 0.3 * 1.2, // {motion.stylization.minimalist.duration-multiplier}
  ease: [0.2, 0, 0, 1], // {motion.stylization.minimalist.easing}
};

const MinimalistReveal = ({ children }) => (
  <motion.div
    initial={{ opacity: 0, y: 10 }}
    animate={{ opacity: 1, y: 0 }}
    transition={minimalistTransition}
  >
    {children}
  </motion.div>
);

// Staggered list
const MinimalistList = ({ items }) => (
  <motion.ul>
    {items.map((item, i) => (
      <motion.li
        key={item.id}
        initial={{ opacity: 0, x: -10 }}
        animate={{ opacity: 1, x: 0 }}
        transition={{
          ...minimalistTransition,
          delay: i * 0.1 // {motion.stylization.minimalist.delay-between}
        }}
      >
        {item.content}
      </motion.li>
    ))}
  </motion.ul>
);

CSS:

.minimalist-transition {
  transition: all 360ms cubic-bezier(0.2, 0, 0, 1);
  /* duration * 1.2, M3 standard easing */
}

/* No overshoot, clean endings */
.minimalist-entrance {
  animation: minimalistEnter 360ms cubic-bezier(0.2, 0, 0, 1) forwards;
}

@keyframes minimalistEnter {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Brutalist Style

Bold, aggressive motion with jarring transitions.

CSS:

/* Stepped animation - no smooth interpolation */
.brutalist-enter {
  animation: brutalistSlide 200ms steps(4) forwards;
  /* {motion.stylization.brutalist.step-count} */
}

@keyframes brutalistSlide {
  from {
    transform: translateX(-100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

/* Linear easing - no softening */
.brutalist-transition {
  transition: all 150ms linear; /* {motion.stylization.brutalist.easing} */
}

/* Overshoot snap-back */
@keyframes brutalistSnap {
  0% { transform: scale(0); }
  70% { transform: scale(1.3); } /* {motion.stylization.brutalist.overshoot} */
  100% { transform: scale(1); }
}

.brutalist-snap {
  animation: brutalistSnap 200ms linear forwards;
}

JavaScript (screen shake):

function brutalistShake(element) {
  const intensity = 5; // {motion.stylization.brutalist.shake-intensity}
  const duration = 200;
  const start = performance.now();

  function shake(timestamp) {
    const elapsed = timestamp - start;
    const progress = elapsed / duration;

    if (progress < 1) {
      const decay = 1 - progress;
      const x = (Math.random() - 0.5) * 2 * intensity * decay;
      const y = (Math.random() - 0.5) * 2 * intensity * decay;
      element.style.transform = `translate(${x}px, ${y}px)`;
      requestAnimationFrame(shake);
    } else {
      element.style.transform = '';
    }
  }

  requestAnimationFrame(shake);
}

Organic Style

Natural motion with subtle randomness.

JavaScript:

class OrganicMotion {
  constructor(element, options = {}) {
    this.element = element;
    this.amplitude = options.amplitude || 3; // {motion.stylization.organic.noise-amplitude}
    this.frequency = options.frequency || 0.5; // {motion.stylization.organic.noise-frequency}
    this.rotationWobble = options.rotation || 2; // {motion.stylization.organic.rotation-wobble}

    this.time = Math.random() * 1000;
    this.animate();
  }

  noise(t) {
    // Simplified Perlin-like noise
    return Math.sin(t) * 0.5 + Math.sin(t * 2.3) * 0.3 + Math.sin(t * 5.7) * 0.2;
  }

  animate() {
    this.time += 0.016 * this.frequency;

    const x = this.noise(this.time) * this.amplitude;
    const y = this.noise(this.time + 100) * this.amplitude;
    const rotation = this.noise(this.time + 200) * this.rotationWobble;

    this.element.style.transform = `translate(${x}px, ${y}px) rotate(${rotation}deg)`;

    requestAnimationFrame(() => this.animate());
  }
}

// Usage
const organicElement = new OrganicMotion(document.querySelector('.organic'));

Framer Motion:

const OrganicFloat = () => {
  const [position, setPosition] = useState({ x: 0, y: 0, rotate: 0 });

  useEffect(() => {
    const interval = setInterval(() => {
      setPosition({
        x: (Math.random() - 0.5) * 6, // ±3px
        y: (Math.random() - 0.5) * 6,
        rotate: (Math.random() - 0.5) * 4 // ±2deg
      });
    }, 2000);
    return () => clearInterval(interval);
  }, []);

  return (
    <motion.div
      animate={position}
      transition={{
        duration: 2,
        ease: [0.4, 0, 0.2, 1] // {motion.stylization.organic.easing}
      }}
    />
  );
};

Playful Style

Bouncy, energetic motion with squash-stretch.

Framer Motion:

const playfulSpring = {
  type: 'spring',
  stiffness: 300, // {motion.stylization.playful.spring-stiffness}
  damping: 12, // {motion.stylization.playful.spring-damping}
};

const PlayfulButton = ({ children, onClick }) => (
  <motion.button
    whileHover={{ scale: 1.05 }}
    whileTap={{ scale: 0.95 }}
    transition={playfulSpring}
    onClick={onClick}
  >
    {children}
  </motion.button>
);

// With squash-stretch
const BouncyBall = () => (
  <motion.div
    animate={{ y: [0, 100, 0] }}
    transition={{
      duration: 0.6,
      repeat: Infinity,
      ease: [0.36, 0, 0.66, -0.56] // Custom bounce
    }}
    style={{ transformOrigin: 'bottom' }}
  >
    <motion.div
      animate={{
        scaleY: [1, 0.85, 1.15, 1], // Squash-stretch
        scaleX: [1, 1.15, 0.85, 1]
      }}
      transition={{
        duration: 0.6,
        repeat: Infinity,
        times: [0, 0.5, 0.55, 1]
      }}
    />
  </motion.div>
);

Glitch Style

Digital distortion and chromatic effects.

CSS:

.glitch-container {
  position: relative;
}

/* RGB split */
.glitch-text {
  position: relative;
}

.glitch-text::before,
.glitch-text::after {
  content: attr(data-text);
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}

.glitch-text::before {
  color: cyan;
  left: 3px; /* {motion.stylization.glitch.chromatic-offset} */
  animation: glitchLeft 0.1s infinite linear alternate-reverse;
  mix-blend-mode: multiply;
}

.glitch-text::after {
  color: magenta;
  left: -3px;
  animation: glitchRight 0.1s infinite linear alternate-reverse;
  mix-blend-mode: multiply;
}

@keyframes glitchLeft {
  0% { clip-path: inset(20% 0 60% 0); }
  20% { clip-path: inset(40% 0 10% 0); }
  40% { clip-path: inset(60% 0 30% 0); }
  60% { clip-path: inset(10% 0 80% 0); }
  80% { clip-path: inset(50% 0 20% 0); }
  100% { clip-path: inset(30% 0 50% 0); }
}

@keyframes glitchRight {
  0% { clip-path: inset(60% 0 20% 0); }
  20% { clip-path: inset(10% 0 40% 0); }
  40% { clip-path: inset(30% 0 60% 0); }
  60% { clip-path: inset(80% 0 10% 0); }
  80% { clip-path: inset(20% 0 50% 0); }
  100% { clip-path: inset(50% 0 30% 0); }
}

JavaScript (random glitch):

function glitchEffect(element) {
  const frequency = 3; // {motion.stylization.glitch.frequency}
  const duration = 100; // {motion.stylization.glitch.duration}

  setInterval(() => {
    if (Math.random() < 0.3) {
      const offsetX = (Math.random() - 0.5) * 20; // {motion.stylization.glitch.offset-x}
      const offsetY = (Math.random() - 0.5) * 10; // {motion.stylization.glitch.offset-y}

      element.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
      element.style.filter = `hue-rotate(${Math.random() * 360}deg)`;

      setTimeout(() => {
        element.style.transform = '';
        element.style.filter = '';
      }, duration);
    }
  }, 1000 / frequency);
}

Remotion Implementation

import { useCurrentFrame, interpolate, Easing } from 'remotion';

// Vintage style composition
export const VintageStyle: React.FC = () => {
  const frame = useCurrentFrame();

  // Film grain animation
  const grainOffset = frame % 4;

  // Subtle flicker
  const flicker = 1 - (Math.random() * 0.05); // {motion.stylization.vintage.flicker-intensity}

  return (
    <div style={{
      filter: `sepia(0.6) contrast(1.1) brightness(${flicker})`,
      position: 'relative'
    }}>
      {/* Grain overlay */}
      <div style={{
        position: 'absolute',
        inset: 0,
        backgroundImage: 'url(grain.png)',
        backgroundPosition: `${grainOffset * 25}% ${grainOffset * 25}%`,
        opacity: 0.15,
        mixBlendMode: 'overlay'
      }} />

      {/* Content */}
      {/* ... */}

      {/* Vignette */}
      <div style={{
        position: 'absolute',
        inset: 0,
        boxShadow: 'inset 0 0 100px rgba(0,0,0,0.3)'
      }} />
    </div>
  );
};

Reduced Motion

For prefers-reduced-motion: reduce:

Full StyleReduced Alternative
Vintage flickerStatic sepia filter
Organic wobbleNo motion, static position
Glitch effectsDisabled entirely
Playful bounceSimple scale or no effect

Implementation:

@media (prefers-reduced-motion: reduce) {
  .vintage-flicker,
  .organic-wobble,
  .glitch-text::before,
  .glitch-text::after {
    animation: none;
  }

  .playful-bounce {
    transition: transform 0.1s ease-out;
  }

  .playful-bounce:hover {
    transform: scale(1.02);
  }
}

Cross-References

  • See color/ for color grading within styles
  • See distortion/ for glitch effect details
  • See blur/ for motion blur in cinematic style
  • See easing/ for style-specific timing curves
  • See particles/ for styled particle effects
  • See typography/ for text animation styles

References

  • No additional references needed for this skill

دانلود ZIP