目的と構造
このシステムは「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 + remark | Markdown 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 — 生成前確認フロー を参照。
生成前に「何を生成するか」を以下の表から選択・宣言する。種別によって解像度・品質・スクリプトが決まる。
| 種別 | 解像度 | quality | スクリプト |
|---|---|---|---|
| 絵コンテカット PNG | 2048×1152 | high | gen.mjs |
| シーンボード | — | — | 退役 (2026-06-10) — 専用スクリプトなし。歴史資産のみ |
| 映像 | — | — | /storyboard UI コピー + Higgsfield MCP |
【種別】絵コンテカット 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」は廃止語彙
概念マップ
このシステムが扱うコンテンツは以下の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 / en | string | 表示名 |
| role | enum | protagonist / rival / guardian / trial_enemy / gauntlet_enemy / mid_boss / enemy / final_boss |
| stage | "N/M" | 進化段階 (例: "1/3") |
| evolution_next | slug? | 次形態への参照 |
| final_form | slug? | 最終形態への参照 |
| threat_level / story_role | string? | 脅威度・物語上の役割 |
アイテム / 補足資料
アイテム (Item) は /items に出る curated エンティティ。 正本は references/items/<slug>/profile.md + refs/sheet.jpg(sync で content/items/<slug>.md + public/items/<slug>.png に派生)。 Item の kind は key_item | mecha の2値 (lib/items.ts ItemMeta)。 章→item の対応は lib/chapter-refs.ts の CHAPTER_ITEMS_MAP。
これとは別レイヤに SupplementItem (lib/supplement-items.ts) があり、/review-items 用の没マニフェスト。こちらの kind はcharacter | 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.ts のSUPPLEMENT_REF_CHARS マップで「引用すべきキャラ slug[]」と紐づく。 これが Canon 注入の参照源になる。→ III — Canon 注入
世界観
世界観 (World) はストーリーの背景設定全体。地理・歴史・社会構造・ 勢力関係・ルール・用語集を含む。 正本は references/style/ivs2026_aesthetic.md とsite/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)
正本の所在(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-env → sync-refs → sync-storyboard →sync-supplement → generate-board-manifest)。sync-refs.mjs が references/ を読み、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)三層構造
プロンプトは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.ts の buildSupplementPrompt() が 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.ts の getPromptBlock('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 は無い (禁則)生成前確認フロー
バッチ実行前に必ずユーザー確認を挟む。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-2 は input_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.json のanchor: true フラグ(旧ハードコード配列は撤去済み。lib/confirmed.ts のCONFIRMED_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 から導出)。
| プリセット名 | size | quality | 用途 | 想定コスト/枚 |
|---|---|---|---|---|
storyboard_cut | 2048x1152 | high | 🎬 絵コンテ cut (章バッチ) | ~$0.011 / 枚 |
char_high | 1536x1024 | high | 👤 キャラクターシート | $0.40 / 枚 |
item_high | 1536x1024 | high | 🛡️ アイテムシート | $0.40 / 枚 |
location_high | 1536x1024 | high | 🏞️ ロケーションシート | $0.40 / 枚 |
sheet_regen | 1536x1024 | high | ♻️ キャラシート再生成 | $0.40 / 枚 |
turnaround | 1536x1024 | high | 📐 三面図 (正面/側面/背面) | $0.40 / 枚 |
※ gpt-image-2 の料金は変動します。OpenAI ダッシュボードで最新単価を確認してください。
データ構造
字コンテは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 | 物語に意味を持つ具体的な物体名 | 抽象的な「小物」のみ |
size | LS=全景 / 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);判定 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)
設計思想 — 全生成物の透明な記録
/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-assets | GET | 全アセット一覧を返す。30秒ポーリングで自動更新 |
/api/storyboard/generate | — | 削除済 (2026-06-10、旧 PV01 master/board 生成 route)。下の regenerate-cut が現役 |
/api/storyboard/regenerate-cut | POST | cut 1 枚を composer 経由で再生成 (style anchor / scene-roles / zikonte の動的 SoT 注入済) |
/api/storyboard/asset-status | POST | 1件の status を approved/ng/generated に変更 |
/api/storyboard/bulk-ng | POST | 1件を approved にし他を全て ng に (1回のBlobアクセス) |
/api/judgments | GET/POST/DELETE | supplement アイテムの OK/NG 判定 |
/api/judgments/sync | POST | 全判定を一括書き込み |
外部ツールでの実装ガイド
このシステムは 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 エンドポイントと、適切なプロンプト構造が本質。
生成思想 — なぜこの手順か
絵コンテ生成の目的は「監督の頭の中にある画を、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 2023 | 360°高速カメラ・太い荒い主線・インク/漫画のラフさ |
| チェンソーマン | MAPPA 2022 | 実写カメラ言語・粘りのある肉体重量・gritty 質感 |
| ダンダダン | Science SARU 2024 | 超広角歪みレンズ・密度マックスの画面・「最速のアニメ」感 |
| サイバーパンク エッジランナーズ | Trigger 2022 | ネオン影・極太輪郭・ドラッグ的な速さ |
| 天国大魔境 | Production I.G. 2023 | 広角レンズ意識・ミニマル線・肉体の重力 |
| シン・エヴァンゲリオン | khara 2021 | 実写カメラをアニメに輸入・Eva スケール対比 |
| モブサイコ 100 III | Bones 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 用の両ヘッダーがそれを参照する。定数なので全チャプターへ一括で揃う。
スキーマ設計
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>)"
環境変数
| 変数名 | 用途 | 設定場所 | 必須 |
|---|---|---|---|
| OPENAI_API_KEY | gpt-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汎用部分 vs プロジェクト固有部分
| 分類 | ファイル / パス | 説明 |
|---|---|---|
| 汎用 | scripts/sync-refs.mjs | references/ → content/ / public/ の同期ロジック |
| 汎用 | lib/judgments-blob.ts | Blob + localStorage dual write |
| 汎用 | lib/judgments-client.ts | クライアント判定ヘルパー |
| 汎用 | lib/project-todos.ts | active 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.ts | BASE_PROMPT (export) / SUPPLEMENT_ITEMS (全書き換え)。配信は prompt-blocks registry |
| 固有 | lib/supplement-references.ts | item → 参照キャラ マップ |
| 固有 | lib/supplement-items.ts | SUPPLEMENT_ITEMS 配列 + SUPPLEMENT_TOTAL |
| 固有 | lib/chapters/ch01..ch15.ts | 字コンテ全文 (各章 default export)。storyboard-jikonte.ts は型 + index のみ |
| 固有 | references/ 配下全て | キャラ・設定・画像のテキスト正本 |
| 固有 | lib/confirmed.ts / rejected.ts | style 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 |
| GitHub | Asaoman/26mv |
| Vercel (本番) | 26mv-theta.vercel.app |
| Vercel (preview) | 26mv-event-projects.vercel.app (401 保護) |
| dev port | 3300 |
| 章数 | 15章 (live: lib/chapter-refs) |
| 補足資料 (アイテム) | 56件 (live: SUPPLEMENT_ITEMS.length) |
| キャラクター | 34体 (live: references/characters/) |
| 補足資料マニフェスト | prompts/world_supplement_v1.yaml |
| 画像 API | OpenAI gpt-image-2 |
| 画像サイズ (補足シート) | 1536x1024 / quality: high (config/generation-params.json) |
| 画像サイズ (絵コンテ cut) | 2048x1152 / quality: high (config/generation-params.json) |
| 映像 API | Higgsfield 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-items | 全56補足の OK/NG 判定 + 再生成 |
/generations | 絵コンテ生成履歴 + スタイル選択 UI |
/docs | このページ |
/docs/ui | UI Design System Template |
別コンセプトで再生成する — 差し替え点
この基盤は「別コンセプトのアニメ MV をワンプロンプト級で再生成する」ことを前提に設計されている。1箇所直すと全体に波及する「差し替え点」を優先度順に押さえれば、派生物は npm run sync とgen.mjs が自動で作り直す。正典の優先順位はstoryboard-gen-spec.md > CLAUDE.md §15 > この /docs。矛盾時は上位を信じる。
| 差し替え点 | ファイル / パス | 波及先 |
|---|---|---|
| シリーズ DNA / トンマナ | site/lib/prompt-codex.ts の export 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 sync で content/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 両方更新 |
| 絵コンテ yaml | repo 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 cutc1-s1-1。 - 禁則: photo-real/3D, chibi/moe, glossy fantasy, generic cyberpunk, loud branding/logo/text overlay。
| 環境 | 値 |
|---|---|
| dev port | 3300 (next dev --port 3300)。確認は localhost:3300 |
| API キー | site/.env.local の OPENAI_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 |