1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Figma MCP × Claude Code】Kotlin Compose for Web のUIを会話だけでリデザインする

1
Last updated at Posted at 2026-03-28

はじめに

Figma の MCP Server を Claude Code に接続すると、チャットだけで Figma にデザインを書き出し、そのままコード修正まで一気通貫できる。

今回、個人開発の NBA ニュースサイト(Kotlin Compose for Web)を、この方法で2026年風にリデザインした。本記事では実装手順とハマったポイントを共有する。

📌 この記事で扱うこと:

  • Figma MCP Server (use_figma) の使い方と制約
  • Compose for Web の StyleSheet DSL でダークモード・Glassmorphism を実装する方法
  • <select> → Pill タブへの移行パターン

環境

項目 バージョン
Kotlin 1.9.22
Compose for Web 1.5.12
Claude Code Opus 4.6
Figma MCP Server 公式プラグイン

全体の流れ

1. Claude Code が Compose for Web のソースを読む
2. use_figma で Figma 上に現在のUIを再現
3. Figma 上で2026リデザイン版を作成
4. デザインをもとに StyleSheet DSL を書き換え

実装

ダークモードの適用

Compose for Web では StyleSheet オブジェクトの init ブロックに CSS を書く。ダークモード化は body と各コンポーネントの色を差し替える。

object AppStylesheet : StyleSheet() {
    init {
        "body" style {
            backgroundColor(Color("#0f172a"))  // slate-900
            color(Color("#f1f5f9"))            // slate-100
        }

        ".app-header" style {
            // ベタ塗り → グラデーション
            property("background",
                "linear-gradient(135deg, #1e40af 0%, #4f46e5 50%, #8b5cf6 100%)")
        }
    }
}

backgroundColor() は Compose for Web の型安全な API だが、linear-gradient のような複合値は property("background", "...") で直書きする必要がある。

Glassmorphism カード

".news-card" style {
    backgroundColor(rgba(30, 41, 59, 0.6))
    borderRadius(20.px)
    property("border", "1px solid rgba(255,255,255,0.08)")
    property("backdrop-filter", "blur(16px)")
    property("box-shadow", "0 4px 24px rgba(0,0,0,0.25)")
    property("transition", "transform 0.2s ease, box-shadow 0.2s ease")
}

".news-card:hover" style {
    property("transform", "translateY(-2px)")
    property("box-shadow", "0 8px 32px rgba(0,0,0,0.35)")
}

rgba() 関数は Compose for Web に組み込みで用意されている。backdrop-filterproperty() で書く。

<select> → Pill タブへの置き換え

カテゴリフィルターを <select> から <button> ベースの Pill タブに変更した。

Before(ドロップダウン):

Select(attrs = {
    classes("category-select")
    onChange { event ->
        val value = event.target.value
        onCategorySelected(if (value.isEmpty()) null else value)
    }
}) {
    categories.forEach { (value, label) ->
        Option(value = value ?: "", attrs = {
            if (selectedCategory == value) selected()
        }) { Text(label) }
    }
}

After(Pill タブ):

Div(attrs = { classes("category-filter") }) {
    categories.forEach { (value, label) ->
        Button(attrs = {
            classes("category-pill")
            if (selectedCategory == value) {
                classes("category-pill-active")
            }
            onClick { onCategorySelected(value) }
        }) {
            Text(label)
        }
    }
}

Select / Option / selected() のインポートが不要になり、コードがシンプルになった。CSS 側はアクティブ状態にグラデーションを適用:

".category-pill-active" style {
    property("background", "linear-gradient(135deg, #3b82f6, #8b5cf6)")
    color(Color.white)
    fontWeight(600)
    opacity(1)
}

Bento Grid

先頭のニュースを大きく見せる Bento Grid は、CSS Grid の :first-child 疑似セレクタで実現:

".news-grid" style {
    display(DisplayStyle.Grid)
    property("grid-template-columns", "repeat(3, 1fr)")
    gap(1.25.em)
}

// 先頭カードを2列分に拡大
".news-grid > *:first-child" style {
    property("grid-column", "span 2")
}

// モバイルではフォールバック
media("(max-width: 600px)") {
    ".news-grid > *:first-child" style {
        property("grid-column", "span 1")
    }
}

Compose for Web の media() 関数でレスポンシブ対応もそのまま書ける。

ハマったポイント

1. Figma MCP: fills の color に alpha を指定できない

// ❌ エラーになる
node.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1, a: 0.9 } }]

Figma Plugin API の fillscolor{r, g, b} のみ。透過は opacity プロパティで設定する:

// ✅ 正しい
node.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]
node.opacity = 0.9

2. Figma MCP: layoutSizingHorizontal = "FILL" の設定タイミング

// ❌ appendChild の前に設定するとエラー
child.layoutSizingHorizontal = "FILL"
parent.appendChild(child)

// ✅ appendChild の後に設定する
parent.appendChild(child)
child.layoutSizingHorizontal = "FILL"

Auto Layout のサイジングモードは、親フレームに追加されたでないと設定できない。use_figma で一番踏みやすいバグ。

3. Figma MCP: 1回のスクリプトでやりすぎない

ヘッダー + フィルター + カード6枚 + フッターを1回の use_figma で書こうとすると、スクリプトが長くなりすぎて失敗する。

セクション単位で分割して、各回で get_screenshot を挟んで確認するのがベスト:

use_figma → ラッパー作成 → get_screenshot で確認
use_figma → ヘッダー作成 → get_screenshot で確認
use_figma → フィルター作成 → get_screenshot で確認
use_figma → カード Row 1 → get_screenshot で確認
use_figma → カード Row 2 → get_screenshot で確認
use_figma → フッター作成 → get_screenshot で確認

4. Compose for Web: property() に頼る場面が多い

型安全な API が用意されているプロパティ(backgroundColor, borderRadius, padding 等)はそのまま使えるが、以下は property() が必要:

プロパティ 書き方
linear-gradient property("background", "linear-gradient(...)")
backdrop-filter property("backdrop-filter", "blur(16px)")
box-shadow property("box-shadow", "0 4px 24px ...")
transform property("transform", "translateY(-2px)")
grid-template-columns property("grid-template-columns", "repeat(3, 1fr)")
grid-column property("grid-column", "span 2")
transition property("transition", "all 0.2s ease")

CSS Grid 系はほぼ全て property() 経由になる。

まとめ

  • Figma MCP × Claude Code で デザイン → プロトタイプ → コード修正 を1セッションで完結できた
  • Compose for Web の StyleSheet DSL は property() を活用すればモダンCSS(Glassmorphism, Grid, グラデーション等)を問題なく実装できる
  • Figma MCP は use_figma のスクリプト分割と fills の alpha 制約に注意

Compose for Web の日本語情報はまだ少ないので、同じ技術スタックで開発している方の参考になれば。


🏀 NBA ISO FLOW: https://www.nba-iso-flow.com/
NBAの最新トレード・FA・ニュースを日本語でリアルタイム配信中。Kotlin Compose for Web + Rust(Axum)で構築した個人開発プロジェクト。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?