mcpField
A
appshot-core

appshot-core

github.com/trunghaiyマーケティング・グロース4959 回インストール21 週間前に更新
リポジトリ

appshot-core について

Appshot の動画・画像スキルが参照する基盤スキルです。プロジェクト構成に加え、アプリ情報、ブランド、機能、ストア情報、画面構造を抽出する手順を示します。

主な機能

  1. 01Remotion と React の構成を説明
  2. 02アプリ情報とブランドカラーを抽出
  3. 03機能とストア情報を確認
  4. 04ナビゲーションとページ構成を分析
  5. 05抽出したプロジェクト情報を保存

活用シーン

  1. 01動画制作向けのアプリ情報準備
  2. 02スクリーンショット生成向けのデザイン抽出
  3. 03アプリの画面遷移とページ一覧の把握

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/trunghaiy/appshot --skill appshot-core

インストール後、Claude Code で/appshot-coreを入力して読み込まれたか確認します。

詳細

Appshot Core — 基盤

すべての Appshot スキルの参照スキルです。appshot-videos または appshot-images を実行する前にお読みください。

アーキテクチャ

  • Remotion 4.0 + React 18 + Tailwind CSS 3.4
  • 設定ではアプリのメタデータとブランドのみを定義します。シーンは設定項目ではなく、カスタムの .tsx ファイルです
  • 各プロジェクトには、カスタムシーンを Remotion の <Sequence> + <SceneWrap> で順序付けるオーケストレーターコンポーネント(例:FooPreview.tsx)があります
  • すべてのプリミティブは、設定の BrandColors から導出される brand プロパティを介してブランドに対応しています

プロジェクトのコンテキスト(自動挿入)

  • パッケージマニフェスト: !cat package.json 2>/dev/null || cat pubspec.yaml 2>/dev/null || cat app.json 2>/dev/null
  • アプリの色: !find . -maxdepth 4 \( -name 'colors.xml' -o -name 'Colors.swift' -o -name 'colors.ts' -o -name 'theme.ts' -o -name 'Color.kt' -o -name 'tailwind.config.js' -o -name 'tailwind.config.ts' \) 2>/dev/null | head -5 | xargs head -50 2>/dev/null
  • アプリアイコン: !find . -maxdepth 5 \( -name 'ic_launcher.png' -o -name 'icon.png' \) -type f 2>/dev/null | head -3
  • ストアのメタデータ: !cat fastlane/metadata/en-US/full_description.txt 2>/dev/null || cat fastlane/metadata/en-US/description.txt 2>/dev/null || cat fastlane/metadata/android/en-US/full_description.txt 2>/dev/null
  • README の抜粋: !head -80 README.md 2>/dev/null

抽出とコンテキストのキャッシュ

appshot-videos と appshot-images は、どちらもこの抽出プロセスを使用します。結果は .appshot-context.json にキャッシュされるため、抽出はプロジェクトごとに一度だけ実行されます。

キャッシュされたコンテキストを確認する

スキャンの前に、プロジェクトのルートに .appshot-context.json があるか確認してください。存在する場合は:

  1. 読み込んで、概要をユーザーに提示します
  2. 「以前の抽出結果が見つかりました。この内容で問題ないか確認するか、再スキャンしますか?」と尋ねます
  3. 確認された場合は、抽出をスキップして、呼び出し元スキルの次のフェーズに進みます
  4. 再スキャンを求められた場合は、以下の抽出を実行してファイルを上書きします
抽出手順
ステップ 1:フレームワークを検出する

以下の順序でマーカーファイルを確認します。最初に一致したものが見つかった時点で終了します。

フレームワークマーカーファイル
Expo / React Nativeapp.json、app.config.ts、app.config.js
Flutterpubspec.yaml
iOS(Swift)*.xcodeproj/、*.xcworkspace/、Package.swift
Android(Kotlin/Java)app/src/main/AndroidManifest.xml、build.gradle.kts、build.gradle
Next.jsnext.config.js、next.config.ts、next.config.mjs
SvelteKitsvelte.config.js
Nuxtnuxt.config.ts、nuxt.config.js
Astroastro.config.mjs、astro.config.ts
Remixremix.config.js、app/root.tsx(@remix-run のインポートを含むもの)
Vite(React/Vue/Solid)vite.config.ts、vite.config.js(package.json で react/vue/solid を確認)

ls または find . -maxdepth 3 を使用して確認します。一致するものがない場合は、フレームワークを検出できなかったことを記録して次に進みます。ユーザーがアプリについて口頭で説明する場合もあります。

ステップ 2:アプリの識別情報を抽出する

Expo / React Native:

  • 名前:app.json -> expo.name または name
  • 説明/タグライン:app.json -> expo.description または description
  • バンドル ID:app.json -> expo.ios.bundleIdentifier または expo.android.package
  • あわせて確認:package.json -> name、description

Flutter:

  • 名前:pubspec.yaml -> name:
  • 説明:pubspec.yaml -> description:
  • あわせて確認:android/app/src/main/AndroidManifest.xml -> android:label、ios/Runner/Info.plist -> CFBundleDisplayName

iOS(Swift):

  • 名前:Info.plist -> CFBundleDisplayName または CFBundleName
  • バンドル ID:Info.plist -> CFBundleIdentifier
  • あわせて確認:project.pbxproj で製品名を確認

Android(Kotlin/Java):

  • 名前:app/src/main/res/values/strings.xml -> <string name="app_name">
  • パッケージ:AndroidManifest.xml -> package 属性
  • あわせて確認:build.gradle.kts または build.gradle -> applicationId

Next.js:

  • 名前:package.json → name。あわせて next.config.* → env.APP_NAME を確認
  • 説明/タグライン:package.json → description。あわせて app/layout.tsx → metadata.description を確認
  • URL:.env または .env.local → NEXT_PUBLIC_APP_URL、NEXT_PUBLIC_SITE_URL を確認

