sb-stories について
sb-storiesは、コンポーネントやページのStorybookストーリーを作成する開発者向けスキルです。実際の利用状況と重要な状態を重視し、検証スクリプトで成果物を確認します。
主な機能
- 01重要な状態のストーリー作成
- 02利用データに基づくバリアント選定
- 03実ページの読み込みとデータのモック
- 04Controls、オーバーレイ、操作の扱い
- 05スクリプトによるストーリー検証
活用シーン
- 01既存コンポーネントの状態ストーリー追加
- 02実ページと異なるデータ状態でページストーリーを作成
- 03複数コンポーネントのストーリー作成と検証
MCP 対応
プロジェクトのMCP設定の有無に応じて執筆ガイドを選びます。WITH_MCPの手順では、MCPがCSF3の規約を提供します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ strongeron/ storybook-workbench --skill sb-storiesインストール後、Claude Code で/sb-storiesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CONTEXT.mdagents/openai.yamlreferences/anti-patterns.mdcomposition-patterns.mddirectory-structure.mdextraction-workflow.mdfactory-patterns.mdstorybook-surface.mdtest-wiring.mdvalidate-workflow.mdwith-mcp.mdwithout-mcp.mdscripts/check-story-ready.shdiscover-runtime.pyextract-prop-shapes.shextract-states.shpage-patterns.pyscaffold-factory.shscaffold-page-story.pyvalidate-stories.shtemplates/controlled-component-story.tsx詳細
sb-stories — 1 つのコンポーネント、その実際の状態
デフォルトの Build モードです。コンポーネントは src/components/ にあり、その表示状態を示すストーリーを記述します。
作成前に確認すること
- 実際に使われていますか?
.storybook/project-inventory.jsonのcomponents.real[]を確認してください。dead[]に含まれている場合は削除し、ストーリーは作成しないでください。vendor(shadcn のui/)の場合は優先度を下げてください。 - 動作や見た目が大きく変わる状態はどれですか? 直積の組み合わせは避けてください。プリミティブごとの最小テーブルは
references/anti-patterns.mdにあります(Button 8、Input 8、Modal 5、Form 6)。推測するのではなく.storybook/component-states.jsonを確認してください。ファイルがない場合は、先に生成してください:scripts/extract-states.sh。(より大きな抽出コンテキストについてはreferences/extraction-workflow.mdを参照してください。)それらすべての状態を1つのキャンバスにレンダリングするには、sb-wrappersのStateGridラッパー(variants × states →StateMatrix)を使ってください。グリッドを手作業で作成しないでください。これらはコンポーネント作成時のラッパーです。データラッパー(ProjectInventory/DesignSystemHealth/AppFlowGraph …)は、それぞれの手順の後に使います。 - このアプリで実際に使われている状態はどれですか?
.storybook/component-usage.jsonを確認してください(sb-inventoryのextract-component-usage.shで生成します。ファイルがない場合は生成してください)。props.<prop>.valuesを使って、実際の呼び出し箇所で渡されているバリアントを優先してください。declaredButUnusedに含まれるもの(例:variant=dangerが一度も使われていない場合)についても、網羅性のために状態を作成しますが、['usage:unused']タグを付けて「このアプリでは未使用」と記載してください。本番環境でレンダリングされない状態でカタログを水増ししないでください。 - コンポーネントごとのドキュメントを手作業で作成する必要はありません。すべて一度だけ合成されます。 各コンポーネントの autodocs ページには、すでに**「このアプリでの実際の使用例」のセクションが追加されています。
sb-setupによってpreview.tsのdocs.pageに一度だけ組み込まれるUsageSectionブロックが、使用状況グラフ(component-pages.json)から読み取った、コンポーネントごとの「使用箇所」**マップ(表示されるページ、内包する要素、レンダリング内容、参照するトークン)を表示します。そのため、ストーリーを追加したら、使用状況のブロックを手動で追加しないでください。refresh-usage.shを実行するだけで、グラフが最新になり、セクションに内容が反映されます。グラフ全体を対話的に調べるには(任意のトークン/コンポーネント/ページから、その使用箇所すべてに移動できます。クリック可能です)、UsageExplorerラッパー(sb-wrappers)を構成してください。詳細と docs.page の構成については、sb-inventory(§「autodocs での実際の使用例」)およびsb-setup(docs-page の構成)を参照してください。 - ファクトリーは必要ですか? 同じデータ形状を共有するストーリーが3つ以上ある場合は必要です。
.storybook/prop-shapes.jsonを確認してください(候補にはliveUsagesのフラグが付きます)。ファイルがない場合は、先にscripts/extract-prop-shapes.shを実行してください。 次にscripts/scaffold-factory.sh <Type> <import-path>を実行し、決定論的なスタブに値を入れてください(references/factory-patterns.md)。それ以外の場合はargsをインラインで記述します。 - タイトルの分類はありますか?
storySort.orderに合わせてください。プロジェクトに設定がない場合は、references/directory-structure.mdを参照して選択してください。 playを追加する価値はありますか? インタラクション、非同期データ、ポータル、CSS による状態、またはアクセシビリティの場合に限り作成してください。単にtoBeVisible()を実行するだけのものは作成しないでください(アンチパターン34)。また、プロジェクトに必要なCssCheckはちょうど1つです(アンチパターン33)。共有プレビューでアプリの CSS が読み込まれていることを証明する唯一の手段として、実際のgetComputedStyleのトークン値を検証するストーリーを1つ作成してください。どちらもnpx storybook ai setupのプロンプトから追加されます。validate-stories.shのチェック13とプロジェクト全体の件数チェックで必須になっています。- 「playground」/ショーケースストーリーは、クリックやホバーではなく Controls で操作します。 レビュアーから「この playground ストーリーとは何ですか?クリックやホバーはできますか?」と聞かれた場合、playground とは Controls パネルが付いたデフォルトストーリーのことだと説明してください。Controls タブで
args(variant、size、state)を変更すると、キャンバスが再レンダリングされます。キャンバス上でのインタラクションではありません。ホバー/フォーカス/アクティブ状態はStateGridのインタラクションマトリクス(addon-pseudo-states)で、スクリプトによるクリック→アサートのフローはplay関数で扱います。つまり、Controls はプロパティの試用、疑似状態はホバー/フォーカスの列、playは実際のインタラクションです。ストーリーがどれに該当するかを明示してください。 - Controls パネルは設定されていますか? コンポーネントのストーリーには、使用可能な Controls パネルを表示する必要があります。これはレビュアーがプロパティを試すためのサンドボックスであり、autodocs の ArgTypes テーブルにも利用されます。react-vite のデフォルト(
react-docgen)では、TS のユニオン型はセレクトとして推論されません。そのため、各 enum/union プロパティにargTypes(control: 'select'|'inline-radio'とoptions)を宣言し、table.categoryでグループ化してください。また、回避用のプロパティやシリアライズできないプロパティ(className、refs、icon/callback/data プロパティ)は非表示にし、レンダリングのみのショーケースストーリーでは Controls を無効にしてください(parameters: { controls: { disable: true } })。パターン全体と docgen の注意点についてはreferences/without-mcp.md§13 を参照してください。(パネル自体が表示されている必要があります。sb-setupはshowPanel: trueを設定したmanager.tsを作成します。sb-auditのaudit-controls.shは、この設定がないコンポーネントストーリーを検出します。)
ソースの作成(相互排他的 — どちらか一方だけを読み込みます)
grep -q '@storybook/addon-mcp' package.json && test -f .mcp.json && echo WITH_MCP || echo WITHOUT_MCP
WITH_MCP→references/with-mcp.md(MCP が CSF3 の規約を適用するため、判断に集中できます)。 ツール名は Storybook のマイナーバージョン間で変わります。現在の名前はreferences/storybook-surface.mdに記載されています。WITHOUT_MCP→references/without-mcp.md(13 の検証ギャップと 4 つの重要な SB10 パターン)。- 制御コンポーネント(Switch/Toggle/Checkbox/Tabs/Accordion/Select)には、
templates/controlled-component-story.tsxを使用します。AI が間違えやすいのはuseArgsによる同期です。
ファイルの保存場所(先に確認してください — リポジトリ内に散在させないでください)。 .storybook/audit/status.md から
storiesLocation を読み取ります(唯一のルールは CONTEXT.md §STORIES LOCATION にあります)。
- 未設定の場合(リポジトリに既に Storybook があり、
sb-setupで確認されていない場合など)、ストーリーを書く前に必ず停止してユーザーに確認してください — 推測したり、暗黙のうちに同じ場所に保存したりしないでください。AskUserQuestion(Claude)/request_user_input(Codex)を使うか、ブロックするツールがない場合は番号付きリストを使用します。ストーリーの保存先はどこにしますか?(それ以外はすべて
.storybook/の下にあります。).storybook/stories/(推奨 — 1 か所にまとめて分離し、src/は変更せず、フォルダーごと削除できます)- コンポーネントと同じ場所
src/**/<Name>.stories.tsx(長期的に所有するプロジェクト向け) - カスタムフォルダー (指定した場所にまとめて保存します)
その後、
.storybook/audit/status.mdにstoriesLocation: <isolated|colocated|PATH>と記録し、main.tsのstoriesにそのパスが含まれていることを確認してから続行します。オプション 1 を推奨します。
isolated(または.storybook/stories/) →.storybook/stories/の下に、ツリー構造を反映して保存します (.storybook/stories/components/CourseCard.stories.tsx)。@/エイリアスを使ってコンポーネントをインポートします。 開発サーバーは.storybook/stories/を監視しません。そのため、ここでストーリーファイルを追加、移動、削除しても、Storybook を再起動するまではインデックスに反映されない(または古い状態のままになる)ため、すべての MCP ツールで「ストーリーが見つかりません」と報告されます。ここでファイルを変更した後は再起動してください(10.6.0 で確認済み。src/のストーリーはリアルタイムで更新されます)。colocated→src/components/<X>/<X>.stories.tsx。カスタムパス → すべてのストーリーをその場所に保存します。
回答にかかわらず、すべてのストーリーをその 1 か所に保存してください — 複数の場所に分けないでください。
タイトル(ファイルパスとは別の、Storybook 内のパス)は .storybook/preview.ts
storySort.order に合わせます。該当しない場合は Components/<Domain>/<Name> を使用します。Overview/Spec/ハブストーリーはエントリーポイントです。storySort.order でルートの先頭に固定します(ルートレベルのハブは最初に配置し、機能ごとの Overview/Spec はグループ内のサブ順序で最初にし、末尾に '*' を置きます)。要約対象のコンテンツの途中にアルファベット順で紛れ込ませないでください。references/directory-structure.md の「Overview/spec/hub」を参照してください。
ページ — 実ページのキャプチャ(モード A)
ページ(pages/ · app/ · routes/ · views/ 配下のルート/ビュー)は再作成しないでください。
まず scripts/page-patterns.py <root> を実行します。ページごとに importable、component、
layout、dataHook とモックの手がかりとなる dataType、レンダリング順を示す
sections(ui/ は除外)、gridHint がレポートされます。さらに sharedSections[] も確認できます。
その後、importable に応じてモードを選びます。
importable: true(ページに default-export コンポーネントがある)→ 実際のページをそのままインポートし、 データレイヤーのみをモックします。scripts/scaffold-page-story.py <root> <page-suffix>でスキャフォールドします。 実際のページをインポートし、検出されたプロバイダー(InertiausePage/ router / store)を接続するPages/<Name>ストーリーが生成されます。props は、dataTypeをキーにしたファクトリーから シードされます(references/factory-patterns.mdに従い、scripts/scaffold-factory.sh <dataType> <import-path>を使用)。 実際に異なる データ の状態(空/データあり/エラー)ごとにストーリーを 1 つ追加します。異なるのはファクトリーの入力であり、 マークアップではありません。ページの JSX を書き直してはいけません(アンチパターン 27)。 レイアウト、カラム、コンポーネントは実際のページのものを使います。importable: false(インラインで組み立てられている/単一のコンポーネントがない)→ ページ構成 (references/composition-patterns.mdの Pattern 4)に切り替えます。実際のsectionsから組み立てます。 引き続きファクトリーを使用し、実際のコンポーネントを使います。
sharedSections[](2 つ以上のページでレンダリングされるセクション)は、再利用可能なページパターンの要素です。
それぞれに独自の Components/* ストーリーを用意し、ページ間で重複させずに組み合わせて使います。
autodocs のオーバーレイ(Dialog / Modal / Sheet / Drawer / Popover)
開いたオーバーレイは、position:fixed inset-0 のオーバーレイを document.body にポータルします。
autodocs ページ上にインラインでレンダリングすると(Primary ブロックと同じ方法)、
オーバーレイが Docs ページ全体 を覆ってしまいます。その結果、タイトル、「実際の使用例」セクション、
Controls が空白の背景の裏に隠れます。したがって、autodocs を使うオーバーレイコンポーネントでは、
ストーリーを専用の iframe に限定します。
parameters: {
layout: 'fullscreen',
docs: { story: { inline: false, height: '640px' } }, // portal stays inside the frame; Docs prose stays readable
}
ストーリービュー(1 つのストーリーをキャンバス全体に表示するビュー)には影響しません。これは Docs ページに限った設定です。 オーバーレイ以外のコンポーネントには適用しないでください(インラインレンダリングのほうが軽量です)。
ページ独自の dataHook はデータにすぎません。プレビューには、ページがレンダリングされるプロバイダーのツリーと
ルート CSS も必要です。 .storybook/runtime.json から確認してください
(ファイルがない場合は scripts/discover-runtime.py . --out .storybook/runtime.json を実行します)。
providers[]、rootCss、portals[]、network.needsMsw は sb-setup によって共有プレビューで一度だけ設定されるため、
ページのストーリーで再接続が必要になることはほとんどありません。スクリプトがすでに
.storybook/*.json に書き出した内容を、シェルスキャンで再導出してはいけません。フィールドを参照してください。
バッチ(複数のコンポーネント)
コンポーネントごとにストーリーを 1 つ作成し(実際の状態だけをカバーします)、その後、
scripts/validate-stories.sh で各ストーリーをゲートします。Claude Code では、Agent ツールを使って
コンポーネントを並列に作成すれば、バッチ処理を高速化できます。ただし、作業内容は同じであり、
特別なサブエージェントは不要です。
完了前のゲート
SKILL=${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}
CORE=${CLAUDE_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}
"$CORE/scripts/validate-stories.sh" path/to/Foo.stories.tsx
# --strict adds tsc + eslint · --diff lints only changed stories
# For the "give me confidence" verdict (setup readiness preflight + conformance in one),
# run "$SKILL/scripts/check-story-ready.sh" path/to/Foo.stories.tsx instead — CONFIDENT when discovery JSONs are present.
FAIL があるとゼロ以外のステータスで終了します。次に進む前に修正してください。play を記述した場合は、
判定用サブエージェントも実行してください(references/validate-workflow.md を参照)。play に意味があるかどうかは
bash では検証できません。ストーリーをエージェントが実行できる CLI ゲート(ヘッドレス vitest + a11y)にする方法は、
references/test-wiring.md を参照してください。