design-to-component-translator について
ビジュアルデザインの仕様を React コンポーネントに変換するスキルです。デザイントークン、操作状態、レスポンシブ対応、アクセシビリティを扱います。
主な機能
- 01デザインの寸法とスタイルを抽出
- 02値をデザイントークンに対応付け
- 03セマンティックな React コンポーネントを生成
- 04操作状態とレスポンシブ状態を実装
- 05アクセシビリティとバリエーションを文書化
活用シーン
- 01Figmaのボタン仕様をReactに変換
- 02デザインレイアウトからレスポンシブなコンポーネントを作成
- 03コンポーネントのバリエーションと表示状態を記録
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ patricio0312rev/ skills --skill design-to-component-translatorインストール後、Claude Code で/design-to-component-translatorを入力して読み込まれたか確認します。
詳細
デザインからコンポーネントへの変換
デザイン仕様を、ピクセル単位で正確な本番環境向け React コンポーネントに変換します。
基本的なワークフロー
- デザイン仕様を分析する:余白、色、タイポグラフィ、寸法を抽出します
- トークンに対応付ける:デザイン値をデザインシステムのトークンに変換します
- 構造を生成する:セマンティックな HTML 構造を作成します
- スタイルを適用する:正確な寸法で Tailwind/CSS を実装します
- 状態を追加する:ホバー、フォーカス、アクティブ、無効の各状態を含めます
- レスポンシブに対応する:ブレークポイントごとのルールを実装します
- アクセシビリティを確保する:ARIA ラベルとキーボードナビゲーションを追加します
- バリエーションを記述する:すべての表示状態と props を列挙します
デザイン仕様の分析
Figma/デザインから抽出する内容
余白とレイアウト:
- パディング:
p-4(16px)、px-6(水平方向に24px) - マージン:
m-2(8px)、mt-4(上方向に16px) - ギャップ:
gap-3(flex アイテム間に12px) - 幅/高さ:
w-64(256px)、h-10(40px)
タイポグラフィ:
- フォントファミリー:
font-sans、font-mono - フォントサイズ:
text-sm(14px)、text-base(16px)、text-lg(18px) - フォントウェイト:
font-normal(400)、font-medium(500)、font-semibold(600) - 行の高さ:
leading-tight、leading-normal、leading-relaxed - 文字間隔:
tracking-tight、tracking-normal、tracking-wide
色:
- 背景:
bg-blue-500、bg-gray-100 - テキスト:
text-gray-900、text-white - 枠線:
border-gray-300、border-blue-600 - 不透明度:
bg-opacity-50、text-opacity-75
枠線と角丸:
- 枠線の幅:
border、border-2、border-t-4 - 枠線の角丸:
rounded(4px)、rounded-md(6px)、rounded-lg(8px)、rounded-full
シャドウ:
shadow-sm、shadow、shadow-md、shadow-lg、shadow-xl
デザイントークンへのマッピング
トークンシステムの作成
// tokens.ts
export const tokens = {
colors: {
primary: {
50: "#eff6ff",
100: "#dbeafe",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
},
gray: {
100: "#f3f4f6",
300: "#d1d5db",
500: "#6b7280",
700: "#374151",
900: "#111827",
},
},
spacing: {
xs: "0.25rem", // 4px
sm: "0.5rem", // 8px
md: "1rem", // 16px
lg: "1.5rem", // 24px
xl: "2rem", // 32px
},
fontSize: {
xs: ["0.75rem", { lineHeight: "1rem" }],
sm: ["0.875rem", { lineHeight: "1.25rem" }],
base: ["1rem", { lineHeight: "1.5rem" }],
lg: ["1.125rem", { lineHeight: "1.75rem" }],
xl: ["1.25rem", { lineHeight: "1.75rem" }],
},
borderRadius: {
sm: "0.25rem", // 4px
md: "0.375rem", // 6px
lg: "0.5rem", // 8px
full: "9999px",
},
shadows: {
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
md: "0 4px 6px -1px rgb(0 0 0 / 0.1)",
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1)",
},
};
Tailwind の設定
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: "#eff6ff",
100: "#dbeafe",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
},
},
spacing: {
18: "4.5rem",
88: "22rem",
},
fontSize: {
"2xs": "0.625rem",
},
},
},
};
コンポーネント変換の例
Figma 仕様からボタンを作成する
Figma の仕様:
- 高さ:40px
- パディング:12px 24px
- 枠線の角丸:6px
- フォント:Inter Medium 14px
- 背景:#3B82F6
- テキスト:#FFFFFF
- ホバー:#2563EB
- シャドウ:0 1px 3px rgba(0,0,0,0.1)
変換後のコンポーネント:
import { cn } from "@/lib/utils";
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
size?: "sm" | "md" | "lg";
}
export const Button = ({
variant = "primary",
size = "md",
className,
children,
...props
}: ButtonProps) => {
return (
<button
className={cn(
// Base styles
"inline-flex items-center justify-center rounded-md font-medium",
"transition-colors duration-200",
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2",
"disabled:pointer-events-none disabled:opacity-50",
// Variant: Primary (matches Figma)
variant === "primary" && [
"bg-primary-500 text-white shadow-sm",
"hover:bg-primary-600",
"active:bg-primary-700",
],
// Size: Medium (40px height, 12px 24px padding)
size === "md" && "h-10 px-6 text-sm",
className
)}
{...props}
>
{children}
</button>
);
};
デザイン仕様からカードを作成する
Figma の仕様:
- パディング:24px
- 枠線の角丸:12px
- 背景:#FFFFFF
- 枠線:1px solid #E5E7EB
- シャドウ:0 1px 3px rgba(0,0,0,0.1)
- 最大幅:400px
変換後のコンポーネント:
interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
elevated?: boolean;
}
export const Card = ({
elevated = false,
className,
children,
...props
}: CardProps) => {
return (
<div
className={cn(
// Base from Figma
"max-w-sm rounded-xl bg-white p-6",
"border border-gray-200",
// Conditional shadow
elevated ? "shadow-lg" : "shadow-sm",
// Hover state (not in Figma, but good UX)
"transition-shadow duration-200 hover:shadow-md",
className
)}
{...props}
>
{children}
</div>
);
};
インタラクションの状態
ホバー状態
// Figma: Background changes from #3B82F6 to #2563EB on hover
className={cn(
'bg-primary-500',
'hover:bg-primary-600',
'transition-colors duration-200'
)}
フォーカス状態
// Accessible focus ring
className={cn(
'focus:outline-none',
'focus-visible:ring-2 focus-visible:ring-primary-500 focus-visible:ring-offset-2'
)}
アクティブ/押下状態
// Figma: Slightly darker on click
className={cn(
'active:bg-primary-700',
'active:scale-[0.98]', // Slight scale down
'transition-all duration-100'
)}
無効状態
// Figma: 50% opacity, no interactions
className={cn(
'disabled:opacity-50',
'disabled:cursor-not-allowed',
'disabled:pointer-events-none'
)}
レスポンシブデザインへの変換
ブレークポイントのマッピング
// Figma artboards → Tailwind breakpoints
// Mobile (375px): default (no prefix)
// Tablet (768px): md:
// Desktop (1024px): lg:
// Wide (1280px): xl:
<div
className={cn(
// Mobile: Stack vertically, full width
"flex flex-col gap-4 w-full",
// Tablet: Side by side, 50% each
"md:flex-row md:gap-6",
// Desktop: Max width container
"lg:max-w-6xl lg:mx-auto"
)}
/>
レスポンシブタイポグラフィ
// Figma mobile: 14px, desktop: 16px
<h1 className="text-sm md:text-base lg:text-lg font-semibold">
Responsive Heading
</h1>
レスポンシブな余白
// Figma mobile: 16px padding, desktop: 24px
<div className="p-4 md:p-6 lg:p-8">Content</div>
デザインシステムとの統合
shadcn/ui のパターンを使用する
// Leveraging shadcn's composable approach
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "underline-offset-4 hover:underline text-primary",
},
size: {
default: "h-10 py-2 px-4",
sm: "h-9 px-3 rounded-md",
lg: "h-11 px-8 rounded-md",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
カラーシステムへの変換
Figma から CSS 変数へ
/* Figma colors → CSS variables */
:root {
/* Primary from Figma #3B82F6 */
--primary: 221 83% 60%;
--primary-foreground: 0 0% 100%;
/* Secondary from Figma #6B7280 */
--secondary: 220 9% 46%;
--secondary-foreground: 0 0% 100%;
/* Backgrounds */
--background: 0 0% 100%;
--foreground: 222 47% 11%;
/* Borders */
--border: 220 13% 91%;
--input: 220 13% 91%;
--ring: 221 83% 60%;
/* Radius from Figma */
--radius: 0.5rem;
}
コンポーネントでの使用
<div className="bg-background text-foreground border-border">
<button className="bg-primary text-primary-foreground">Button</button>
</div>
アニメーションとトランジション
Figma のマイクロインタラクション
// Figma: Button scales slightly on hover
<button className={cn(
'transition-all duration-200',
'hover:scale-105',
'active:scale-95'
)}>
Hover me
</button>
// Figma: Card lifts on hover
<div className={cn(
'transition-all duration-300',
'hover:-translate-y-1 hover:shadow-lg'
)}>
Card content
</div>
// Figma: Fade in on mount
<div className="animate-in fade-in duration-500">
Fading content
</div>
寸法の変換
Figma のピクセル → Tailwind クラス
| Figma | Tailwind | 値 |
|---|---|---|
| 2px | 0.5 | 0.125rem |
| 4px | 1 | 0.25rem |
| 8px | 2 | 0.5rem |
| 12px | 3 | 0.75rem |
| 16px | 4 | 1rem |
| 20px | 5 | 1.25rem |
| 24px | 6 | 1.5rem |
| 32px | 8 | 2rem |
| 40px | 10 | 2.5rem |
| 48px | 12 | 3rem |
カスタム値
// Figma: 18px (not in default Tailwind)
<div className="w-[18px] h-[18px]">{/* or add to config */}</div>
アクセシビリティへのマッピング
ビジュアルデザインからアクセシビリティへ
// Figma shows disabled state
<button
disabled={isDisabled}
aria-disabled={isDisabled}
className={cn(
isDisabled && 'opacity-50 cursor-not-allowed'
)}
>
Submit
</button>
// Figma shows error state
<input
aria-invalid={hasError}
aria-describedby={hasError ? 'error-message' : undefined}
className={cn(
hasError && 'border-red-500 focus:ring-red-500'
)}
/>
よく使われるパターン
フォーム入力の変換
Figma の仕様:
- 高さ:44px
- パディング:12px 16px
- 枠線:1px #D1D5DB
- 枠線の角丸:8px
- フォーカス時の枠線:2px #3B82F6
<input
className={cn(
"h-11 w-full rounded-lg border border-gray-300 px-4",
"text-base text-gray-900 placeholder:text-gray-500",
"focus:border-primary-500 focus:ring-2 focus:ring-primary-500 focus:ring-offset-0",
"disabled:cursor-not-allowed disabled:opacity-50"
)}
/>
アイコンボタンの変換
Figma の仕様:
- サイズ:40x40px
- アイコン:20x20px、中央揃え
- 枠線の角丸:8px
- ホバー時の背景:#F3F4F6
<button
className={cn(
"flex h-10 w-10 items-center justify-center rounded-lg",
"text-gray-700 transition-colors",
"hover:bg-gray-100",
"focus-visible:ring-2 focus-visible:ring-primary-500"
)}
>
<Icon className="h-5 w-5" />
</button>
ベストプラクティス
- 二度測る:すべての寸法がFigmaと完全に一致していることを確認します
- デザイントークンを使用する:ハードコードされた値ではなく、トークンにマッピングします
- すべての状態に対応する:ホバー、フォーカス、アクティブ、無効、エラーを含めます
- レスポンシブにする:デザインにあるすべてのブレークポイントを実装します
- アクセシビリティ:Figmaに状態が示されている場合はARIAを追加します
- アニメーション:トランジションのタイミングをデザインに合わせます
- ダークモード:デザインがある場合は、クラスバリアントを使用して実装します
- コンポーネントバリアント:再利用可能なバリアント用のpropsを作成します
- ドキュメント:デザインからの逸脱があれば記録します
- レビュー:実装についてデザイナーの承認を得ます
出力チェックリスト
デザインからコンポーネントへの変換には、次の項目をすべて含めてください。
- Figmaの寸法に正確に一致する間隔
- タイポグラフィのスケールとウェイト
- デザインシステムのすべての色の値
- 角丸とシャドウ
- ホバー状態のスタイル
- フォーカス状態のスタイル(アクセシブル)
- アクティブ/押下状態のスタイル
- 無効状態のスタイル
- レスポンシブブレークポイントのルール
- デザイントークンのマッピングに関するドキュメント
- アクセシビリティ属性
- 状態に応じたコンポーネントバリアント
コメント
Markdown 対応