SvelteKit:

  • 名前:package.json → name
  • 説明:package.json → description。src/app.html → <title>、<meta name="description"> を確認

Vite(React/Vue):

  • 名前:package.json → name
  • 説明:package.json → description。index.html → <title>、<meta name="description"> を確認
ステップ 3:ブランドカラーを抽出する

色の定義を検索します。各フレームワークで最初に見つかったものを読み取ります。

Expo / React Native — 検索パス(順番どおり):

  1. src/theme.ts または src/theme.js
  2. src/colors.ts または src/constants/colors.ts
  3. theme/colors.ts または theme/index.ts
  4. tailwind.config.js または tailwind.config.ts -> theme.extend.colors
  5. app.json -> expo.primaryColor、expo.backgroundColor

確認する項目:名前付きの色のエクスポート(primary、secondary、background、surface、accent、success、danger/error)、16 進数文字列、rgb() 値。

Flutter — 検索パス:

  1. lib/theme.dart または lib/theme/app_theme.dart
  2. lib/theme/colors.dart または lib/constants/colors.dart
  3. lib/main.dart -> ThemeData()

確認する項目:Color(0xFF...) 定数、primaryColor、accentColor、colorScheme の定義。

iOS(Swift) — 検索パス:

  1. *.xcassets/Colors/**/*.colorset/Contents.json — components を解析して RGB を確認
  2. **/Theme.swift または **/Colors.swift または **/ColorScheme.swift

確認する項目:静的な Color プロパティ、UIColor の 16 進数イニシャライザー、アセットカタログの色の定義。

Android — 検索パス:

  1. app/src/main/res/values/colors.xml — <color name="primary">#RRGGBB</color>
  2. app/src/main/res/values/themes.xml — <item name="colorPrimary">
  3. **/ui/theme/Color.kt — Jetpack Compose の Color() 定義

Web(すべてのフレームワーク) — 検索パス(順番どおり):

  1. tailwind.config.js または tailwind.config.ts → theme.extend.colors
  2. src/styles/globals.css または src/app/globals.css → CSS カスタムプロパティ(--primary、--background など)
  3. src/theme.* または src/lib/theme.*
  4. src/styles/variables.css
ステップ 4:アプリアイコンを探す
フレームワーク確認する場所
Expo/RNapp.json の expo.icon フィールド(通常は ./assets/icon.png)
Flutterandroid/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png または ios/Runner/Assets.xcassets/AppIcon.appiconset/
iOS*.xcassets/AppIcon.appiconset/ -> 最も大きい .png を探す
Androidapp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Web(すべて)public/favicon.svg、public/favicon.ico、public/logo.svg、public/logo.png、app/favicon.ico、src/assets/logo.*
ステップ 5:機能を抽出し、メタデータを保存する

これらのソースはすべてのフレームワークで使用できます。

ソースパス抽出する内容
Fastlane(iOS)fastlane/metadata/en-US/description.txt or full_description.txtストアの説明全文
Fastlane(iOS)fastlane/metadata/en-US/subtitle.txtApp Store のサブタイトル
Fastlane(iOS)fastlane/metadata/en-US/keywords.txt検索キーワード
Fastlane(Android)fastlane/metadata/android/en-US/full_description.txtPlay Store の説明
Fastlane(Android)fastlane/metadata/android/en-US/short_description.txt短い説明
READMEREADME.md最初の 80 行 — アプリの説明、機能の箇条書き
CLAUDE.mdCLAUDE.md存在する場合はプロジェクトの説明
ステップ 5b:ASO キーワードを抽出する

Apple と Google は現在、ビジュアルインテリジェンスを通じて、スクリーンショットや動画内のテキストを読み取ることができます。高価値の検索語句をオーバーレイテキストに自然に取り入れられるよう、キーワードリストを抽出してください。

主なソース: fastlane/metadata/en-US/keywords.txt(カンマ区切り)。これは開発者独自のキーワード戦略であり、権威あるリストとして使用してください。

代替ソース(Fastlane のキーワードがない場合):次の情報からキーワード候補を 8~12 個導き出します。

  1. App Store のサブタイトル(fastlane/metadata/en-US/subtitle.txt)— 個々の語句に分割する
  2. ストアの説明 — 繰り返し登場する名詞と動作を表す動詞を抽出する
  3. 抽出した機能名 — 機能名をユーザー向けの検索語句に対応付ける
  4. ステップ 6 のシグナル表にあるアプリカテゴリの用語

出力: 重要度の高い順に並べたキーワードリスト。「habits」「streak」のような単語と、「reading tracker」「book log」のような短いフレーズの両方を含めます。キーワードは最大 12 個にします。

ステップ 6:アプリカテゴリを推定する

抽出したキーワード、説明、機能名に基づき、アプリのカテゴリを推定します。

カテゴリシグナル
習慣トラッキングstreak, habit, daily, routine, consistency, track days
フィットネスworkout, exercise, gym, reps, sets, calories, steps
ファイナンスbudget, expense, money, savings, transactions, spending
生産性task, todo, note, project, organize, calendar
ソーシャルchat, message, friend, follow, post, share
教育learn, quiz, study, course, flashcard, practice
健康meditation, sleep, mood, journal, wellness, mindful
旅行trip, itinerary, booking, destination, explore
食事recipe, meal, restaurant, cooking, ingredients
SaaSdashboard, subscription, plan, pricing, onboarding, workspace, team, analytics
E コマースcart, checkout, product, shop, order, payment, inventory
開発者向けツールAPI, SDK, CLI, documentation, playground, sandbox, webhook
コンテンツ/出版blog, article, post, publish, editor, CMS, newsletter
AI/MLmodel, inference, prompt, generate, embed, vector, chat, completion
コミュニティforum, discussion, thread, community, member, profile

