---
name: release-script
description: リリースノートとX投稿ドラフトからMulmoScript（リリースノート動画用）を生成する。/release-xpost 完了後に実行。
allowed-tools: Read, Write, Glob, Grep, Bash, AskUserQuestion
argument-hint: "<version> (例: 1.0.11)"
---

バージョン $ARGUMENTS のリリースノート動画用 MulmoScript を生成する。

## 前提条件

- `docs/release_notes/v$ARGUMENTS/release_notes_v$ARGUMENTS.md` が作成済みであること
- `docs/release_notes/v$ARGUMENTS/xpost_v$ARGUMENTS_draft.md` が作成済みであること
- `docs/release_notes/v$ARGUMENTS/images/` にスクリーンショットが保存されていること

## 手順

### Step 1: 入力ファイルの読み込み

以下を読み込む:

1. `docs/release_notes/v<version>/release_notes_v<version>.md` — 機能の詳細
2. `docs/release_notes/v<version>/xpost_v<version>_draft.md` — 構成と画像参照
3. `docs/release_notes/v<version>/images/` — スクリーンショット一覧

### Step 2: 既存スクリプトの参照

過去のスクリプトをテンプレートとして参照する:

```bash
ls docs/release_notes/v*/release_v*_script.json
```

最新のスクリプトを読み込み、パラメータ部分（`$mulmocast` 〜 `audioParams`）をテンプレートとして使用する。

### Step 3: Beats の構成

xpost draft の構成に沿って beats を作成する:

#### 3a. タイトルスライド（2ビート構成）

バージョン番号にドットが含まれるため、`textSplit` の `.` 区切りで `v1.0.11` が分割されてしまう。これを回避するため、タイトルスライドは2ビートに分ける:

**ビート1**: バージョン番号を含む挨拶（caption分割を無効化）
```json
{
  "speaker": "Presenter",
  "text": "マルモキャスト バージョン<version読み>をリリースしました！",
  "captionParams": {
    "captionSplit": "none",
    "textSplit": { "type": "none" }
  },
  "id": "title-slide",
  "image": {
    "type": "markdown",
    "markdown": [
      "<div style='display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; text-align: center;'>",
      "",
      "# 🎉 MulmoCast v<version> Released!",
      "## <日付>",
      "",
      "</div>"
    ]
  }
}
```

**ビート2**: サマリー（デフォルトのcaptionParamsを使用、タイトルスライドの画像を参照）

単なる機能列挙ではなく、リリースの背景・価値・ユーザーへの影響を1〜2文で伝える。動画では視聴者に文脈を与え、`mulmo markdown` で生成する記事の冒頭も充実する。

**避けるパターン**: 「このバージョンでは、○○、△△などの更新があります。」（機能名の羅列）
**良いパターン**: 変更の背景や、ユーザーにとっての意味を伝える文にする

```json
{
  "speaker": "Presenter",
  "text": "<リリースの背景・価値を伝えるサマリー>",
  "id": "title-overview",
  "image": {
    "type": "beat",
    "id": "title-slide"
  }
}
```

#### 3b. 機能紹介ビート

xpost draft の各ポスト（メインポスト + 連投ポスト）から:

1. **画像**: `images/` 内のスクリーンショットを `kind: path` で参照
2. **ナレーション**: release notes の詳細を元に日本語で作成
3. **構成**: 1機能につき1〜複数ビート（スクショの数に応じて）

**画像マッピングルール**:
画像ファイル名のプレフィックス `{ポスト番号}-{画像番号}_` でビートに自動対応:
- `01-*` → メインポストのビート
- `02-*` → 連投1のビート
- `03-*` → 連投2のビート（以降同様）
- 1ポストに複数画像がある場合、画像ごとに別ビートを作成

プレフィックスがない旧形式の画像は、xpost draft の添付メディア記述から対応を判断する。

```json
{
  "speaker": "Presenter",
  "text": "<日本語ナレーション>",
  "id": "<機能を表すID>",
  "image": {
    "type": "image",
    "source": {
      "kind": "path",
      "path": "images/<filename>.png"
    }
  }
}
```

**mp4（動画）を参照する場合**:

動画ファイルを使うビートは `"type": "movie"` を使う。`"type": "image"` では動画は再生されない:

