phoenix-duskmoon-design について
Phoenix のページを DuskMoon デザインシステムに沿って設計するためのスキルです。テーマ、コンポーネント、色、タイポグラフィ、レイアウト、動きを扱います。
主な機能
- 01テーマの設定と切り替え
- 02コンポーネントの配色規則
- 03トークンに基づく色のルール
- 04タイポグラフィとレイアウトの指針
- 05サーフェス階層と動きの規則
活用シーン
- 01Phoenix ページのビジュアル方針の策定
- 02DuskMoon コンポーネントの配色統一
- 03フォーム、ナビゲーション、データ画面の設計
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gsmlg-dev/ code-agent --skill phoenix-duskmoon-designインストール後、Claude Code で/phoenix-duskmoon-designを入力して読み込まれたか確認します。
詳細
Phoenix DuskMoon のデザイン規約
デザインの考え方
ページやビューを構築する前に、DuskMoon デザインシステムの中で意図的なデザインの方向性を決めます。
- 目的:このページの役割は何ですか?ダッシュボード、フォーム、マーケティング、管理、コンテンツのどれですか?
- 密度:データを詰め込んだ UI と、ゆとりのあるエディトリアルな余白のどちらにするか、ビューごとに選びます。
- 強調:最も重要なアクションまたはコンテンツブロックを 1 つ特定します。そこにプライマリカラーを使い、ほかの要素は控えめにします。
- 奥行き:このビューには何層のサーフェスが必要ですか?フラット(1~2 レベル)にするか、レイヤー構成(3~4 レベル)にするかを決めます。
DuskMoon が提供するのはトークンです。一律に使うのではなく、意図を持って使うことがあなたの役割です。
テーマの設定
CSS エントリー(必須)
@import "tailwindcss";
@plugin "@duskmoon-dev/core/plugin";
@import "phoenix_duskmoon/components";
HTML ルート(必須)
<html lang="en" data-theme="sunshine">
テーマ:sunshine(ライト)、moonlight(ダーク)。
body のベース
<body class="bg-surface text-on-surface">
すべてのページは、surface 上に on-surface のテキストを配置して開始します。例外はありません。
テーマ切り替え
アプリバーには必ず <.dm_theme_switcher /> を含めます。ThemeSwitcher フックが必要です。
コンポーネントのデフォルトカラー
ページのシェル
| コンポーネント | カラー | クラス/パターン |
|---|---|---|
| アプリバー | primary | appbar appbar-primary appbar-sticky |
| ページの背景 | surface | <body> に bg-surface |
| サイドバー | secondary | bg-secondary text-secondary-content |
| フッター | surface-container-high | bg-surface-container-high |
| ボトムナビゲーション | primary | color="primary" |
| ドロワー | secondary | bg-secondary text-secondary-content |
アプリバーはブランドの基点となるため、常に primary を使います。サイドバーとドロワーには secondary を使い、コンテンツ領域とは異なる、明確なナビゲーションの印象を作ります。ページの body は常に surface にします。フッターには、さりげなく区切りをつけるため、より高いサーフェスのエレベーションを使います。
<.dm_appbar title={@page_title} sticky>
<:logo>...</:logo>
<:menu to={~p"/dashboard"} active={@active == :dashboard}>Dashboard</:menu>
<:user_profile><.dm_theme_switcher /></:user_profile>
</.dm_appbar>
<div class="flex">
<aside class="bg-secondary text-secondary-content w-64 min-h-screen p-4">
<.dm_left_menu active={@current_path}>
<:menu>...</:menu>
</.dm_left_menu>
</aside>
<main class="flex-1 p-6">
<%= @inner_content %>
</main>
</div>
<.dm_page_footer label="© 2026 MyApp" />
アクション
| コンポーネント | デフォルト | 変更する場合 |
|---|---|---|
| プライマリボタン | variant="primary" | ページのメインアクション。ビューごとに 1 つ |
| セカンダリボタン | variant="secondary" | 代替アクション |
| ターシャリボタン | variant="tertiary" | アクセント機能、特別な強調 |
| 破壊的アクションボタン | variant="error" | 削除、取り消し、元に戻せない操作 |
| ゴーストボタン | variant="ghost" | ツールバー、控えめな強調、キャンセル |
| リンクボタン | variant="link" | インラインテキストのアクション |
| アウトラインボタン | variant="outline" | 中程度の強調、切り替え可能 |
<div class="flex gap-2">
<.dm_btn variant="ghost">Cancel</.dm_btn>
<.dm_btn variant="primary">Save Changes</.dm_btn>
</div>
コンテンツ
| コンポーネント | カラー | 備考 |
|---|---|---|
| カード | surface-container | デフォルトの CSS。クラスは不要 |
| カード(浮き上がり) | surface-container-high | shadow="md" を追加 |
| モーダル/ダイアログ | surface-container-highest | 最も高いエレベーション |
| ツールチップ | primary | デフォルトは color="primary" |
| ポップオーバー | surface-container-high | |
| アコーディオン | surface-container | |
| ボトムシート | surface-container-high | |
| スナックバー | inverse-surface またはタイプ別 | 意味に応じて type を使用 |
データ表示
| コンポーネント | カラー | 備考 |
|---|---|---|
| バッジ | variant="primary" | カテゴリーの区別には secondary/tertiary を使用 |
| チップ | color="primary" | ステータスには意味に応じた色を使用:success、error |
| プログレス | color="primary" | 完了には success、上限には error を使用 |
| アバター | color="primary" | イニシャルのプレースホルダーの色 |
| 統計 | 色なし | 主要な指標にのみ color="primary" を使用 |
| タイムライン | 項目ごとのセマンティックカラー | completed = 緑、active = primary |
| テーブル | 色なし | 読みやすさのために zebra と hover を使用 |
フォーム
| コンポーネント | カラー | 備考 |
|---|---|---|
| 入力 | 色なし | アウトラインの境界線を使用。強調する場合のみ color を設定 |
| チェックボックス | color="primary" | |
| ラジオボタン | color="primary" | |
| スイッチ | color="primary" | |
| セレクト | 色なし | |
| スライダー | color="primary" | |
| 評価 | color="primary" | 星評価には warning を使用 |
フィードバック
| コンポーネント | 色 | 備考 |
|---|---|---|
| Alert | タイプに基づく | variant="info"、"success"、"warning"、"error" |
| Flash | 種類に基づく | :info、:error |
| Toast | タイプに基づく | 常に type を設定します |
| ローディングスピナー | variant="primary" |
ナビゲーション
| コンポーネント | 色 | 備考 |
|---|---|---|
| Appbar | primary | 常に |
| Navbar | surface-container-high | navbar-surface-container-high |
| Tabs | 色なし | アクティブ時は primary の下線 |
| Breadcrumb | on-surface-variant | 控えめなテキスト |
| Steps | color="primary" | 完了済み=塗りつぶし、未完了=アウトライン |
| 左メニュー | secondary | アクティブ項目=primary-content のハイライト |
色のルール
ルール 1:ハードコードした色は使わない
16 進数、rgb、hsl、色名、Tailwind のパレットクラス(bg-blue-500、text-slate-600)は使わないでください。色はすべてデザイントークンから指定します。
<%# FORBIDDEN %>
<div style="background: #3b82f6;">
<div class="bg-blue-500 text-white">
<%# CORRECT %>
<div class="bg-primary text-primary-content">
ルール 2:背景色とテキスト色を組み合わせる
すべての背景トークンには、対応するテキストトークンがあります。必ず組み合わせて使用してください。
| 背景 | テキスト |
|---|---|
bg-primary | text-primary-content |
bg-secondary | text-secondary-content |
bg-tertiary | text-tertiary-content |
bg-surface | text-on-surface |
bg-surface-container-* | text-on-surface |
bg-primary-container | text-on-primary-container |
bg-error | text-error-content |
bg-error-container | text-on-error-container |
bg-inverse-surface | text-inverse-on-surface |
ルール 3:サーフェスの高さ — 低から高へ
サーフェスを低いものから高いものへとネストします。高さの高いサーフェスの内側に、低いサーフェスを配置しないでください。
surface (page)
├─ secondary (sidebar, drawer)
└─ surface-container (card)
└─ surface-container-high (navbar, popover, elevated card)
└─ surface-container-highest (dialog, tooltip)
ルール 4:状態の表現にのみセマンティックカラーを使う
success、warning、error、info は状態を示すためのものです。装飾やブランディングには使わないでください。
<%# CORRECT %>
<.dm_alert variant="error">Validation failed</.dm_alert>
<.dm_badge variant="success">Active</.dm_badge>
<%# WRONG %>
<.dm_btn variant="success">Submit</.dm_btn> <%# Use primary %>
ルール 5:Primary=ブランド、Secondary=サポート、Tertiary=アクセント
| 役割 | 目的 | 例 |
|---|---|---|
| Primary | ブランドのアイデンティティ、主要なアクション、重要なフォーカス | Appbar、メインの CTA、アクティブなナビゲーション |
| Secondary | サポートするアクション、代替の強調 | セカンダリ CTA、トグル |
| Tertiary | 特別なハイライト、装飾的なアクセント | 機能バッジ、アクセントカード |
ルール 6:1 つのビューにつき Primary アクションは 1 つ
表示されるセクションごとに、variant="primary" のボタンは 1 つだけにします。サポートするアクションには secondary、ghost、または outline を使います。
ルール 7:アイコンは色を継承する
dm_mdi と dm_bsi は、デフォルトで currentcolor を使います。アイコンの色を周囲のテキストと異なるものにする必要がある場合を除き、明示的な color= は設定しないでください。
ルール 8:控えめに強調するにはコンテナカラーを使う
色付きの背景を低いコントラストで使う場合は、primary-container / on-primary-container を使用します。特集セクション、ハイライトカード、選択状態に適しています。
<div class="bg-primary-container text-on-primary-container p-4 rounded-lg">
Featured content with softer emphasis
</div>
タイポグラフィ
フォント戦略
DuskMoon は書体を指定しません。プロジェクトごとに選択してください。ルール:
- 見出しには個性のあるディスプレイフォントを選びます。Inter、Roboto、Arial、system-ui は避けてください。Google Fonts から読み込むか、セルフホストしてください。
- ディスプレイフォントと調和する、読みやすい本文用フォントを組み合わせます。
- コードブロックには等幅フォント(JetBrains Mono、Fira Code など)を使います。
- フォントはインラインではなく、CSS 変数として定義します。
/* Project CSS — after DuskMoon imports */
:root {
--font-display: 'Instrument Serif', serif;
--font-body: 'DM Sans', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
body { font-family: var(--font-body); }
h1, h2, h3 { font-family: var(--font-display); }
code, pre { font-family: var(--font-mono); }
文字サイズのスケール
| 要素 | クラス | 用途 |
|---|---|---|
| ページタイトル | text-3xl font-bold | ページごとに 1 つ |
| セクション見出し | text-2xl font-semibold | |
| カードタイトル | text-lg font-semibold | |
| 本文 | text-base | デフォルト |
| セカンダリテキスト | text-sm text-on-surface-variant | 控えめな補足情報 |
| キャプション | text-xs text-on-surface-variant | タイムスタンプ、メタデータ |
テキストカラーの階層
| 優先度 | トークン | 用途 |
|---|---|---|
| プライマリテキスト | text-on-surface | 見出し、本文、ラベル |
| セカンダリテキスト | text-on-surface-variant | 説明、ヒント、タイムスタンプ |
| 無効状態のテキスト | text-on-surface-variant と opacity-50 | 無効状態 |
| リンクテキスト | text-primary | クリック可能なインラインテキスト |
レイアウト構成
空間設計の原則
- コンテンツページ:余白を広く取ります。メインには
p-6またはp-8、カード間にはgap-6を使用します。 - データビュー:間隔を詰めます。メインには
p-4、アイテム間にはgap-3を使用します。 - 一貫した間隔:ビューごとに1つのスケールを選びます(
gap-4またはgap-6。混在させないでください)。 - 最大幅:コンテンツ領域の幅を制限します。幅広の領域には
max-w-7xl mx-auto、テキスト中心の領域にはmax-w-3xlを使用します。
カードグリッド
<div class="grid grid-cols-auto-fit-80 gap-6">
<.dm_card :for={item <- @items}>
<:title><%= item.name %></:title>
<%= item.description %>
</.dm_card>
</div>
サイドバー+コンテンツ
<div class="flex min-h-screen">
<aside class="bg-secondary text-secondary-content w-64 border-r border-outline-variant p-4 shrink-0">
<.dm_left_menu active={@current_path} />
</aside>
<main class="flex-1 bg-surface p-6 overflow-auto">
<%= @inner_content %>
</main>
</div>
奥行きのあるセクションの積み重ね
<section class="bg-surface-container-low p-8 rounded-2xl">
<h2 class="text-2xl font-semibold mb-6">Featured</h2>
<div class="grid grid-cols-3 gap-4">
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
<.dm_card shadow="md">...</.dm_card>
</div>
</section>
背景と奥行き
サーフェスのレイヤー化
平坦なページにしないでください。サーフェストークンを使って奥行きを作ります。
<body class="bg-surface text-on-surface">
<header class="bg-primary text-primary-content">...</header>
<div class="bg-surface-container-low -mt-8 pt-12 pb-8 rounded-t-3xl">
<div class="max-w-6xl mx-auto px-6">
<.dm_card shadow="lg" class="bg-surface-container">
...
</.dm_card>
</div>
</div>
</body>
ヒーローセクション
ヒーロー領域にはコンテナカラーのグラデーションを使用します。
.hero {
background: linear-gradient(
135deg,
var(--color-primary-container) 0%,
var(--color-tertiary-container) 100%
);
}
スクリムとオーバーレイ
.overlay {
background-color: hsl(var(--color-scrim) / 0.5);
backdrop-filter: blur(4px);
}
境界線と区切り線
outline-variant→ 控えめな区切り線、装飾的な境界線outline→ インタラクティブな境界線(入力欄、フォーカス時の状態)
<hr class="border-outline-variant" />
<div class="border border-outline rounded-lg">Interactive element</div>
モーションとトランジション
テーマのトランジション
* {
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
カードのホバー
.interactive-card {
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.interactive-card:hover {
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
モーションの軽減
ユーザーの設定を必ず尊重します。
@media (prefers-reduced-motion: reduce) {
* { transition: none !important; animation: none !important; }
}
モーションの原則
- インタラクションごとにトランジション対象のプロパティは1つにします。すべてをアニメーションさせないでください。
- ルート変更時にページレベルのアニメーションを適用します(LiveView トランジション)。
- カードやボタンのホバー状態は控えめにします。
translateY(-2px)を上限とします。 - ローディング状態には
dm_loading_spinnerまたはスケルトンコンポーネントを使用します。カスタムスピナーは使用しないでください。
アンチパターン
- Tailwind のカラースケール —
bg-blue-500やtext-gray-600は使用しないでください。テーマの切り替えが機能しなくなります。 - 色のハードコード — hex、rgb、hsl、名前付きカラーは使用しないでください。
- 不透明度でサーフェスを表現する —
bg-white/80は使用しないでください。surface-container-*トークンを使用します。 - インラインのカラー指定 —
style="color: ..."は使用しないでください。 - コンポーネントの代わりに生のHTMLを使う — 使用可能な場合は
dm_*コンポーネントを使用します。 - どこでも一様にプライマリカラーを使う — ビューごとにプライマリアクションは1つにします。補助的なアクションは目立たなくします。
- 装飾目的でセマンティックカラーを使う —
success/error/warning/infoは状態表示にのみ使用します。 - 汎用フォント — 意図的な選択肢として Inter、Roboto、Arial を使用しないでください。個性のある書体を選びます。
- テキストとの組み合わせがない — すべての
bg-*に、対応するtext-*-contentまたはtext-on-*を指定します。 - 平坦なレイアウト — サーフェスの高さを使って奥行きを作ります。ページが単一の平面のように感じられてはいけません。
- 控えめすぎる色使い — 主役となるプライマリカラーに鮮明なアクセントを加えるほうが、均等に分散した曖昧なパレットより効果的です。色の階層を明確にします。
- 画一的なページ — ビューの種類(ダッシュボード、フォーム、コンテンツ、マーケティング)ごとに、空間構成を変えます。どこでも同じレイアウトをコピーして使わないでください。