明確に一致するカテゴリがない場合は「カテゴリ未分類」と記載してください。ユーザーが уточします。

詳細分析

アプリの識別情報や色だけでなく、アプリが実際に何をするのかを理解してください。

画面一覧。 ナビゲーションファイルを調べ、すべての画面を特定します。

  • React Native/Expo:App.tsx、すべての *Navigator.tsx、*Router.tsx、タブバー設定、react-navigation の設定を読む
  • Flutter:lib/main.dart、ルーター設定、GoRouter または MaterialApp のルートを読む
  • iOS:ストーリーボードの参照、UITabBarController の設定、SwiftUI の NavigationStack/TabView を読む
  • 次の項目を探します:画面名、タブのラベル、ナビゲーション構造(タブ、スタック、ドロワー) ナビゲーションのクローム抽出。 リアルなモック画面を作成するため、ユーザーが実際に目にするナビゲーションパターンを抽出します。
  • ナビゲーションの種類:タブ、スタック、ドロワー、またはその組み合わせ
  • タブバー:各タブのラベルテキスト、アイコンの説明(例:「家のアイコン」「虫眼鏡」「人の円形アイコン」)、デフォルト/ホームのタブ
  • ナビゲーションヘッダー:タイトルのスタイル(大きなタイトルまたはインライン)、戻るボタンの有無、右側のバー項目(例:「歯車アイコン」「プラス」「ベル」)
  • ステータスバーのスタイル:ライトコンテンツ(暗い背景向けの白いテキスト)またはダークコンテンツ(明るい背景向けの黒いテキスト)
  • ホームインジケーター:最新の iPhone ではすべて表示(下部のバー)、古いデバイスでは非表示

確認する場所:

  • React Native / Expo:ナビゲーターファイル内の screenOptions、tabBarLabel、tabBarIcon、headerTitle、headerRight、navigationOptions
  • Flutter:BottomNavigationBar の項目、AppBar のタイトル/アクション、Scaffold の設定
  • iOS:UITabBarItem の設定、navigationItem.title、navigationItem.rightBarButtonItems、SwiftUI の .tabItem / .navigationTitle / .toolbar
  • Android:BottomNavigationView のメニュー XML、Toolbar / TopAppBar の設定、Jetpack Compose の NavigationBar 項目

ページ/ルート一覧(ウェブ)。 ルーターの設定を調べて、すべてのページを見つけます。

  • Next.js:app/ ディレクトリ構造を確認(page.tsx を含む各フォルダーがルート)、または pages/ ディレクトリを確認
  • SvelteKit:src/routes/ ディレクトリ構造を確認(+page.svelte を含む各フォルダーがルート)
  • Vite/React:ルーターの設定(react-router、tanstack-router)を確認するか、ルート定義を検索
  • 確認する項目:ページ名、レイアウト構造、保護されたルートと公開ルート

ランディングページの分析。 ランディングページ/マーケティングページがある場合:

  • ヒーローの見出しとサブ見出しを抽出します
  • 機能紹介のセクションを抽出します
  • CTA のテキスト(「始める」「無料で登録」など)を記録します
  • 料金体系が表示されている場合は記録します

機能の分析。 見つかった各画面について、コンポーネントファイルを読み、以下を把握します。

  • 表示されるデータ
  • ユーザーが実行できる操作
  • 見た目に特徴や独自性を与えている要素

UI パターンの抽出。 コンポーネントのスタイルを調べ、アプリのビジュアルデザイン言語を把握します。実際のアプリの外観と一致しないモック画面は信頼性を損ないます。この情報でその差を埋めます。

抽出する項目:

  • 角丸:ボタン、カード、入力欄の角丸(例:「完全に丸みを帯びたボタン」「角が 8px のカード」「ピル形の入力欄」)
  • 余白のリズム:コンテナー内や要素間に使われているパディング/マージンの値(例:「左右のパディング 16px」「セクション間の余白 24px」)
  • タイポグラフィ:フォントファミリー(カスタムまたはシステム)、見出しのウェイト(例:700 と 800)、本文のサイズ、セクション見出しにすべて大文字を使っているか
  • ボタンのスタイル:形状(角丸長方形、ピル形、円形)、サイズ、塗りつぶしかアウトラインか、アイコンのみのボタン
  • カードのスタイル:背景色、境界線、影の深さ、ガラス/ぼかし効果
  • アイコンライブラリ:使用しているアイコンセット(SF Symbols、Material Icons、Lucide、カスタム SVG、Ionicons)
  • 特殊な UI 要素:波形ビジュアライザー、進捗リング、グラデーション背景、タグ/チップのスタイル、バッジ表示

確認する場所:

  • React Native / Expo:StyleSheet.create() ブロック、インラインの style={}、NativeWind/Tailwind クラス、コンポーネントライブラリのインポート(react-native-paper、tamagui、gluestack)
  • Flutter:ウィジェットファイルやテーマデータ内の BoxDecoration、BorderRadius、TextStyle、ButtonStyle
  • iOS(Swift):.cornerRadius、.font()、.padding()、UIFont ディスクリプター、SwiftUI/UIKit 内の SF Symbol 名
  • Android:shapes.xml、styles.xml、Compose の RoundedCornerShape()、MaterialTheme.typography、Material アイコンのインポート

価値提案/差別化要素。 README、ストアの説明、CLAUDE.md、マーケティング文、またはランディングページから抽出します。

  • このアプリはどのような問題を解決しますか?
  • 競合製品との違いは何ですか?
  • どのような感情的価値を約束しますか? 主要なアクションループ。 ユーザーが最も頻繁に行う単一のアクションを特定します。
  • ユーザーはアプリを開くたびに何をしますか?
  • タップや手順はいくつ必要ですか?
  • 完了後、どのようなフィードバックが得られますか?

