System Doctrine — v2.0

システム設計法典

AI 画像生成・判定フロー・コンテンツ管理を統合した創作プロジェクト基盤の設計書。 他プロジェクトへの移植を前提に、汎用パターンとして記述する。 プロジェクト固有の設定値は XI — プロジェクト固有設定 にまとめる。

Overview

目的と構造

このシステムは「AI を使った創作物の生成→判定→正本化」を 繰り返す制作ワークフローを Next.js + Vercel 上に実装したものです。 キャラクター・アイテム・ロケーションなどの設定資料をテキスト正本として管理し、 そこからプロンプトを自動構築、AI で画像を生成、人間が判定して正本に昇格させる、という 一方向フローが中心にあります。 コンテンツモデルの全定義は I — コンテンツモデル を参照。

references/                ← テキスト正本 (git 管理)
  characters/<slug>/
    profile.md             ← キャラ設定の Single Source of Truth
    refs/sheet.jpg         ← 参照画像 (style anchor)
  style/ivs2026_aesthetic.md ← 共通ビジュアル指針
prompts/                   ← repo root 直下 (references の外)
  world_supplement_v1.yaml ← アイテム/背景マニフェスト
  storyboard_pv01.yaml     ← 絵コンテ定義

  ↓ npm run sync (predev / prebuild で自動)