```json
{
  "speaker": "Presenter",
  "text": "<日本語ナレーション>",
  "id": "<機能を表すID>",
  "image": {
    "type": "movie",
    "source": {
      "kind": "path",
      "path": "images/<filename>.mp4"
    }
  }
}
```

**重要**: `type: movie` ビートではナレーションの TTS 長さが mp4 の duration を超えないようテキストを調整する。超えると次ビートに音声がはみ出して、映像・字幕・次ビートの開始タイミングがズレる。mp4 が短い場合はナレーションを 1 文程度に絞るか、補足説明を後続ビートに分ける。

**デリミタ文字を含むテキストの分割ルール**:

ナレーション中にバージョン番号（`0.25`、`4.0`）、モデル名（`gemini-3.1-flash-image-preview`）など、`textSplit` のデリミタ（`.`、`,`）を含む文字列がある場合、その部分でキャプションが意図せず分割される。これを回避するため、デリミタを含む部分を独立ビートに分離する:

```json
// ビート1: 導入文（デフォルトの captionParams）
{
  "speaker": "Presenter",
  "text": "1：TTS読み上げ速度オプションを追加しました",
  "id": "tts-speed",
  "image": { "type": "image", "source": { "kind": "path", "path": "images/01-01_speed.png" } }
}

// ビート2: 数値を含む部分（caption分割を無効化、同じ画像を参照）
{
  "speaker": "Presenter",
  "text": "OpenAI TTSでは0.25倍速から4.0倍速まで設定できます",
  "captionParams": { "captionSplit": "none", "textSplit": { "type": "none" } },
  "id": "tts-speed-detail",
  "image": { "type": "beat", "id": "tts-speed" }
}

// ビート3: 続きの文（デフォルトの captionParams、同じ画像を参照）
{
  "speaker": "Presenter",
  "text": "読み上げ速度は設定画面から変更できます",
  "id": "tts-speed-usage",
  "image": { "type": "beat", "id": "tts-speed" }
}
```

ポイント:
- デリミタを含むビートのみ `captionParams` で `captionSplit: "none"` + `textSplit: { type: "none" }` を設定
- 前後のビートは `image: { type: "beat", id: "..." }` で同じ画像を参照
- 1機能が2〜3ビートに分かれるのは正常

#### 3c. クロージングスライド（2ビート構成）

タイトルスライドと同様に、バージョン番号を含む文を分離する。

**ビート1**: その他の改善・案内
```json
{
  "speaker": "Presenter",
  "text": "その他、軽微な改善を行いました。\n起動中のアプリに更新通知が届きます。\nダウンロードは公式サイトから行えます。",
  "id": "thank-you-slide",
  "image": {
    "type": "markdown",
    "markdown": [
      "<div style='display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; text-align: center;'>",
      "",
      "# Thank You!",
      "",
      "## MulmoCast v<version>",
      "",
      "### Happy Creating!",
      "</div>"
    ]
  }
}
```

**ビート2**: バージョン番号を含む締め（caption分割を無効化、Thank Youスライドの画像を参照）
```json
{
  "speaker": "Presenter",
  "text": "マルモキャスト バージョン<version読み>をお楽しみください！",
  "captionParams": {
    "captionSplit": "none",
    "textSplit": { "type": "none" }
  },
  "id": "thank-you-closing",
  "image": {
    "type": "beat",
    "id": "thank-you-slide"
  }
}
```

#### 3d. Markdown スライドの設計原則

機能紹介・告知用 Markdown スライドを設計する際の指針。

- **スタイル統一**: 同じ役割のスライド（機能紹介系・変更告知系など）はレイアウト・揃え方・見出しレベルを揃える。タイトル / クロージング等の「ブックエンド系」と本編系で雰囲気を分ける程度に留め、本編内で混在させない（揃っていないと「なぜ違うのか」という認知ノイズになる）
- **抽象まとめより具体列挙**: 「N 件追加」のような数や抽象表現だけで終わらせず、主要な要素名（モデル名・機能名等）を bullet で列挙する。ユーザーは「いくつ」ではなく「何が」を見たい
- **テキストとスライドの役割分担**: ナレーションテキスト（TTS）はスライドの読み上げではなく、内容の補足・文脈付けに使う