テーマの検出。 アプリがライトモード/ダークモードに対応しているか確認します。

  • 設定内のテーマ切り替え、useColorScheme、Appearance、ThemeProvider、darkMode を探します
  • デフォルトまたは主なテーマを記録します
  • アプリがダークテーマのみかどうかを記録します(Spotify や映画アプリなど、一部のブランドが該当します)
コンテキストを保存する

抽出後、ユーザーの確認を得てから、結果をプロジェクトのルートにある .appshot-context.json に保存します。

{
  "version": 2,
  "extractedAt": "ISO timestamp",
  "app": { "name": "", "tagline": "", "icon": "", "platform": "", "framework": "", "url": "string or null" },
  "brand": { "primary": "", "primaryLight": "", "background": "", "surface": "", "textPrimary": "", "textSecondary": "", "success": "", "danger": "", "accent": "" },
  "category": "string",
  "theme": "light | dark | both",
  "themeDefault": "light | dark",
  "navigation": {
    "type": "tabs | stack | drawer | tabs+stack",
    "tabs": [{ "label": "", "iconDescription": "", "isDefault": false }],
    "headerStyle": "largeTitle | inline",
    "statusBarStyle": "light | dark"
  },
  "screens": [{ "name": "", "tab": "", "description": "" }],
  "pages": [{ "route": "", "name": "", "description": "", "layout": "" }],
  "landingPage": { "heroHeadline": "string or null", "heroSubheadline": "string or null", "cta": "string or null", "featureSections": ["string"] },
  "uiPatterns": {
    "borderRadius": { "button": "string", "card": "string", "input": "string" },
    "spacing": { "horizontal": "string", "sectionGap": "string" },
    "typography": { "fontFamily": "string or 'system'", "headingWeight": "number", "bodySize": "string", "capsHeaders": "boolean" },
    "buttonStyle": "string — e.g., 'pill filled, 56px height' or 'rounded-lg outline'",
    "cardStyle": "string — e.g., 'dark surface, 16px radius, no border, subtle shadow'",
    "iconLibrary": "string — e.g., 'SF Symbols' or 'Ionicons' or 'custom SVG'",
    "specialElements": ["string — e.g., 'waveform visualizer', 'gradient background', 'pill-shaped tags'"]
  },
  "features": ["string"],
  "coreAction": "string",
  "valueProps": ["string"],
  "keywords": ["string — ranked ASO keywords, most important first, max 12"],
  "screenshots": [{
    "referenceFile": "original file path (for re-reading if needed)",
    "screen": "matched screen name",
    "description": "what this screenshot shows",
    "visualSpec": "structured visual analysis — layout, colors, components, typography, special elements (the actual styling reference for mock UI)"
  }],
  "storeDescription": "string or null",
  "sources": { "name": "source file", "colors": "source file", "keywords": "source file or 'derived'" }
}

スキーマ v2 に関する注意事項:

  • screenshots — ユーザーが自動モックを選択した場合は空の配列、実際のスクリーンショットを提供した場合は値を設定します
  • app.framework の有効な値:"expo" | "flutter" | "ios" | "android" | "nextjs" | "sveltekit" | "nuxt" | "astro" | "remix" | "vite" | "web"
  • app.platform の有効な値:"ios" | "android" | "both" | "web"
  • pages — Web のルート一覧(モバイルアプリの場合は空の配列)
  • landingPage — 抽出したランディングページのデータ(モバイルアプリの場合は null)
調査結果を提示する

見つかった内容を簡潔にまとめます。ユーザーが確認できるよう、必ず出典ファイルを明記します。

I scanned your project and found:

- **App:** [name] (from [source file])
- **Tagline:** [text] (from [source file])
- **Platform:** [iOS/Android/both] (from [evidence])
- **Colors:** primary [hex], background [hex], surface [hex], ... (from [source file])
- **Icon:** [file path]
- **Category:** [category] based on [keywords/description]
- **Store description:** [found at path / not found]
- **Theme:** [light only / dark only / both — default is X]

**Navigation:** [tabs / stack / drawer] — [header style: large title / inline]
**Tab bar:** [Tab1 (icon)] | [Tab2 (icon)] | [Tab3 (icon)] — default: [Tab1]
**Status bar:** [dark content / light content]

**Screen inventory:**
- [Tab 1]: [ScreenName] — [what it shows]
- [Tab 2]: [ScreenName] — [what it shows]
- [Modal/Detail]: [ScreenName] — [what it shows]
- ...

**Page inventory (web):**
- `/` — [Landing page] — [hero headline, feature sections]
- `/dashboard` — [Dashboard] — [what it shows]
- `/settings` — [Settings] — [configuration options]
- ...

**Landing page:** [hero headline] / [CTA text] / [number of feature sections]
**URL:** [extracted URL or "not found"]

**Key features:** [bullet list of 3-5 main features extracted from code/docs]

**Core action loop:** [what users do most — e.g., "tap Log -> enter page number -> save (3 taps, ~5 seconds)"]

**Value props:**
- [Primary differentiator]
- [Secondary differentiator]
- [Emotional promise]

**UI patterns:** [font family], [heading weight], [button style], [card style], [border radius], [icon library]
**Special elements:** [waveform, gradient bg, pill tags, ...]

**ASO keywords:** [keyword1], [keyword2], [keyword3], ... (from [fastlane/keywords.txt / derived])

**Pre-filled config:**
[Show the AppConfig object with app, brand, and video sections filled in]

Does this look right? Anything to correct before I proceed?

不足している項目があれば、その旨を伝えます。「ブランドカラーが見つかりませんでした。テーマファイルはありますか?それとも一緒に色を選びましょうか?」

確認を得てから、以下のスクリーンショット収集手順に進みます。

