Slidev のデザインシステムを CSS変数と CLAUDE.md で作る:移植が簡単

Hero banner with large dark blue Japanese headline on pale background, featuring pastel yellow highlights and logos for SIOS Tech.Lab and SLIDev x CLAUDE CODE.

手作業じゃ間に合わない、だからAIで作れる環境を整えた

ども!Slidev と Claude Code でスライドを量産してる龍ちゃんです。

ここ最近、ほんとにスライドばっかり作ってるんですよ。セミナー、勉強会、社内共有……気づけば毎週どこかで1本。正直、これを1枚1枚手作業でデザインしてたら、どう考えても間に合わない。

なので、AIに作らせることにしました。ただ、AIに丸投げすると、トーンがバラバラになります。色は勝手に増えるし、変なグラデは湧くし、フォントも気分で変わる。それっぽく見えるんですが、そのまま使用することはできないですね。

そこで、AIがいつも同じトーンで作れるように、環境のほうを整備しました。色・レイアウトの型・よく使う部品・作っていい範囲のルール、この一式を”ひな型”として用意して、AIにはその枠の中だけで作らせる。そしたら、新規作成がグッとラクになって、しかも毎回トーンが揃います。揃うというより、揃うように設定した、が正確ですね。

この記事では、そのひな型(コード一式+ルールを書いた CLAUDE.md)を丸ごと公開します。AIにブログ読み込ませれば、あなたのスライドにも同じシステムがまるっと実装できます。持ち帰ってすぐ使える形にしました。

下のようなものがサクッと作ることができます。

前提:AIと相性のいい環境=Slidev

本題に入る前に、前提だけ共有させてください。

僕がスライドを作ってるのは、Slidev ってツールです。ざっくり言うと、Markdown でスライドを書けるツール。1枚のスライドが、画像でもパワポのオブジェクトでもなく、丸ごとコード(テキスト) になります。

で、スライドが丸ごとテキストだと、うれしいことが続きます。なかでも本命は、いちばん上の AI との相性です。

  • AI との相性が抜群
    中身が Markdown(テキスト)だから、AI(Claude Code)に読ませるのも書かせるのも思いのまま。そもそもこの記事の「AIにスライドを量産させる」が成り立つのは、これがあるからです。
  • Git で管理できる
    差分も履歴も残せて、普通のコードと同じノリでバージョン管理・レビューができる。
  • フロントエンドの感覚で作れる
    レイアウトも部品も Vue コンポーネントとして書けるので、Web を作るのと同じノリ。一度組んだ部品は使い回せるし、凝った見せ方もできます(フロントエンドに慣れてる人ほど、ありがたみが分かるはず)。
  • デザインをコードで縛れる
    色もサイズも余白も、CSS 変数で一元管理できる。

そして、この記事でこれから掘るのは、主にこの下のほう ── レイアウトと部品を Vue で組んで、色やサイズを変数で縛る。これも全部、”スライド=テキスト”だから成立する話です。パワポや Google スライドだと、こうはいきません。

なので、これから開けて見せる4階建て(style.css / layouts/ / components/ / CLAUDE.md)は、まるごと Slidev プロジェクトの中身です。動作環境は Slidev v51 系 / Vue 3 / UnoCSS(Slidev 標準同梱)。

そしてもう一方の前提が、AI 側に使ってる Claude Code です。とはいえ肝は「AI にルールを書いたファイルを渡す」という考え方のほうで、Claude Code 専用の話ではありません。CLAUDE.md という名前は、Claude Code がそのファイルを自動で読み込んでくれるから付けてるだけ。他の AI コーディングツールでも、ルールを読ませる場所に置くなり、プロンプトに貼るなりすれば、同じように効きます。

(Slidev のセットアップそのものは第1部に書いたので、「そもそも Slidev って?」という人はそちらから。)

デザインシステムは4階建て ― トークン・型・部品・ルール

で、その整備した環境の中身がこれです。”ひな型”って言うとフワッとしてますけど、構成としては4階建てになってます。

  • 1階:トークンstyle.css):色・サイズ・余白を変数で決めた「枠」
  • 2階:layouts/):繰り返すレイアウトの構造
  • 3階:部品components/):繰り返すパーツ
  • 4階:ルールCLAUDE.md):上の3つをどう使うかの作法

トークンの上に型が乗って、型の上に部品が乗って、その全部を4階のルールが束ねてる。上から下まで噛み合った1セットなんですよ。だから丸ごと持っていけるし、後から足して育てられる。

順番に見ていきましょう。まずは実物から。

まず実物を見る:トークン → 型 → 部品

理屈は後回しで、まず1〜3階を実物で見ていきます。掲載するコードはどれも要点を抜いた最小版です(実物はクラスや props がもう少し付いてますが、肝の部分は同じ)。テンポよくいきましょう。

コードはどれも、PNG エクスポートまで実際に確認したものです。