site/
  content/characters/*.md  ← Next.js が読む派生物
  public/sheets/*.jpg      ← 配信用画像

  ↓ buildSupplementPrompt()

JSONL (prompt + reference_images)
  ↓ openai_batch_with_refs --concurrency 8
out/<batch>/*.png

  ↓ /review-items で OK / NG 判定 → #promote

site/public/items/<slug>.png   ← 採用 (promote)
site/public/sheets/_ng/*.jpg   ← 没 (move-rejected-to-ng)

技術スタック

レイヤー技術役割
フロントエンドNext.js 15 (App Router)UI + API Routes
スタイルTailwind CSS v3トークンベース styling
画像生成OpenAI gpt-image-2テキスト→画像 / 画像参照生成
永続化Vercel Blob判定 JSON / 字コンテ JSON のクロスブラウザ共有
デプロイVercel (GitHub 連携)push → 自動ビルド・公開
コンテンツgray-matter + remarkMarkdown frontmatter → データ

設計原則

  • テキストが正本 — 画像は派生物。設定変更は必ず references/ から。
  • sync は冪等npm run sync を何度実行しても結果が同じ。
  • 判定は永続化 — localStorage + Vercel Blob のデュアル書き込みで offline でも動く。
  • プロンプトはコードで管理 — プロンプト文字列を UI に直接書かない。lib/prompt-codex.ts を唯一の編集場所にする。
  • push = 本番反映 — main への merge は即デプロイ。ローカルで型チェックを通してから push する。
  • 生成前は必ず確認 — バッチ実行前に生成リストを提示し、承認を得てから実行する。詳細は #gen-confirm

生成確認ルール(画像・映像共通)

1枚・1本でも同じ。バッチ実行コマンドを叩く前に、必ず以下の 2ステップを踏む。 承認なしで実行しない。パイプラインの詳細は IV — 生成前確認フロー を参照。

STEP 0 — 種別の確認

生成前に「何を生成するか」を以下の表から選択・宣言する。種別によって解像度・品質・スクリプトが決まる。

種別解像度qualityスクリプト
絵コンテカット PNG2048×1152highgen.mjs
シーンボード退役 (2026-06-10) — 専用スクリプトなし。歴史資産のみ
映像/storyboard UI コピー + Higgsfield MCP
STEP 1 — バッチ計画の提示と承認
【種別】絵コンテカット PNG — gen.mjs
【解像度】2048×1152 / quality: high

| # | id        | サイズ     | 品質 | 内容概要             |
|---|-----------|------------|------|----------------------|
| 1 | ch04_C1   | 2048×1152  | high | 沼辺の全景、霧の夜明け |
| 2 | ch04_C2   | 2048×1152  | high | ハニワ腰〜頭 MS      |

合計 2 枚 / スクリプト: node site/scripts/gen.mjs ch04 --go
【種別】映像 — /storyboard UI コピー (lib/video/prompt.ts ビルダー) + Higgsfield MCP generate_video (Kling V3 i2v 主軸 / Seedance サブ)

| # | id      | モデル                       | 長さ | 内容             |
|---|---------|------------------------------|------|------------------|
| 1 | c1-s1-1 | Kling V3 i2v (mode=pro)      | 5s   | ハニワ出土シーン |

合計 1 本 / 実行: Higgsfield MCP generate_video(コピーしたプロンプトを使用)
※ モデルは Higgsfield MCP 側で選択 (Kling V3 image-to-video 主軸 / Seedance 2.0 サブ)。
   「Omni / multi-ref」は廃止語彙
IContent Model

概念マップ

このシステムが扱うコンテンツは以下の11概念で構成される。 各概念は独立したデータ構造を持ち、参照関係でつながる。

ストーリー (Story)
  └─ 章立て (Chapter) × N
       └─ シーン (Scene) × M
            └─ 字コンテ (Jikonte) — テキストによるカット仕様
                 └─ カット (Cut) × K
                      └─ カット画像 (Cut Image) — AI生成PNG
            ※ シーンボード画像 (storyboard-boards) は 2026-06-11 廃止

キャラクター (Character) — ストーリー/シーンに登場する存在
アイテム (Item / Supplement) — 物語に登場する道具・武器・背景・場所の概念画
世界観 (World) — ストーリーの背景設定 (地理・歴史・社会・ルール)
ロケーション (Location) — 具体的な撮影場所の定義

ストーリー / 章立て

ストーリー (Story) は物語全体。複数の章 (Chapter) で構成される。 正本は references/ 配下の Markdown ファイルと site/app/story/page.tsx の TypeScript 定義が担う。

章立て (Chapter) はストーリーを分割する最大単位。 章ごとに「場所・時刻・登場キャラ・主要イベント」を定義し、 字コンテ・絵コンテの親コンテナとなる。

id:            "ch01"          // 識別子 (固定)
chapter_no:    1               // 表示番号 (1始まり)
chapter_label: "第1章·ハニワくん出土"
location:      "再開発地区·東京(夜)"
time_of_day:   "深夜(午前2〜3時)"
characters:    ["haniwa_boy"]   // 登場キャラ slug[]
scenes:        [...]            // JikonteScene[] → #jk-schema

シーン

シーン (Scene) は章の下位単位。場所・照明・状況が連続するひとまとまりの出来事。 映画の「シーン」概念と同じ。シーン ID は ch01_sc01 形式 (章_シーン通し番号)。

シーンは以下の情報を持つ:

  • situation — 観客には見えない感情・状況の因果。カット記述ではなくシーンの「なぜ」。
  • lighting — 光源・色温度・入射方向・感情効果。
  • props — 物語に意味を持つ具体的な物体。
  • refs[] — 登場するキャラ/アイテム/背景の参照画像 slug。
  • cuts[] — このシーンを構成するカットの配列。

字コンテ

字コンテ (Jikonte) はカット単位で映像構図をテキストで記述したデータ構造。 「撮影台本」に相当し、AI 絵コンテ生成の入力になる。 正本は site/lib/storyboard-jikonte.ts の TypeScript 配列。

字コンテのデータ階層: JikonteChapter → JikonteScene → JikonteCut。 詳細スキーマは V — 字コンテシステム を参照。

scene_id: "ch01_sc01"   // シーン ID (ch<NN>_sc<NN>)

// cut.n が overlay / API / ファイル名の単一マスターキー
// 形式 = "c1-s1-1" (c<ch>-s<scene>-<cut>)。混成キー ${scene_id}_${cut.n} は spec §2 で廃止
// 表示用は cutDisplayId() で "CH01-S1-C1" に整形 (cut-naming.ts)

絵コンテ / カット / カット画像

絵コンテ (Ekonte / Storyboard) は字コンテをもとに AI 生成した画像の集合体。 現行はカット単位の「カット画像」のみ (シーン単位の「ボード画像」public/storyboard-boards/ は 2026-06-11 廃止 — 字コンテ + カット画像 + 動画が正でありボードは冗長)。

概念説明ファイルパス
カット画像カット単位の AI 生成フレーム (1枚1カット)public/storyboard-cuts/<chId>/<slug>.png

カット (Cut) は1回のカメラポジション変更単位。 フレームサイズ (LS/WS/MS/MCU/CU/ECU/INSERT)、カメラムーブ、アングル、 デュレーション、セリフ、構図記述を持つ。→ V — 字コンテシステム

キャラクター

キャラクター (Character) はストーリーに登場する人物・存在。 正本は references/characters/<slug>/profile.md。 外見の正本は refs/sheet.jpg (style anchor として全バッチに伝播)。

フィールド説明
name (slug)string内部識別子 (snake_case)
display_name_ja / enstring表示名
roleenumprotagonist / rival / guardian / trial_enemy / gauntlet_enemy / mid_boss / enemy / final_boss
stage"N/M"進化段階 (例: "1/3")
evolution_nextslug?次形態への参照
final_formslug?最終形態への参照
threat_level / story_rolestring?脅威度・物語上の役割

アイテム / 補足資料

アイテム (Item)/items に出る curated エンティティ。 正本は references/items/<slug>/profile.md + refs/sheet.jpg(sync で content/items/<slug>.md + public/items/<slug>.png に派生)。 Item の kindkey_item | mecha の2値 (lib/items.ts ItemMeta)。 章→item の対応は lib/chapter-refs.tsCHAPTER_ITEMS_MAP

これとは別レイヤSupplementItem (lib/supplement-items.ts) があり、/review-items 用の没マニフェスト。こちらの kindcharacter | item | background で、Item エンティティの kind とは別物。

// Item エンティティ (lib/items.ts ItemMeta) — /items の curated 正本
interface ItemMeta {
  name:        string;
  display_name_ja: string;
  display_name_en: string;
  kind:        "key_item" | "mecha";   // ← 2値のみ
  tagline_ja?: string;
  appears_in_boards?: string[];
}

// SupplementItem (lib/supplement-items.ts) — /review-items 用の没マニフェスト (別物)
interface SupplementItem {
  no:         number;
  slug:       string;
  kind:       "character" | "item" | "background";  // ← Item.kind とは別系統
  title_ja:   string;
  title_en:   string;
  importance: "critical" | "high" | "medium" | "low";
  summary:    string;      // プロンプトに注入される設定概要
}

各アイテムは site/lib/supplement-references.tsSUPPLEMENT_REF_CHARS マップで「引用すべきキャラ slug[]」と紐づく。 これが Canon 注入の参照源になる。→ III — Canon 注入

世界観

世界観 (World) はストーリーの背景設定全体。地理・歴史・社会構造・ 勢力関係・ルール・用語集を含む。 正本は references/style/ivs2026_aesthetic.mdsite/app/world/page.tsx のインライン定義。 世界観の要素は補足資料 (世界観七章) として /world ページで公開される。

ロケーション

ロケーション (Location) はシーンの撮影場所を定義した概念。 正本は references/world/locations/<slug>/ のディレクトリ毎 slug 構造 (profile.md + refs/sheet.jpg)。references/locations は存在しない。 絵コンテ生成時の三層リファレンス「層2: ロケーション」として参照される。 → VIII — 三層リファレンス

references/world/locations/<slug>/profile.md   ← テキスト正本 (SoT)
references/world/locations/<slug>/refs/sheet.jpg ← 参照画像 (SoT)

  ↓ npm run sync (sheet.jpg → png 変換)

site/content/locations/<slug>.md   ← 派生 (プロンプト注入用)
site/public/locations/<slug>.png   ← 派生 (絵コンテ生成の ref)
IIData Architecture

正本の所在(Single Source of Truth)

コンテンツの正本は references/ 配下のテキストファイルです。site/content/site/public/ は sync スクリプトが生成する派生物であり、直接編集しません。

references/                    ← テキスト正本 (characters/ items/ style/ world/ boards/ brand/)
  characters/
    <slug>/
      profile.md          必須。frontmatter + 設定本文
      refs/sheet.jpg      参照画像 (style anchor として使用)
  items/
    <slug>/
      profile.md          アイテム設定 (kind: key_item|mecha)
      refs/sheet.jpg      参照画像
  world/locations/
    <slug>/
      profile.md          ロケーション設定
      refs/sheet.jpg      概念画 (sheet → public/locations/<slug>.png に変換)
  style/
    ivs2026_aesthetic.md  プロジェクト共通ビジュアル指針 (→ content/aesthetic.md)

prompts/                       ← repo root 直下 (references の外)
  world_supplement_v1.yaml     補足資料マニフェスト
  storyboard_pv01.yaml         絵コンテ定義

同期パイプライン

npm run sync は5本のスクリプトを連結する (sync-envsync-refssync-storyboardsync-supplementgenerate-board-manifest)。sync-refs.mjsreferences/ を読み、site/content/site/public/ に書き出します。predev / prebuild フックで自動実行され (整合チェック check:cutid / check:overlay も走る)、 開発者が手動実行する必要はありません。部分同期はnode scripts/sync-refs.mjs --only=character|item|location [--slug=<slug>]

{
  "scripts": {
    "sync":     "node scripts/sync-env.mjs && node scripts/sync-refs.mjs && node scripts/sync-storyboard.mjs && node scripts/sync-supplement.mjs && node scripts/generate-board-manifest.mjs",
    "predev":   "npm run sync && npm run check:cutid && npm run check:overlay",
    "prebuild": "npm run sync && npm run check:cutid && npm run check:overlay",
    "dev":      "next dev --port 3300"
  }
}

スキーマ設計

frontmatter は型安全に扱うため、lib/characters.ts で 手動パースして TypeScript 型に変換します。

---
name: haniwa_boy                    # 内部 slug (必須)
display_name_ja: ハニワモード(少年期)  # 表示名 (必須)
display_name_en: Haniwa Mode (Boy)
role: protagonist                   # enum: protagonist|rival|guardian|trial_enemy
                                    #       |gauntlet_enemy|mid_boss|enemy|final_boss
stage: "1/3"                        # 進化段階 (optional)
evolution_prev: ...                 # 前形態 slug (optional)
evolution_next: haniwa_youth        # 次形態 slug (optional)
final_form: haniwa_ashura           # 最終形態 slug (optional)
tagline_ja: ...                     # optional
threat_level: ...                   # optional
story_role: ...                     # optional
---
# 派生 (derived): sheet / ng / turnaround。alive フィールドは無い (生死は別ロジック)
本文: キャラクター設定の詳細 (Markdown)
IIIPrompt Architecture

三層構造

プロンプトは3つの層を重ねて構築します。上の層ほど変更頻度が低く、 下の層ほど生成物ごとに変わります。

Layer 1: BASE_PROMPT (export, lib/prompt-codex.ts)
  └─ プロジェクト全体の DNA。色・様式・禁則・メタファー変換表。
     変更は全バッチに波及するため慎重に。配信は prompt-blocks registry
     (getPromptBlock('sheet.base_prompt')) 経由。[BASE_TONMANA] は
     TEMPLATES 内の穴埋めトークン (export ではない)。

Layer 2: Subject Meta
  └─ 生成対象ごとのメタデータ (slug / kind / summary / scene)。
     SUPPLEMENT_ITEMS[] に列挙。

Layer 3: CHARACTER_CANON
  └─ 参照キャラの profile.md 全文を inline 注入。
     これによりキャラ外見の一貫性を担保する。

Canon 注入の実装

lib/supplement-prompt.tsbuildSupplementPrompt() が SUPPLEMENT_REF_CHARS マップ (#cm-item) を参照し、 対象 item に紐づくキャラの content/characters/<slug>.md 全文を 読んでプロンプト末尾に埋め込みます。

// 本文ブロックは getPromptBlock registry (lib/prompt-blocks.ts) 経由で読む
export function buildSupplementPrompt(item: SupplementItem): string {
  const refs = SUPPLEMENT_REF_CHARS[item.slug] ?? [];
  const refBlock = refs.map((slug) => {
    const md = readFileSync(`content/characters/${slug}.md`, "utf-8");
    // canon ヘッダは "### Character canon: <ja> (<en>) — slug:<slug>" 形式
    return `### Character canon: ... — slug:${slug}\n${md}`;
  }).join("\n\n");

  return [
    `# Tonmana base\n` + getPromptBlock("sheet.base_prompt"),  // = prompt-codex BASE_PROMPT 系
    `# Target\nslug: ${item.slug}\nkind: ${item.kind}\n${item.summary}`,
    `# Embedded character canon\n` + refBlock,
    `# Layout requirements\n` + getPromptBlock(`supplement.kind_layout.${item.kind}`),
    getPromptBlock("supplement.trail"),
  ].join("\n\n");
}

種別レイアウト (KIND_LAYOUT)

生成物の種別(item / character / background)ごとに構図指示を切り替えます。 本文 SoT は lib/prompt-blocks.tsgetPromptBlock('supplement.kind_layout.<kind>') registry (2026-06-10 に SoT 統合)。lib/supplement-prompt.ts は registry から re-export するだけ、lib/prompt-codex.ts は本文を持たない。character に chibi は禁則 (BASE_PROMPT / AVOID で排除) なので層に chibi は入らない。

// getPromptBlock('supplement.kind_layout.character')
character:
  1) large central full-body illustration;
  2) front / side / back turnaround row;
  3) 4-5 action pose thumbnails (labelled in Japanese);
  4) 3-5 equipment/ability close-ups with annotations;
  5) personality / role text box (JP+EN sub);
  6) story-position diagram;
  7) color palette swatches.
  // chibi は無い (禁則)
IVGeneration Pipeline

生成前確認フロー

バッチ実行前に必ずユーザー確認を挟む。1枚・1本でもこの手順を省略しない。 確認フォーマットは 序 — 生成確認ルール を参照。

STEP 0: 種別を宣言する
  → 絵コンテカットPNG / シーンボード / 映像 のどれか
  → 解像度・品質・スクリプトが種別で決まる(序 #gen-confirm 参照)
  ↓
STEP 1: JSONL (またはリクエストリスト) を構築
  ↓
STEP 2: 以下を表形式で提示してユーザー承認を待つ
  - 種別 / id / サイズ / 品質 / 内容 (画像)
  - id / モデル / 長さ / 内容        (映像)
  - 合計枚数 / 推定コスト
  ↓ (承認後のみ)
STEP 3: バッチ実行
  カット   : node site/scripts/gen.mjs <chId> --go
             (内部 python は --concurrency 10 --quality high --size 2048x1152 を自動付与)
  補足シート: python -m src.openai_batch_with_refs <jsonl> --concurrency 8
  映像     : /storyboard UI コピー → Higgsfield MCP generate_video
  ※ raw openai_batch 直焼きは禁止 (format anchor が乗らない)
  ※ gpt-image-2 は input_fidelity 未対応 (2026-05-25 API 400)。忠実度は
    プロンプト文言 (STRICTLY MATCH / PER-IMAGE ROLE MANIFEST) で担保
  ↓
STEP 4: 結果を out/<timestamp>/ に保存
STEP 5: npm run sync → public/ に反映 → /review-items で判定

Windows 環境での実行時は PYTHONIOENCODING=utf-8 を設定してから実行する。 設定しないと UTF-8 文字 (↳ 等) で cp932 エラーが発生する。

$env:PYTHONIOENCODING = "utf-8"
cd C:\Users\akihi\26mv
python -m src.openai_batch_with_refs out/_supplement_with_refs.jsonl --concurrency 8

JSONL バッチ設計

大量生成は JSONL ファイルに1行1リクエストで記述し、 Python スクリプトが並列で OpenAI API を叩きます。--from=N フラグで N 番目以降のアイテムのみを書き出せます。

{
  "slug": "pact_seal",
  "prompt": "<buildSupplementPrompt の出力>",
  "size": "1536x1024",
  "quality": "high",
  "output_format": "png",
  "reference_images": ["public/sheets/haniwa_boy.jpg"]
}
# 全件書き出し (format anchor + style anchor を reference_images に添付)
node site/scripts/dump-supplement-prompts-with-refs.mjs

# 出力: out/_supplement_with_refs.jsonl

gpt-image-2input_fidelity を未サポート (2026-05-25 確認: API 400)。fidelity 引数は openai_batch_with_refs の DEFAULT として残るがimages.edit call には乗らない。reference 忠実度はプロンプトのSTRICTLY MATCH 文言と PER-IMAGE ROLE MANIFEST で担保する。

スタイル錨(Style Anchor)

2系統あるので混同しない。(A) 補足/シート系 の anchor SoT は content/judgments.jsonanchor: true フラグ(旧ハードコード配列は撤去済み。lib/confirmed.tsCONFIRMED_CHARS は overlay を同期読みする後方互換シム)。 anchor キャラの sheet 画像を、以降の全補足バッチに reference_images として添付します。

(B) カット系 の style anchor は別物。storyboard-masters.ts の master 階層 (cut.master_override > scene.scene_master >chapter.chapter_master > 章最初の base cut c1-s1-1、動的chapterAnchor が chapter_master を override) で 1枚を解決し、scene-reference-roles.ts の PER-IMAGE ROLE MANIFEST で役割を明示する。 詳細は VIII — 品質ガード

// SoT: content/judgments.json — { "<uid>": { decision, note, anchor?: true } }
// lib/confirmed.ts は overlay mirror から anchor:true の slug 集合を導出するシム
export const CONFIRMED_CHARS: string[] = Array.from(readOverlayMirror().anchor);

// server からの判定取得は lib/judgments-blob.ts::getJudgmentsBySlug() (slug キー)
// anchor の追加/削除は /review-items または content/judgments.json で行う
// scripts/dump-supplement-prompts-with-refs.mts が anchor キャラの sheet 画像を
// 自動収集 → JSONL の reference_images に追加

API 設定とコスト試算

プリセットは lib/api-presets.ts から live 表示 (size / quality は config/generation-params.json の単一 SoT から導出)。

プリセット名sizequality用途想定コスト/枚
storyboard_cut2048x1152high🎬 絵コンテ cut (章バッチ)~$0.011 / 枚
char_high1536x1024high👤 キャラクターシート$0.40 / 枚
item_high1536x1024high🛡️ アイテムシート$0.40 / 枚
location_high1536x1024high🏞️ ロケーションシート$0.40 / 枚
sheet_regen1536x1024high♻️ キャラシート再生成$0.40 / 枚
turnaround1536x1024high📐 三面図 (正面/側面/背面)$0.40 / 枚

※ gpt-image-2 の料金は変動します。OpenAI ダッシュボードで最新単価を確認してください。

VJikonte System

データ構造

字コンテは3階層の TypeScript 型で定義される。 正本ファイルは site/lib/storyboard-jikonte.ts

// 階層1: Chapter
interface JikonteChapter {
  id:              string;   // "ch01"
  chapter_no:      number;   // 1–16
  chapter_label:   string;   // "第1章·ハニワくん出土"
  location:        string;
  time_of_day:     string;
  characters:      string[]; // slug[]
  scenes:          JikonteScene[];
  chapter_master?: string;   // 章単位の style anchor (cut slug)
}

// 階層2: Scene
interface JikonteScene {
  scene_id:           string;       // "ch01_sc01"
  scene_no:           number;
  scene_label:        string;
  situation:          string;       // 観客に見えない因果・感情
  lighting:           string;
  props:              string;
  refs:               JikonteRef[]; // 参照画像
  cuts:               JikonteCut[];
  // ── 任意フィールド ──
  scene_transition?:  unknown;      // シーン境界の遷移技法 (resolveSceneTransition で解決)
  combat?:            boolean;      // true で cut 動画既定 = Battle Bridge
  scene_master?:      string;       // シーン単位の style anchor (cut slug)
  scene_video?:       unknown;      // scene 丸ごと長尺の first/last 等
  seedance_sequence?: unknown;      // Seedance Pro シーケンス overlay
}

// 参照画像 (三層リファレンス)
interface JikonteRef {
  slug:  string;
  kind:  "character" | "item" | "background" | "location";
  label: string;
  // path フィールドは無い。public パスは refImagePath(ref) で導出する
}

// 階層3: Cut
interface JikonteCut {
  n:                 string;  // "c1-s1-1" 形式 (c<ch>-s<scene>-<cut><suffix>。chapter→scene→cut 順。グローバル連番は廃止)
  size:              string;  // 推奨語彙 LS|WS|MS|MCU|CU|ECU|INSERT (自由記述)
  move:              string;  // 推奨語彙 FIX|DOLLY-IN|PAN-L|CRANE... (自由記述。例 "DOLLY-IN 高度から降下")
  angle:             string;  // 推奨語彙 BIRD|HI|EYE|LO|DUTCH (自由記述)
  sec:               string;  // "0:03"
  dialogue:          string | null;
  dialogue_speaker?: string;  // 任意
  composition:       string;  // カメラが何をどう切り取るか (2–5文)
  // ── 生成挙動を支配する任意フィールド ──
  orientation?:      "front" | "back";  // back で背面プロンプト + sheet_back.jpg を自動注入
  master_override?:  string;            // この cut だけ style anchor を上書き (極稀)
  reveal_namecard?:  {                  // 墨絵 namecard 1枚 (BEFORE/AFTER 2フレーム制は 2026-06-11 廃止)
    character_slug: string;
    display_name_ja: string;
    display_name_en: string;
    tagline_ja?: string;
    iconic_pose?: string;
  };
  cut_characters?:   string[];          // この cut の出演キャラ slug ホワイトリスト
  seedance?:         {                  // 二点キーフレーム長尺 (やられ描写等)
    last_cut: string;
    duration: number;
    intent?: string;
    beats?: string[];
  };
}

生成パイプライン

字コンテ TypeScript (storyboard-jikonte.ts + chapters/ch??.ts)
  ↓  node site/scripts/gen.mjs <chId> --go   (内部: dump-cuts.ts → cut-prompt-composer
                                              → openai_batch_with_refs → sync → webp → check)
PNG  → public/storyboard-cuts/<chId>/<slug>.png

命名ルール (cut-naming.ts cutToSlug):
  chId  = "ch01" / "ch02" ...
  slug  = cutToSlug(cut.n) (小文字化のみ)。cutToSlug("c1-s1-1") → "c1-s1-1"
          cut.n は c<ch>-s<scene>-<cut><suffix> 形式、scene-local 固定、グローバル連番は廃止

例: public/storyboard-cuts/ch01/c1-s1-1.png  ← Ch.1 シーン1カット1

設計ルール

フィールド書くべきこと書いてはいけないこと
situation観客の視点では見えない感情・状況の因果カット単位の映像記述 (それは composition)
lighting光源・色温度・入射方向・感情的効果「明るい」「暗い」の二択
props物語に意味を持つ具体的な物体名抽象的な「小物」のみ
sizeLS=全景 / WS=環境 / MS=腰上 / MCU=胸上 / CU=顔 / ECU=瞳・手 / INSERT=物ファジーな表現
composition「主体 + 前景 + 背景 + 光の向き」の絵の説明セリフや感情の説明 (それは situation)

朱 (vermilion) 発光の演出ルール: 各章に最低1カット「章内朱①②…」タグをつけて 朱発光シーンを記録する。ハニワの目の穴の光は常に朱。御札の光は金→朱の順。

Blob 管理

字コンテデータは zikonte/v1.json として Vercel Blob に保存する。 絵コンテ生成ステータスは storyboard/status-v1.json。 ページは export const dynamic = "force-dynamic" で毎リクエスト再取得。

// POST /api/storyboard/bulk-ng { approved_id }
// 1回の Blob read-modify-write で全アセットを ng に (approved_id のみ除外)
// N 回ループは禁止 (Blob 書き込みコスト増大)

const db = await readBlobJson("storyboard/status-v1.json");
for (const [id, asset] of Object.entries(db.assets)) {
  if (id !== approved_id) asset.status = "ng";
}
await writeBlobJson("storyboard/status-v1.json", db);
VIReview & Promote

判定 UI の構造

/review-items は補足資料の画像を並べ、OK / NG / 再生成を カードごとに操作できる判定 UI です。判定状態は slug をキーに管理します。

type Decision = "ok" | "ng" | "pending";

interface JudgmentRecord {
  decision:   Decision;
  note?:      string;     // NG 理由 or OK ポイント
  updated_at: string;     // ISO timestamp
}

interface JudgmentsStore {
  version:    "v1";
  updated_at: string;
  items:      Record<string, JudgmentRecord>;
}

判定の永続化(Blob dual write)

判定は localStorage に即書きし、非同期で Vercel Blob にも送信します。BLOB_READ_WRITE_TOKEN 未設定時は localStorage のみで動作し、 API が 503 を返しても UI は壊れません。

export async function saveJudgment(slug: string, record: JudgmentRecord) {
  // 1. localStorage に即書き (offline 対応)
  const local = loadAll();
  local[slug] = record;
  localStorage.setItem(STORAGE_KEY, JSON.stringify(local));

  // 2. 非同期で Blob に push (失敗しても UI は壊れない)
  await fetch("/api/judgments", {
    method: "POST",
    body: JSON.stringify({ slug, ...record }),
  }).catch(() => {});
}

採用・没フロー

【採用 (OK → canonical)】
POST /api/promote { slug, base64png, target: "items" | "sheets" }
  → site/public/items/<slug>.png を上書き
  → 旧版を site/public/items/_versions/<slug>_<timestamp>.png に退避
  → site/content/items/<slug>.md を生成/更新 (canonical_status: promoted)

【没 (NG)】
  1. lib/rejected.ts の REJECTED_CHARS 配列に slug を追加
  2. node scripts/move-rejected-to-ng.mjs を実行
     → site/public/sheets/<slug>.jpg を _ng/ に 1/4 圧縮で退避
  3. /characters グリッドの「没・廃案図鑑」セクションに小サムネで表示

canonical 三画面同期パターン

/characters / /items / /locations の3ページは 同じパターンで Blob データを参照する。

// ページ先頭に必須
export const dynamic = "force-dynamic";

const [all, judgmentsDoc, blobMap] = await Promise.all([
  getAllXxx(),         // references/ 由来の canonical エントリ
  getJudgments(),     // judgments/items-v1.json → ok/ng 判定
  getCanonicalMap(),  // canonical/promotions-v1.json → promote 済みの image_url
]);

const okSlugs       = new Set(Object.entries(judgmentsDoc.items)
  .filter(([, v]) => v.decision === "ok").map(([k]) => k));
const promotedSlugs = new Set(Object.keys(blobMap.items));

// 3 セクション表示:
// 1. references/ 由来の正本  (canonical)
// 2. Blob 昇格済みの補足     (promotedSlugs)
// 3. OK 判定済み・未昇格     (okSlugs - promotedSlugs)
VIIGenerations Page

設計思想 — 全生成物の透明な記録

/generations は「生成ログ」であり「スタイル選択UI」である。AI画像生成プロジェクトでは大量の画像が生まれ、どれが良くてどれが没かが把握できなくなる。 このページはその問題を解決するために、全生成物を以下の情報とともにリストする:

  • 生成日時・使用エンドポイント・サイズ・クオリティ
  • 使用したキャラシート (ref_slugs) とロケーション画像
  • スタイルアンカーの有無と asset_id
  • プロンプト全文 (折りたたみ)
  • approved / ng / generated のステータス管理

Blob スキーマ

全アセットは Vercel Blob の1つの JSON ファイルで管理する。 ファイルパス: storyboard/status-v1.json

{
  "version": "v1",
  "updated_at": "2026-05-20T...",
  "assets": {
    "<asset_id>": {
      "status":       "generated" | "approved" | "ng" | "pending",
      "image_url":    "https://...",
      "generated_at": "ISO 8601",

      // 生成コンテキスト (再現性のために記録)
      "prompt_text":        "...",
      "ref_slugs":          ["haniwa_boy"],
      "ref_image_urls":     ["/sheets/..."],
      "location_image_url": "/locations/...",
      "style_ref_url":      "https://...",
      "style_ref_asset_id": "ch01_...",

      // 生成パラメータ
      "size":         "1536x864",
      "quality":      "low" | "high",
      "api_endpoint": "/v1/images/edits" | "/v1/images/generations",

      // メタデータ
      "asset_label":   "Ch.1 再開発地区 — MASTER",
      "asset_type":    "master" | "sheet",
      "scene_id":      "ch01_sc01",
      "chapter_no":    1,
      "director_note": "...",
      "note":          "..."
    }
  },
  "proposals": {
    "<scene_id>__<proposal_id>": true
  }
}

read-modify-write パターン: アセットの追加・更新は常に 「全体読み込み → 1件更新 → 全体書き戻し」で行う。

API 設計

エンドポイントメソッド役割
/api/storyboard/all-assetsGET全アセット一覧を返す。30秒ポーリングで自動更新
/api/storyboard/generate削除済 (2026-06-10、旧 PV01 master/board 生成 route)。下の regenerate-cut が現役
/api/storyboard/regenerate-cutPOSTcut 1 枚を composer 経由で再生成 (style anchor / scene-roles / zikonte の動的 SoT 注入済)
/api/storyboard/asset-statusPOST1件の status を approved/ng/generated に変更
/api/storyboard/bulk-ngPOST1件を approved にし他を全て ng に (1回のBlobアクセス)
/api/judgmentsGET/POST/DELETEsupplement アイテムの OK/NG 判定
/api/judgments/syncPOST全判定を一括書き込み

外部ツールでの実装ガイド

このシステムは Next.js/Vercel に依存しているが、概念は任意のスタックで実装できる。 以下は Python + ローカルファイルでこの /generations の仕組みを再現するガイド。

import base64, json, time
from pathlib import Path

BLOB_PATH = Path("./db/status-v1.json")

def load_db() -> dict:
    if BLOB_PATH.exists():
        return json.loads(BLOB_PATH.read_text())
    return {"version": "v1", "updated_at": "", "assets": {}, "proposals": {}}

def save_db(db: dict):
    db["updated_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
    BLOB_PATH.write_text(json.dumps(db, ensure_ascii=False, indent=2))

def generate_and_save(asset_id: str, prompt: str, ref_images: list[bytes]) -> str:
    import requests
    files = [("image[]", (f"ref_{i}.png", b, "image/png"))
             for i, b in enumerate(ref_images)]
    resp = requests.post(
        "https://api.openai.com/v1/images/edits",
        headers={"Authorization": f"Bearer {OPENAI_API_KEY}"},
        # 注: size/quality は外部移植の縮小デモ値。実値は
        # config/generation-params.json 由来 (cut=2048x1152/high, supplement=1536x1024/high)
        data={"model": "gpt-image-2", "prompt": prompt,
              "size": "1536x864", "quality": "low", "n": "1"},
        files=files,
    )
    b64 = resp.json()["data"][0]["b64_json"]
    out_path = Path(f"./generated/{asset_id}.png")
    out_path.write_bytes(base64.b64decode(b64))

    db = load_db()
    db["assets"][asset_id] = {
        "status": "generated",
        "image_url": str(out_path),
        "generated_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
    }
    save_db(db)
    return str(out_path)

ポータビリティの核心: ストレージは Vercel Blob でも S3 でもローカルファイルでも構わない。 UIは Next.js でも Python Streamlit でも CLI でも構わない。 gpt-image-2 の /edits エンドポイントと、適切なプロンプト構造が本質。

VIIIStoryboard Workflow

生成思想 — なぜこの手順か

絵コンテ生成の目的は「監督の頭の中にある画を、AIが1発で出力する」ことではない。 正しい目的は「監督が OK を出せる範囲の画を高速で量産し、スタイルを収束させる」こと。 3段階で確定を進める。

PHASE 1: スタイル確定 (Style Lock)
  1. マスターショットを複数バリエーション生成 (v1, v2, v3 ...)
  2. /generations でビジュアルを確認
  3. 「これだ」と思った1枚を ★ Style Anchor に設定
  結果: 以降の全生成がこのスタイルをリファレンスとして引き継ぐ

PHASE 2: シーン展開 (Scene Expansion)
  1. スタイルアンカー固定のまま、各章のマスターショットを生成
  2. OK/NG を /generations でチェック → approved に昇格
  3. マスターショットが確定した章から絵コンテシートを生成

PHASE 3: 正本化 (Canonicalization)
  1. /review-items で採用画像を promote → public/ に配置
  2. git push → Vercel 本番に反映

ビジュアル DNA — スタイルの言語化

生成AIはプロンプトの「固有名詞」に強く反応する。 「かっこいいアニメ」より「JJK 渋谷弧島×Chainsaw Man OP×Dandadan」と書く方が精度が高い。

参照作品スタジオ抽出する要素
呪術廻戦 渋谷弧島MAPPA 2023360°高速カメラ・太い荒い主線・インク/漫画のラフさ
チェンソーマンMAPPA 2022実写カメラ言語・粘りのある肉体重量・gritty 質感
ダンダダンScience SARU 2024超広角歪みレンズ・密度マックスの画面・「最速のアニメ」感
サイバーパンク エッジランナーズTrigger 2022ネオン影・極太輪郭・ドラッグ的な速さ
天国大魔境Production I.G. 2023広角レンズ意識・ミニマル線・肉体の重力
シン・エヴァンゲリオンkhara 2021実写カメラをアニメに輸入・Eva スケール対比
モブサイコ 100 IIIBones 2022荒いハッチング影・背景が生き物のように歪む
# VISUAL STYLE — [PROJECT NAME]
# MANDATORY: This is a FINISHED production key frame. NOT a sketch.

## Style DNA: [Anime_A] × [Anime_B] × [Anime_C]
[STUDIO_A] [YEAR] — [what to extract]
[STUDIO_B] [YEAR] — [what to extract]

## Line Art
- OUTER SILHOUETTE: THICK, HEAVY. [8–14px] brushstroke weight.
- INTERIOR STRUCTURE: Medium [3–6px].
- TECHNIQUE: Pressure variation. Taper at line ends. Never uniform.

## Shadow System
- PARALLEL HATCHING at 45°. NOT smooth gradient.
- SOLID BLACK for absolute darks.

## FORBIDDEN
[List what destroys your aesthetic]

カメラワーク言語

gpt-image-2 は「カメラ」の概念を持たないが、実写映画の用語で指示すると劇的に精度が上がる。 「かっこいい構図」のような抽象的な指示は避け、常にカメラマンへの指示として書く。

カメラ手法プロンプトキーワード効果
超広角歪みultra-wide lens 14mm, straight lines bow at edgesダンダダン/JJK的「画面の中に入る」感
極端なローアングルcamera at ground level, 30° upward tiltエヴァ的スケール感。主人公を神話化
ダッチアングルDutch angle 18°, right side low, commit fully心理的不安定・混乱の予感
前景オクルージョンlarge dark element in IMMEDIATE foreground partially blocking frame edge空間の奥行きと現実感
三分割奥行きdepth: near (dark machinery) → mid (character, lit) → far (city skyline)前景/中景/遠景で3層の情報密度

三層リファレンス構造

生成 API に渡す参照画像を3層に分類し、それぞれの役割を明確に分ける。 コンテンツモデルの定義は #cm-location / #cm-character を参照。

内容役割
層1: キャラシートreferences/characters/{slug}/refs/sheet.jpgキャラの canonical 外見。服装・武器・比率・色を画像で伝える
層2: ロケーションsite/public/locations/{slug}.png舞台の雰囲気・スケール・色調。場の空気感を継承させる
層3: スタイルアンカーlocalStorage に保存された Blob URL確定したビジュアルスタイルを次の生成に引き継ぐ

スタイルアンカー確定プロセス

STEP 1: 同じシーンを3〜5バリエーション生成 (スタイルアンカーなし)
STEP 2: 「これだ」の1枚を選ぶ
  判定基準:
    ① 線質 — 手描き感・筆圧変化・テーパー
    ② 影の質 — ハッチング密度・ベタ黒の使い方
    ③ 色の深度 — フラットでなく情報量がある
    ④ カメラ言語 — 狙ったアングルが出ているか
    ⑤ キャラ再現度 — シートとの一致
STEP 3: ★ Style Anchor ボタンを押す → localStorage に保存
STEP 4: 以降の全生成でアンカーが自動適用される

プロンプト構築の順序

[1] ANIM_STYLE ヘッダ         ← シリーズ DNA (全体の30-40%)
[2] PROJECT AESTHETIC         ← aesthetic.md から補足
[3] REFERENCE IMAGES          ← 添付画像の役割を宣言
    "CHARACTER SHEETS (haniwa_boy): match every detail exactly"
    "LOCATION IMAGE: inherit atmosphere and scale"
    "STYLE ANCHOR: match this line art style and color depth"
[4] LOCATION BLOCK            ← location_profile.md の内容
[5] SCENE SPECIFICATION       ← 章・シーン・Duration・Director's Shot Note
[6] APPROVED PROPOSALS        ← Director が確定した設定
[7] CHARACTER CANON           ← CHAR_SHEET_ANCHORS (シートあり) or 全文記述
[8] DIRECTOR'S NOTE           ← このリクエスト固有の追加指示 (省略可)
[9] RENDER TASK               ← 最後に「何を生成するか」を明示

絵コンテシート の作り方(廃止 2026-06-11)

廃止: シーン単位の絵コンテシート(シーンボード)は生成・表示・要求とも全廃。 字コンテ + カット画像 + 動画が正。以下は歴史記録として残す。

要素仕様
グリッド4列 × 3行 = 最大12パネル
カメラリズム引き(Wide)→寄り(CU)→衝撃(Dutch angle)→余韻の4拍子
台詞縦書き日本語・白地・黒枠の吹き出し。YAML の dialogue[] から注入
IVSスタンプ右下コーナーに「IVS ∞ KYOTO」朱色スタンプ
  • 禁止: オノマトペ (ザシュ/ドン/ガッ等) — 通常パネルでは絶対NG
  • 禁止: 集中線 (speed lines) を主役エレメントとして使用
  • 例外: 新キャラ初登場パネルのみ — 大きな墨文字のキャラ名 + シルエット + 漆黒背景

Director Note — いつ・何を書くか

書くべきこと書かないこと
構図のバリエーション指定 (「ローアングルで」「後姿で」)スタイル全般 (ANIM_STYLEで済んでいる)
今回だけの特別な演出 (「ハニワくんが泥まみれで」)キャラの外見全般 (シートが担う)
NG 理由からの修正指示 (「前回は刀が紐になったのでchainと書け」)場所の説明 (location_profileで済んでいる)
照明の強調 (「月明かりをより強く。顔に朱のリムライト」)感情の説明 (ポーズ・構図で表現する)

生成品質ガード(汎用パターン)

カット画像を量産すると ①章ごとにスタイルがドリフトする ②シーン固有のスタイルを読まない ③後ろ姿が前面化する の3事故が起きやすい。 これらは「プロンプトに書けば直る」問題ではなく、参照画像の構造とパイプラインの強制で防ぐ。他プロジェクトにも移植できる汎用パターン。 詳細ルールの正典は storyboard-gen-spec.md §4–§8、自動検査は site/scripts/check-consistency.mts

① Style Anchor 強制(ドリフト防止)

全カットの reference_images先頭は必ず style anchor 画像とし、マスター階層で解決する。

cut.master_override        ← 個別上書き(極稀)
scene.scene_master          ← シーン単位の style anchor
chapter.chapter_master      ← 章単位の style anchor
defaultChapterMaster        ← fallback: 章最初の base cut (cut.n が
                              c<ch>-s<scene>-<cut> suffix無し、現行 = c1-s1-1) の slug。
                              動的 chapterAnchor があればそれが最優先
  • fail-loud: 解決できる anchor が1枚も無いと char sheet だけが style 源になりドリフトする。composer は styleAnchorMissing 警告を出し、整合チェッカーが該当 cut を検出(W6)。無言で空にしない。
  • 新規章(cut 0枚)の 2フェーズ生成: ①章の c1-s1-1 を STYLE_BASE フルで先に1枚生成 → ②それを chapter_master に当てて残りを生成。または既存の curated マスターを cross-chapter で流用(章を跨いだ master チェーン)。
  • 1st ref は STYLE のみ継承: 構図・アングル・設定は SHOT 仕様が支配。anchor からは色・線・質感・密度だけを写し、構図は複製しない。

② Orientation 制御(前後の描き分け)

キャラの向きを機械可読にし、背面は専用プロンプト + 専用参照で前面複製を防ぐ。

  • orientation フィールド"front" | "back")を cut に持たせる。未指定なら composition の背面語(背中 / 背面 / 後ろ姿 / rear view)を自動検出。
  • 背面判定時に rear view, back of head, no face + キャラ別ルール(Haniwa = 無孔の dome 後頭部 / Dogu = 甲背板 + sash 結び目、同心円目を背面に出さない)を強制注入。
  • 背面 turnaround sheet(sheet_back.jpgを参照に追加。チェッカーが背面 cut の back sheet 欠落を検出(W7)。

③ 動画スタイルの単一ソース

動画プロンプトの style header を複数定義すると「12fps が入ったり入らなかったり」章ごとにブレる。共通コア定数CORE_ANIM_STYLE: hand-drawn 2D cel / 12fps limited animation / no CG・tween・interp)を1つ持ち、cut 用・scene 用の両ヘッダーがそれを参照する。定数なので全チャプターへ一括で揃う。

IXTODO System

スキーマ設計

active TODO は TypeScript 配列で管理し、done になったものは即座に Markdown ファイルにアーカイブします。「完了済みを配列に残さない」が鉄則です。

export interface TodoItem {
  id:      string;   // "slug-like-id"
  title:   string;
  status:  "in_progress" | "pending" | "future";
  owner:   "claude" | "user" | "system";
  detail?: string;
  refs?:   string[]; // ファイルパス / issue URL
}

export const PROJECT_TODOS: TodoItem[] = [
  // ← done になったものは削除してアーカイブへ
];

アーカイブ運用

# 1. アーカイブ MD を作成
site/content/completed-tasks/<YYYY-MM-DD>__<id>.md

---
id: <short-slug>
title: <タイトル>
owner: claude | user | system
completed_at: YYYY-MM-DD
tags: [tag1, tag2]
---
何をしたか・どこを変えたか

# 2. project-todos.ts から該当 entry を削除

# 3. commit message に以下を含める
"PROJECT_TODOS から <id> を archive (content/completed-tasks/<file>)"
XDeploy

環境変数

変数名用途設定場所必須
OPENAI_API_KEYgpt-image-2 画像生成site/.env.local / Vercel必須
BLOB_READ_WRITE_TOKEN判定の Blob 永続化Vercel Dashboard (自動バインド)任意*

* 未設定時は localStorage fallback で動作。本番でブラウザ間共有が必要な場合のみ設定。

OPENAI_API_KEY=sk-...
BLOB_READ_WRITE_TOKEN=vercel_blob_...   # vercel env pull で取得

Vercel 設定

{
  "buildCommand": "cd site && npm run build",
  "outputDirectory": "site/.next",
  "installCommand": "cd site && npm install"
}

# または Vercel Dashboard > Project Settings > Build & Output
# Root Directory: site
XIPorting Guide

汎用部分 vs プロジェクト固有部分

分類ファイル / パス説明
汎用scripts/sync-refs.mjsreferences/ → content/ / public/ の同期ロジック
汎用lib/judgments-blob.tsBlob + localStorage dual write
汎用lib/judgments-client.tsクライアント判定ヘルパー
汎用lib/project-todos.tsactive TODO スキーマ
汎用app/api/judgments/判定 CRUD API
汎用app/api/regenerate/gpt-image-2 再生成 API
汎用app/api/promote/画像の canonical 昇格 API
汎用app/api/storyboard/絵コンテ生成 / Blob 管理 API 群
汎用lib/storyboard-jikonte.ts (型定義)JikonteChapter / Scene / Cut 型
固有lib/prompt-codex.tsBASE_PROMPT (export) / SUPPLEMENT_ITEMS (全書き換え)。配信は prompt-blocks registry
固有lib/supplement-references.tsitem → 参照キャラ マップ
固有lib/supplement-items.tsSUPPLEMENT_ITEMS 配列 + SUPPLEMENT_TOTAL
固有lib/chapters/ch01..ch15.ts字コンテ全文 (各章 default export)。storyboard-jikonte.ts は型 + index のみ
固有references/ 配下全てキャラ・設定・画像のテキスト正本
固有lib/confirmed.ts / rejected.tsstyle anchor / 没キャラリスト
固有prompts/world_supplement_v1.yaml補足資料マニフェスト (全書き換え)

移植手順

[ ] 1. リポジトリを fork または template として複製
[ ] 2. references/ 配下を全削除 → 新プロジェクトの設定資料で再構築
[ ] 3. lib/prompt-codex.ts の export const BASE_PROMPT を新プロジェクト用に書き換え
       (prompt-blocks registry / video STYLE_HEADER 定数も固有として併せて見直す)
[ ] 4. lib/supplement-items.ts を新アイテム構成に書き換え
[ ] 5. lib/supplement-references.ts を新 item/char 構成に合わせて書き換え
[ ] 6. prompts/world_supplement_v1.yaml を新アイテムで再構築
[ ] 7. lib/chapters/ch01..ch15.ts を新章構成で書き換え
       (章を増減する時は ch??.ts 追加 + storyboard-jikonte.ts の import & JIKONTE_CHAPTERS map 両方更新)
[ ] 8. lib/confirmed.ts / rejected.ts を空配列でリセット
[ ] 9. lib/project-todos.ts を空配列でリセット
[ ] 10. site/content/ と site/public/sheets|items|storyboard/ を削除
      (npm run sync で再生成される)
[ ] 11. site/.env.local に OPENAI_API_KEY を設定
[ ] 12. npm run dev で動作確認 (port 3300)
[ ] 13. 字コンテ確定後に cut 画像を再生成:
       node site/scripts/gen.mjs ch01      (DRY 確認)
       node site/scripts/gen.mjs ch01 --go (実生成。ch02..ch15 反復)

# 汎用部分 (scripts / lib の型定義 / app/api) はそのまま流用できる

このプロジェクトの設定一覧

移植時に「このプロジェクトでは何に設定しているか」の参照。固有 設定の具体値。

項目
プロジェクト名サムライカンフーくん / IVS 2026 KYOTO
GitHubAsaoman/26mv
Vercel (本番)26mv-theta.vercel.app
Vercel (preview)26mv-event-projects.vercel.app (401 保護)
dev port3300
章数15章 (live: lib/chapter-refs)
補足資料 (アイテム)56件 (live: SUPPLEMENT_ITEMS.length)
キャラクター34体 (live: references/characters/)
補足資料マニフェストprompts/world_supplement_v1.yaml
画像 APIOpenAI gpt-image-2
画像サイズ (補足シート)1536x1024 / quality: high (config/generation-params.json)
画像サイズ (絵コンテ cut)2048x1152 / quality: high (config/generation-params.json)
映像 APIHiggsfield MCP 経由 Kling V3 (image-to-video, mode=pro, 主軸) / Seedance 2.0 (サブ)。Omni / multi-ref は廃止語彙 (kling-client.ts KlingModel union を正典に参照)
Blob: 字コンテzikonte/v1.json
Blob: 判定judgments/items-v1.json
Blob: 絵コンテ生成履歴storyboard/status-v1.json

ルート一覧

route内容
/Hero + 序章 + 役柄別キャラギャラリー
/story全16章の物語覚え書き(公式正本・絵コンテ/設定資料/世界観を統合した LP)
/storyboard絵コンテ (JikonteView)
/characters全キャラのグリッド (現状 34体)
/characters/[slug]キャラ詳細:シート + 生死簿 + 本文 + 進化線
/items重要アイテムと神殿類のギャラリー
/locations重要ロケーションギャラリー
/world世界観七章 + 美術指針
/manual召喚之書(プロンプト指南書)
/review-items56補足の OK/NG 判定 + 再生成
/generations絵コンテ生成履歴 + スタイル選択 UI
/docsこのページ
/docs/uiUI Design System Template
XIIReconcept Runbook

別コンセプトで再生成する — 差し替え点

この基盤は「別コンセプトのアニメ MV をワンプロンプト級で再生成する」ことを前提に設計されている。1箇所直すと全体に波及する「差し替え点」を優先度順に押さえれば、派生物は npm run syncgen.mjs が自動で作り直す。正典の優先順位はstoryboard-gen-spec.md > CLAUDE.md §15 > この /docs。矛盾時は上位を信じる。

差し替え点ファイル / パス波及先
シリーズ DNA / トンマナsite/lib/prompt-codex.tsexport const BASE_PROMPT (L13-49)全画像生成 (補足シート / キャラ sheet / cut)。buildSupplementPrompt・review.ts・sheet-regen・dump-* 全経路。配信は lib/prompt-blocks.ts registry (/prompt-blocks で Blob 編集)
キャラ正本 (SoT)references/characters/<slug>/{profile.md, refs/sheet.jpg}npm run synccontent/characters/*.md + public/sheets/*.jpg(+webp) へ一方向派生
アイテム/背景マニフェストrepo root prompts/world_supplement_v1.yaml + lib/supplement-items.ts + lib/supplement-references.ts補足シート生成。references 配下ではない
字コンテ (構図テキスト)site/lib/chapters/ch01.ts〜ch15.ts (15章, 各章 default export)cut 画像生成・動画ビルダー。storyboard-jikonte.ts は型 + index のみ。章増減 = ch??.ts 追加 + import/map 両方更新
絵コンテ yamlrepo root prompts/storyboard_pv01.yaml絵コンテ定義
style anchor / 没リストsite/lib/confirmed.ts (CONFIRMED_CHARS) / site/lib/rejected.ts (REJECTED_CHARS)補足バッチの reference_images。reconcept 時は空配列にリセット
生成パラメータconfig/generation-params.json (Node/Python 共読)補足 vs cut の size/quality/concurrency

派生物 (触らない・自動再生成)

以下は npm run sync 派生物。手で編集しても次の sync で巻き戻る。references/ が SoT。

  • site/content/ — references/ 由来の Markdown 派生
  • site/public/{sheets, items, storyboard, storyboard-cuts}/ — 配信画像 (webp twin 追従)
  • lib/seedance-clips.generated.ts / lib/scene-transitions.generated.ts — 自動生成 (手編集禁止)

最短コマンド列

テキスト/設定を上記「差し替え点」で編集した後、以下を順に実行する。

# 1. テキスト/設定を差し替え (上記「差し替え点」を編集)
#    references/characters/* / prompts/*.yaml / lib/prompt-codex.ts BASE_PROMPT
#    lib/supplement-items.ts / supplement-references.ts / lib/chapters/ch*.ts
#    lib/confirmed.ts / rejected.ts / project-todos.ts を新内容/空配列に

cd site && npm run sync          # references→content/public 同期 (predev/prebuild で自動)

# 2. 補足アイテム/背景シート生成 (正規経路: format anchor 同梱)
node site/scripts/dump-supplement-prompts-with-refs.mjs
python -m src.openai_batch_with_refs out/_supplement_with_refs.jsonl --label supplement_v1 --concurrency 8
cd site && npm run sync

# 3. 絵コンテ cut 画像生成 (1コマンド統合, 章ごと)
node site/scripts/gen.mjs ch01           # DRY: cut一覧+anchor健全性+概算費用→停止(確認)
node site/scripts/gen.mjs ch01 --go      # 実生成: dump→batch→sync→webp→check
#   ...ch02〜ch15 反復。bootstrap章(cut0枚)は chapter_master に既存master を当てるか c1-s1-1 先行1枚

# 4. 動画は Higgsfield MCP (Kling V3 i2v mode=pro 主軸 / Seedance 2.0 サブ)。/manual の正規プロンプト使用

画像生成の不変ルール・環境

  • 並列固定: gpt-image-2 は常に並列 (--concurrency 8, cut は cut_batch=10。1枚 60-180s)。--concurrency 1 禁止。
  • cut 画像: 2048×1152 / quality high 固定。テキスト/ラベル/cut番号/IVS印章/border を画像内に焼かない (CUT_IMAGE_SPEC)。
  • raw 直焼き禁止: raw openai_batch は format anchor が乗らない。必ず with_refs 経路。
  • reference_images 順序: [style master(1枚) → location → 前cut continuity → char sheets] (char sheets は最後)。この配列順 = PER-IMAGE ROLE MANIFEST の IMAGE N。
  • master 階層: cut.master_override > scene.scene_master > chapter.chapter_master > 章最初の base cut c1-s1-1
  • 禁則: photo-real/3D, chibi/moe, glossy fantasy, generic cyberpunk, loud branding/logo/text overlay。
環境
dev port3300 (next dev --port 3300)。確認は localhost:3300
API キーsite/.env.localOPENAI_API_KEY (親 .env から sync-env.mjs が同期)
Windows 実行PYTHONIOENCODING=utf-8 必須 (cp932 回避)。cut dump は USE_ZIKONTE_BLOB=1 (gen.mjs が自動付与)
公開26mv-theta.vercel.app (Root Directory=site)。main push=本番 auto-deploy (毎回明示許可制)
正典優先順位storyboard-gen-spec.md > CLAUDE.md §15 > /docs