スクリーンショットを収集する(任意)

抽出内容の確認後、視覚的な参考資料として実際のアプリのスクリーンショットを提供するか、ユーザーに尋ねます。スクリーンショットは参考資料であり、コンテンツではありません。最終出力に埋め込まれることはありません。代わりに、視覚的な参考資料の分析によって、スクリーンショットから正確な色、形、余白、タイポグラフィを抽出します。このスキルはその情報を使い、実際のアプリに似たアニメーション付きのモック UI を作成します。

AskUserQuestion({
  questions: [{
    question: "Do you have screenshots of your app to use as screen content?",
    header: "Screenshots",
    options: [
      { label: "Yes, I'll provide screenshots", description: "Highest fidelity — your screenshots are analyzed and the mock UI is built to match exactly." },
      { label: "No, generate mock screens", description: "Skill builds UI from extracted code patterns. Good for most cases." }
    ],
    multiSelect: false
  }]
})

ユーザーがスクリーンショットを提供した場合:

  1. スクリーンショットのファイルパスを送るか、会話にドロップするようユーザーに依頼します
  2. 各スクリーンショットの画像を読み取り、何が表示されているかを把握します
  3. 各スクリーンショットを、抽出内容にある画面に対応付けます:
    I mapped your screenshots to app screens:
    
    - recording.png → Voice Recording screen
    - transcription.png → Transcription Detail screen  
    - scan-preview.png → Document Scan screen
    - home.png → Home / Notes List screen
    
    Missing: Settings screen (will use mock UI for this one)
    
    Does this mapping look right?
    
  4. 各スクリーンショットに対して視覚的な参考資料の分析を実行します(以下を参照)
  5. 不足している画面、つまりスクリーンショットがない画面を記録します。これらの画面では、uiPatterns に基づいて作成したモック UI を使用します。
  6. 対応付けと視覚的な分析を .appshot-context.json の screenshots に保存します
ビジュアルリファレンスの分析

重要: スクリーンショットが提供されている場合、このステップは必須です。これを行わないと、モックシーンがありきたりな見た目になり、実際のアプリと一致しません。

提供されたスクリーンショットごとに画像を確認し、構造化されたビジュアル仕様を作成します。この仕様は次の2つの用途で使います。

  • そのまま使用するシーン:スクリーンショットを<Img>でそのまま使用し、仕様で表示内容を確認します
  • モックシーンと不足部分の補完:アニメーション用、スクリーンショットがない場合、またはコンテンツを変更する場合など、シーンにモックUIが必要なときに、仕様をスタイルの基準にします

スクリーンショットごとに記録する内容:

## [filename] → [Screen Name]

**Layout:**
- [top-to-bottom description of what appears: nav bar, content sections, bottom bar]
- [approximate vertical proportions: "nav bar 8%, content 78%, tab bar 8%, home indicator 6%"]

**Colors (sample from the image):**
- Background: [exact color, e.g., "#0A1628 — very dark navy, NOT pure black"]
- Cards/surfaces: [e.g., "#1A2940 — slightly lighter navy with subtle border"]
- Accent: [e.g., "#3BB8E0 — teal/cyan for CTAs and active states"]
- Text primary: [e.g., "#E8ECF1 — off-white"]
- Text secondary: [e.g., "#6B7A8D — muted blue-grey"]
- Highlight/badge: [e.g., "#E5C044 — warm yellow for 'Voice Recording' badge"]

**Components (describe exactly what you see):**
- Back button: [e.g., "48px rounded-square (#1A2940 bg), white chevron, no text"]
- Nav actions: [e.g., "three icon buttons: more (⋯), share (↑), delete (🗑), same rounded-square style"]
- Type badge: [e.g., "'Voice Recording' in yellow text on dark pill, microphone emoji prefix"]
- Content cards: [e.g., "rounded-xl (~16px), #1A2940 bg, 1px border #2A3A50, 20px padding"]
- Buttons: [e.g., "'Enhance · 2 credits' — outlined, teal border, rounded-full, 48px height"]
- Tab bar: [e.g., "3 tabs with SF Symbol icons above labels, active=teal, inactive=grey, dark bg"]

**Typography:**
- Headings: [e.g., "32px, weight 700, white — 'May 28 at 11:03 PM'"]
- Section headers: [e.g., "ALL CAPS, 13px, weight 600, letter-spacing 1px, teal — 'TRANSCRIPTION'"]
- Body: [e.g., "16px, weight 400, off-white, line-height ~1.5"]
- Labels: [e.g., "12px, weight 500, muted grey — metadata, tab labels"]

**Special elements:**
- [e.g., "Waveform: grey rounded-rect container, horizontal bars, blue play button 48px circle"]
- [e.g., "Speed pills: row of 4 (0.75x, 1x, 1.5x, 2x), active has teal bg, others have dark bg"]
- [e.g., "Coral/red horizontal divider line below title, 2px height"]
- [e.g., "Vietnamese flag emoji + 'VI' in language selector pill"]

分析時のルール:

  • 漏れなく記録してください。 スクリーンショットに表示されている、個別のUI要素をすべて列挙し、数を記録します。15個の要素が見える場合は、15個すべてを記録してください。見落としやすい一般的な要素には、ナビゲーションバーのすべてのアクションボタン(戻るボタンだけではありません)、タブバーのアイコン、速度/再生コントロール、CTA、バッジ表示、クレジット数、言語セレクター、区切り線、ホームインジケーターなどがあります。
  • 色を正確に記述してください。推測せず、実際の画像から色を取得します。「#0A1628」と「#000000」は大きく異なります。
  • コンポーネントの形状を正確に記述してください。「角丸ボタン」ではなく、「半径12pxの48px角丸正方形」のように記述します。
  • 余白を記録してください。「カード内側のパディングは20px」「要素間の間隔は12px」のように記述します。
  • 存在しない要素も記録してください。「カードに影はない」「ボタンに枠線はない」「リスト項目間に区切り線はない」のように記述します。
  • UIコード抽出から得たuiPatternsと矛盾する場合、この分析を優先します。スクリーンショットが視覚的な正解です。
  • ビジュアル仕様のサイズは、スマートフォンの論理ピクセル単位です。 886px幅のApp Store Previewキャンバスは、iPhone 16 Pro(393px)の2.25倍の幅です。シーンコードを書く際は、すべてのサイズを2.25倍にしてください。48pxのボタンは108px、16pxのテキストは36px、11pxのタブラベルは25pxになります。コードガイドには完全な倍率表があります。