色とサイズを決める(style.css のトークン)

1階は土台。色・サイズ・余白を、ぜんぶ style.css:root変数(トークン)として置きます。スライド側で生の #C2410C みたいな値を直接書くことは、もう一切しない。必ずこの変数を経由する。

/* style.css:色・サイズ・余白を「変数」で一箇所に集める(これが土台の全部) */
:root {
  /* ブランド色 */
  --navy-900: #0B1F3A;   /* メインの濃いネイビー */
  --navy-700: #1B3357;
  --navy-300: #93A8C4;
  --bg-white: #FFFFFF;
  --bg-light: #F6F8FB;
  --text-primary:   #1E293B;
  --text-secondary: #475569;
  --text-muted:     #64748B;
  --accent:      #C2410C;   /* 抑えた朱。強調はこの1色だけ */
  --accent-soft: rgba(194, 65, 12, 0.10);
  --border-light: #E2E8F0;

  /* Notice 用の「意味の色」 */
  --info:    #1D4ED8;  --info-bg:    #EFF4FF;
  --warning: #B45309;  --warning-bg: #FFF7ED;
  --success: #15803D;  --success-bg: #ECFDF3;
  --danger:  #B91C1C;  --danger-bg:  #FEF2F2;

  /* コード表示(ネイビー地。暗地は朱が沈むので明色を別建て) */
  --code-bg: var(--navy-900);  --code-bar: var(--navy-700);
  --code-text: #E8EEF6;  --code-comment: #93A8C4;  --code-accent: #FFB27A;

  /* サイズ・余白 */
  --font-body:    20px;   /* 本文。19px は下回らない */
  --font-lead:    24px;
  --font-heading: 35px;
  --space-sm: 8px;  --space-md: 16px;  --space-lg: 24px;
}

そのうえで、全スライド共通の「地」を一度だけ当てておきます。フォント・背景・本文サイズみたいな、どのスライドでも必ず効いてほしいやつですね。

/* 全スライド共通の「地」。.slidev-layout に一度だけ当てる */
.slidev-layout {
  font-family: 'Noto Sans JP', sans-serif;
  background: var(--bg-white);
  color: var(--text-primary);
  font-size: var(--font-body);
  line-height: 1.6;
}

サイズ感の目安は「本文は最低 19px(--font-body は 20px で運用)、投影メインなら 24px くらいまで上げる」。この1本だけ決めておけば、あとはブレません。

つまり”自由に選ばせない/用意した中から選ばせる”に倒すわけです。

この「色とサイズを変数で縛る」考え方そのものは第3部でみっちり書いたので、ここでは実物だけ。要は、使う色とサイズをここで確定させて、あとは選ぶだけにするってことです。

型をそろえる(layouts/)

2階はレイアウトの「型」。繰り返す構造を layouts/ に置いて、スライドからは layout: 名前 で呼ぶだけにします。

ここで僕がひとつだけ決めてるルールがあります。構造が単純なら UnoCSS のユーティリティだけで書く/ヘッダ固定みたいに構造が複雑なら <style> で構造CSSを書く。この使い分け1本です。

たとえば「縦中央そろえ」みたいな単純なやつは、UnoCSS だけで完結します。

<!-- layouts/centered.vue:縦中央そろえ。UnoCSS だけ、scoped CSS なし -->
<template>
  <div class="slidev-layout h-full flex flex-col justify-center px-14 py-10">
    <slot />
  </div>
</template>

一方、上部にヘッダを固定して…みたいに構造が入り組むやつは、素直に <style> で組む。headingkicker を props で受けて、本文は <slot /> に流します。

<!-- layouts/fixed-header.vue:上部固定ヘッダ+本文。複雑なので <style> で構造を組む -->
<script setup>
defineProps({ heading: String, kicker: String })
</script>

<template>
  <div class="slide-with-fixed-header">
    <header class="slide-fixed-header">
      <h2 class="header-heading">{{ heading }}</h2>
      <span class="header-kicker">{{ kicker }}</span>
    </header>
    <main class="slide-body"><slot /></main>
  </div>
</template>

<style>
.slide-with-fixed-header { height: 100%; display: flex; flex-direction: column; }

/* 上部に固定する帯。色は当然トークン参照(生 HEX は書かない) */
.slide-fixed-header {
  height: 64px;
  background: linear-gradient(90deg, var(--navy-900), var(--navy-700));
  color: #fff;
  display: flex; align-items: center; padding: 0 40px;
}

/* 残りを本文に。flex:1 で高さを埋める=縦の中身を扱いやすくなる */
.slide-body { flex: 1; padding: 36px 44px; font-size: var(--font-body); }
</style>

<style> で「ヘッダを上に固定して、残りを本文が埋める」という構造を組んでます。こういう”骨格”が要るやつは、UnoCSS のクラスを並べるより <style> で書いたほうが見通しがいい。これが「複雑なら構造CSS」の中身です。

