mcpField
S
style-dictionary

style-dictionary

github.com/dylantarreデザイン・UI5047 回インストール43 週間前に更新
リポジトリ

style-dictionary について

style-dictionary は、単一のソースにあるデザイントークンを各プラットフォーム向けのコード形式に変換するための設定スキルです。カスタム変換や出力形式、複数テーマの設定、ビルド工程への統合を扱います。

主な機能

  1. 01トークンソースからプラットフォーム別の出力を生成
  2. 02色や寸法などの値を変換
  3. 03カスタム変換と出力形式の設定
  4. 04複数テーマとブランドのトークン設定
  5. 05トークンのビルドをパイプラインに統合

活用シーン

  1. 01Web、iOS、Android 向けのトークン出力
  2. 02Figma から書き出したトークンのコード変換
  3. 03ビルド工程でのトークンファイル生成
  4. 04トークン変換や出力形式の拡張

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dylantarre/design-system-skills --skill style-dictionary

インストール後、Claude Code で/style-dictionaryを入力して読み込まれたか確認します。

詳細

Style Dictionary

概要

Style Dictionary をセットアップして、デザイントークンをプラットフォーム固有の形式に変換します。単一のトークンソースからウェブ、iOS、Android、その他のプラットフォーム向けに出力する必要があるデザインシステムの業界標準です。

使用する場面

  • マルチプラットフォームに対応する新しいデザインシステムをセットアップする
  • Figma のトークンをコードに変換する
  • 1 つのソースから CSS、SCSS、iOS Swift、Android XML を生成する
  • カスタムのトークン変換やフォーマットを追加する
  • ビルドパイプラインにトークンを統合する

クイックリファレンス:主要な概念

概念目的例
トークンメタデータを含むデザイン値{ "value": "#3b82f6", "type": "color" }
変換トークンの値を変換するcolor/hex → color/rgb
フォーマットファイル形式に出力するCSS 変数、Swift、XML
プラットフォーム対象環境web、ios、android

手順

  1. トークンソースを確認する:トークンはどこで定義されていますか?(Figma、JSON、YAML)
  2. プラットフォームを特定する:どのプラットフォームでトークンが必要ですか?
  3. 設定する:style-dictionary.config.js を作成します
  4. 変換を定義する:必要なカスタム値変換を追加します
  5. ビルドする:style-dictionary build を実行します
実装チェックリスト

Style Dictionary のセットアップ時に、このチェックリストをコピーしてください。

Style Dictionary Setup:
- [ ] Install: `npm install style-dictionary`
- [ ] Create tokens/ directory with source JSON files
- [ ] Create style-dictionary.config.js with source paths and platform outputs
- [ ] Add build script to package.json: `"tokens:build": "style-dictionary build"`
- [ ] Run build and verify output files are generated correctly

プロジェクトのセットアップ

インストール
npm install style-dictionary
# or
yarn add style-dictionary
ディレクトリ構成
tokens/
├── base/
│   ├── colors.json
│   ├── spacing.json
│   └── typography.json
├── semantic/
│   ├── colors.json
│   └── components.json
└── themes/
    ├── light.json
    └── dark.json

build/                    # Generated output
├── css/
│   └── variables.css
├── ios/
│   └── StyleDictionary.swift
└── android/
    └── colors.xml

style-dictionary.config.js

設定

基本設定
// style-dictionary.config.js
module.exports = {
  source: ['tokens/**/*.json'],
  platforms: {
    css: {
      transformGroup: 'css',
      buildPath: 'build/css/',
      files: [
        {
          destination: 'variables.css',
          format: 'css/variables',
        },
      ],
    },
  },
};
マルチプラットフォーム設定
// style-dictionary.config.js
module.exports = {
  source: ['tokens/**/*.json'],

  platforms: {
    // Web - CSS Custom Properties
    css: {
      transformGroup: 'css',
      buildPath: 'build/css/',
      files: [
        {
          destination: 'variables.css',
          format: 'css/variables',
          options: {
            outputReferences: true, // Keep token references
          },
        },
      ],
    },

    // Web - SCSS Variables
    scss: {
      transformGroup: 'scss',
      buildPath: 'build/scss/',
      files: [
        {
          destination: '_variables.scss',
          format: 'scss/variables',
        },
      ],
    },

    // Web - JavaScript/TypeScript
    js: {
      transformGroup: 'js',
      buildPath: 'build/js/',
      files: [
        {
          destination: 'tokens.js',
          format: 'javascript/es6',
        },
        {
          destination: 'tokens.d.ts',
          format: 'typescript/es6-declarations',
        },
      ],
    },

    // iOS - Swift
    ios: {
      transformGroup: 'ios-swift',
      buildPath: 'build/ios/',
      files: [
        {
          destination: 'StyleDictionary.swift',
          format: 'ios-swift/class.swift',
          className: 'StyleDictionary',
        },
      ],
    },

    // Android - XML Resources
    android: {
      transformGroup: 'android',
      buildPath: 'build/android/',
      files: [
        {
          destination: 'colors.xml',
          format: 'android/colors',
          filter: { type: 'color' },
        },
        {
          destination: 'dimens.xml',
          format: 'android/dimens',
          filter: { type: 'dimension' },
        },
      ],
    },
  },
};