スクリーンショットの要件(ユーザーに伝えてください):

  • 解像度は問いません。これらは参照画像であり、出力には埋め込まれません。
  • 余計な表示がない状態にしてください。通知やデバッグ用バナーがない状態であれば、実際のデザインを分析できます。
  • 画面や機能ごとにスクリーンショットを1枚用意してください。同じ画面の複数の状態も歓迎します。
  • スキルがスクリーンショットを分析し、アプリの外観に正確に一致するアニメーション付きモックUIを作成します。

ユーザーが提供を辞退した場合は、screenshots: []を設定して続行します。スキルは従来どおり、抽出したパターンからモックUIを生成します。

このステップの後、呼び出し元のスキルの次のフェーズに進みます。

プロジェクト構成

src/
  app-config.ts         # App metadata, brand colors, video settings
  Root.tsx              # Remotion entry — registers the composition
  [AppName]Preview.tsx  # Orchestrator — sequences scenes with <Sequence> + <SceneWrap>
  scenes/
    S1_[Name].tsx       # Custom scene components (one per scene)
    S2_[Name].tsx
    ...
  components/           # Shared primitives library (imported from template)
    PhoneFrame.tsx      # Device frame with bezel, Dynamic Island, spring entrance
    AmbientBackground.tsx # Animated gradient bg with floating orbs
    Caption.tsx         # Word-by-word animated caption with frosted pill
    FadeIn.tsx          # Directional spring fade-in wrapper
    SceneWrap.tsx       # Fade envelope for scene transitions
    AppIcon.tsx         # App icon with optional glow pulse
    TypeWriter.tsx      # Character-by-character text reveal
    BrowserFrame.tsx    # macOS browser chrome (light/dark)
    AnimatedCursor.tsx  # Bezier-interpolated cursor with click ripple
    index.ts
  config.ts             # Type definitions, device dimensions, defaults
public/
  icon.png              # App icon
  *.png                 # Screenshots, assets

設定スキーマ

設定にはアプリの識別情報、ブランドカラー、動画設定が含まれます。シーンはカスタムコンポーネントのため、設定には含まれません。

interface AppConfig {
  app: {
    name: string;        // Display name
    tagline: string;     // One-line value prop
    icon: string;        // Filename in public/
    platform: "ios" | "android" | "both";
  };
  brand: BrandColors;
  video: {
    fps: number;         // 30
    width: number;       // 886
    height: number;      // 1920
    device: DevicePreset;
    backgroundMusic?: string;       // Filename in public/
    backgroundMusicVolume?: number; // 0-1
  };
}

interface BrandColors {
  primary: string;       // Main brand color (hex)
  primaryLight: string;  // Tinted background
  background: string;    // App background
  surface: string;       // Card/container background
  textPrimary: string;   // Main text
  textSecondary: string; // Secondary/muted text
  success: string;       // Positive states
  danger: string;        // Destructive/error states
  accent?: string;       // Optional secondary brand color
}

プリミティブライブラリ

以下のすべてのコンポーネントはsrc/components/で使用できます。"../components"からインポートしてください。

PhoneFrame

ベゼル、サイドボタン、ノッチ/Dynamic Islandを備えたデバイスのモックアップです。任意のコンテンツを囲み、実際のスマートフォンの画面のように見せます。

プロパティ型デフォルト値説明
childrenReactNode必須画面のコンテンツ
deviceDevicePreset"iphone-15"デバイスモデル
delaynumber0表示アニメーションの遅延(フレーム数)
scalenumber1拡大縮小率
screenBackgroundstring"#FAFAF8"画面内の背景色

使用場面: スマートフォン内にアプリUIを表示するすべてのシーン。モバイルアプリの動画の中心的な視覚要素です。

AmbientBackground

ぼかした球体が浮遊する、アニメーション付きのグラデーション背景です。各シーンの雰囲気を演出します。

プロパティ型デフォルト値説明
brandBrandColors必須グラデーションと球体の色
variant"light" | "medium" | "deep" | "dark""light"強さ/雰囲気

使用場面: すべてのシーンの背景に使用します。機能や解決策のシーンには"light"または"medium"、課題や対比のシーンには"dark"、感情や実績を示すシーンには"deep"を使用します。

Caption

下部に固定され、単語ごとに表示されるアニメーション付きのテキストオーバーレイです。読みやすいように、暗いピル型の背景を使用します。

PropTypeDefaultDescription
textstring必須キャプションのテキスト(最大8単語)
delaynumber0表示開始までの遅延(フレーム)
fontSizenumber44フォントサイズ(px)
maxWidthnumber820コンテナーの最大幅

使用する場面: 各シーンに1つ配置してください。音声をオフにして視聴するユーザーに、キャプションでストーリーを伝えます。

FadeIn

Remotion のスプリングを使った方向指定可能なフェードインアニメーションで、任意の要素をラップします。

PropTypeDefaultDescription
childrenReactNode必須アニメーションを適用するコンテンツ
delaynumber0開始フレーム
direction"up" | "down" | "left" | "right" | "none""up"スライドの方向
distancenumber40スライド距離(px)
classNamestring—Tailwind クラス
styleCSSProperties—インラインスタイル

