figma-integration

تبدیل پروتوتایپ‌های Figma به انیمیشن‌های production-ready و توکن‌های موشن هماهنگ

این Skill جریان کاری تبدیل پروتوتایپ‌های Figma به کد انیمیشن را پوشش می‌دهد؛ از تحلیل transitionها و variantها تا نگاشت Smart Animate به CSS و Framer Motion.

همچنین به شما کمک می‌کند متغیرها و styleهای موشن را به توکن‌های قابل‌استفاده در کد تبدیل کنید، Motion Spec بسازید و handoff منظم‌تری با تیم طراحی داشته باشید.

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

  • نگاشت Figma Variables به motion tokens برای duration و easing
  • تحلیل prototype transitionها، triggerها و propertyهای متحرک
  • تولید نمونه کد CSS و Framer Motion از تفاوت stateها
  • تبدیل Figma variants و interactionها به stateهای قابل‌استفاده در React
  • چک‌لیست handoff، naming convention و ملاحظات reduced motion

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

  • تیم‌های محصولی که می‌خواهند انیمیشن‌های Figma را به کد frontend منتقل کنند
  • طراحان و توسعه‌دهندگانی که design token و motion system مشترک می‌سازند
  • پروژه‌هایی با component stateهای متعدد مانند hover، pressed و disabled

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

  • ساخت انیمیشن‌های کاملاً مستقل از Figma یا طراحی موشن سینمایی پیچیده
  • پروژه‌هایی که به همگام‌سازی tokenها یا تحلیل prototype نیاز ندارند

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

Figma Integration

Workflows for translating Figma designs to production motion code.

Design Token Mapping

Figma Variables → Motion Tokens

Figma VariableMotion TokenType
duration/shortmotion.duration.short-4Duration
duration/mediummotion.duration.medium-2Duration
easing/standardmotion.easing.standardEasing
easing/emphasizedmotion.easing.emphasized-decelerateEasing

Export Variables to JSON

// Figma plugin code
function exportMotionVariables() {
  const collection = figma.variables.getLocalVariableCollections()
    .find(c => c.name === 'Motion');

  const tokens = {};

  collection.variableIds.forEach(id => {
    const variable = figma.variables.getVariableById(id);
    const value = variable.valuesByMode[Object.keys(variable.valuesByMode)[0]];

    tokens[variable.name] = {
      $value: value,
      $type: getTokenType(variable.resolvedType),
      $description: variable.description
    };
  });

  return tokens;
}

Token Sync Script

// sync-figma-tokens.js
const FigmaAPI = require('figma-api');

async function syncMotionTokens(fileKey) {
  const api = new FigmaAPI({ personalAccessToken: process.env.FIGMA_TOKEN });

  const file = await api.getFile(fileKey);
  const styles = file.styles;

  // Extract motion-related styles
  const motionTokens = Object.entries(styles)
    .filter(([_, style]) => style.name.startsWith('motion/'))
    .reduce((acc, [key, style]) => {
      acc[style.name] = parseMotionStyle(style);
      return acc;
    }, {});

  // Write to tokens file
  fs.writeFileSync(
    './tokens/figma-motion.tokens.json',
    JSON.stringify(motionTokens, null, 2)
  );
}

Prototype Animation Analysis

Reading Prototype Transitions

// Figma plugin - analyze prototype connections
function analyzePrototypeAnimations() {
  const page = figma.currentPage;
  const flows = page.flowStartingPoints;

  const animations = [];

  // Walk through prototype connections
  page.findAll(node => {
    if (node.reactions) {
      node.reactions.forEach(reaction => {
        if (reaction.action?.type === 'NODE' && reaction.action.transition) {
          animations.push({
            trigger: reaction.trigger.type,
            from: node.name,
            to: reaction.action.destinationId,
            transition: {
              type: reaction.action.transition.type,
              duration: reaction.action.transition.duration,
              easing: mapFigmaEasing(reaction.action.transition.easing)
            }
          });
        }
      });
    }
  });

  return animations;
}

function mapFigmaEasing(figmaEasing) {
  const easingMap = {
    'EASE_IN': 'ease-in',
    'EASE_OUT': 'ease-out',
    'EASE_IN_AND_OUT': 'ease-in-out',
    'LINEAR': 'linear',
    'CUSTOM_BEZIER': figmaEasing.easingFunctionCubicBezier
  };
  return easingMap[figmaEasing.type] || 'ease';
}

Generate Motion Spec

// Convert Figma prototype to motion spec
function generateMotionSpec(prototypeData) {
  return {
    $schema: 'motion-spec/1.0',
    name: prototypeData.from,
    trigger: prototypeData.trigger,
    animation: {
      type: prototypeData.transition.type,
      duration: `${prototypeData.transition.duration}ms`,
      easing: prototypeData.transition.easing,
      properties: inferAnimatedProperties(prototypeData)
    }
  };
}

