Communitygithub.com

carnufex/pr-demo

プルリクエストのコードを表示する代わりに、変更内容、動作の仕組み、修正の動作確認、レビューの要点とテストを1つのシーンにまとめた25~40秒の動画をレンダリングし、SlackにPRリンクとともに投稿します。

pr-demo とは?

このスキルは、開発者がプルリクエスト(PR)を素早く理解できるよう、コード差分を開かなくても変更の全体像を把握できる短いデモ動画を自動生成します。動画は「変更内容」「新しいフローの動作」「Before/After(UI変更の場合)」「修正の動作確認」「レビューキーの結果とテスト結果」の5つのシーンで構成され、合計30秒程度に収まります。対応プラットフォームはSlackで、PRのスレッドとして動画とメッセージを投稿し、ボットを使用して確実に通知します。また、GitHubのPR説明欄にも同一の情報(動画は非対応だがMermaid図とリンク)を追記します。設定はリポジトリの`.claude/profiles/delivery.md`に記述されており、動画の素材収集、JSON設定ファイルの作成、レンダリング、投稿の各ステップを実行します。

対応✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/carnufex/claude-skills/tree/HEAD/plugins/showcase/skills/pr-demo

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

PRデモ

レビュアーは、コード差分を開かなくても1分以内に変更内容を理解できるべきです。変更点、新しい動作、動作確認の証拠、そしてどこを見ればよいか。リポジトリの設定情報(キャプション言語、変更フローの録画方法、投稿先)は .claude/profiles/delivery.md に記載されています(Demo、Notify セクション)。

簡潔で率直なものが、完全なものに勝ります。 以下の順序で、合計30秒・5シーンに収めます。変更にないものは無理に追加せず省略してください。

  1. 変更内容 — タイトルと最大3つの箇条書き。
  2. 新しい動作 — フロー図。変更箇所をマーク。
  3. Before/After — 視覚的な変更がある場合のみ。バックエンド変更ではスキップ。
  4. 修正の動作確認 — 録画。重要な部分だけにトリミングし、12秒未満。
  5. 証拠 — レビューキーのチェック結果 と テスト結果を1つのkeyシーンにまとめる。両者は同じ疑問に答えるため、それぞれ別シーンにはしない。

1. 素材の収集

out/demo/<PRまたはIssue番号>/ ディレクトリに保存します(git管理対象外)。

  • レビューキーのエビデンス: out/review-key/<番号>/result.json および key-reviewer の判定結果(review-key)。
  • UI変更のスクリーンショット: 同じビューを変更前(ベースブランチ)と変更後で、同じサイズ・同じデータで比較。変更部分のみにトリミング。1280pxの全ページだと変更が小さすぎて見えません。
  • 変更フローの録画: プロファイルの Demo コマンド、またはPlaywrightで browser.newContext({ recordVideo: { dir, size: { width: 1280, height: 800 } }, viewport: { width: 1280, height: 800 } }) を使用してE2Eテストの該当ステップを録画(コンテキストクローズ時にファイル生成)。20秒未満に保ち、重要な画面から始め、ログイン画面は映さない。
  • 変更のフロー図: mermaid flowchart LR(または TD)。5~9ノードでユーザーまたはリクエストの経路を示す。変更箇所に :::changed、新規追加に :::added、削除に :::removed を付ける。ファイルではなく動作を説明する。
  • 実行したテスト: 各テストに数値を1つ(476 tests、12 flows など)。

2. demo.json の作成

素材と同じディレクトリに配置します(パスは相対パス)。テキストはプロファイルのキャプション言語で記述。短文に — 各シーンは表示秒数内で読まれます。バッククォートと **太字** が使用可能です。

{
  "lang": "en",
  "brand": "**shop** · PR #352",
  "ref": "Closes #331",
  "kicker": "Bugfix",
  "title": "The checkout fits at 1280 px",
  "subtitle": "The pay button covered the basket, and the coupon field was 49 px wide.",
  "chips": [{ "text": "Review key: PASS", "ok": true }, "3 files"],
  "scenes": [
    { "type": "title", "seconds": 3 },
    { "type": "bullets", "items": ["…", "…", "…"], "seconds": 5 },
    { "type": "flow", "mermaid": "flowchart LR\n  A[Width] --> B{\"< 1440 px?\"}\n  B -- yes --> C[Icons]:::changed", "seconds": 6 },
    { "type": "compare", "before": "before.png", "after": "after.png", "seconds": 5 },
    { "type": "clip", "heading": "Recorded at 1280 px", "src": "run.webm", "caption": "e2e: checkout-fit", "speed": 1.5, "maxSeconds": 12 },
    { "type": "key", "result": "../../review-key/331/result.json", "baseFails": true, "seconds": 7,
      "rows": [{ "ok": true, "text": "`verify.sh` · 476 tests" }] },
    { "type": "end", "title": "Ready for review", "lines": ["PR: **github.com/…/pull/352**", "3 am: …"], "seconds": 3 }
  ]
}