使用する場面: カードの表示、見出しの登場、アニメーションで表示したいあらゆる要素に使用します。

SceneWrap

各シーンをラップし、フェードイン/フェードアウトのトランジション(各12フレーム)を適用します。オーケストレーターで使用します。

PropTypeDefaultDescription
childrenReactNode必須シーンのコンテンツ
durationInFramesnumber必須シーンの合計時間
fadeInbooleantrueフェードインを有効にする
fadeOutbooleantrueフェードアウトを有効にする

使用する場面: オーケストレーターコンポーネントで、各シーンを <Sequence> と <SceneWrap> の内側に配置します。

AppIcon

オプションのアニメーション付きグロー効果を加えて、アプリアイコンを表示します。

PropTypeDefaultDescription
srcstring必須public/ 内のファイル名または URL
sizenumber120アイコンのサイズ(px)
glowbooleanfalse脈動するグローを有効にする
glowColorstring"rgba(0,122,255,0.4)"グローの色

使用する場面: CTA/クロージングシーンに使用します。ブランドの認知度向上につながります。

TypeWriter

点滅するカーソルをオプションで表示できる、文字単位のテキスト表示アニメーションです。

PropTypeDefaultDescription
textstring必須入力するテキスト全体
startFramenumber必須入力を開始するフレーム
charsPerFramenumber2入力速度
classNamestring—Tailwind クラス
cursorbooleantrue点滅するカーソルを表示する
cursorColorstring"#2196F3"カーソルの色

使用する場面: 検索バー、テキスト入力欄、チャットメッセージなど、ユーザーの入力をシミュレートしたい場面に使用します。

BrowserFrame

信号機、アドレスバー、コンテンツ領域を備えた macOS スタイルのブラウザー枠です。ライトとダークのバリエーションがあります。

PropTypeDefaultDescription
childrenReactNode必須ページコンテンツ
urlstring"app.example.com"アドレスバーのテキスト
delaynumber0表示アニメーションの遅延(フレーム)
scalenumber1拡大縮小率
variant"light" | "dark""light"ブラウザー枠のテーマ
AnimatedCursor

ベジェ補間を使用し、キーフレーム位置間を移動するカーソルです。クリック時の波紋効果も表示します。

PropTypeDefaultDescription
keyframesCursorKeyframe[]必須{ frame, x, y, click? } の位置
visiblebooleantrueカーソルの表示/非表示

アニメーションパターン

削除されたプリミティブ(FloatingCard、StatCard、HeatMap、ProgressBar、AppStoreBadge、IconSet)は、エージェントをハードコードされたサイズに制約するシンプルなラッパーでした。代わりに、キャンバスに合わせて適切なサイズに調整し、これらのパターンをインラインで記述してください。

アニメーション付きカウンター(変更前/変更後の統計):

const counter = spring({ frame, fps, delay: 10, config: { mass: 0.6, damping: 18, stiffness: 80 } });
const value = Math.round(interpolate(counter, [0, 1], [beforeValue, afterValue]));

セル単位で塗りつぶすグリッド(ヒートマップ/貢献グリッド):

{cells.map((cell, i) => {
  const cellEnter = spring({ frame, fps, delay: baseDelay + i * 0.4, config: { mass: 0.2, damping: 10, stiffness: 180 } });
  return <div key={i} style={{ opacity: 0.3 + cellEnter * 0.7, transform: `scale(${0.6 + cellEnter * 0.4})` }} />;
})}

プログレスバーの塗りつぶし:

const progress = interpolate(frame, [delay, delay + 30], [0, targetPercent], { extrapolateRight: "clamp" });
<div style={{ width: `${progress}%`, height, backgroundColor: color, borderRadius }} />

スプリングインで表示するカード(FloatingCard の代替):

const entrance = spring({ frame, fps, delay, config: { mass: 0.8, damping: 14, stiffness: 120 } });
<div style={{ opacity: entrance, transform: `translateY(${(1 - entrance) * 20}px)`, borderRadius, padding, background }}>

App Store/Play Store バッジ(マーケティング CTA シーン用):

// iOS badge — black rounded rect with Apple SVG
<div style={{ background: "#000", borderRadius: 14, padding: "14px 28px", display: "flex", alignItems: "center", gap: 12 }}>
  <svg width="28" height="34" viewBox="0 0 28 34" fill="white">
    <path d="M23.2 17.8c0-3.6 2.9-5.3 3-5.4-1.6-2.4-4.2-2.7-5.1-2.8-2.1-.2-4.2 1.3-5.3 1.3-1.1 0-2.8-1.2-4.6-1.2C8.5 9.8 6 11.2 4.6 13.5c-2.8 4.9-.7 12.1 2 16.1 1.3 1.9 2.9 4.1 5 4 2-.1 2.8-1.3 5.2-1.3 2.4 0 3.1 1.3 5.2 1.3 2.2 0 3.5-2 4.8-3.9 1.5-2.2 2.1-4.3 2.2-4.4 0-.1-4.2-1.6-4.2-6.4zM19.3 7.5c1.1-1.3 1.8-3.2 1.6-5-1.6.1-3.4 1-4.6 2.3-1 1.2-1.9 3-1.6 4.8 1.7.2 3.5-.9 4.6-2.1z" />
  </svg>
  <div>
    <div style={{ fontSize: 16, color: "rgba(255,255,255,0.8)" }}>Download on the</div>
    <div style={{ fontSize: 28, fontWeight: 600, color: "#FFF" }}>App Store</div>
  </div>
</div>

デバイスプリセット