スライド側は、もう呼ぶだけです。

---
layout: fixed-header
heading: 監視の3本柱
kicker: basics
---

部品の色をそろえる(components/)

3階は「部品」。2回以上出てくるパーツは、Vue コンポーネントにして components/ に置いて、<PointCard> みたいに呼ぶだけにします。

部品で一番大事なのは、色だけは必ずトークン参照にすること。下が実物のカード部品ですが、背景やラベルの色を、生の HEX じゃなく var(--xxx) で書いてるのが分かると思います。

<!-- components/PointCard.vue:scoped CSS は書かず UnoCSS。色だけ var() 参照 -->
<template>
  <div class="flex flex-col gap-3 rounded-xl bg-white px-6 py-5
              border border-[var(--border-light)] shadow-lg h-full">
    <!-- ラベルの背景色も、トークンから選ぶだけ(朱 or ネイビー) -->
    <span :class="tone === 'accent' ? 'bg-[var(--accent)]' : 'bg-[var(--navy-900)]'">
      {{ label }}
    </span>
    <div class="text-[var(--text-primary)]"><slot /></div>
  </div>
</template>

スライド側は、型と同じでもう呼ぶだけ。さっきの fixed-header の本文を grid で割って、そこに PointCard を並べた1枚が、これです。

---
layout: fixed-header
heading: 監視の3本柱
kicker: basics
---

<div class="flex-1 flex flex-col justify-center">
<div class="grid grid-cols-3 gap-6">

<PointCard label="Logs" tone="navy">

「何が起きたか」の記録。まずはエラーログを1か所に集約する

</PointCard>

<PointCard label="Metrics" tone="accent">

「どれくらいか」の数値。レイテンシ・エラー率・飽和度を継続観測

</PointCard>

<PointCard label="Traces" tone="navy">

「どこで遅いか」の経路。リクエストをサービス横断で追う

</PointCard>

</div>
</div>

こうしておくと、部品が10個20個と増えても色が割れない。新しいカードを足しても、必ず同じ朱・同じネイビーになる。これがシステムが崩れない肝なんですよ。

部品は一度作っちゃえば、あとは使い回しができます。ちなみに、こうやって「良かったパターンを型・部品・ルールに貯める」っていう考え方自体は第4部で書いた話です。この記事はその”実物”を全部開けて見せてる、という位置づけですね。

4階の CLAUDE.md ― 素材を“毎回そろえて持ち運ぶ”

ここまでの3階(トークン・型・部品)は、個別単位で効く”素材”です。で、正直に先に言っておくと、この素材、AIはわりと素直に使ってくれます(どのくらい上手いかは、この記事の後半でわざと意地悪な実験をして確かめます)。

じゃあ4階のルールは何のためにあるのか。「毎回・誰がやっても・同じ枠」にそろえるためです。素材があっても、放っておくとAIは毎回ちょっとずつ違うものを出すし、ときどき”惜しい”はみ出し方をします。絵文字を入れて文字化けさせたり、本文がスッと小さくなったり。ルールとして明文化することで無視をする確立を減らします。

このシステムで 「いちばん持ち運ぶ価値があるのも、この4階」 です。1〜3階の素材は、”使い方”のルールが一緒にないと、ただのファイルの寄せ集めになってしまいます。

だから、1〜3階の使い方を全部ルールにして CLAUDE.md に書く。Slidev のプロジェクトに CLAUDE.md を置いておくと、Claude Code はそのディレクトリのファイルを触ったとき自動で読み込みます。つまりこれが、AIに毎回手渡す”誓約書”になるわけです。(たまーに全力で無視をするときは後からCLAUDE.mdを参照させて自己修復させたりします)

ルールの全文(これを渡すだけ)

中身はそんなに難しくないです。1〜3階で見た作法を、そのまま言葉にするだけ。出し惜しみしても仕方ないので、僕が実際に使ってる CLAUDE.md を全文そのまま載せます。これをコピーして自分の Slidev プロジェクトの CLAUDE.md に置けば、それだけで枠が効きます。

# スライド作成ルール(Slidev デザインシステム)

このプロジェクトのスライドは、**1つの統一されたデザインシステム**の内側だけで作る。
AI(Claude Code)はスライドを生成・編集するとき、**必ず以下のルールに従う**こと。
このファイルごと渡せば、別プロジェクトにも同じシステムを移植できる(それが狙い)。

---

## 0. 大原則:自由に書かせない(制約が速さを生む)

- 色・サイズ・余白・アイコンを**その場で勝手に決めない**。下のトークン/ルールの中からだけ選ぶ。
- 「いい感じに」ではなく「**この枠の中で**」。選択肢を絞るほど出力は安定する。
- 迷ったら**増やさず減らす**。強調は1色、レイアウトは既存の型を優先。

## 1. 色(トークン)