### Step 4: ナレーションテキストのルール

- **言語**: 日本語
- **読み方**: バージョン番号は「バージョン1.0.11」→「バージョン いってん ぜろ てん いちいち」のように自然な読みに
- **トーン**: ニュースキャスターのような明瞭でプロフェッショナルな読み上げ
- **長さ**: 1ビートあたり1〜2文（長すぎない）
- **番号付け**: 機能ごとに「1：」「2：」と番号を振る（「。」は `textSplit` の区切り文字のため使わない）
- **字幕改行**: `\n` で字幕の表示行を制御する。1行あたり約25〜30文字を目安に、意味の切れ目で `\n` を入れる。`\n` は `textSplit` の区切り文字なので字幕分割ポイントになる
- **内容**: release notes の詳細情報を元に、要約しつつわかりやすく

### Step 5: テンプレートパラメータ

以下は固定値（テンプレート）:

```json
{
  "$mulmocast": { "version": "1.1", "credit": "closing" },
  "canvasSize": { "width": 1280, "height": 720 },
  "speechParams": {
    "speakers": {
      "Presenter": {
        "displayName": { "ja": "ナレーター" },
        "voiceId": "shimmer",
        "speechOptions": {
          "instruction": "Speak clearly and professionally like a news announcer reading release notes. Use a neutral, informative tone with clear enunciation."
        },
        "provider": "openai"
      }
    }
  },
  "imageParams": { "provider": "openai", "images": {} },
  "movieParams": { "provider": "mock", "model": "", "transition": { "type": "fade", "duration": 1 } },
  "soundEffectParams": { "provider": "replicate" },
  "textSlideParams": { "cssStyles": ["h3 {margin-left: 20px; margin-top: 20px}"] },
  "captionParams": {
    "lang": "ja",
    "captionSplit": "estimate",
    "textSplit": {
      "type": "delimiters",
      "delimiters": ["。", "．", ".", "！", "!", "？", "?", "；", ";", "、", ",", "\n"]
    }
  },
  "audioParams": {
    "padding": 0.3,
    "introPadding": 1,
    "closingPadding": 0.8,
    "outroPadding": 1,
    "bgm": { "kind": "path", "path": "../bgm/20251217031931-8c55b232.mp3" },
    "bgmVolume": 0.1,
    "audioVolume": 1,
    "suppressSpeech": false
  }
}
```

### Step 6: JSON の組み立てと保存

テンプレートパラメータ + `title` + `description` + `lang` + `beats` を組み立て、以下に保存:

```
docs/release_notes/v<version>/release_v<version>_script.json
```

**ファイル名ルール**: バージョンのドットをアンダースコアに変換（例: `1.0.11` → `release_v1_0_11_script.json`）

### Step 7: PDF ハンドアウトの生成

MulmoScript から PDF ハンドアウトを生成する。出力ディレクトリは `-o` オプションで指定すれば `mulmo` が自動作成するため、`mkdir` は不要。

```bash
npm install -g mulmocast@latest
mulmo pdf --pdf_mode handout docs/release_notes/v<version>/release_v<version>_script.json -o docs/release_notes/v<version>/output
```

**ファイル名ルール**: スクリプトのファイル名に合わせる（例: `release_v1_0_11_script.json`）

### Step 8: PDF の確認後、日本語版動画の生成

PDF ハンドアウトの生成結果をユーザーに報告し、PDF が OK であれば動画を生成する。

```bash
mulmo movie docs/release_notes/v<version>/release_v<version>_script.json -o docs/release_notes/v<version>/output -l ja -c ja
```

生成後、JA タイムスタンプを抽出する（Step 11 で使用）:

```bash
npx tsx .claude/skills/release-script/extract-timestamps.ts docs/release_notes/v<version>/output/release_v<version>_script_studio.json
```

### Step 9: 英語版動画の生成

日本語版が OK であれば、英語版も生成する（MulmoCast の翻訳機能で自動翻訳される）。

```bash
mulmo movie docs/release_notes/v<version>/release_v<version>_script.json -o docs/release_notes/v<version>/output -l en -c en
```

**注意**: `_studio.json` は `mulmo movie` 実行ごとに上書きされる。そのため JA 生成後に JA タイムスタンプを読み取ってから EN を生成すること。

