mobile-taste について
mobile-tasteは、クロスプラットフォームのReact Nativeアプリで画面、ナビゲーション、コンポーネントを構築するスキルです。要件と既存の技術スタックを先に把握し、設計や実装の判断に反映します。
主な機能
- 01要件からアプリの方向性を推定
- 02既存プロジェクトの技術スタックを確認
- 03画面より先にナビゲーションを設計
- 04表現、モーション、密度を設定
- 05設計判断をMOBILE-DESIGN.mdに記録
- 06状況に応じたモバイル設計指針を適用
活用シーン
- 01新しいモバイルアプリの画面を構築
- 02ナビゲーションとコンポーネントを計画
- 03既存アプリの技術スタックを引き継いで開発
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ draftbit/ mobile-taste-skill --skill mobile-tasteインストール後、Claude Code で/mobile-tasteを入力して読み込まれたか確認します。
詳細
mobile-taste:スロップを防ぐ React Native スキル
クロスプラットフォームのモバイルアプリ向け:画面、ナビゲーション、コンポーネント、モーション。マーケティング 用ウェブサイトではありません(そちらには original taste-skill を使ってください)。ゲームやネイティブモジュールも対象外です。 以下のルールはすべて状況に応じて適用します。自動的に適用されるものはありません。まず要件を読み、 そのうえで適切なものだけを取り入れてください。
関連スキル(このスイートはタスクごとに分かれています):mobile-design-review(既存アプリの監査)、mobile-redesign-screen / mobile-redesign-app(既存 UI の改善)、
mobile-nav-plan(ナビゲーション設計のみ)、mobile-design-system(トークン+
テーマ)。このスキルは構築を担当します。
必要に応じて読み込む詳細なリファレンス:
../_shared/references/navigation.md- ナビゲーションの決定ツリー、Expo Router の規約、ナビゲーションの読み取り例../_shared/references/skeletons.md- LLM が間違えやすいパターンの、Reanimated/ジェスチャーの標準コード../_shared/references/tells.md- スロップの兆候を網羅したカタログ(追記専用)+実行可能な grep チェックリスト../_shared/references/versions.md- バージョンに左右されるすべての情報(SDK の組み合わせ、パッケージのメジャーバージョン)。意図的に、このファイル内ではバージョンに触れていません。../_shared/blocks/- 実績のある画面パターンの実装(スキーマはセクション 12)
0. アプリの読み取り(何よりもまず状況を把握する)
コードに手を加える前に、ユーザーが本当に求めているものを推測してください。モバイル向けの LLM 出力の多くが質の低いものになるのは、状況を読み取らず、決まりきったテンプレート(インディゴのグラデーション、5 つのタブ、カードの積み重ね)に飛びつくためです。
0.0 スタックの確認(既存プロジェクトでは、読み取り前に実施)
まず package.json、app.json、および Tailwind/テーマ設定を読みます。Expo SDK、
ルーター(Expo Router と React Navigation のどちらか)、スタイリング方式(NativeWind、StyleSheet、Tamagui、Paper のどれか)、アイコンの種類、
既存のテーマトークン、そして MOBILE-DESIGN.md が存在するか(0.E)を確認します。
存在する場合は読み込み、その定めを継続的な前提として扱ってください。検出したスタックは、このスキル内のあらゆるデフォルトより優先されます。最初のコード生成で誤ったスタイリングシステムをインポートすると、成果は台無しになります。30 秒かけて確認すれば、それを防げます。
0.A まず次のシグナルを読み取る
- アプリの種類 - コンシューマー向けソーシャル、ユーティリティ/ツール、フィットネス/ヘルス、フィンテック、E コマース、 コンテンツ/メディア、生産性、子ども向け、現場/運用ツール。
- 雰囲気を表す言葉 - 「すっきり」「遊び心のある」「プレミアム」「iOS ネイティブのような使用感」「Airbnb のような」 「情報密度が高い/プロ向け」「落ち着いた」「ブランドらしい」。
- ユーザーが挙げた参考アプリ。モバイルでは、ウェブにおける参考サイトと同じように、実在のアプリがデザイン言語の参考になります。
- 対象ユーザーと利用状況 - 電車で片手操作するのか、ソファで両手操作するのか、 それとも現場で手袋をしたまま操作するのか。好みではなく、利用状況に応じて情報密度とタップ対象のサイズを決めます。
- 対象プラットフォーム - iOS/Android/ウェブのどれか、またどのプラットフォームを最優先するか。
- 表に出にくい制約 - アクセシビリティを最優先するユーザー、子ども(大きなタップ対象、ダークパターンなし)、規制対象(フィンテック/ヘルスケアにおける情報開示のパターン)、オフライン利用が多いケース。
0.B 生成前にアプリの読み取り結果を出力する
APP READ: <app kind> for <audience>, <vibe> language, leaning <design language / stack>.
platforms: iOS first-class · Android first-class · web best-effort
posture: unified-brand | iOS-first | Android-first | per-platform-native
例:「アプリの読み取り:忙しい社会人向けの習慣記録ユーティリティ。落ち着いたミニマルな表現で、NativeWind とネイティブのクロームを活用。対象プラットフォーム:iOS と Android を同等に重視、ウェブは対象外。方針:統一ブランド。」
プラットフォーム方針は設計上の約束です。per-platform-native はコンポーネントをプラットフォームごとに変えること(SF Symbols と Material アイコン、iOS のスイッチと Material のスイッチなど)を意味します。unified-brand は、ネイティブのナビゲーション用クロームの上に、どのプラットフォームでも同じ外観を適用することを意味します。
0.C 要件が曖昧な場合は、推測せず質問を 1 つだけする
読み取り結果が実際に分かれる場合に限ります(例:「Things のような iOS ネイティブの雰囲気にしますか。それとも Duolingo のようにブランドを前面に出しますか?」)。確信を持って推測できる場合は、読み取り結果を明示して作業を進めてください。
0.D デフォルトに安易に頼らない
次のようなものをデフォルトにしないでください:インディゴ/バイオレットのグラデーション、中央に FAB を置いた 5 タブのバー、すべての画面に白い角丸カードを積み重ねるデザイン、アイコン代わりの絵文字、イラスト付きの 3 枚スライド式オンボーディング、「おかえりなさい、John! 👋」。これらは LLM が陥りがちなデフォルトです。意識的にそこから離れてください。
0.E MOBILE-DESIGN.md(永続的な成果物)
App Read、Nav Read、ダイヤル値、デザイントークンは、チャット上だけの一時的な情報ではなく、確定事項です。内容が固まったら、プロジェクトルートにある MOBILE-DESIGN.md に記述し、デザインの信頼できる情報源として扱います。以降のセッション(およびほかのエージェント)は、UI に関する判断を行う前に必ずこれを読みます。再実行時は最初から生成し直すのではなく、内容を更新し、変更点を報告します。画面 3、4、5 が別のアプリのように変わってしまうのを防ぐのが、このファイルの役割です。(mobile-design-system スキルはトークンのセクションを記述し、このスキルは各種の読み取り内容とダイヤルを記述します。)
1. 3 つのダイヤル
App Read の後、3 つのダイヤルを設定します。以下のレイアウト、モーション、密度に関する判断は、これらの値によって決まります。
DESIGN_EXPRESSION: 4- 1 = 厳密にプラットフォーム標準、10 = 完全に独自のブランド表現MOTION_INTENSITY: 4- 1 = ネイティブの画面遷移のみ、10 = あらゆる場面でジェスチャー駆動の物理的な動きを採用VISUAL_DENSITY: 4- 1 = 余白の多い一般消費者向け、10 = プロ向けツールのコックピット
基準値は 4 / 4 / 4 です。 モバイルの基準値はウェブより低めです。スマートフォンでは、慣例に従うことも機能のひとつです。必要に応じて、ブリーフの内容に基づき、会話の中で調整してください。
1.A ダイヤルの推定
| シグナル | EXPRESSION | MOTION | DENSITY |
|---|---|---|---|
| 「iOS 標準/すっきり/Apple Notes や Things のような」 | 1-3 | 2-3 | 3-4 |
| 「実用的/ツール/ちゃんと動けばよい」 | 3-4 | 3-4 | 4-5 |
| 「一般消費者向けソーシャル/コンテンツフィード」 | 5-7 | 5-7 | 4-5 |
| 「ブランド感/遊び心/Duolingo 風/子ども向け」 | 7-9 | 6-8 | 2-4 |
| 「高級/ラグジュアリー/ファッションコマース」 | 7-9 | 5-7 | 2-3 |
| 「プロ向けツール/トレーディング/オペレーション/データ重視」 | 3-5 | 2-3 | 7-9 |
| 「フィンテック(一般消費者向け)」 | 4-6 | 3-5 | 4-6 |
1.A2 カテゴリーごとの傾向(アプリの種類ごとに、推奨/回避)
| アプリの種類 | 推奨 | 回避 |
|---|---|---|
| フィンテック | 数値の明瞭さ(表形式の数字、金額には等幅フォント)、信頼感のあるニュートラルカラー、お金が動く操作の明示的な状態表示 | 遊び心のあるマスコット、グラデーションの残高カード、アニメーション中に揺れ動く小数点以下の数字 |
| ヘルスケア/フィットネス | 画面ごとに主要指標を 1 つ、ゆとりのある文字組み、励ましつつも簡潔なコピー | 3 つの統計値を並べたダッシュボード、進捗色としての赤、連続記録で罪悪感をあおるパターン |
| 一般消費者向けソーシャル | コンテンツを最優先(メディアそのものが UI)、高速なフィード、控えめな画面装飾 | すべての投稿を囲む大きなカード、エンゲージメントをあおるバッジ |
| E コマース | 余白を活かした商品写真、価格と CTA を固定表示して明確に提示、誠実な緊急性のみ | バッジの乱用、カウントダウンタイマー、情報過多な商品カード |
| 生産性/ツール | 装飾より情報密度、キーボード優先の操作フロー、即時の反応 | オンボーディングツアー、すべての画面に配置するイラスト付きの空状態、祝賀モーダル |
| 子ども向け | 大きなタップ領域(>= 56pt)、高いコントラスト、ダークパターンなし | 小さなアイコンボタン、広告に隣接したレイアウト、無限スクロールの仕組み |
1.E シグネチャー要素
各画面で大胆な表現は最大 1 つにします。特徴的なヘッダー表現、独自の操作、表情豊かなコンポーネントのいずれか 1 つです。それ以外は控えめにし、ネイティブらしさを保ちます。大胆さは 1 か所に集中させます。すべてが表情豊かな画面は雑然と見え、どの画面も強く主張するアプリには声がありません。これは CHROME LAGS CONTENT(1.C)を画面単位で言い換えたものです。
1.B DESIGN_EXPRESSION の段階(実務向け)
- 1-3 プラットフォーム標準: システムフォント、ネイティブのヘッダーとタブバー、プラットフォーム標準のコンポーネントとピッカーを使用し、デフォルトではプラットフォームごとに異なる設計にします(通常、方針は
per-platform-native)。 - 4-7 ブランド化されたネイティブ: 独自のカラー/タイポグラフィトークンとコンテンツコンポーネントを使用し、ナビゲーションの画面装飾(ヘッダー、タブバー、画面遷移)はネイティブのままにします。
- 8-10 完全なカスタム: カスタムのタブバーと画面遷移を採用し、ブランドフォントをあらゆる場所で使用して、プラットフォーム間で統一感のある外観にします。ネイティブの画面装飾が無料で担っていたセーフエリアのインセット、押下状態、アクセシビリティロールを、すべて自分で管理する必要があります。
1.C CHROME LAGS CONTENT(必須)
コンテンツのスタイリングが完全にブランドに合わせられていても、DESIGN_EXPRESSION >= 8 になるまでは、ナビゲーションのクロームをネイティブのままにしてください。安全領域が崩れ、押下状態もない独自描画のタブバーは、「表現豊かな」AI アプリで最もよくある失敗です。まずコンテンツにブランドを反映し、クロームはその後に手を加えてください。
1.D 最低基準(ダイヤルで変更不可)
VISUAL_DENSITY: 10でも、タッチターゲットは 44pt 以上を確保してください。MOTION_INTENSITY: 3を超える場合も、視差効果の低減設定を尊重してください。- すべてのモーションレベルで、アニメーションは UI スレッド上で実行してください(セクション 8)。
2. ブリーフ → スタックの対応表
ブリーフをもとに基盤を選んでください。まず、プロジェクトの既存の package.json を確認してください。既存のスタックは、以下のすべてのデフォルトに優先します。
| ブリーフの特徴 | 選択肢 | 理由 |
|---|---|---|
| クロスプラットフォーム対応でブランドを反映できるアプリ(デフォルト) | Expo + Expo Router + NativeWind + React Native Reusables | Tailwind 構文によるスタイリング、shadcn スタイルの独自コンポーネント、ファイルベースのナビゲーション |
| Material/Android を優先する製品 | React Native Paper(Material 3) | 公式品質の M3 コンポーネントとテーマ設定 |
| iOS ネイティブの操作感 | ネイティブのクローム + システムフォント + SF Symbols(expo-symbols)、最小限のスタイリングレイヤー | あらゆるコンポーネントライブラリよりも HIG への忠実さを優先 |
| パフォーマンスが重要な独自デザインシステム | Tamagui | コンパイラーで最適化されたトークンとバリアント |
| 保守的な選択/ビルドツールを使いたくない場合 | Plain StyleSheet.create + React Navigation | 不要な仕組みがなく、すべての RN 開発者が理解できる |
| 既存の Draftbit v1 アプリ | @draftbit/ui(Jigsaw) | 既存のコンポーネントシステムに合わせる |
誠実さを保つルール(taste-skill から本質をそのまま引き継ぐ):
- サードパーティライブラリをインポートする前に、必ず
package.jsonを確認してください。見つからない場合は、コードを提示する前にインストールコマンド(SDK に適合するバージョンを解決できるnpx expo install …)を出力してください。 - アプリごとにコンポーネントシステムは 1 つにしてください。同じツリーで Paper と Reusables を混在させないでください。
- アプリごとにアイコンファミリーは 1 つにしてください。SF Symbols、Material icons、Lucide を混在させないでください。
- プラットフォームのパターンを近似する場合(例:独自コンポーネントで iOS の大きなタイトルのヘッダーを再現する場合)、コメントで近似であることを明記してください。
3. デフォルトのアーキテクチャと規約
スタック対応表で別の選択肢が指定されない限り、以下を適用します。
- フレームワーク: Expo + TypeScript。Expo Router を使ったファイルベースのナビゲーション(
app/ディレクトリ)。 - スタイリング: NativeWind(Tailwind 構文)。デザイントークン(色、文字のスケール、角丸)は Tailwind の設定/テーマファイルに定義し、画面ファイル内でインラインの hex 値は一切使いません。
- リスト: 件数に上限がないものには FlashList(または FlatList)を使います。
ScrollViewは短く固定されたコンテンツに限って使います。FlashList のバージョンに関する詳細は versions.md を参照してください。 - 画像: リストセルでは、
placeholder(blurhash)とrecyclingKeyを指定してexpo-imageを使います。 - セーフエリア:
react-native-safe-area-context(useSafeAreaInsets)。ステータスバーのパディングをハードコードしないでください。 - アイコン:
@expo/vector-icons、Lucide RN、Phosphor RN のいずれか、または iOS ネイティブの設計方針にはexpo-symbolsを使い、ファミリーを 1 つに統一してください。サイズとストロークの太さはグローバルで統一します。アイコンに絵文字を使わないでください。手描きの SVG アイコンパスも使わないでください。 - フォント: デフォルトではシステムフォントを使います(6.1 を参照)。カスタムフォントには
expo-font/@expo-google-fontsを使い、スプラッシュ画面を隠す前に読み込みます。 - アニメーション: Reanimated + Gesture Handler。
GestureHandlerRootViewはルートに 1 つだけ配置します。 - 触覚フィードバック:
expo-hapticsを使い、6.5 の指針に従ってください。通常のナビゲーションタップでは使わないでください。 - レイアウトの仕組み: flexbox のみを使います(RN に CSS Grid はありません)。マージンを連ねるより
gapを優先してください。ピクセル単位で幅/高さを固定するのはアイコンとアバターに限り、画面は flex でレイアウトします。
4. ナビゲーションアーキテクチャ
画面を作る前にナビゲーションを設計します。完全な判断ツリー、Expo Router の規約、実例については ../_shared/references/navigation.md を参照してください。必ず守るべき要件は以下のとおりです。
4.A ナビゲーションの読み取り(コードを書く前に出力)
app/ ディレクトリの構成案を兼ねた、構造化されたルートツリー:
NAV READ
platforms: iOS + Android (web: best-effort)
tabs (4): Today · Search · Library · Profile
app/
(auth)/sign-in, sign-up fullscreen group, swapped on session
(tabs)/
index Today → push workout/[id]
search Search → push workout/[id]
library Library → push collection/[id] → workout/[id]
profile Profile → push settings, settings/units
new-workout modal (pageSheet), max 1 internal step
player/[id] fullscreen modal, custom dismiss
entry points: settings ← gear (Today header) · new-workout ← + (Library header)
sheets: workout-options, filter (write "sheets: none" when there are none)
deep links: /workout/:id, /collection/:id
android back: default pop everywhere; new-workout confirms discard
max taps to any core screen: 2
4.B コンテナの判断ツリー(上から順に評価)
- ユーザーが繰り返し戻る最上位の移動先で、ほかの移動先と同列にあり、 独立した状態を持つか? → タブのルート。
- 明確な親画面がある階層的な画面(一覧 → 詳細、設定 → サブ設定)か? → プッシュ。
- 完了すると元の画面に戻る、単独で完結する作成・編集タスク(作成、フィルター、プロフィール編集など)か? → モーダル(iOS のデフォルトは
pageSheet)。 - 親画面のコンテキストを表示したままにする必要があり、簡単な選択、プレビュー、アクションメニューを表示するものか? コンテンツが1画面未満で、内部ナビゲーションがないか? → ボトムシート。シートに独自の戻るスタックが必要になった時点で、それはモーダルにすべきです。
- 没入型または操作を妨げるもの(カメラ、メディアビューアー、ペイウォール、オンボーディング、認証など)か? → フルスクリーンモーダル/ルートグループ。
4.C ナビゲーションの厳守ルール
- タブは3〜5個。 移動先が2つならタブバーは不要です。6つならタブバーではなく、情報アーキテクチャに問題があります。 ラベルは常に表示し、それぞれ1語にします。
- 設定タブもログアウトタブも作らない。 設定はプロフィールの背後に置き、ログアウトは設定内に置きます。
- 中央の FAB は、作成が中核となるアクションである場合にのみ使用します。その場合、タブ数は4個以下にし、Nav Read で根拠を説明します。
- 入れ子のタブバーは禁止。ヘッダーを二重にしない。 各画面のヘッダーの所有者は1つだけです。
- Android の戻る操作 = ヘッダーの戻る操作。 Nav Read で宣言した破棄確認以外では、
BackHandlerによるオーバーライドは禁止です。 - すべてのモーダルに明示的な閉じる操作(X またはキャンセル)を設けます。スワイプで閉じる操作だけでは不十分です。
- 認証/オンボーディングはルートグループ(セッションに応じて
(auth)を切り替える)にし、画面内の条件付きレンダリングにしないでください。 - すべての詳細画面はディープリンク可能(パラメーターを持つルートファイル)にし、妥当な戻るスタックで開くようにします。
- ドロワーは大規模な二次カタログ(Gmail クラス)のために使用します。コンシューマーアプリの主要ナビゲーションには使用せず、タブにすべき4つの移動先を隠すハンバーガーメニューにも使用しないでください。
- 2つを超える種類のボトムシートを開く画面は、情報アーキテクチャをシート内に隠しています。
5. 画面の構造とレイアウト規律
- セーフエリア: ナビゲーターヘッダーがある場合、上部のインセットはヘッダーが管理します。それ以外の場合は
useSafeAreaInsets()を使用します。すべてのスクロール可能な領域の下部には、contentContainerStyle={{ paddingBottom: insets.bottom + <spacing> }}を指定します。paddingTop: 50のような根拠のない固定値は使わないでください。 - ヘッダーの所有権: 画面タイトルはナビゲーションヘッダーが管理します。すでにヘッダーに表示されているタイトルを、その下のコンテンツ内で
<Text>の見出しとして繰り返さないでください。 - タッチ領域: 実効サイズを44x44pt以上にします。小さなグリフには
hitSlopを設定します。行の高さは44pt以上にします。 - 親指の届く範囲: 主要なアクションは画面の下半分に配置します。破壊的な操作や使用頻度の低い操作は上部に配置できます。固定フッターの CTA はセーフエリアを考慮し、
bottom: 30は使用しないでください。 - 間隔のグリッド: 4/8pt スケール(4、8、12、16、24、32)を使用します。画面の左右のパディングは16(高密度)または20(ゆったり)を選び、全体で統一します。
- 垂直方向の構成: コンテンツは上揃えにします。
justifyContent: 'center'を使うのは、空の状態、認証、インタースティシャルの場合に限ります。データ画面では、コンテンツが増えるとレイアウトが飛んでしまいます。 - リスト: 行の高さを統一し、動的なテキストすべてに
numberOfLinesを指定します。すべてのフィードにプルリフレッシュ(RefreshControl)を実装し、項目数が約20を超える場合は仮想化します。 - キーボード: 入力欄のあるすべての画面で、キーボードを意図的に扱います(標準的なスケルトンは skeletons.md を参照)。キーボードを開いた状態でも送信ボタンが見えるようにします。
- テキスト入力: 入力欄の上にラベルを配置します。すべての入力欄に、適切な
keyboardTypeとtextContentType/autoCompleteを設定します(メールアドレスにはメール用キーボード、名前や住所には自動入力)。プレースホルダーをラベル代わりにしないでください。エラーテキストは入力欄の下に表示します。
6. デザインエンジニアリングの指針(バイアス補正)
6.1 タイポグラフィ
- モバイルではシステムフォントを標準にするのが妥当です。 SF Pro と Roboto は見劣りするフォントではなく、品質の高いアプリで使われるフォントです。これは Web スキルの Inter 禁止を覆すものです。カスタムフォントを採用するには、それに見合う理由が必要です。使用するファミリーは最大 1~2 種類とし、スプラッシュ画面を非表示にする前に読み込み、Dynamic Type での表示を検証してください。
- ありがちな画一化に注意してください: カスタムフォントが本当に必要な場合でも、AI が選びがちな「無難なカスタムフォント」の定番、Poppins、Nunito、一般的な幾何学的な丸ゴシック(Web における Space Grotesk の罠に相当)に収束しないでください。ブリーフにある実際の特徴に基づいて選び、プロジェクトごとに変化をつけてください。
- タイプスケールはトークンで定義し、画面ごとに
fontSizeを直接指定しないでください。 画面で必要なのは最大でも、ディスプレイ(まれ)、タイトル、本文、キャプションです。すべての画面をfontSize: 32 / fontWeight: '700'とグレーのサブタイトルで始めないでください。どの画面でも同じリズムを使うと、テンプレートを使ったことが見抜かれます。 - Dynamic Type は双方向に対応します: スケーリングをサポートしつつ、上限も設定してください。カスタム UI のテキスト(ボタン、カスタムヘッダー)では
maxFontSizeMultiplierを約 1.3~1.5 に設定し、本文では上限を設けません。ネイティブが管理する UI(ナビゲーターのタブラベル、ネイティブヘッダー)にはそのようなプロパティがありません。スケーリングはコードではなく、実機で検証してください(14.C)。 - Android の注意点: ディスプレイ用の文字には
includeFontPadding: falseと明示的なlineHeightを設定してください。
6.2 カラーの調整
- デフォルトではアクセントカラーは最大 1 色とし、彩度は 80%未満にします。ニュートラルカラーの段階(グレーは 1 系統のみ。同じアプリで暖色系と寒色系のグレーを混在させないでください)をテーマファイルで定義してください。
- インディゴの定番パターンを禁止:
#6366F1/#8B5CF6/#7C3AEDとLinearGradientを使ったヘッダー/CTA/オンボーディングは、AI 製モバイルアプリの典型的な特徴です。デフォルトでは禁止します。ブランドカラーが本当に紫の場合のみ例外とし、その意図をもって仕上げ、雑なグラデーションは使わないでください。 - グラデーションはデフォルトでアプリあたり最大 1 つとし、構成上の理由がある場合に限って使用してください。
- 最初から
useColorSchemeとセマンティックトークン(background、surface、text-primary、accent)でダークモードに対応してください。 リリース前に両方のモードをテストしてください。 - OLED の例外: モバイル(OLED)では、純粋な
#000000を意図的なダークモードの選択として使うことは妥当です。禁止されるのは、よく考えずにデフォルトとして純粋な黒を使うことです。ライトモードでは純粋な黒のテキストを避け、黒に近い色を使ってください。 - カラーの一貫性を徹底してください: アクセントカラーは 1 色に統一し、すべての画面で同じように使用してください。リリース前に監査してください。
6.3 サーフェス、エレベーション、カード
- グループ化の方法はカードだけではありません。 余白、細い区切り線(
StyleSheet.hairlineWidth)、グループ化されたリストセクション(iOS のインセットグループスタイル)も活用してください。カードとは、独立していて、タップ可能で、自己完結したオブジェクトです。グレーの背景に、白く角が丸いrounded-2xlの影付きカードを積み重ねた画面は、AI 製モバイルアプリで最もよくあるレイアウトです。 - クロスプラットフォームのエレベーショントークン: 2~3 段階を一度だけ定義してください(各段階には iOS のシャドウプロパティと Android の
elevationを組み合わせます)。elevationのないshadowColorは Android では表示されません。どちらか一方だけを設定した状態でリリースしないでください。 - シェイプの一貫性を徹底してください: 役割ごとに適用する半径のスケール(例:8/12/16)を 1 つ定めてください。半径 8 のカードの隣に、入力欄として
borderRadius 24を使わないでください。 - ぼかし(
expo-blur) はメディアやオーバーレイの上にのみ使ってください。「高級感を出すため」にカードやタブバーに使わないでください。
6.4 インタラクティブな状態(データを表示する画面ごとに全状態への対応が必須)
- 読み込み中: コンテンツ画面では最終的なレイアウトを反映したスケルトンを使い、スピナーはボタン単位の操作に限ってください。タブバーを覆う全画面スピナーは使わないでください。
- 空の状態: 表示内容を追加するためのアクションを含めて構成してください。この場合は中央揃えで問題ありません。
- エラー: フォームではインライン表示、コンテンツでは再試行できる手段、一時的なエラーではトースト/スナックバーを使ってください。
- オフライン: フィードやデータアプリでは、オフラインバナーとキャッシュ済みコンテンツの動作を用意してください。これはネットワーク層がある場合に限ります。ローカルファーストのアプリでは、App Read に「offline: N/A」と記載すれば、この項目は省略できます。
- 更新中: フィードでは
RefreshControlを使ってください。初回読み込みとは別に扱います。 Alert.alert()は破壊的な操作の確認にのみ使用してください。 成功、エラー、情報の通知には使わないでください。成功時は状態を変更し、必要に応じてハプティクスを加えます。エラーはインラインで表示してください。
6.5 ハプティクスの語彙
ピッカーやトグルの選択には選択時のハプティクス、意味のある確認には軽いインパクト、非同期処理の結果(成功/失敗)には通知のハプティクスを使います。単なるタップやナビゲーションでは絶対に使いません。 ハプティクスの使いすぎは、過剰に修正している兆候です。
6.6 権限リクエスト前の説明(LLM はほぼ 100% の確率でここを間違えます)
初回起動時やマウント時の useEffect では、システム権限を絶対にリクエストしないでください。ユーザーの意図が生じた瞬間に、背景を説明してからリクエストします。
| 権限 | リクエストするタイミング |
|---|---|
| 通知 | 最初の価値を実感した後(最初のタスク作成後、最初の注文後) |
| 位置情報 | ユーザーが位置情報に依存する機能をタップしたとき |
| カメラ/写真 | ユーザーが撮影/アップロードを開始したとき |
| 連絡先 | ユーザーが招待/共有フローを開いたとき |
6.7 コピーとコンテンツ(taste-skill から移植・汎用)
- すべての表示文字列で全角ダッシュ(
—)を完全に禁止します。 ハイフンを使うか、文を組み替えてください。 - 「John Doe」/「Acme」/完璧すぎる架空の数値(
99.99%)は使いません。現実的な名前や、雑然としたデータを使ってください。 - 中身のない動詞は使いません。「Elevate」「Seamless」「Unleash」「Supercharge」などです。
- 感嘆符を使ったオンボーディング調の文体は避けます(「さあ、始めましょう!🎉」「準備はすべて整いました!」など)。
- パーソナライズがプロダクトそのものでない限り、「おかえりなさい、{name}!👋」という挨拶の見出しは使いません。
- 出荷前にコピーをセルフチェックします。 すべての表示文字列を読み直し、文法が崩れているもの、指示対象が不明確なもの、LLM っぽく気取ったものは書き直してください。
7. モーション
ここで扱うすべての内容の標準コード:../_shared/references/skeletons.md。ルールは以下のとおりです。
- モバイルのモーションの優先順位: (1) ナビゲーション遷移。ネイティブで、追加コストがなく、再実装しません。(2) 押下時のフィードバック。タップ可能なすべての要素に適用し、スプリングで約 0.97 に縮小します。(3) 状態遷移。挿入/削除/並べ替えにはレイアウトアニメーションを使います。(4) スクロール連動のクローム。折りたたみ式ヘッダーなどです。(5) ジェスチャー駆動。シートやスワイプ可能な行などです。この順序で実装してください。押下状態がないのに視差効果がある画面は、優先順位が逆です。
- モーションには明確な目的が必要です。 階層、フィードバック、状態変化、ストーリーテリングのいずれかに役立つものにしてください。正当化を一文で説明できないなら、削除してください。
- インタラクティブなフィードバックには、時間曲線よりスプリングを使います。線形イージングは禁止です。
- 仮想化リストのセルでは、表示時のアニメーションを無条件に実行しません。 再利用されたセルでは、スクロール中にアニメーションが再生されてしまいます。初回マウント時のスタガーは最初の約 6 行までにし、インデックスで制御してください。
- 避けるべき実装(デフォルトでは試みないでください): 共有要素遷移(安定した API がないため、フェード+スケールで近似し、その旨を明記します)、カスタムのプル・トゥ・リフレッシュ(
RefreshControlを使います)、手動でのタブ切り替え遷移(ナビゲーターに任せます)。 - モーションの軽減:
MOTION_INTENSITY: 3を超える場合はuseReducedMotionを尊重します。ジェスチャーは引き続き機能させ、装飾的なモーションは瞬時に切り替わるようにします。
8. パフォーマンスのガードレール
- アニメーションは UI スレッド上でのみ実行します。 Reanimated の worklet/ネイティブドライバーを使います。transform/opacity に対する
useNativeDriver: falseは重大な不具合です。onScrollでuseStateを更新するのも重大な不具合です。スクロール位置は共有値で管理します。 - レンダー中に
.valueを読み書きしません。 worklet から JS を呼び出すにはrunOnJSを使います。 - 制限なく増えるリストは仮想化し、行コンポーネントをメモ化し、
keyExtractorを安定させます。 - キャッシュとプレースホルダーには
expo-imageを使い、セルではrecyclingKeyを設定します。 - スプラッシュ画面との連続性: スプラッシュ画面の背景色は最初の画面の背景色に合わせます。フォントと初期データはスプラッシュ画面を非表示にするまで読み込みが完了するよう制御し、白いフラッシュやフォント切り替え時のフラッシュを防ぎます。
- 再レンダーを適切に管理します。 コンテキストは変更頻度ごとに分割します。リスト画面は、離れた入力欄への入力のたびに再レンダーされないようにします。
9. プラットフォーム規約
- 押下時のフィードバック: Android のリップル(
android_ripple)と iOS の不透明度/スケールを使い分けるか、EXPRESSION >= 6では両方で一貫してブランド独自の押下スタイルを使用します。 - ピッカー、日付/時刻、スイッチ、共有: デフォルトではシステムコンポーネントを使用します(
EXPRESSION <= 7)。カスタムピッカーの使用は最終手段です。 - Android: ジェスチャー/ハードウェアの「戻る」との同等性(4.C)を保ちます。適切なナビゲーションバーのインセットを適用してエッジツーエッジにし、リップルを行の範囲内に収めます。
- iOS: モーダルはデフォルトで
pageSheetにします。破壊的な操作の確認には ActionSheet を使い、ホームインジケーターを考慮します。 - Web(react-native-web): ホバーは段階的な機能強化としてのみ扱い、ホバーが必須となる設計にはしません。依存する前に FlashList/ジェスチャーライブラリの Web 対応状況を確認してください(versions.md を参照)。Web レイアウトには最大コンテンツ幅(約 640~760px)を設定します。スマートフォン向けレイアウトを 1440px に引き伸ばすのは、設計として破綻しています。
Platform.selectの使い方: プラットフォームごとの分岐は、画面ファイル内に散在させず、トークン/コンポーネントにまとめます。
10. モバイル AI の典型的な兆候(禁止パターン)
兆候の完全なカタログ(追記のみ、42 項目以上)と実行可能な grep チェックリスト:
../_shared/references/tells.md。
リリース前に読んでください。特に認識されやすい 10 のパターンは、常に禁止です。
- アイコンチップの行 - すべての行の先頭に、色付きアイコンを入れた 40x40 の色付き角丸四角形を配置します。RN の低品質な作り込みを示す、最も典型的な兆候です。
- インディゴのパイプライン -
#6366F1系の色とLinearGradientのヘッダー/CTA(6.2)。 - カードを積み重ねた画面 - すべての画面が、白い角丸の影付きカードの山になっています(6.3)。
- 絵文字アイコン - タブバー、ボタン、空の状態に 🔥⚙️📊 を使います。
- デフォルトの「5 タブ+FAB」 - アプリに関係なく、Home/Search/+/Alerts/Profile を配置します(4.C)。
- データ配列を ScrollView で表示 - 範囲に上限のないデータに
<ScrollView>{items.map(…)}</ScrollView>を使います。 - マジックナンバーの padding-top - セーフエリアのインセットではなく、
paddingTop: 50を使います(5)。 - 3 枚スライドのオンボーディング - イラスト+見出し+ドット+Skip で構成された、ほぼ同じ内容のスライドを 3 枚並べます。
- 何にでも ALERT.ALERT() - 破壊的な操作の確認にのみ使用します(6.4)。
- 「おかえりなさい、ジョン! 👋」 - あいさつ見出しのあるホーム画面と、感嘆符を多用するオンボーディングの文体です(6.7)。
この一連のガイドでは、兆候を番号で参照します。番号は tells.md で管理され、追記のみです。
11. 既存アプリの再設計
再設計は独自のスキルを持つ、独立した専門分野です。ここから独断で進めないでください。
- 1 画面 →
mobile-redesign-screenスキル。 - アプリ全体 →
mobile-redesign-appスキル(ナビゲーションの再構成を提案できる唯一のスキル)。 - 何も変更せずに監査 →
mobile-design-reviewスキル。
3 つすべてが ../_shared/references/redesign-protocol.md(監査チェックリスト、モダナイズの手段、リスク管理)と review-rubric.md に基づいて動作します。既存のコードを扱う際に、このスキルにも適用されるルールが 1 つあります。黙って変更しないこと。タブの順序、ルート/ディープリンクのパス、テーマトークン名、フォームフィールドのセマンティクス、ユーザーが慣れたジェスチャーを変更してはいけません。
12. ブロックライブラリ(契約)
../_shared/blocks/<category>/<name>.md - 実証済みの画面パターンです。カテゴリー:オンボーディング、認証、フィード、詳細、プロフィール、設定、ペイウォール、検索、空の状態、ナビゲーション。
ブロック優先のルール: オンボーディング、認証、フィード、設定、ペイウォール、空の状態など、典型的な画面を独自に作成する前に、../_shared/blocks/ を一覧表示し、使用するダイヤルに対応する dial_compatibility を持つブロックがあるか確認してください。ブロックを調整して使い、ゼロから作り直さないでください。
Frontmatter スキーマ
---
name: value-first-onboarding
category: onboarding
dial_compatibility:
expression: [3, 8]
motion: [3, 7]
density: [2, 5]
platforms: [ios, android, web]
when_to_use: "Consumer apps where the aha-moment can be shown, not told."
not_for: "Pro tools; apps where signup is legally required first."
stack: ["expo-router", "nativewind", "reanimated"]
---
必須の本文セクション
- 画面のスケッチ(ASCII または説明) 2. Props/ルート API 3. コードのスケッチ
- プラットフォームに関する注意点(iOS/Android/Web の差異) 5. MOTION バンドごとのモーションバリエーション+モーション低減 6. ダークモードに関する注意点 7. アンチパターン 8. 実例。
ブロックはセクション 14 の事前チェックに合格する必要があります。1 ファイルにつき 1 ブロックです。
13. 対象外
- マーケティング/ランディングサイト → 元の taste-skill。
- ゲーム、3D、キャンバスを多用するアプリ(Skia/GL はコンポーネントとしてなら問題ありませんが、アプリとしては対象外です)。
- watchOS/tvOS/ウィジェット/アプリクリップ。
- ネイティブモジュールの作成、ビルドツール、ストアへの申請。
- Flutter/SwiftUI/Kotlin - このスキルの対象は React Native です。
依頼内容がこれらのいずれかに該当する場合は、その旨を伝え、適切なツールを案内してください。
14. 最終事前チェック
提出前にすべての項目を確認してください。検証方法ごとに分けています。
14.A grep で機械的に確認(以下をそのまま実行してください - 用意済みのブロックは ../_shared/references/tells.md の末尾にあります)
- 表示文字列に em ダッシュ(
—/–)が含まれていない - JSX テキストに絵文字が含まれていない(依頼内容が明示的に遊び心のあるものの場合を除く。その場合も意図的に控えめに使用)
-
#6366F1|#7C3AED|#8B5CF6が含まれていない。LinearGradientの数は 1 以下 - 画面ファイルにインラインの16進数カラーコードがない(トークンのみ)
-
.map(で上限のないデータを囲むScrollViewがない(grep してから該当箇所を確認: 上限のある静的な map は問題ありません) - マジックナンバーの
paddingTop: [4-6][0-9]がない。セーフエリアのインセットを使用 -
useNativeDriver: falseがない。onScrollを値の更新元とするuseStateがない -
Alert.alertは破壊的な操作の確認にのみ使用 -
shadowColorに、同じ階層のelevationが必ず指定されている - メールアドレス/電話番号/氏名を入力する
TextInputすべてにkeyboardTypeとtextContentType/autoCompleteが設定されている - ジェスチャー/シートを使用する場合、ルートに
GestureHandlerRootViewが1つだけ存在する
14.B デザインを機械的に確認(コードを数えて確認)
- App Read + Nav Read が出力されている。ダイヤルは明示され、理由も説明されている
- タブは3~5個で、ラベルが表示されている。Settings/Logout のタブはない。FAB は妥当な理由があるか、使用されていない
- タブバーの入れ子がない。ヘッダーが二重になっていない。認証はルートグループにまとめられている
- すべてのモーダルに明示的な閉じる操作がある。Android の戻る操作と同等の動作がある(未宣言の BackHandler は使用しない)
- コンテンツよりもクロームの変化を遅くする:EXPRESSION >= 8 でない限り、ネイティブのナビゲーションクロームを使用
- アイコンファミリーは1つ。アクセントカラーは1つ。角丸のスケールは1つ。グレーの色調は1つ
- タッチターゲットは 44pt 以上(小さなグリフには hitSlop を設定)。行の高さは統一
- 画面のパディングは全体で一定(16 または 20)
- データを扱うすべての画面で状態の全サイクルに対応:スケルトン/空/エラー/オフライン/更新 (ローカルファーストと明記されたアプリでは、オフラインは該当なしでも可)
- 権限のリクエストは、ユーザーが意図した時点で事前に促す。マウント時には行わない
- 用語に沿ったハプティクスを使用。すべてのタッチ可能要素に押下フィードバックがある
- 画面への表示アニメーションはインデックスで制御し、リスト項目では無条件に実行しない
- ダークモードのトークンが揃っている。両方のモードを確認済み
- Dynamic Type:カスタムクロームのテキストには
maxFontSizeMultiplierを設定し、本文には上限を設けない (ネイティブ側が管理するクロームは14.Cのデバイスチェック項目) - コピーの自己監査を実施済み(埋め草の動詞なし、文字列の崩れなし、挨拶を見出しにしない)
- すべてのカスタム Pressable に
accessibilityLabel/accessibilityRoleがある
14.C シミュレーター/デバイスが必要(正直に記載)
- キーボード:キーボード表示中も送信操作が見える。両プラットフォームで確認
- スプラッシュ画面 → 最初の画面:白いフラッシュなし、フォントの切り替わりなし
- 最も長いリストのスクロール性能(空白のセルなし、カクつきなし)
- タブバーが1.3倍のフォントスケールでも正常に表示される
- Android の edge-to-edge インセットが正しい
シミュレーター/デバイスのツールを利用できない場合は、14.C のどの項目を 検証できなかったかを正確に記載してください。 未検証の項目を検証済みと主張するのは、チェック漏れより重大な失敗です。
1つでも正直にチェックを付けられない項目がある場合、アプリは未完成です。提出前に修正してください。