design-system-patterns
デザイントークン、テーマインフラ、コンポーネントアーキテクチャパターンを活用して、スケーラブルなデザインシステムを構築します。デザイントークンの作成、テーマ切り替えの実装、コンポーネントライブラリの構築、またはデザインシステムの基盤確立が必要な際に使用してください。
description の原文を見る
Build scalable design systems with design tokens, theming infrastructure, and component architecture patterns. Use when creating design tokens, implementing theme switching, building component libraries, or establishing design system foundations.
SKILL.md 本文
デザインシステムパターン
デザインシステムアーキテクチャをマスターして、Web およびモバイルアプリケーション全体で一貫性があり、保守可能でスケーラブルな UI 基盤を作成しましょう。
このスキルを使う場面
- 色、タイポグラフィ、スペーシング、シャドウのデザイントークンを作成する
- CSS カスタムプロパティでライト/ダークテーマ切り替えを実装する
- マルチブランドのテーミングシステムを構築する
- 一貫性のある API を持つコンポーネントライブラリをアーキテクチャ化する
- Figma トークンを使用したデザイン・ツー・コードワークフローを確立する
- セマンティックトークン階層(プリミティブ、セマンティック、コンポーネント)を作成する
- デザインシステムのドキュメントとガイドラインを設定する
コア機能
1. デザイントークン
- プリミティブトークン(生の値:色、サイズ、フォント)
- セマンティックトークン(文脈的な意味:text-primary、surface-elevated)
- コンポーネントトークン(具体的な使用法:button-bg、card-border)
- トークン命名規則と整理
- マルチプラットフォームトークン生成(CSS、iOS、Android)
2. テーミングインフラストラクチャ
- CSS カスタムプロパティアーキテクチャ
- React のテーマコンテキストプロバイダー
- 動的テーマ切り替え
- システム設定の検出(prefers-color-scheme)
- テーマストレージの永続化
- 縮減モーションと高コントラストモード
3. コンポーネントアーキテクチャ
- 複合コンポーネントパターン
- ポリモーフィックコンポーネント(as プロパティ)
- バリアントとサイズシステム
- スロットベースの構成
- ヘッドレス UI パターン
- スタイルプロパティと応答性バリアント
4. トークンパイプライン
- Figma からコードへの同期
- Style Dictionary 設定
- トークン変換とフォーマット
- トークン更新用の CI/CD 統合
クイックスタート
// CSS カスタムプロパティを使用したデザイントークン
const tokens = {
colors: {
// プリミティブトークン
gray: {
50: "#fafafa",
100: "#f5f5f5",
900: "#171717",
},
blue: {
500: "#3b82f6",
600: "#2563eb",
},
},
// セマンティックトークン(プリミティブを参照)
semantic: {
light: {
"text-primary": "var(--color-gray-900)",
"text-secondary": "var(--color-gray-600)",
"surface-default": "var(--color-white)",
"surface-elevated": "var(--color-gray-50)",
"border-default": "var(--color-gray-200)",
"interactive-primary": "var(--color-blue-500)",
},
dark: {
"text-primary": "var(--color-gray-50)",
"text-secondary": "var(--color-gray-400)",
"surface-default": "var(--color-gray-900)",
"surface-elevated": "var(--color-gray-800)",
"border-default": "var(--color-gray-700)",
"interactive-primary": "var(--color-blue-400)",
},
},
};
キーパターン
パターン 1:トークン階層
/* レイヤー 1:プリミティブトークン(生の値) */
:root {
--color-blue-500: #3b82f6;
--color-blue-600: #2563eb;
--color-gray-50: #fafafa;
--color-gray-900: #171717;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-4: 1rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 1rem;
}
/* レイヤー 2:セマンティックトークン(意味) */
:root {
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-600);
--surface-default: white;
--interactive-primary: var(--color-blue-500);
--interactive-primary-hover: var(--color-blue-600);
}
/* レイヤー 3:コンポーネントトークン(具体的な使用法) */
:root {
--button-bg: var(--interactive-primary);
--button-bg-hover: var(--interactive-primary-hover);
--button-text: white;
--button-radius: var(--radius-md);
--button-padding-x: var(--space-4);
--button-padding-y: var(--space-2);
}
パターン 2:React でのテーマ切り替え
import { createContext, useContext, useEffect, useState } from "react";
type Theme = "light" | "dark" | "system";
interface ThemeContextValue {
theme: Theme;
resolvedTheme: "light" | "dark";
setTheme: (theme: Theme) => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>(() => {
if (typeof window !== "undefined") {
return (localStorage.getItem("theme") as Theme) || "system";
}
return "system";
});
const [resolvedTheme, setResolvedTheme] = useState<"light" | "dark">("light");
useEffect(() => {
const root = document.documentElement;
const applyTheme = (isDark: boolean) => {
root.classList.remove("light", "dark");
root.classList.add(isDark ? "dark" : "light");
setResolvedTheme(isDark ? "dark" : "light");
};
if (theme === "system") {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
applyTheme(mediaQuery.matches);
const handler = (e: MediaQueryListEvent) => applyTheme(e.matches);
mediaQuery.addEventListener("change", handler);
return () => mediaQuery.removeEventListener("change", handler);
} else {
applyTheme(theme === "dark");
}
}, [theme]);
useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);
return (
<ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
{children}
</ThemeContext.Provider>
);
}
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) throw new Error("useTheme must be used within ThemeProvider");
return context;
};
パターン 3:CVA を使用したバリアントシステム
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
// ベーススタイル
"inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50",
{
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 bg-background 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: "text-primary underline-offset-4 hover:underline",
},
size: {
sm: "h-9 px-3 text-sm",
md: "h-10 px-4 text-sm",
lg: "h-11 px-8 text-base",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
},
);
interface ButtonProps
extends
React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean;
}
export function Button({ className, variant, size, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
パターン 4:Style Dictionary 設定
// style-dictionary.config.js
module.exports = {
source: ["tokens/**/*.json"],
platforms: {
css: {
transformGroup: "css",
buildPath: "dist/css/",
files: [
{
destination: "variables.css",
format: "css/variables",
options: {
outputReferences: true, // トークン参照を保持
},
},
],
},
scss: {
transformGroup: "scss",
buildPath: "dist/scss/",
files: [
{
destination: "_variables.scss",
format: "scss/variables",
},
],
},
ios: {
transformGroup: "ios-swift",
buildPath: "dist/ios/",
files: [
{
destination: "DesignTokens.swift",
format: "ios-swift/class.swift",
className: "DesignTokens",
},
],
},
android: {
transformGroup: "android",
buildPath: "dist/android/",
files: [
{
destination: "colors.xml",
format: "android/colors",
filter: { attributes: { category: "color" } },
},
],
},
},
};
ベストプラクティス
- 目的でトークンに名前を付ける:ビジュアルな説明(dark-gray)ではなくセマンティック名(text-primary)を使用する
- トークン階層を維持する:プリミティブ > セマンティック > コンポーネントトークン
- トークン使用法を記述する:トークン定義に使用ガイドラインを含める
- トークンをバージョン管理する:トークン変更を semver を使用した API 変更として扱う
- テーマの組み合わせをテストする:すべてのテーマがすべてのコンポーネントで機能することを確認する
- トークンパイプラインを自動化する:Figma からコードへの同期用の CI/CD
- 移行パスを提供する:明確な代替案を示してトークンを段階的に廃止する
一般的な問題
- トークンの拡散:明確な階層がない多すぎるトークン
- 命名の不一貫性:混合された命名規則(camelCase vs kebab-case)
- ダークモードの欠落:テーマ変更に対応しないトークン
- ハードコードされた値:トークンの代わりに生の値を使用する
- 循環参照:トークンがループで相互に参照している
- プラットフォーム間のギャップ:一部のプラットフォーム(Web だけでなくモバイルも)でトークンが欠落している
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- wshobson
- リポジトリ
- wshobson/agents
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/wshobson/agents / ライセンス: MIT
関連スキル
nano-banana-2
inference.sh CLIを通じてGoogle Gemini 3.1 Flash Image Preview(Nano Banana 2)で画像を生成します。テキストから画像を生成する機能、画像編集、最大14枚の複数画像入力、Google Searchグラウンディング機能に対応しています。トリガーワード:「nano banana 2」「nanobanana 2」「gemini 3.1 flash image」「gemini 3 1 flash image preview」「google image generation」
octocode-slides
洗練されたマルチファイル形式のHTMLプレゼンテーションを生成します。6段階のフロー(概要 → リサーチ → アウトライン → デザイン → 実装 → レビュー)で構成されています。各スライドは独立したHTMLファイルとなり、iframeで読み込まれます。「スライドを作成してほしい」「プレゼンテーションを作ってほしい」「HTMLスライドを生成してほしい」「デックを構築してほしい」といった依頼や、ノート・ドキュメント・コードを洗練されたプレゼンテーションに変換する際に使用できます。
gpt-image2-ppt
OpenAIのgpt-image-2を使用して、視覚的に優れたPPTスライドを生成します。Spatial Glass、Tech Blue、Editorial Monoなど10種類のキュレーション済みスタイルに対応し、ユーザーが提供したPPTXファイルを模倣するテンプレートクローンモードも搭載しています。HTMLビューアと16:9形式のPPTXファイルを出力します。プレゼンテーション、スライド、ピッチデック、投資家向けPPT、雑誌風PPTの作成依頼などで活用してください。
nano-banana
Nano Banana PRO(Gemini 3 Pro Image)およびNano Banana(Gemini 2.5 Flash Image)を使用したAI画像生成機能です。以下の場合に活用できます:(1)テキストプロンプトからの画像生成、(2)既存画像の編集、(3)インフォグラフィックス、ロゴ、商品写真、ステッカーなどのプロフェッショナルなビジュアルアセット制作、(4)複数画像での人物キャラクターの一貫性保持、(5)正確なテキスト描画を含む画像生成、(6)AI生成ビジュアルが必要なあらゆるタスク。「画像を生成」「画像を作成」「写真を作る」「ロゴをデザイン」「インフォグラフィックスを作成」「AI画像」「nano banana」またはその他の画像生成リクエストをトリガーとして機能します。
oiloil-ui-ux-guide
モダンでクリーンなUI/UXガイダンス・レビュースキルです。新機能や既存システム(Webアプリ)に対して、実行可能なUI/UX改善提案、デザイン原則、デザインレビューチェックリストが必要な場合に活用できます。CRAP(コントラスト・反復・配置・近接)をベースに、タスクファーストなUX、情報設計、フィードバック・システムステータス、一貫性、affordances、エラー防止・復旧、認知負荷を重視します。モダンミニマルスタイル(クリーン・余白・タイポグラフィ主導)を強制し、不要なテキストを削減、アイコンとしての絵文字を禁止し、統一されたアイコンセットから直感的で洗練されたアイコンを推奨します。
axiom-hig-ref
Apple Human Interface Guidelines リファレンス — 色(セマンティックカラー、カスタムカラー、パターン)、背景(マテリアル階層、ダイナミック背景)、タイポグラフィ(標準スタイル、カスタムフォント、Dynamic Type)、SF Symbols(レンダリングモード、色、多言語対応)、ダークモード、アクセシビリティ、プラットフォーム固有の考慮事項を網羅したガイドラインです。