### Step 10: 翻訳テキストの確認

英語版動画生成後、`output/release_v<version>_script_lang.json` を確認する。

MulmoCast の翻訳機能は「マルモキャスト」を誤訳することがある（例: 「MarmoCast」「MarmCast」）。以下を実行:

1. `_lang.json` を読み込む
2. 「MulmoCast」以外の表記（`MarmoCast`、`MarmCast`、`MarumoCast` 等）を検索
3. すべて「MulmoCast」に置換する
4. 置換した場合は英語版動画を再生成する
5. 確定した EN 動画の `_studio.json` から EN タイムスタンプを抽出する（再生成した場合はタイムスタンプが変わるため、必ず最終版から抽出すること）:

```bash
npx tsx .claude/skills/release-script/extract-timestamps.ts docs/release_notes/v<version>/output/release_v<version>_script_studio.json
```

### Step 11: タイムスタンプの作成（ビート単位）

Step 8 で抽出した JA タイムスタンプと Step 10 で抽出した EN タイムスタンプを、まずビート単位で書き出す。

**タイムスタンプ抽出ルール**:

1. `_studio.json` の `beats` 配列から各ビートの `startAt`（秒）を取得
2. ビートのインデックスはスクリプトの `beats` 配列と1対1対応
3. タイトルスライド（2ビート構成）とクロージングスライド（2ビート構成）は**最初のビートの `startAt` を使用**して1項目にまとめる
4. 秒を `M:SS` 形式に変換（例: 69.192s → `1:09`）
5. 各ビートに言語に応じたラベルを付ける（JA: 日本語、EN: 英語）

この段階では各ビートが 1 項目として残っている状態（粒度が細かい）。

### Step 12: X 投稿構成に合わせた機能単位の集約

ビート単位のタイムスタンプを、**X 投稿の構成（メインポスト + 各連投ポスト）に合わせて機能単位で集約**する。`docs/release_notes/v<version>/xpost_v<version>_draft.md` を参照して、X 投稿の 1 ポスト = タイムスタンプ 1 項目になるように統合する。

**集約ルール**:

- X 投稿の 1 ポスト内で複数ビートに分かれている機能（例: モデル一覧が OpenAI/Replicate Image/Replicate Video の 3 ビートに分かれている場合）は、**最初のビートの `startAt` を使用**して 1 項目にまとめる
- 機能名は X 投稿のセクションタイトルに合わせる（例: 「Now available / 新しいAIモデル」→ JA: 「新しいAIモデル」 / EN: 「New AI models」）
- 細かい補足ビート（生成サンプル、プロジェクト上書き等）は親機能の項目に吸収する
- 結果として X 投稿のポスト数とほぼ同数のタイムスタンプ行になる

集約後の最終結果を `docs/release_notes/v<version>/timestamps_v<version>.md` に保存する。

**フォーマット例**（X 投稿が 4 ポスト構成のリリースの場合）:

```markdown
## JA Timestamps

0:00 はじめに
0:16 Azure OpenAIサービス対応
0:42 Vertex AI 設定
1:08 おわりに

## EN Timestamps

0:00 Introduction
0:14 Azure OpenAI Service
0:38 Vertex AI Settings
1:02 Thank you
```

このファイルは `/release-youtube` スキルが参照する。

### Step 13: 完了報告

生成した MulmoScript のファイルパス、ビート数、PDF・動画（日本語版・英語版）の出力先を報告する。

## 重要なルール

- **画像は `kind: path` で参照** — ローカルスクリーンショットを使用（X の URL は使わない）
- **ナレーションは日本語** — TTS 用のテキストとして自然な日本語で記述
- **テンプレートパラメータは原則固定** — 変更が必要な場合はユーザーに確認
- **BGM パスが動作しない場合は調整** — MulmoCast のパス解決に依存するため
- **ユーザー確認は不要** — アプリ上でブラッシュアップする前提のため、生成後そのまま保存する
- **ビート構成の変更時は全体を通して確認** — 部分修正の積み重ねは image / text / id の不整合を生みやすい。構成変更が入ったら beats 配列全体を読み直し、画像参照・ナレーション内容・id の整合性を一括で確認すること