- 色は `style.css` の `:root` で定義した **CSS変数だけ**を使う。生 HEX の直書きは**禁止**。
- 必ず `var(--xxx)` 経由で指定する(UnoCSS なら `bg-[var(--accent)]` のように arbitrary value で参照)。
- 使える色:
  - 背景:`--bg-white` / `--bg-light`
  - 文字:`--text-primary` / `--text-secondary` / `--text-muted`
  - ネイビー:`--navy-900` / `--navy-700` / `--navy-300`
  - 強調:`--accent`(抑えた朱)/ `--accent-soft`
  - 罫線:`--border-light`
  - コード(ネイビー地):`--code-bg` / `--code-bar` / `--code-text` / `--code-comment` / `--code-accent`(暗地は朱が沈むので強調は明るい朱橙の `--code-accent` を使う)
- **強調色は3色まで**。基本は朱 `--accent` の1色で十分。色数を増やすと「どこが大事か」が消える。

## 2. サイズ・余白(トークン)

- フォントサイズは `--font-*` を使う。**本文は `--font-body`(19px は下回らない)**。投影・配信で読めるラインを守る。
  - `--font-body` / `--font-lead` / `--font-heading`
- 余白は `--space-*`(`--space-sm` / `--space-md` / `--space-lg`)を使う。刻みを揃える。
- UnoCSS を使う場合は既製スケールに乗ってよい(**本文は `text-xl` 以上(=20px。`text-lg` は 18px で下限割れ)**、余白は `gap-4` / `p-4` など)。
- 色・サイズ・余白は**すべて変数 or ユーティリティ経由**。マジックナンバーの直書きをしない。

## 3. アイコン

- アイコンは **Material Icons に一本化**する:`<span class="material-icons">名前</span>`。
- **絵文字(🚀✨✅ など)は使わない**。エクスポート(PNG/PDF)で消える・豆腐化するため。

## 4. 型(layouts/)と 部品(components/)

- 繰り返す構造は**型**(`layouts/`)、繰り返すパーツは**部品**(`components/`)にして、`layout:` / タグで呼ぶ。
- 新規スライドは**まず既存の型・部品から組む**。無いときだけ新しく作る(§7 の作り方に従う)。
- レイアウトの実装は**1つの使い分けルール**で選ぶ:
  - **構造が単純** → `centered.vue` のように **UnoCSS ユーティリティのみ**(scoped CSS を書かない)。
  - **構造が複雑**(ヘッダ固定・本文枠など)→ `fixed-header.vue` のように **`<style>` の構造CSS**。
- **コンテンツ枚は基本 `fixed-header`(上部固定ヘッダ)で統一**。「課題」「まとめ」等のセクションも heading に入れてヘッダー化する(地味に効く統一感)。
- **横並び(columns)**:ヘッダ付きの中での横並びは fixed-header の本文を Tailwind の `grid grid-cols-2 gap-10` で割る。ヘッダ無しの全面2カラムが要るときだけ `two-col.vue`。`.columns` のような global ユーティリティは作らない。
- 縦中央に伸ばす(旧 content-expand)は **Tailwind の `flex-1 flex flex-col justify-center`** で閉じる。global クラスにしない。
- 部品の色は**必ずトークン参照**(`bg-[var(--accent)]` 等)。部品が増えても色が割れないようにする。
- **フロー(ステップを矢印でつなぐ/§7 の推奨形)**:`PointCard` を `flex items-stretch gap-3` の行に `flex-1` で並べ(カードは等高に揃える)、各カードには `card-class="justify-center"` を渡して**本文を縦中央寄せ**にし、間の矢印 `<span class="material-icons text-4xl">arrow_forward</span>`(`items-center` で挟む)と視線の高さを合わせる。矢印は専用部品を作らず Material Icons+トークン色(`text-[var(--navy-300)]`)で閉じる(独自の矢印SVG・生HEXは使わない)。※カード本文を縦中央寄せにしないと、本文が上寄りのとき矢印だけがカード縦中央=テキストより下に取り残されて見える。

## 5. 「どこに書くか」(CSS の置き場所)

判断は1つ:**「どのスライドでも必ず効いてほしいか?」**

- **全スライド共通の土台**(トークン、ベースのフォント・色・背景)→ `style.css`。
- **その型・部品の中だけの見た目** → その `layouts/` `components/` の中に閉じ込める。
- **この1枚だけ** → そのスライドに `<style>`(常に scoped・他に漏れない)。

書き方の作法:

- `style.css` の共通スタイルは **`.slidev-layout` の配下に書く**(素の `h1 {}` は発表者モードUIにまで漏れる)。
- **`!important` は基本使わない**。効かないときは置き場所・継承(§6)を疑う。(Slidev 組み込みの高優先度スタイルとどうしても競合する箇所=固定ヘッダの見出し等だけ、そこに限って許容する)