シーンタイプ: title、bullets(items 最大4つ)、flow(mermaid、legend: false で凡例非表示)、compare(before、after、ラベル;layout: "stack" で縦並び、ツールバーなどの横長に)、clip(src .webm/.mp4、from/to 秒、speed、maxSeconds デフォルト20、crop {x, y, w, h} で録画のピクセル単位で重要部分を拡大;長さはファイルから取得)、key(result = keycheckのresult.jsonまたはオブジェクト;verdict、baseFails、claim、rows と count {value, total, label} で上書き — 例:8ケースを実行する1つのチェックは 8/8 と表示する方が分かりやすい)、checks(items に name、detail、ok)、end(title、lines)。すべてのシーンに heading、kicker、seconds を設定可能。変更にないものは省略 — バックエンド変更には compare や clip は不要。純粋なリファクタリングには key シーンで同値性のみを示す。

key シーンの左パネルには最大8行まで表示でき、レビューキーのチェック前に独自の rows を追加できるため、テストは各行に1つずつ("verify.sh · 476 tests"など)配置し、その後のchecks シーンには回さない。checks` シーンはレビューキーを表示する必要がない場合にのみ使用する。

表現の注意

キャプションは表示秒数内で読まれるため、すべての単語に意味を持たせる必要があります。視聴者をいら立たせたデモから学んだ3つのルール:

  • 結果を述べよ、称賛するな。 判定スタンプと「key-reviewerによる独立検証済み」ですでにキー通過と検証者を示しています。「PASS、カンニングなし」や「完全検証済み」は作者が自分の宿題を採点しているように読めます。判定について余計なことは一切書かない。
  • カウントラベルは名詞で: checks pass、cases identical、tests。「fail」のような動詞をラベルに使うと「5/5」が逆に読まれる文になります — 「5件中5件が失敗」は変更が壊れているように聞こえますが、実際にはベースブランチが失敗している意味です。ベースが失敗することを伝えたい場合は、baseFails 行を使用してください。これは自動的に適切な表現になります。
  • 無駄な言葉を削除: 「successfully」「as expected」「this ensures that」、およびタイトルを言い換えただけの箇条書きはカット。レビュアーが「ええ、当然だよね」と思うような箇条書きは、箇条書きにする価値がありません。

3. レンダリング

node <このスキルのディレクトリ>/scripts/render-demo.mjs out/demo/<番号>/demo.json [--webm]

Chromiumで各シーンをフレーム単位で描画し(テキストは鮮明、ドロップフレームなし)、demo.mp4(H.264、Slack・GitHub・ブラウザでインライン再生)、demo.png(ポスター画像:フローまたはキーシーン)、および --webm オプションでVP9の demo.webm をエンコードします。ffmpegが必要で、プロジェクトからPlaywrightを使用するか、なければ ~/.cache/carnufex-showcase に一度インストールします。レンダリング時間は動画1秒あたり約1秒です。

送信前に確認: 各シーンからフレームを抽出し(ffmpeg -ss <時間> -i demo.mp4 -frames:v 1 f.png)、確認します。テキストの切れ、空のダイアグラム、ログイン画面のクリップなどがあれば修正して再レンダリングします。

4. 投稿

プロファイルの Notify に指定されたチャンネルに、ボットとして 投稿します。これにより、相手に実際の通知が届きます(Slackコネクタ経由で投稿すると本人からのメッセージ扱いになり、Slackは自分のメッセージを通知しません)。PRごとに1つのスレッド: デモがPRのスレッドを開始し、その後のCI、レビューラウンド、マージ、デプロイ、本番確認、ロールバックはすべてそのスレッドへの返信として投稿します(ship がそれらを投稿)。チャンネルには全リポジトリにわたって、PRごとに1行が表示されます。メッセージはファイルに書き込みます。メッセージは単独で意味をなす必要があり(Slack mrkdwn)、リポジトリ名で始めます:

*<リポジトリ>* · PR #<番号> · <タイトル> — ready for review
<PR URL>
• <変更内容、1行目>
• <2行目>
Review key (<種類>): *PASS*, checked independently: <判定結果から1行>
3 am: <シグナル>
node <このスキルのディレクトリ>/scripts/post-slack.mjs --channel <ID> --pr <PRのURL> --file out/demo/<番号>/demo.mp4 --title "<リポジトリ> PR #<番号>: <タイトル> (<秒数> s)" --comment-file out/demo/<番号>/message.md
node <このスキルのディレクトリ>/scripts/post-slack.mjs --channel <ID> --pr <PRのURL> --text-file update.md [--broadcast]

--pr はチャンネル内のPRのURLからスレッドを検索します(状態は保持しません):見つかればそのスレッドに投稿、見つからなければ新規スレッドを開始します。--text-file はファイルなしでメッセージを投稿します。--broadcast はスレッドの返信をチャンネルにも表示します(結果報告(本番稼働またはロールバック)に使用)。スレッドとパーマリンクが出力されます。ボットトークンは SLACK_BOT_TOKEN またはslack-channelプラグインの ~/.claude/channels/slack/.env から取得します。ボットはチャンネルに参加している必要があります(not_in_channel の場合:/invite @<ボット名>)。ボットがない場合は、Slackコネクタ(slack_get_file_upload_url → バイナリPOST → slack_complete_file_upload)にフォールバックし、通知が送信されないことを伝えます。

同じ3行のテキスト、Mermaidフローチャート、SlackリンクをPRの説明欄にも追加します(GitHubはMermaidを描画しますが、API経由でアップロードした動画は再生できません)。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

関連スキル