トークン形式

Design Tokens Community Group(DTCG)形式
{
  "color": {
    "primary": {
      "$value": "#3b82f6",
      "$type": "color",
      "$description": "Primary brand color"
    },
    "secondary": {
      "$value": "#64748b",
      "$type": "color"
    }
  },
  "spacing": {
    "sm": {
      "$value": "8px",
      "$type": "dimension"
    },
    "md": {
      "$value": "16px",
      "$type": "dimension"
    }
  }
}
Style Dictionary の従来形式
{
  "color": {
    "primary": {
      "value": "#3b82f6",
      "type": "color",
      "comment": "Primary brand color"
    }
  },
  "spacing": {
    "sm": { "value": "8px" },
    "md": { "value": "16px" }
  }
}
トークン参照(エイリアス)
{
  "color": {
    "base": {
      "blue": {
        "500": { "value": "#3b82f6" }
      }
    },
    "primary": {
      "value": "{color.base.blue.500}"
    },
    "button": {
      "background": {
        "value": "{color.primary}"
      }
    }
  }
}

カスタム変換

カスタム変換の登録
// style-dictionary.config.js
const StyleDictionary = require('style-dictionary');

// Transform px to rem
StyleDictionary.registerTransform({
  name: 'size/pxToRem',
  type: 'value',
  matcher: (token) => token.type === 'dimension',
  transformer: (token) => {
    const px = parseFloat(token.value);
    return `${px / 16}rem`;
  },
});

// Transform color to OKLCH
StyleDictionary.registerTransform({
  name: 'color/oklch',
  type: 'value',
  matcher: (token) => token.type === 'color',
  transformer: (token) => {
    // Use a color library like culori
    const { formatCss, oklch, parse } = require('culori');
    return formatCss(oklch(parse(token.value)));
  },
});

module.exports = {
  source: ['tokens/**/*.json'],
  platforms: {
    css: {
      transforms: [
        'attribute/cti',
        'name/cti/kebab',
        'size/pxToRem',      // Custom
        'color/oklch',        // Custom
      ],
      buildPath: 'build/css/',
      files: [
        {
          destination: 'variables.css',
          format: 'css/variables',
        },
      ],
    },
  },
};
よく使われるカスタム変換
// Clamp font sizes for fluid typography
StyleDictionary.registerTransform({
  name: 'size/fluidType',
  type: 'value',
  matcher: (token) => token.attributes?.category === 'font' && token.attributes?.type === 'size',
  transformer: (token) => {
    const min = parseFloat(token.value) * 0.875;
    const max = parseFloat(token.value);
    return `clamp(${min}rem, 2vw + 1rem, ${max}rem)`;
  },
});

// Shadow to CSS format
StyleDictionary.registerTransform({
  name: 'shadow/css',
  type: 'value',
  matcher: (token) => token.type === 'shadow',
  transformer: (token) => {
    const { x, y, blur, spread, color } = token.value;
    return `${x}px ${y}px ${blur}px ${spread}px ${color}`;
  },
});

カスタムフォーマット

