/note/tech

Figmaと実装の乖離は怠慢ではなく、構造の欠陥である

要約:

■ 1. 主張と結論

  • デザインと実装の乖離は、運用の改善や頑張りでは解決できない
  • Figmaとコードはパラダイムが違うため、どちらか一方を「正」とした時点で乖離が構造的に発生する
  • 解決策はFigmaにもコードにも正を置かず、ツール中立なComponent Spec(コンポーネント仕様書)を「正」に置くこと
  • FigmaとコードはSpecから生成される「派生物」と捉えることで、乖離は「頑張って同期するもの」から「検出して再生成で消すもの」に変わる

■ 2. AIがデザインを生成する時代の到来

  • Figma Make、Pencil、Claude Design、Figma AgentなどAIによるデザイン生成ツールが相次いで登場した
  • 制約なしの生成指示では「プロトタイプ止まり」の出力しか得られない
  • 実プロダクトとして通用するには、サービスのデザインルール(使ってよい色・コンポーネント・余白の体系)をAIに明示する必要がある
  • この「ルールの集合体」こそデザインシステムであり、AIへの入力そのものになった今、その重要性が一段上がった

■ 3. 従来のデザインシステムの限界

  • これまでのデザインシステムはFigmaにトークンとコンポーネントライブラリがあれば十分とされてきた
  • 以下の情報は厳密に文書化されず、デザイナーの経験・勘・コミュニケーションで補完されてきた:
    • コンポーネントをどこで使い、どこで使ってはいけないか
    • 似たコンポーネントとの役割の違い
  • 人間のチームは暗黙知で運用できるが、AIには書かれていないルールは存在しないルールと同じ
  • AIリーダブル(AIが読める)であることが新しい要件として加わった

■ 4. 乖離が構造的に発生するメカニズム

  • デザインをプロダクトにする際、エンジニアがFigmaを見てコードに手作業で再現する「翻訳」の工程が発生する
  • 翻訳過程で抜け落ちた情報が負債となり、乖離の谷が深まっていく:
    • 実装の都合で変えた角丸
    • Figmaに存在しない中間状態
    • 誰も文書化しなかった例外
  • AIはデザイン生成だけでなくコード生成も可能になり、翻訳工程をAIに委ねられる段階になった

■ 5. Figmaとコードのパラダイムの違い

  • Figmaのコンポーネントと実装(React等)のコンポーネントは、同じ見た目を作る場合も表現の仕組みがまったく異なる
  • ボタンの5状態(default / hover / active / focus / disabled)を例にすると:
    • Figma: 「state」プロパティで5状態をバリアントとして平らに並べる
    • 実装: disabledはprops、hover/focusはCSSの擬似クラス/イベント、押下中はuseStateと、複数の仕組みに分散する
  • 片方のパラダイムをもう片方に強制すると都合の悪い部分が抜け落ちる:
    • Figmaを正にすると: 実装が「バリアント」という実装に存在しない概念からコードを推測することになる
    • コードを正にすると: Figmaが「props・擬似クラス・useStateの使い分け」を1軸に無理やり潰すことになる
  • この抜け落ちこそが乖離の正体

■ 6. Component Specとは

  • どちらのパラダイムにも属さない場所に「正」を置く文書
  • 「このコンポーネントは何であり、どんな状態を持ち、どう振る舞い、何をしてはいけないか」をツール中立な言葉で記述する
  • Specが正であることの3つの帰結:
    • 乖離の「検出」が可能になる: FigmaとコードがズレたらSpecを見ればどちらが間違いか判定できる
    • 派生物は作り直せる: AIがデザインもコードも生成できる今、Specから両方を生成し直すコストが急速に下がっている
    • ツールに寿命が来ても正は残る: FigmaやReactが別ツールに替わっても失うのは派生物だけ
  • AIが読めるのはキャンバスではなく構造化されたSpecそのもの。AIリーダブルなデザインシステムの核はSpecにある

■ 7. Component Specの構成と内容

  • YAML部分(機械が読む)とドキュメント部分(人間とAIが読む)の2層構成
  • Specに書く内容:
    • 事実: 「このコンポーネントは6つの状態を持つ」「isLoading時は横幅を縮めない」など
    • 判断基準: いつ使い・いつ使わないか、似たコンポーネントとの役割の違いなど
    • AIへの指示: どう考えて選択すべきかをAIに直接語りかけるセクション
  • Specに書かない内容:
    • パラダイム依存の情報(Figmaでバリアントとして並べるか、実装でprops/CSS/useStateに振り分けるかなど)
    • パラダイム依存の情報を持ち込まないことが、Specをツール中立な「正」として保つための最重要規律
  • 変更履歴も含み、乖離が発生した際の裁定者として機能する

■ 8. Code Connectとの関係

  • Code Connectへの評価: 肯定的であり、使えるなら使うべき機能
  • Code ConnectとComponent Specの役割の違い:
    • Code Connect: Figmaとコードという派生物同士をつなぐ「配管」として翻訳をスムーズにする
    • Component Spec: 両方の派生物が従うべき「事実」として、ズレたときの裁定者となる
  • Code Connectが答えられないこと: 角丸8pxのFigmaと角丸4pxの実装がマッピングされていても、どちらを直すべきかは判定できない
  • Code Connectのマッピングを書く際の判断根拠を文書化したものがSpecに相当する
  • 競合ではなく補完関係。将来的にはSpecからCode Connectのマッピングを生成することも可能になる
  • Code Connectのみで十分なケース: Dev Modeで正しいコード片が見られれば十分な段階のチーム