## 6. ★ 最重要の罠:自作レイアウトは `.slidev-layout` を継承しない

- 組み込みレイアウト(default / two-cols 等)は、その template 内で **自分で** `class="slidev-layout"` を付けている(Slidev が自動で付けるわけではない)。だから `style.css` の共通スタイルが効く。
- **自作レイアウトは自分で `class="slidev-layout"` を付けないと、`style.css` の共通スタイル(トークン・見出し色・kicker・マーカー)が一切効かない**。見出しが素の小さい黒文字に戻る。
- 対処(どちらか):
  1. 型の wrapper に `class="slidev-layout"` を足す。
  2. 型の中身を UnoCSS で完結させる(共通スタイルに依存しない)。

## 7. AIっぽさの回避(必ず守る)

| やりがち(AIっぽい) | 代わりにこうする |
|---|---|
| Inter / Poppins フォント | Noto Sans JP に寄せる |
| 紫〜青のグラデ背景 | 単色(ネイビー/白)+必要なら薄いノイズ |
| 完全対称なレイアウト | わざと少し非対称に(scale / opacity の差) |
| 同じカードを3枚横並び | 矢印でつなぐフロー形式に |
| 角丸カードで全面を埋める | レイアウトを複数種類使い分ける |

- **1つの図・1枚のスライドに1メッセージ**。詰め込まない。
- 配信向けは可読性最優先(本文を十分大きく。目安 24px 以上)。

## 8. 仕上げ(必ず)

- ルールに書いた=画面でその通り出てる、とは限らない。**最後は必ず PNG にエクスポートして、画像を目で見て確認**する。
  - `cd application/slides && npx slidev export src/<name>/slides.md --format png --per-slide --output src/<name>/export/slide`
- 崩れていたら §5・§6(置き場所・継承)をまず疑う。

---

## このプロジェクトの現物

**原則:global は「地」だけ。構造は layouts/、装飾は components/、細部は Tailwind(UnoCSS) で閉じる。**

| 種類 | ファイル | 中身 |
|---|---|---|
| 地(global) | `style.css` | `:root` トークン+ `.slidev-layout` の地(font・色・背景・size・h1・インラインcode)だけ |
| 型:タイトル | `layouts/title.vue` | ダークネイビーのヒーロー。`.slidev-layout` を付けず型内で完結(閉じる) |
| 型:縦中央 | `layouts/centered.vue` | UnoCSS のみ(scoped CSS ゼロ) |
| 型:固定ヘッダ | `layouts/fixed-header.vue` | 上部固定ヘッダ+本文(構造CSS)。props `heading` / `kicker` |
| 型:横並び | `layouts/two-col.vue` | 自作 two-col(UnoCSS grid)。本文=左、`::right::`=右 |
| 罠デモ | `layouts/trap.vue` | あえて `.slidev-layout` を付けない(§6 の実演用) |
| 部品:見出しラベル | `components/Kicker.vue` | 朱の縦バー。slot |
| 部品:箇条書き | `components/Points.vue` | 朱ひし形マーカー。slot に markdown リスト |
| 部品:Notice | `components/NoticeBox.vue` | `type`(info/warning/success/danger)+ `title` + slot。Material Icon・色はセマンティックトークン |
| 部品:カード | `components/PointCard.vue` | `label` / `tone` + slot。色はトークン参照 |
| 部品:ルール箱 | `components/RuleBox.vue` | ルール提示ボックス。slot |
| 部品:コードブロック | `components/CodeBlock.vue` | ネイビー地のコードパネル。`file` / `lang` props。装飾は scoped で閉じ、色は `--code-*` トークン参照 |