Smart Animate Translation

Figma Smart Animate → CSS

Figma PropertyCSS Property
X, Ytransform: translate()
Width, Heightwidth, height (avoid if possible)
Rotationtransform: rotate()
Opacityopacity
Fillbackground-color
Strokeborder-color
Corner Radiusborder-radius

Code Generation

// Generate CSS from Figma state diff
function generateCSSTransition(fromState, toState, transition) {
  const changes = diffStates(fromState, toState);
  const properties = changes.map(c => c.cssProperty);

  return `
.element {
  transition: ${properties.join(', ')} ${transition.duration}ms ${transition.easing};
}

.element.active {
  ${changes.map(c => `${c.cssProperty}: ${c.toValue};`).join('\n  ')}
}
`;
}

// Generate Framer Motion
function generateFramerMotion(fromState, toState, transition) {
  const changes = diffStates(fromState, toState);

  return `
const variants = {
  initial: {
    ${changes.map(c => `${c.framerProperty}: ${c.fromValue}`).join(',\n    ')}
  },
  animate: {
    ${changes.map(c => `${c.framerProperty}: ${c.toValue}`).join(',\n    ')}
  }
};

<motion.div
  variants={variants}
  initial="initial"
  animate="animate"
  transition={{
    duration: ${transition.duration / 1000},
    ease: ${JSON.stringify(transition.easing)}
  }}
/>
`;
}

Interactive Component States

Mapping Figma Variants to Code

// Figma component variants
const figmaVariants = {
  'State=Default': { scale: 1, opacity: 1 },
  'State=Hover': { scale: 1.02, opacity: 1 },
  'State=Pressed': { scale: 0.98, opacity: 0.9 },
  'State=Disabled': { scale: 1, opacity: 0.5 }
};

// Generated Framer Motion variants
const motionVariants = {
  default: { scale: 1, opacity: 1 },
  hover: { scale: 1.02, opacity: 1 },
  pressed: { scale: 0.98, opacity: 0.9 },
  disabled: { scale: 1, opacity: 0.5 }
};

// With transitions
const transitions = {
  default: { type: 'spring', damping: 20, stiffness: 300 },
  hover: { duration: 0.2 },
  pressed: { duration: 0.1 },
  disabled: { duration: 0.3 }
};

Interaction Triggers

// Map Figma triggers to React events
const triggerMap = {
  'ON_CLICK': 'onClick',
  'ON_HOVER': 'onHoverStart',
  'MOUSE_ENTER': 'onMouseEnter',
  'MOUSE_LEAVE': 'onMouseLeave',
  'ON_PRESS': 'onTapStart',
  'ON_DRAG': 'onDrag'
};

Plugin Workflow

Design Handoff Plugin

// Figma plugin UI
figma.showUI(__html__, { width: 400, height: 500 });

figma.ui.onmessage = async (msg) => {
  if (msg.type === 'export-motion') {
    const selection = figma.currentPage.selection;

    const motionData = selection.map(node => ({
      name: node.name,
      states: extractStates(node),
      transitions: extractTransitions(node),
      tokens: extractUsedTokens(node)
    }));

    figma.ui.postMessage({
      type: 'motion-data',
      data: motionData
    });
  }
};

Lottie Export

// Export Figma animation to Lottie
// Requires bodymovin-like plugin or LottieFiles integration

async function exportToLottie(frameId) {
  // Use Figma's exportAsync for frames
  const frame = figma.getNodeById(frameId);

  // For complex animations, use LottieFiles plugin
  // or manually construct Lottie JSON from Figma data

  const lottieData = {
    v: '5.7.4',
    fr: 60,
    ip: 0,
    op: 60,
    w: frame.width,
    h: frame.height,
    layers: convertFigmaLayersToLottie(frame.children)
  };

  return lottieData;
}

Best Practices

Design System Setup

  1. Create Motion Variable Collection in Figma
  2. Define duration variables: short, medium, long
  3. Define easing presets: standard, emphasized, accelerate
  4. Document in component library

Handoff Checklist

  • ☐ All transitions use motion variables
  • ☐ States are clearly named (Default, Hover, Active, etc.)
  • ☐ Prototype connections documented
  • ☐ Reduced motion alternatives specified
  • ☐ Motion spec exported

Naming Conventions

motion/duration/short-1
motion/duration/short-2
motion/duration/medium-1
motion/easing/standard
motion/easing/emphasized-decelerate
motion/spring/fast
motion/spring/default

Related Skills

  • Dependencies: easing, duration, motion-specs
  • See also: code-generation, storyboarding, tools
  • Integrations: Figma, FigJam, Figma Tokens

دانلود ZIP