■ 9. 注意点

  • Specの維持コスト:
    • 部品作成に加えて文書を書いて維持する工程が発生する
    • 中途半端なSpecはないより悪く、FigmaとコードとSpecの「3者のズレ」という最悪の状態を生む
    • 「Specを更新しない変更は存在しない」を守り切ることが前提条件
  • Specが向かない現場:
    • 小規模チームの探索期
    • 使い捨ての案件
    • Specは参照される回数が多いほど効いてくる投資

■ 10. まとめ

  • AIがデザインを生成する時代になり、デザインシステムは「AIへの入力」になった
  • AIリーダブルであることが新しい要件であり、暗黙のルールはAIには存在しないルールと同じ
  • Figmaとコードはパラダイムが違うため、どちらを正にしても乖離が構造的に発生する
  • 正はツール中立なComponent Specに置き、Figmaとコードは派生物と捉える
  • 乖離は「議論して直すもの」から「検出して再生成で消すもの」に変わる

Appendix:

name: Button
description: ユーザーのアクションをトリガーするコンポーネント
status: stable

props:
 variant:
   type: enum
   values: [solid, outlined, ghost]
   default: solid
   description: 見た目のスタイル(塗り / 枠線 / 透過)
 tone:
   type: enum
   values: [brand, neutral, danger, success, info, warning]
   default: brand
   description: 色味・意味のトーン
 size:
   type: enum
   values: [sm, md, lg]
   default: md
   description: ボタンのサイズ
 shape:
   type: enum
   values: [rounded, pill]
   default: rounded
   description: 角の形(rounded=通常の角丸 / pill=完全な丸み)
 isDisabled:
   type: boolean
   default: false
   description: 無効状態。クリック・キー操作を受け付けない
 isLoading:
   type: boolean
   default: false
   description: 処理中の状態。操作を受け付けず、スピナーと専用ラベルを表示。
     横幅は元のラベルと loadingLabel の広い方に合わせる(縮めない)
 isFullWidth:
   type: boolean
   default: false
   description: 親要素の幅いっぱいに広がる
 type:
   type: enum
   values: [button, submit, reset]
   default: button
   description: HTML の button type 属性に対応
   platforms: [web]
   visual: false
 loadingLabel:
   type: string
   default: 処理中
   description: ローディング中(isLoading)に表示する専用ラベル
 startIcon:
   type: element
   default: null
   part: icon
   description: ラベルの前に置くアイコン(省略可)
 endIcon:
   type: element
   default: null
   part: icon
   description: ラベルの後に置くアイコン(省略可)

states: [default, hover, pressed, focused, disabled, loading]

style:
 variant:
   solid:
     brand:
       background: color.brand.500
       foreground: color.white
       hover:
         background: color.brand.700
       pressed:
         background: color.brand.800
   # …(outlined / ghost、他のtoneも同形式で続く)

related:
 - name: Link
   reason: ページ移動、外部リンク
 - name: IconButton
   reason: アイコンだけのアクション
## いつ使うか

ユーザーが自分から何かを実行する場面で使う。フォームの送信、保存、削除の確定、ダイアログのアクション、画面内の機能の実行など。「押すと何かが起きる」操作の起点には、Button を使う。

## いつ使わないか

- ページ移動・外部リンクが目的のとき → `Link` を使う。Button は移動ではなく、動作の実行に使う
- アイコンだけで、ラベルがないアクション → `IconButton` を使う
- オン / オフの2つの状態を切り替えるとき → `Switch` か `Toggle` を使う。Button は状態を持たない
- 複数の Button を、意味のあるまとまりとして並べるとき → `ButtonGroup` を使う

## variant の使い分け

`variant` は「色をどう塗るか」の軸。

- `solid` は背景を塗りつぶす、最も強い見た目。画面の中で一番注目させたいアクションに使う。
- `outlined` は枠線だけ。`solid` を引き立てる、2番目のアクションに使う。
- `ghost` は枠線も背景もない、最も控えめな見た目。情報が密集した場所や、補助的なアクションに使う。

見た目の強さは solid > outlined > ghost。

## tone の使い分け

`tone` は「どの意味の色か」の軸で、`variant` とは別。

- `brand` は主要なアクション。
- `danger` は削除や取り消しなど、元に戻せない・壊す系のアクション。
- `success` / `info` / `warning` は、文脈を強調したいときに使う。ただし使いすぎると意味が薄れるので、基本は `brand` か `neutral` に寄せる。
- `neutral` は、意味の色を付けたくない中立的なアクションに使う。

`tone` は意味を表す。「赤くしたい」という見た目の理由で `danger` を選んではいけない。

## AI エージェントへのガイダンス

Button を選ぶときは、まず「押すと何かが起きるか」を確認する。移動が目的なら Link、状態の切り替えなら Switch / Toggle に倒す。次に `variant` と `tone` を別々に決める。`variant` は画面の中での重要度で選ぶ(主要なら solid、補助なら outlined、控えめなら ghost)。`tone` は意味で選ぶ(普通は brand、壊す系の操作だけ danger、中立は neutral)。1つの領域に solid は1つだけにする。size は領域の中でそろえる。壊す系でないアクションに danger を使わないこと。