- **コードブロックは `CodeBlock.vue` で閉じる**:slot に素の `<pre>` を入れ、強調は `<span class="c">`(コメント)/`<span class="k">`(キー)の2色だけ。Slidev の ` ``` ` フェンス(Shiki)は生成色=非トークンの色が混ざるので、地が暗いコード掲載には使わない。

- 横並び=`two-col.vue` を使う(`.columns` のような global ユーティリティは作らない)。
- 縦中央に伸ばす(旧 content-expand)= Tailwind の `flex-1 flex flex-col justify-center` で閉じる(global クラスにしない)。
- 装飾の色は**すべてトークン参照**(`var(--x)` / `bg-[var(--x)]`)。生 HEX 直書きはしない。

長いですけど、やってることはシンプルです。「色は変数だけ・強調は1色・本文19px・アイコンは Material Icons・レイアウトは単純=UnoCSS/複雑=構造CSS・部品の色はトークン参照」。これを全部”やっていいこと/ダメなこと”として具体的に言い切ってるだけ。「いい感じに」じゃなくて「この枠の中で」。選択肢を絞れば絞るほど、AIの出力は安定します。

特に効くのが、上のルールにある「AIっぽさの回避」の表。放っておくとAIが寄っていく”なんかダサい方向”(紫青グラデ、絵文字、カード3枚横並び……)を、先回りで名指しして塞いでます。ここがあるだけで、出力の”AI製っぽさ”がガクッと減るんですよ。

上の CLAUDE.md の末尾には、実は「今後デザインを追加するときの実例プロンプト集」も付けてあります。それは次の章で実際に使ってみせるので、ここでは省きました。

何度もはまる罠についてはルール化して永続化する

ルールが効くって話で、わかりやすい例を一つ。

Slidev にはやっかいな罠があります。自作のレイアウトは、style.css に書いた共通スタイルを自動では継いでくれないんですよ。種を明かすと、Slidev 同梱のレイアウト(defaulttwo-cols)は、その中で class="slidev-layout"自分で付けてるから共通スタイルが効くだけ。Slidev が勝手に付けてくれるわけじゃないんです。だから自作レイアウトも、自分で付けないと効かない。付け忘れると、せっかくトークンで決めた見出しの色やサイズが全部すっぽ抜けて、見出しが素の小さい黒文字に戻ります。連載を通しでやってると、地味に一番ハマるやつです。

で、これも対処はルールに1行書くだけ。「自作レイアウトには必ず class="slidev-layout" を付ける」。たったこれで、AIは二度とこの罠を踏まなくなる。ハマって覚えた知見も、こうやってルールに畳んでおけるんですよ。

このファイルを渡す=枠の内側に閉じ込める

要するに、この1枚を AI に渡しておくと、出力がシステムの内側に収まりやすくなるし、まるごとコピーすれば別プロジェクトにも移植できる。……って、口で言うのは簡単ですよね。本当に効くの? っていうのを、ここから実際に試していきます。

で、どう打つの? ― プロンプトで「足す」・言葉で「回す」

ここからは実演です。さっきの CLAUDE.md を渡した状態で、実際にどんなプロンプトを打つと、どう返ってくるのか。「足す」と「回す」の2つを見せます。

足す:既存システムに新要素をプロンプトで追加

まずは「足す」。既存のデッキに、新しい要素をプロンプトで追加するパターンです。

たとえば「矢印でつなぐフローのスライドを1枚足して」と頼むとき、僕はこう打ちます。

このデッキに、複数のステップを矢印でつなぐ「フロー」のスライドを1枚追加して。
- まず同じディレクトリの CLAUDE.md を読んで、そのルールに必ず従うこと。
- 既存の型(layouts/)と部品(components/)を使い、トーンに合わせる。
- 矢印やステップの色もトークンに合わせる。生 HEX の直書きはしない。
- 追加したら PNG にエクスポートして、見た目が崩れてないか自分で確認して。
- ルールに無い要素や崩れが出たら、その場しのぎで直さず CLAUDE.md に1行足す形で対応して(=育てる)。

ミソは最後の2行です。「CLAUDE.md に従う」と「最後に PNG で確認」をセットで毎回言う。これで枠から出なくなるし、出来上がりを自分で目視チェックさせられる。

実際これでフローを足したのがこれです。矢印は絵文字じゃなく Material Icons、色は既存のトークン。ちゃんとシステムのトーンに乗ったまま追加されてます(Slidev 標準のアイコンは Iconify ですが、CDN を1行読むだけで設定いらずな Material Icons に寄せてます。絵文字と違ってエクスポートでも消えないので)。

もう一つ、面白かった話を。別のとき、同じ”足す”プロンプトで「コードブロックのスライドを足して」と頼んだら、AIが「いまのルールにはコード表示の色指定が無いですね」と気づいて、CodeBlock.vue という部品を自分で作り、CLAUDE.md にもルールを足してきたんですよ。

これ、証拠がさっきの CLAUDE.md に残ってます。色のところにある --code-bg / --code-text / --code-accent(暗地コード用に明るい朱橙を別建てするやつ)――あれ、最初から書いてたんじゃなくて、このとき AI が足したものです。指示したのは「ルールに無い要素が出たら CLAUDE.md に1行足して」だけ。足りないものに気づいて、その場で埋めて、次から使える形にしてくれた。これがまさに”育てる”です。

回す:自然言語ループでレイアウトを動かす

もう一つは「回す」。一度出てきたスライドを、言葉だけで何度も作り替えていくパターンです。

あるフローのスライドが、横並び4枚に長い説明文を詰め込んでて、日本語が単語の途中で折り返して詰まって見えたんですよ。で、CSS は一切触らず、こんなプロンプトで作り替えていきました。

7枚目のフローを「縦積み」レイアウトに作り替えて。CLAUDE.md のルールに従い、CLAUDE.md 自体は変更しないこと。
- 4ステップを上から下へ縦に積む。各ステップは横長の1バンド。
- 左に「番号+短いタイトル」、右に説明文(左右で分離)。横幅が広いので1行に収まる。
- ステップ間は下向き矢印でつなぐ。
- 直したら PNG で7枚目を必ず目で見て、溢れてないか確認して。

横並び → 2×2に分離 → 縦積み、と段階的に動かしたんですが、全部 自然言語のプロンプトだけ。手でCSSを書いた箇所はゼロです。

しかもこの間ずっと、色はトークンのまま、部品も既存のまま。枠の中で動かしてるから、どう作り替えてもトーンが崩れない。「言葉だけで回す」が成立するのは、土台にルールがあるからなんですよね。

本当に移植できるのか ― CLAUDE.md だけで建て直してみた

「足せる」「回せる」は分かった。でも一番でかい主張、このシステムは丸ごと別プロジェクトに移植できるってやつ。これは本当なのか。ちょっと意地悪な実験をしてみました。

やり方はこう。新しい Claude Code のセッションに、CLAUDE.md だけを渡す。トークンも型も部品も、お手本になる既存のデッキも、一切見せない。そのうえで「Git ブランチ戦略の入門スライドを、別のブランド色で一から作って」と頼む。ルールだけを頼りに、ゼロから建てられるか?という実験です。

先に言っておくと、ガチガチに統制した実験じゃなく”やってみた記録”です(各1回ずつ)。ただ今回は、ルールを渡した版と ルールを一切渡さない「対照」版 の両方を回したので、ルールが本当に効いてるのか・どこに効いてるのかが、わりとハッキリ見えました。順番にいきます。

CLAUDE.md を渡したら、別ブランドのデッキが建った

実際に投げたのが、このプロンプトです。「お手本を絶対に見るな」と念押ししてるのがミソ。これで「真似したから揃った」の逃げ道を塞いでます。

application/slides/src/git-branching/ に、Slidev のデッキを「一から」作ってほしい。
- このディレクトリには CLAUDE.md だけが置いてある。まずそれを読み、必ず従うこと。
- style.css / layouts/ / components/ / slides.md はまだ無い。CLAUDE.md のルールに沿って自分で新規に作る。
- ★重要:他のデッキ(特に blog-design-system/)の style.css・layouts・components は
  絶対に開かない・参照しない。手元の CLAUDE.md だけを唯一の根拠にすること。
- ブランド色は元(ネイビー+朱)とは別系統にする(例:ダークグリーン+抑えた琥珀)。
  生 HEX を置くのは style.css の :root だけ。利用側は var() 参照。
- 題材は「Git ブランチ戦略入門」。タイトル / アジェンダ / 課題 / 比較カード /
  Notice / コマンド例 / 導入フロー / まとめ を含む 6〜8 枚。
- できたら PNG にエクスポートして、崩れてないか自分で確認して。
- ルールに無い要素や崩れが出たら、その場しのぎで直さず CLAUDE.md に1行足す形で対応して(=育てる)。

結果から言うと、建ちました

渡したのは CLAUDE.md 1枚だけ。なのに別セッションのAIは、style.css のトークンを自分で定義し直して(しかも色は元のネイビー+朱じゃなく、ちゃんと別系統のダークグリーン+琥珀にして)、レイアウトの型も部品も白紙から組んで、8枚のデッキを作り上げました。

色も題材も別物なのに、できあがったものは「同じデザインシステムの色違い版」にしか見えないデザインが出てきました。主観だけだと弱いので、数えられる事実で言うと、こうです。

  • ブランド色は別系統に振られてた(元 #0B1F3A#C2410C → ダークグリーン+琥珀 #102a1d#b07d24
  • 生 HEX の直書きは style.css:root 定義以外ゼロ。利用側は全部 var() 参照
  • 固定ヘッダ・強調1色・矢印フロー・暗地のコードパネルと、規律はそのまま再現
  • 8枚すべて PNG 化して崩れなし

お手本のデッキは一切見せてないのに、です。

「本当に見てないの?」も裏取りしました。Claude Code の操作ログで元デッキ(blog-design-system)を一度も開いてないことを確認したうえで、トークンの値もレイアウトの実装も元とは別物(クラス名も手法も違う)なのを照合済み。真似たんじゃなく、ルールから独立に建てた、です。

ルール無しと比べたら ― 素の Claude は何点か

じゃあ逆に、ルールを一切渡さなかったらどうなるのか。まっさらなセッションに、CLAUDE.md もトークンも何も渡さず、「Git ブランチ戦略のスライドをいい感じに作って」とだけ頼んでみました(さっきと同じ題材で)。

これがね、けっこう上手いんですよ。正直びっくりしました。

  • 色は頼んでないのに CSS変数(トークン)化してた。生 HEX の直書きはほぼ無し
  • カード3枚並びで終わらせず、矢印フローも自分から使ってた
  • レイアウトも部品も自前で切って、見た目はちゃんとプロっぽい

つまり、この記事で「ルールのおかげ」と思ってた作法のかなりの部分は、Claude が素でやれます。ここは正直に認めます。Claude Code、地力が高い。

でも、ルール無しだと小さいところで転ぶんですよ。

  • 絵文字を使って豆腐(□)化してた。フォントに無いグリフで文字化けして、後から自分で直すハメに(ルールがあれば最初から Material Icons に寄せて回避)
  • 本文に 0.6〜0.8rem の小さすぎる字が散在。投影したら読めないやつ(19px 下限ルールが防ぐ)
  • 自作レイアウトに class="slidev-layout" を付けてなかった。共通スタイルを .slidev-layout に置いてるのに、です。今回はたまたま自前のスタイルで隠れてたけど、一歩間違えれば見出しが死ぬ、さっきの継承の罠そのもの(「自作レイアウトに class を付ける」ルールが明示で潰すやつ)

要するに、体感だと、素の Claude が 80点くらい。ルールがそれを 90〜95点に引き上げて、毎回そこに揃う感じです。ゼロから品質を生む魔法じゃなく、“惜しい小さな躓き”を先回りで縛るものなんですよね。しかも素の80点は一回こっきり・自己流で、次のデッキも同じ80点になる保証はないし、チームの他の人が同じトーンになる保証もない。毎回・誰でも・同じ品質にして、それを丸ごと移植できるようにする。そこがルールの本当の値打ちです。

ルールを1行直すと、全デッキが同時に直る

おまけに、システムを持つことの一番のうまみも実演できました。

実は途中で、僕が CLAUDE.md に書いた「矢印フローの作法」にちょっとしたバグがあったんですよ。矢印がカードの本文より下にズレる、ってやつ。で、これが元のデッキと、移植先のデッキ、両方に伝染してた。コピーで不具合も一緒に広まる、ってやつですね。

でも直すのは簡単で。バグってるのは”ルールの1行”なので、そこを直して各デッキに反映するだけ。スライドを1枚ずつ直して回る必要がない。直すべき場所がルールに1か所、っていうのがミソです。バラバラにスライドを作ってたら、同じ崩れを全部のスライドで手作業で潰すハメになる。1つのシステムに統一してるからこそできる芸当なんですよ。

ただ、これは裏を返すと注意でもあって。配る CLAUDE.md にバグがあると、コピー先全部に一緒に伝染する。なので、このルールを持っていったら、CLAUDE.md にも書いてある「最後に必ず PNG で目視確認」を忘れずに。コピーは便利だけど、不具合ごとコピーしてないかは自分の目で見る、です。

1つに統一するから、移植できて・育つ

バラバラに便利なパーツを集めても、デザインは育ちません。トークン+型+部品+ルールを、1つの噛み合ったシステムに統一する。そうすると、こうなります。

  • AIに作らせても毎回トーンが揃う(揃うように設定したから)
  • 別プロジェクトにも移植できる。普段はデッキを丸ごとコピー、最悪 CLAUDE.md 1枚でも AI が建て直せる(さっき実際に試したとおり)
  • ルールを直せば、コピー先のデッキもまとめて直せる

持ち帰り方はシンプルです。AIにこちらのブログを読み込ませて自分の環境で取り込んでみてくださいstyle.csslayouts/components/ がそのまま手元に残るので、色だけ自分のブランドに差し替えれば、もう同じシステムが動きます。再利用の単位は「ルール」じゃなくて「動く実装一式」、これが日常の本線です。

そのうえで、さっきの実験がいいフォールバックを見せてくれました。最悪、CLAUDE.md を1枚引っ越すだけでも助かる。実装ファイルを持ち歩けなくても、ルールさえ渡せば AI が残りを建て直してくれる。そこまで本質がルールに宿ってる、という証明でもあります。普段はコピーで速く、いざとなればルールだけでも建つ ── これが「丸ごと持っていける」の中身です。

もう1つ。移植できるまで育ったこの一式(layouts/ components/ styles/)は、Slidev の theme のディレクトリ規約とほぼ同じ構成です。「複数プロジェクトで配りたい」となったとき、package.json を1枚追加するだけで theme として切り出せます。書き直しは要りません。

「theme を作るぞ」と最初から意気込むより、使って気に入ったものを貯めて、作って壊してを繰り返して、最後に残ったものを theme に蒸留する、という順番のほうが長続きします。theme は出発点じゃなくて、育ったあとの結果なので。

今回は”実物”の話に振り切りましたが、「なんでトークンで縛るの?」「型・部品・ルールに貯めるってどういうこと?」っていう設計思想のほうは、連載の第3部(デザイントークン)と第4部(デザインシステムの育て方)でじっくり書いてます。実物で気になったところがあれば、そっちも覗いてみてください。

それでは、よいスライドライフを!

シリーズ:AI×スライドづくり

AIに丸投げせず、制約とルールで「意図どおりの95点」を毎回そろえて作るシリーズです。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。
エンジニア募集中!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です