ダークモード対応 CSS
StyleDictionary.registerFormat({
  name: 'css/variables-themed',
  formatter: ({ dictionary, options }) => {
    const lightTokens = dictionary.allTokens
      .filter(t => !t.path.includes('dark'))
      .map(t => `  --${t.name}: ${t.value};`)
      .join('\n');

    const darkTokens = dictionary.allTokens
      .filter(t => t.path.includes('dark'))
      .map(t => {
        const name = t.name.replace('dark-', '');
        return `  --${name}: ${t.value};`;
      })
      .join('\n');

    return `:root {\n${lightTokens}\n}\n\n[data-theme="dark"] {\n${darkTokens}\n}`;
  },
});
Tailwind 設定形式
StyleDictionary.registerFormat({
  name: 'tailwind/config',
  formatter: ({ dictionary }) => {
    const colors = {};
    const spacing = {};

    dictionary.allTokens.forEach(token => {
      if (token.type === 'color') {
        const path = token.path.slice(1).join('-');
        colors[path] = token.value;
      }
      if (token.type === 'dimension' && token.path[0] === 'spacing') {
        spacing[token.path[1]] = token.value;
      }
    });

    return `module.exports = {
  theme: {
    extend: {
      colors: ${JSON.stringify(colors, null, 2)},
      spacing: ${JSON.stringify(spacing, null, 2)},
    },
  },
};`;
  },
});

マルチテーマのセットアップ

トークン構造
tokens/
├── core/
│   ├── colors.json      # Primitives (blue-500, gray-100)
│   └── spacing.json
├── semantic/
│   ├── light.json       # Semantic mappings for light
│   └── dark.json        # Semantic mappings for dark
└── brand/
    ├── default.json     # Default brand
    └── partner.json     # White-label brand
テーマ固有の設定
// style-dictionary.config.js
const themes = ['light', 'dark'];
const brands = ['default', 'partner'];

module.exports = {
  source: ['tokens/core/**/*.json'],

  platforms: brands.flatMap(brand =>
    themes.map(theme => ({
      [`css-${brand}-${theme}`]: {
        transformGroup: 'css',
        buildPath: `build/${brand}/`,
        files: [
          {
            destination: `${theme}.css`,
            format: 'css/variables',
            filter: (token) =>
              token.filePath.includes('core') ||
              token.filePath.includes(theme),
          },
        ],
        source: [
          `tokens/semantic/${theme}.json`,
          `tokens/brand/${brand}.json`,
        ],
      },
    }))
  ),
};

ビルドパイプラインへの統合

package.json のスクリプト
{
  "scripts": {
    "tokens:build": "style-dictionary build",
    "tokens:watch": "style-dictionary build --watch",
    "tokens:clean": "rm -rf build/",
    "prebuild": "npm run tokens:build"
  }
}
Figma Tokens Plugin との連携
# 1. Export from Figma Tokens plugin to tokens/figma.json
# 2. Transform with Style Dictionary

npx token-transformer tokens/figma.json tokens/transformed.json
style-dictionary build
GitHub Actions
# .github/workflows/tokens.yml
name: Build Tokens

on:
  push:
    paths:
      - 'tokens/**'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run tokens:build
      - uses: actions/upload-artifact@v4
        with:
          name: tokens
          path: build/

出力例

入力トークン
{
  "color": {
    "primary": {
      "value": "#3b82f6",
      "type": "color"
    }
  }
}
CSS 出力
:root {
  --color-primary: #3b82f6;
}
SCSS 出力
$color-primary: #3b82f6;
JavaScript 出力
export const ColorPrimary = '#3b82f6';
iOS Swift 出力
public class StyleDictionary {
    public static let colorPrimary = UIColor(red: 0.231, green: 0.510, blue: 0.965, alpha: 1.0)
}
Android XML 出力
<?xml version="1.0" encoding="UTF-8"?>
<resources>
  <color name="color_primary">#3b82f6</color>
</resources>

よくある問題と解決策

問題解決策
循環参照トークンのエイリアスがループしていないか確認します
トークンが見つからない参照内のパスが完全に一致しているか確認します
出力形式が違う変換グループがプラットフォームと一致しているか確認します
トークンが不足しているfilter によって除外されていないか確認します
ビルドが古いビルド前に tokens:clean を実行します

Style Dictionary v4(最新版)

// style-dictionary.config.js (v4 syntax)
import StyleDictionary from 'style-dictionary';

export default {
  source: ['tokens/**/*.json'],
  preprocessors: ['tokens-studio'], // For Figma Tokens
  platforms: {
    css: {
      transformGroup: 'css',
      buildPath: 'build/',
      files: [{
        destination: 'variables.css',
        format: 'css/variables',
      }],
    },
  },
};
# Run with ESM
node --experimental-json-modules ./node_modules/.bin/style-dictionary build

コメント