プリセット画面ノッチストア
iphone-16-pro393x852Dynamic IslandApp Store
iphone-15375x812Dynamic IslandApp Store
ipad-pro-131024x1366なしApp Store(iPad)
pixel-9412x915パンチホールPlay Store
ストアとデバイスの対応
ストアコンポジション ID のサフィックスデバイスプリセット
App Store-AppStoreiphone-16-pro
Play Store-PlayStorepixel-9

複数のストアに対応するプロジェクトでは、Root.tsx にストアごとに 1 つの <Composition> を登録します。シーンは共通で、デバイスフレーム(およびナビゲーションのクロームスタイル)のみが異なります。どちらもキャンバスサイズは 886×1920 です。注:App Store プレビュー動画では、CTA にストアバッジを含めません(ストアの掲載ページ内では重複するため)。マーケティング動画では、CTA にインラインのストアバッジを含めます(SVG スニペットについては、上記の「アニメーションパターン」を参照)。

出力先

AppShot は、異なるビジュアルルールを適用する 2 つの出力先に対応しています。

出力先用途デバイスフレームオーバーレイテキスト画面コンテンツ
App Store プレビューApp Store/Play Store の動画プレビューとスクリーンショットデバイスフレームなし。 アプリ画面がキャンバス全体を端から端まで埋めます。テキストオーバーレイはアプリ画面の上に表示します(読みやすさのため、半透明のピル型背景を使用)。実際のスクリーンショットのように見せるため、ナビゲーションのクローム(ステータスバー、ナビゲーションバー、タブバー)を含める必要があります。
マーケティングソーシャルメディア、ウェブサイト、ピッチデッキ、広告アプリ画面を囲むデバイスフレーム(PhoneFrame)。テキストやカードはデバイスフレームの横または周囲に表示します。ナビゲーションのクロームは任意です(PhoneFrame が「デバイス」のコンテキストを示します)。

重要な理由: Apple は、デバイスフレームを含むプレビューや、アプリの使用状況が十分に示されていないプレビューを却下します。App Store プレビュー出力先を選ぶことで、この要件に準拠できます。マーケティング出力先では、ストア以外の用途向けに、現在の洗練された見た目を維持できます。

デフォルト: appshot-videos と appshot-images では App Store プレビューを使用します。ソーシャルメディア/ウェブ向けではマーケティングを使用します。

ユーザーが App Store プレビュー 出力先を選択した場合:

  • どのシーンでも PhoneFrame を使用しないでください
  • アプリ UI で、キャンバス全体(動画では 886×1920、スクリーンショットではストア指定の寸法)を埋めてください
  • すべてのモック画面に、ステータスバー、ナビゲーションバー、タブバー、ホームインジケーターを含めてください
  • キャプション/オーバーレイテキストには、アプリ UI の上でも読みやすいよう、半透明のピル型背景を使用してください
  • 結果は、テキストオーバーレイ付きの画面録画のように見えるようにしてください

ユーザーが マーケティング 出力先を選択した場合:

  • これまでどおり、PhoneFrame をスケール 1.5 で使用してください
  • テキスト、カード、バッジはデバイスフレームの外側または周囲に表示してください
  • スマートフォン内のナビゲーションのクロームは、あると望ましいものの必須ではありません

ストア要件

動画
プラットフォーム寸法長さ形式
iPhone 6.7"886x192015-30sH.264, MP4/MOV
iPhone 6.1"886x192015-30sH.264, MP4/MOV
iPad 13"1200x160015-30sH.264, MP4/MOV
Google Play886x192015-30sH.264, MP4

デフォルトの出力サイズは 886×1920 です。このキャンバスは、App Store(iPhone 6.7″ のネイティブ解像度)と Google Play の両方で使用できます。appshot-videos のすべてのサイズ設定ルールは、このキャンバス幅に合わせて調整されています。

スクリーンショット

iOS App Store:

デバイス寸法(縦向き)必須
iPhone 6.9"1320x2868はい(必須のメインサイズ)
iPhone 6.7"1290x2796任意(Apple が 6.9" から拡大縮小)
iPhone 6.5"1242x2688任意(旧サイズ)
iPad 13"2064x2752アプリが iPad に対応している場合は必須

Google Play:

デバイス寸法(縦向き)備考
スマートフォン1080x1920推奨される標準サイズ
7" タブレット1200x1920アプリが 7" タブレットを対象とする場合
10" タブレット1600x2560アプリが 10" タブレットを対象とする場合

プロジェクトのセットアップ

このスキルは、フェーズ 3 のコード生成時に、対象プロジェクト内に appshot-video/ ディレクトリを生成します。生成手順の全容については、code-guide.md を参照してください。

cd appshot-video
npm run dev     # Preview at localhost:3000
npm run build   # Render to out/AppPreview.mp4

オーケストレーターパターン

オーケストレーターは Remotion の <Sequence> を使用してシーンを順番に並べ、各シーンを <SceneWrap> でラップしてフェード遷移を実現します。

import { Composition, Sequence } from "remotion";
import { SceneWrap } from "./components";
import { S1_Hook } from "./scenes/S1_Hook";
import { S2_Feature } from "./scenes/S2_Feature";
import { S3_CTA } from "./scenes/S3_CTA";

const scenes = [
  { component: S1_Hook, duration: 120 },
  { component: S2_Feature, duration: 150 },
  { component: S3_CTA, duration: 120 },
];

export const AppPreview: React.FC = () => {
  let offset = 0;
  return (
    <>
      {scenes.map(({ component: Scene, duration }, i) => {
        const from = offset;
        offset += duration;
        return (
          <Sequence key={i} from={from} durationInFrames={duration}>
            <SceneWrap durationInFrames={duration}>
              <Scene />
            </SceneWrap>
          </Sequence>
        );
      })}
    </>
  );
};

共有リソース

  • コピーの原則:copy-principles.md
  • 抽出ロジックはこのスキルに組み込まれています(上記の「抽出とコンテキストキャッシュ」を参照)

コメント