diff --git a/docs/glossary.md b/docs/glossary.md index bac006a6b..bea4dac39 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -707,11 +707,11 @@ AI エージェントが実施する前提で、作業の A・H・L・C を類 | 語 | 識別子 | 意味 | 廃止した語 | 廃止した識別子 | 正本 | | --- | --- | --- | --- | --- | --- | -| トーン&マナー | — | スライドの書体・色・文字サイズ・著作権表示・ロゴの値の組。プロジェクトごとに差し替える | — | — | — | -| ページの枠組み | — | 見出し・罫線・ロゴ・著作権表示・ページ番号の位置を固定した、ページを作る共通の関数(page / box / note / tbl / section) | — | — | — | -| 生成スクリプト | — | pptx を出力するスクリプト(pptxgenjs の build-deck.js)。スライドの正本になる | — | — | — | -| 汎用テンプレート | — | 会社色を持たないトーン&マナーとページの枠組みを持つ、生成スクリプトの出発点 | — | — | — | -| 構成メモ | — | スライドのページごとの番号・見出し・役割・根拠の表と、構成の考え方を書いた文書 | — | — | — | -| 台本 | — | ページごとの見出しと読み上げの原稿。配分秒数は見出しに付けてよい(任意)。スピーカーノートへ入れる | — | — | — | -| トーン&マナーのファイル | — | プロジェクトのトーン&マナーの値を持つ JSON(slides/theme.json)。書いた項目だけが汎用テンプレートの既定値を上書きする | — | — | — | -| 尺 | — | 台本の読み上げにかかる時間。読み上げの字数を 350 字/分で割って出す | — | — | — | +| トーン&マナー | — | スライドの書体・色・文字サイズ・著作権表示・ロゴの値の組。プロジェクトごとに差し替える | — | — | `docs/specifications/ndf-slide-generation.md` | +| ページの枠組み | — | 見出し・罫線・ロゴ・著作権表示・ページ番号の位置を固定した、ページを作る共通の関数(page / box / note / tbl / section) | — | — | `docs/specifications/ndf-slide-generation.md` | +| 生成スクリプト | — | pptx を出力するスクリプト(pptxgenjs の build-deck.js)。スライドの正本になる | — | — | `docs/specifications/ndf-slide-generation.md` | +| 汎用テンプレート | — | 会社色を持たないトーン&マナーとページの枠組みを持つ、生成スクリプトの出発点 | — | — | `docs/specifications/ndf-slide-generation.md` | +| 構成メモ | — | スライドのページごとの番号・見出し・役割・根拠の表と、構成の考え方を書いた文書 | — | — | `docs/specifications/ndf-slide-generation.md` | +| 台本 | — | ページごとの見出しと読み上げの原稿。配分秒数は見出しに付けてよい(任意)。スピーカーノートへ入れる | — | — | `docs/specifications/ndf-slide-generation.md` | +| トーン&マナーのファイル | — | プロジェクトのトーン&マナーの値を持つ JSON(slides/theme.json)。書いた項目だけが汎用テンプレートの既定値を上書きする | — | — | `docs/specifications/ndf-slide-generation.md` | +| 尺 | — | 台本の読み上げにかかる時間。読み上げの字数を 350 字/分で割って出す | — | — | `docs/specifications/ndf-slide-generation.md` | diff --git a/docs/glossary/glossary.json b/docs/glossary/glossary.json index 6af6d6376..129bddd43 100644 --- a/docs/glossary/glossary.json +++ b/docs/glossary/glossary.json @@ -4088,57 +4088,49 @@ "term": "トーン&マナー", "context": "ndf-slide", "meaning": "スライドの書体・色・文字サイズ・著作権表示・ロゴの値の組。プロジェクトごとに差し替える", - "source": "", - "pending_source": "issues/issue-2065-requirements.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "ページの枠組み", "context": "ndf-slide", "meaning": "見出し・罫線・ロゴ・著作権表示・ページ番号の位置を固定した、ページを作る共通の関数(page / box / note / tbl / section)", - "source": "", - "pending_source": "issues/issue-2065-requirements.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "生成スクリプト", "context": "ndf-slide", "meaning": "pptx を出力するスクリプト(pptxgenjs の build-deck.js)。スライドの正本になる", - "source": "", - "pending_source": "issues/issue-2065-requirements.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "汎用テンプレート", "context": "ndf-slide", "meaning": "会社色を持たないトーン&マナーとページの枠組みを持つ、生成スクリプトの出発点", - "source": "", - "pending_source": "issues/issue-2065-requirements.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "構成メモ", "context": "ndf-slide", "meaning": "スライドのページごとの番号・見出し・役割・根拠の表と、構成の考え方を書いた文書", - "source": "", - "pending_source": "issues/issue-2065-requirements.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "台本", "context": "ndf-slide", "meaning": "ページごとの見出しと読み上げの原稿。配分秒数は見出しに付けてよい(任意)。スピーカーノートへ入れる", - "source": "", - "pending_source": "issues/issue-2065-design.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "トーン&マナーのファイル", "context": "ndf-slide", "meaning": "プロジェクトのトーン&マナーの値を持つ JSON(slides/theme.json)。書いた項目だけが汎用テンプレートの既定値を上書きする", - "source": "", - "pending_source": "issues/issue-2065-design.md" + "source": "docs/specifications/ndf-slide-generation.md" }, { "term": "尺", "context": "ndf-slide", "meaning": "台本の読み上げにかかる時間。読み上げの字数を 350 字/分で割って出す", - "source": "", - "pending_source": "issues/issue-2065-design.md" + "source": "docs/specifications/ndf-slide-generation.md" } ] } diff --git a/docs/specifications/README.md b/docs/specifications/README.md index 59de81a00..7933a272d 100644 --- a/docs/specifications/README.md +++ b/docs/specifications/README.md @@ -93,5 +93,6 @@ | [cross-drive-rerun-pause-and-denials.md](cross-drive-rerun-pause-and-denials.md) | cross-review・cross-refactoring の drive が完了した回を返す前に PR の head と結果を変える引数を比べること、計画の前の止まっていた時間の差し引きと使える時間が無い計画の中断、成功で終わった claude の permission_denials を警告にとどめること(#1263 #1944 #1513) | | [ndf-release-approval-materials.md](ndf-release-approval-materials.md) | 承認資料の検査の結果と未検証・残る危険に、レビュー・リファクタリング・全体テスト・設計文書の未確認・未実施のリリース後テストを集める契約と、材料を読む元(#1885 #1686 #1488。範囲の PR は ndf-release-approval-included-prs.md) | | [ndf-sprint-misjudgments-unknown-record-and-manual-none.md](ndf-sprint-misjudgments-unknown-record-and-manual-none.md) | スプリントの誤判定: 記録の置き場が分からない close は課題を開いたまま残し、「無し」の手動確認の行を数えない(#1875 #1675) | +| [ndf-slide-generation.md](ndf-slide-generation.md) | スライドの生成スクリプトの経路(汎用テンプレートのページの枠組みと座標・theme.json の重ね合わせと検査・台本からのスピーカーノートと尺・build-deck.js と script-time.js と slides-thumbnails.py の終了コード・常に成り立つ条件・決定の理由)。作り方の手順は release の form-slide.md が正 | Skill の挙動仕様はここに置かない。Skill に関する詳細は対象 Skill の `SKILL.md` を参照する。 diff --git a/docs/specifications/ndf-google-workspace-gws.md b/docs/specifications/ndf-google-workspace-gws.md index d199799b6..4facbf7a3 100644 --- a/docs/specifications/ndf-google-workspace-gws.md +++ b/docs/specifications/ndf-google-workspace-gws.md @@ -26,7 +26,7 @@ | 3 段の流れ(確かめる → 同意のうえ入れる → 認証を案内する)と、終了コードごとの次の手 | [`google-workspace` の SKILL.md](../../plugins/ndf/skills/google-workspace/SKILL.md) の「流れ」 | | 同意の取り方(明示の依頼を同意とみなす・暗黙の依頼では待つ・人がいない起動で止まる) | 同上の「流れ」の 2. | | Drive の操作の対応表(エクスポート・ダウンロード・アップロード・フォルダの共有範囲の確認・公開リンクの付与・pptx の Google Slides への変換と同じ URL のままの差し替え)と、エクスポートの MIME | 同上の「操作の対応表」 | -| Google Slides のページの ID とサムネイルの取得(サムネイルはスクリプト `slides-thumbnails.py`。契約は #2065 の設計の「入出力の契約」) | 同上の「操作の対応表」と [`issues/issue-2065-design.md`](../../issues/issue-2065-design.md) | +| Google Slides のページの ID とサムネイルの取得(サムネイルはスクリプト `slides-thumbnails.py`。契約はスライドの生成スクリプトの確定仕様の「外部連携」) | 同上の「操作の対応表」と [ndf-slide-generation.md](ndf-slide-generation.md#外部連携) | | Drive の素材の取り込みと PDF の取得の経路 | `document-systems` の [`references/system-gdrive.md`](../../plugins/ndf/skills/document-systems/references/system-gdrive.md) | | playwright-kit の利用者向けの移行の案内 | [`plugins/playwright-kit/README.md`](../../plugins/playwright-kit/README.md) と根の `CHANGELOG.md` の playwright-kit 3.0.0 | diff --git a/docs/specifications/ndf-slide-generation.md b/docs/specifications/ndf-slide-generation.md new file mode 100644 index 000000000..92f902f1e --- /dev/null +++ b/docs/specifications/ndf-slide-generation.md @@ -0,0 +1,435 @@ +# スライドの生成スクリプト: 汎用テンプレート(pptxgenjs)がページの枠組みを持ち、`theme.json` がトーン&マナーを差し替え、台本がスピーカーノートと尺を決め、gws が Google Slides へ変換してサムネイルで確かめる + +## 概要 + +**NDF のスライドは、生成スクリプト(pptxgenjs)の 1 つの経路で作る。** `release` Skill の +[assets/slides/](../../plugins/ndf/skills/release/assets/slides/) にある汎用テンプレートを資料のディレクトリへ写し、 +変える値だけを `slides/theme.json` に書き、台本(`script.md`)からスピーカーノートと尺を出す。出た pptx は +下書き先が Google Drive のとき Google Slides へ変換し、ページごとのサムネイルで体裁を見る。 + +例: このリポジトリの発表資料 [docs/presentations/2026-10-17-skill-plugin-development/](../presentations/2026-10-17-skill-plugin-development/README.md) +は、次の並びと 3 つのコマンドで作る。 + +```text +2026-10-17-skill-plugin-development/ +├── README.md # 成果物・トーン&マナー・写した時点の lib/ の内容のハッシュ +├── notes.md # 構成メモ(台本の 21 ページの表) +├── script.md # 台本(スピーカーノートの正本) +└── slides/ + ├── build-deck.js # 生成スクリプト(スライドの正本) + ├── theme.json # {"copyright": "NDF — github.com/devbasex/ai-plugins"} だけを書く + ├── package.json・package-lock.json # pptxgenjs 4.0.1 + └── lib/ # 汎用テンプレートの枠組みの写し(書き換えない) +``` + +```bash +(cd slides && npm ci) +node slides/lib/script-time.js script.md --limit 35 # 21 ページの字数・尺の表。35 分を超えると 1 +node slides/build-deck.js /tmp/skill-plugin-development.pptx +# → /tmp/skill-plugin-development.pptx: 27 ページ(章扉 6) +``` + +この文書は、その形に**なぜしたか**(決定と理由・常に成り立つ条件・入出力の契約・構成・テスト観点)を持つ。 +作り方の手順(写し方・構成メモと台本の書き方・ページの文言・変換と確認の順)は +[`release` の references/form-slide.md](../../plugins/ndf/skills/release/references/form-slide.md) が、 +体裁設計で決める項目は [`design` の references/layout-slide.md](../../plugins/ndf/skills/design/references/layout-slide.md) が、 +gws のコマンドは [`google-workspace` の SKILL.md](../../plugins/ndf/skills/google-workspace/SKILL.md) の「操作の対応表」が持つ。 + +## 用語 + +「トーン&マナー」「ページの枠組み」「生成スクリプト」「汎用テンプレート」「構成メモ」「台本」「トーン&マナーのファイル」「尺」の +定義は用語集([docs/glossary.md](../glossary.md))の「NDF のスライドの作成(`ndf-slide`)」が正である。 +「章扉」は枠組みの `section` が作るページで、構成を見せ、台本のページを消費しない。 + +## コンテキスト + +| コンテキスト | 何の語が 1 つの意味に決まるか | +| --- | --- | +| スライドの作成(`ndf-slide`) | 汎用テンプレート・ページの枠組み・トーン&マナー・生成スクリプト・構成メモ・台本・尺 | +| Google Workspace(`ndf-google-workspace`) | gws の操作・ファイルの ID・変換・サムネイル | + +**スライドの作成が顧客、Google Workspace が供給者である。** スライドの作成は、変換とサムネイルの取得を +`google-workspace` の操作の対応表とスクリプトに頼み、gws のコマンドを自分の規約に写さない。供給者は +顧客の要求(pptx の変換・同じ URL のままの差し替え・ページごとのサムネイル)を対応表に持つ。 + +## 背景 + +スライドの規約(体裁設計・生成・描画・体裁レビュー)が原則だけを持つと、AI は資料ごとにその場で作り方を組み立て、 +同じ台本からでも作りが揃わない。手本のプロジェクトの資料は、同じ値の定数と同じ枠組みの関数と同じ gws の変換手順を +資料ごとに写して持っていた。枠組み・トーン&マナー・変換手順は資料をまたいで繰り返されるため、共通の部品として +NDF が持つ。 + +## 決定と理由 + +| # | 決定 | 理由 | +| ---: | --- | --- | +| 1 | Skill を増やさず、体裁設計(`layout-slide.md`)・生成(`form-slide.md`)・変換と描画(`system-gdrive.md` と `google-workspace`)・体裁レビュー(`layout-review`)の既存の持ち場へ足す | 足すものはどれかの持ち場に収まる。新しい Skill を作ると、同じ手順の持ち場が 2 つになる | +| 2 | 汎用テンプレートは `release` Skill の `assets/slides/` に置く | Skill のディレクトリは 4 ランタイムへディレクトリごと配られ、生成の手順とテンプレートが同じ版で届く。`docs/` は配布物に含まれない | +| 3 | スライドの生成の経路は「生成スクリプトを書く(pptxgenjs)」の 1 つだけにする。変換器(Markdown から作るもの)・python-pptx・AI エージェントがその場で組む経路は使わない | 変換器の出力は開いた後に文字と図形を直せない。ほかの 2 つは同じ台本から同じ資料が出ない。生成スクリプトは決定的で、Google Slides と PowerPoint で開いて直せる | +| 4 | トーン&マナーは `theme.json` で既定値に重ね、枠組み(`lib/`)は写して書き換えない。座標は枠組みの定数だけが持つ | 枠組みの更新は `lib/` を写し直すだけで済み、プロジェクトの値が上書きされない。環境変数や引数で渡すと資料ごとの値がリポジトリに残らず、同じ資料を作り直せない | +| 5 | 既定の書体は Noto Sans JP、強調の色は 1 色(`2B6CB0`)。著作権表示とロゴは既定で描かない | 会社色を持たない。Noto Sans JP は Google Slides の書体の一覧にあり、作業の端末の描画(Noto Sans CJK JP)とも字形が揃う。著作権表示とロゴは持ち主ごとに違う | +| 6 | 枠組みが台本を読み、ページを作るたびに同じ番号の読み上げをスピーカーノートへ付け、保存の前にページ数を照合する | 生成スクリプトに読み上げを写すと、台本を直したときに片方だけが古くなる | +| 7 | 尺の計算(`script-time.js`)は枠組みと同じ JavaScript で、同じ台本の読み取り(`readScript`)を使う | 同じ形を読む関数が 2 つの言語に分かれると、片方だけが直る | +| 8 | サムネイルの取得はスクリプト(`slides-thumbnails.py`)にし、変換と差し替えは対応表のコマンドを AI が打つ | サムネイルはページ数だけ同じ手順を繰り返す。変換と差し替えは 1〜2 回で、アップロード先の共有範囲を確かめる判断を挟む。Google Slides は PDF を経ずにその描画をそのまま見られる | +| 9 | このリポジトリの発表資料は枠組みを `slides/lib/` に写して持ち、`plugins/` の汎用テンプレートを直接読まない | `docs/presentations/` は発表日時点の記録で、枠組みを変えても過去の資料の生成結果が変わらない。配布先と同じ手順をこのリポジトリでも通す | +| 10 | pptx をコミットせず、Google Slides を成果物にする。公開ページの入口(`index.html`)に足さず、`docs/presentations/README.md` の資料一覧にだけ足す | pptx は作り直せる。社外へ出す前の資料を公開の場所へ置かない | +| 11 | CI の pytest のジョブに Node.js 22 を入れ、生成のテストが `npm ci` で依存を入れて pptx を検査する | 生成のテストを手元だけで回すと、版面と差し替えの壊れを CI が見逃す | +| 12 | 章扉は台本のページを消費しない。ページの文言は台本の文を縮めて載せず、1 ページ 1 メッセージにする | 章扉に読み上げは無く、台本に区切りを置くと尺の計算と台本の番号が章扉の数だけずれる。読み上げはスピーカーノートが持ち、ページには要点だけを置くと聞き手が読める | + +## 対象範囲 + +| 対象 | 置き場 | +| --- | --- | +| 体裁設計の項目(トーン&マナー・ページの枠組み・章立て・ページの文言・構成) | `plugins/ndf/skills/design/references/layout-slide.md`、経路ごとの渡し方は `layout-common.md` | +| 生成の経路・起点・1 ページの区切り・生成スクリプトの経路の手順 | `plugins/ndf/skills/release/references/form-slide.md`、形の一覧は `distribution-forms.md` | +| 汎用テンプレート | `plugins/ndf/skills/release/assets/slides/`(`build-deck.js`・`script.md`・`package.json`・`package-lock.json`・`lib/deck-frame.js`・`lib/script-time.js`) | +| Google Slides への変換・差し替え・描画の手段 | `plugins/ndf/skills/document-systems/references/system-gdrive.md` | +| gws のコマンドとサムネイルの取得 | `plugins/ndf/skills/google-workspace/SKILL.md` の操作の対応表、`scripts/slides-thumbnails.py`・`scripts/gws_common.py` | +| 描画して見る手段(Google スライドはページごとのサムネイル) | `plugins/ndf/skills/layout-review/SKILL.md` | +| スライドの新規作成の振り分け(公式の `pptx` は既存の .pptx を読む・直す依頼だけ) | `plugins/ndf/skills/official-skills-autoloader/SKILL.md` | +| 発表資料の置き場と追加の仕方 | `docs/presentations/README.md` と各資料のディレクトリ | + +`docs/presentations/` の `2026-08-06-ai-plugins-intro`(md・html・pdf)は発表日時点の記録で、この仕様の対象に入らない。 + +## 仕様 + +### 集約 + +| 集約 | 持ち主(書き換えてよいもの) | 根 | エンティティ | 値オブジェクト | +| --- | --- | --- | --- | --- | +| 汎用テンプレート | NDF の配布物(`release/assets/slides/`)。プロジェクトは写すだけで書き換えない | ページの枠組み(`lib/deck-frame.js`) | — | 枠組みの座標(`FRAME`)・既定のトーン&マナー(`DEFAULT_THEME`) | +| 資料 | プロジェクトの資料のディレクトリ(生成の作業をする AI) | 生成スクリプト(`slides/build-deck.js`) | ページ | トーン&マナー(`theme.json` の値)・読み上げ・尺 | +| 変換したスライド | 利用者の Drive(gws を通して操作する) | Google Slides のファイル | ページ(`objectId`) | サムネイル | + +資料は汎用テンプレートを、写した時点の `lib/` の内容のハッシュ(`cat slides/lib/*.js | sha256sum`。資料の `README.md` に書く)で参照する。 + +### 構成要素と責務 + +| 要素 | 責務 | +| --- | --- | +| `lib/deck-frame.js` の `createDeck` | `theme` と `script` を読み、枠組みの関数を持つ `Deck` を返す。色を項目名から値へ置き換え、ページ番号・台本の番号・章扉の数を数え、`save` で照合して書き出す | +| `lib/deck-frame.js` の `run` | 生成スクリプトの入口。引数を読み、`theme.json` の置き場を決め、`build(deck)` の後に保存し、失敗を `DeckError` の `code` で終える | +| `lib/deck-frame.js` の `mergeTheme`・`parseScript` | `theme.json` の検査と重ね合わせ、台本の読み取りと番号の検査 | +| `lib/script-time.js` | `readScript` で台本を読み、ページごとと合計の字数・尺・配分秒数を表か JSON で出す | +| `build-deck.js`(見本) | 表紙・章扉・本編(表と注)の 3 ページを作る。写した後に資料の中身へ書き換える出発点 | +| `script.md`(見本) | 表紙と本編の 2 ページの台本。章扉の区切りを持たない | +| `package.json`・`package-lock.json` | pptxgenjs `4.0.1`(MIT)を固定する。資料へ写して `npm ci` で入れる | +| `google-workspace/scripts/slides-thumbnails.py` | Google Slides の全ページの ID を取り、ページごとのサムネイルを PNG で保存し、結果 JSON で保存先を返す | +| `google-workspace/scripts/gws_common.py` | gws の出力の末尾の切り出し(20 行)と、`stopped` の結果を出して終える関数 | + +```mermaid +graph TD + subgraph 規約["既存の規約"] + LC[layout-common.md] + LS[layout-slide.md] + FS[form-slide.md] + DF[distribution-forms.md] + GD[system-gdrive.md] + LR[layout-review] + GW[google-workspace の対応表] + OA[official-skills-autoloader] + end + subgraph テンプレート["汎用テンプレート release/assets/slides"] + FR[lib/deck-frame.js] + ST[lib/script-time.js] + SB[build-deck.js と script.md] + PK[package.json と package-lock.json] + end + TS[slides-thumbnails.py] + subgraph 資料["資料のディレクトリ"] + DB[slides/build-deck.js] + TH[slides/theme.json] + CP[slides/lib の写し] + MM[notes.md] + SC[script.md] + end + T[テストと CI] + LC --> LS --> FS + DF --> FS + OA --> FS + FS --> FR + FS --> GD --> GW --> TS + LR --> GD + SB --> FR + ST --> FR + FR -. 写す .-> CP + SB -. 写す .-> DB + PK -. 写す .-> DB + DB --> CP + DB --> TH + CP --> SC + MM --- SC + T --> FR + T --> TS + T --> DB +``` + +### 常に成り立つ条件 + +| # | 集約 | 条件 | 破れたときの扱い | +| --- | --- | --- | --- | +| I1 | 汎用テンプレート | 枠組みの関数が置く見出し・罫線・ロゴ・著作権表示・ページ番号・注の座標は、`FRAME` の定数だけが持ち、`theme.json` の値を変えても動かない | `theme.json` に座標の項目は無い(知らない項目は終了コード 1)。テストが落とす | +| I2 | 資料 | トーン&マナーの差し替えは `slides/theme.json` だけで済み、`slides/lib/` を書き換えない。`lib/` を写し直してもプロジェクトの値が残る | `lib/` の内容のハッシュが `README.md` の値と違えば書き換えた資料とみなし、プロジェクトの値を `theme.json` へ移してから写し直す。ハッシュは NDF の版数で代えない(同じ版数のまま `develop` で `lib/` が変わる)。写し直したら `README.md` のハッシュを書き換える | +| I3 | 資料 | 生成スクリプトと枠組みの関数の本体に書体名と色の値を書かない。色は `theme.colors` の項目名で指す | 項目名でない色を渡すと終了コード 1 で止まり、その値を出す。テストが落とす | +| I4 | 資料 | スピーカーノートは台本の読み上げから入れ、生成スクリプトに読み上げを写さない | 枠組みが台本を読み、台本の番号でノートを付ける | +| I5 | 資料 | 作ったページ数から章扉を除いた数は、台本のページ数と等しい。章扉はノートを持たず、台本の番号を進めない。ページ番号は章扉も数える | 保存の前に終了コード 1 で止まり、台本のページ数・章扉を除いて作ったページ数・章扉の数を出す。pptx は書かない | +| I6 | 資料 | 尺は読み上げの字数を 1 分あたりの字数(既定 350)で割った値で、合計はページごとの値の和に等しい | `--limit` を超えると終了コード 1。構成メモで削るページを決めて台本を直す | +| I7 | 汎用テンプレート・資料 | 手本のプロジェクトの社名・案件名・コーポレートカラーの値・ロゴを入れない | 差分の追加行を検索して 1 件でもあれば直す | + +### 処理の流れ + +```mermaid +sequenceDiagram + participant AI as スライドを作る AI + participant R as 規約(layout-slide → form-slide) + participant T as 汎用テンプレート + participant D as 資料のディレクトリ + participant G as gws と Google + participant L as 体裁レビュー + AI->>R: 体裁設計の項目を決める(E1) + AI->>T: build-deck.js・script.md・lib/・package*.json を写す + AI->>D: theme.json を書き、npm ci(E2) + AI->>D: 構成メモと台本を書く + AI->>D: script-time.js で尺を測る(E3) + alt 尺が上限を超える + AI->>D: 構成メモで削るページを決めて台本を直す + end + AI->>D: node build-deck.js で pptx(E4) + alt 下書き先の system が gdrive + AI->>G: 上げて変換、または同じ URL のまま差し替え(E5) + AI->>G: slides-thumbnails.py でページごとの PNG + end + AI->>L: 描画を見て記録を残す(E6) + alt 文字あふれ・重なり + L-->>AI: 差し戻し(体裁設計・生成・執筆) + end + AI->>D: 生成スクリプト・構成メモ・台本・README をコミット(E7) +``` + +| # | イベント | 発生元 | 受け手 | +| --- | --- | --- | --- | +| E1 | 版面・トーン&マナー・ページの枠組みを決めた | 体裁設計(`layout-slide.md`) | 生成(`form-slide.md`) | +| E2 | 汎用テンプレートを写し、トーン&マナーをプロジェクトの値へ差し替えた | 生成 | 生成スクリプト(`theme.json` を読む) | +| E3 | 構成メモと台本を書き、尺を測った | 執筆 | 生成スクリプト(台本を読む)・体裁設計(尺が超えたら削るページを決める) | +| E4 | pptx を作った | 生成スクリプト | 変換(gws) | +| E5 | pptx を Google Slides へ変換した(同じ URL のままの差し替えを含む) | 変換(`google-workspace`) | サムネイルの取得 | +| E6 | ページごとの描画を見て、体裁レビューの記録を残した | 体裁レビュー(`layout-review`) | 差し戻し先か、コミット | +| E7 | 生成スクリプト・構成メモ・台本・README をコミットした | 生成の作業をする AI | Pull Request | + +**Google Slides への変換は、下書き先(`.ndf/document.json` の `draft`)の `system` が `gdrive` のときだけ行う。** +ほかの下書き先では pptx を Drive へ上げず、Google の認証も求めない。描画の手段は下書き先の `system-<名前>.md` が持つ。 +プロジェクトに生成スクリプト(`slides/build-deck.js`)が既にあれば、汎用テンプレートを写さずにそれに従う。 + +### ページの枠組み + +`deck-frame.js` が公開する型と関数だけを描く。ページの中身(資料ごとの図形)は描かない。 + +```mermaid +classDiagram + class Theme { + font + colors 項目名と 6 桁の 16 進 + sizes 項目名と pt + copyright + logo + } + class Frame { + <<定数 インチ>> + slide 10 × 5.625 + title 0.26 0.15 8.29 0.63 + rule 0.24 0.80 9.52 + logo 8.78 0.24 0.96 0.23 + lead 0.26 0.90 9.5 0.34 + copyright 0.26 5.18 3.2 0.3 + pageNo 9.27 5.18 0.5 0.3 + note 0.26 4.88 9.5 0.28 + body・callout・section・cover + } + class Script { + no + title + seconds 配分秒数(任意) + reading 読み上げ + } + class Deck { + cover(title, sub, meta) + page(title, lead) Slide + section(title, sub) + box(slide, x, y, w, h, fill, line) + chip(slide, x, y, w, h, text, fill, opt) + arrow(slide, x, y, w, h, color) + text(slide, text, opt) + note(slide, text) + tbl(slide, rows, opt) + callout(slide, y, h, fill, head, body) + H・C・B 表のセル + color(name) 値 + save(out) + } + Deck --> Theme : DEFAULT_THEME に theme.json を重ねる + Deck --> Frame : 座標を読む + Deck --> Script : 台本の番号でノートを付ける +``` + +- `createDeck({ theme, script, title, author, baseDir })` が `Deck` を返す。`theme` は `theme.json` のパスか値、`script` は台本のパス(省略するとノートを付けず、照合もしない)。pptxgenjs は `baseDir`、次に枠組みの置き場から探す +- 色(`color`・`fill.color`・`line.color`・`border.color`)は `theme.colors` の項目名で受ける。文字の大きさは pt か `theme.sizes` の項目名で受ける(I3) +- `cover` と `page` は台本の番号を 1 つ進め、`section` は進めない(I5)。著作権表示は `copyright` が空なら描かず、ロゴは `logo` が `null` なら描かない +- 版面は pptxgenjs の `LAYOUT_16x9`(10 × 5.625 インチ) + +## データ・設定 + +### トーン&マナーのファイル(`slides/theme.json`) + +**書いた項目だけが既定値を上書きする。** `colors` と `sizes` は項目ごとに重ね、ほかは値ごと置き換える。 +項目名と既定値の正本は `deck-frame.js` の `DEFAULT_THEME` で、この文書は値を写さない(決定 5 の書体と強調の色を除く)。 + +| 項目 | 型 | 検査(違えば終了コード 1) | +| --- | --- | --- | +| `font` | 文字列 | 空でない | +| `colors.<項目名>` | 6 桁の 16 進(`#` なし) | 項目名が `DEFAULT_THEME.colors` にある。値は大文字にそろえる | +| `sizes.<項目名>` | pt | 項目名が `DEFAULT_THEME.sizes` にある。正の数 | +| `copyright` | 文字列 | 文字列。空なら描かない | +| `logo` | 文字列か `null` | `theme.json` の置き場からの相対パスで、ファイルがある。`null` なら描かない | + +最上位に `font`・`colors`・`sizes`・`copyright`・`logo` 以外の項目があると、項目名を出して終了コード 1 で止まる +(書き損じが既定値のまま通らない)。JSON として読めないときも 1。 + +### 台本(`script.md`) + +形(区切り・読み上げ・ほかの行・章扉)は `form-slide.md` の「台本を書き、尺を測る」が持つ。読み取りの契約は次のとおり。 + +| 規則 | 内容 | +| --- | --- | +| 区切り | `## <番号>. <見出し>`。見出しの末尾の `(<秒>秒)`(半角の括弧も可)を配分秒数として外す | +| 読み上げ | 区切りの中の `>` の行。`**` と `` ` `` を外す。`>` だけの行とほかの行が段落を切り、段落は改行でつなぐ | +| 番号の無い見出し | `#` か `##` で始まる番号の無い行の下は、次の区切りまで読まない | +| 番号の検査 | 区切りが無い・番号が重なる・1 から最大の番号までに欠けがある → 終了コード 2 と、重なる番号か欠けた番号を出す | +| ファイルが無い | 終了コード 1 | + +### 構成メモ(`notes.md`) + +`## 構成` の節の表の行数はページ数(章扉を除く)と等しく、番号は 1 から続く。形は `form-slide.md` の「構成メモを書く」が持つ。 + +### コマンド + +| コマンド | 出力 | 終了コード | +| --- | --- | --- | +| `node slides/build-deck.js <出力>.pptx []` | pptx と、標準出力の `<出力>: ページ(章扉 )` | 0 成功 / 1 引数(出力が無い・`.pptx` で終わらない)・渡した `theme.json` が無い・`theme.json` の検査・項目名でない色・ページ数の照合(I5)・台本が無い / 2 台本の番号の検査 | +| `node slides/lib/script-time.js <台本> [--wpm 350] [--limit <分>] [--json]` | 既定は Markdown の表(番号・見出し・字数・尺の秒・配分秒数と合計の行)。`--json` は `{wpm, pages[{no, title, chars, seconds, planned}], total{pages, chars, seconds, planned}, limit{minutes, over}}` | 0 / 1 合計が `--limit` を超えた・引数の誤り・台本が無い / 2 台本の番号の検査 | + +- `theme.json` を引数で渡さなければ `slides/theme.json` を読み、無ければ既定値で作る +- 字数は読み上げの空白を除いた文字の数。尺の秒は `字数 ÷ wpm × 60` を 0.1 秒に丸め、合計はページごとの値の和 +- 配分秒数の合計は、どのページにも配分が無ければ `null`(表では `—`) + +### 依存と追跡 + +| 項目 | 決まり | +| --- | --- | +| pptxgenjs | 汎用テンプレートと資料の `slides/package.json`・`package-lock.json` で `4.0.1` に固定し、`npm ci` で入れる | +| 追跡から外すもの | `node_modules/` と `*.pptx`(根の `.gitignore`) | +| CI | `.github/workflows/pytest.yml` が `actions/setup-node` で Node.js 22 を入れる。`npm ci` はテスト(`slide_deck_support.ensure_node_modules`)が打つ。`node` と `npm` が無いときの扱いは根の `conftest.py` の `REQUIRED_COMMANDS`(既定は失敗) | + +## 外部連携 + +### gws の操作 + +変換(pptx を `ignoreDefaultVisibility` 付きで上げ、`mimeType` を Google Slides に指定して複製する 2 手)・同じ URL のままの +差し替え(`files update --upload`。pptx のあるディレクトリで打つ)・ページの ID の取得のコマンドは、 +[`google-workspace` の SKILL.md](../../plugins/ndf/skills/google-workspace/SKILL.md) の「操作の対応表」が正である。 +置き場所と順は [`system-gdrive.md`](../../plugins/ndf/skills/document-systems/references/system-gdrive.md) の「投稿の手段」が持つ。 + +### `slides-thumbnails.py` + +```bash +python3 "$SKILL_DIR/scripts/slides-thumbnails.py" <出力のディレクトリ> [--size SMALL|MEDIUM|LARGE] +``` + +1. `gws slides presentations get`(`fields` は `slides(objectId)`)でページの ID をページ順に取る +2. ページごとに `gws slides presentations pages getThumbnail` を打ち、返った `contentUrl` を `curl -fsSL` で取る +3. `<出力のディレクトリ>/p<番号>.png`(番号は 1 から、ページ順)へ保存する + +結果は `step_result` の形の 1 行の JSON(`tool` は `slides-thumbnails`)。 + +| 終了コード | `status` | 意味 | `items` | +| --- | --- | --- | --- | +| 0 | `ok` | 全ページを保存した。`metrics` は `pages`・`size`・`out_dir` | ページごとに `name`(`p<番号>`)・`objectId`・`detail`(保存先) | +| 1 | `stopped` | gws か curl が失敗した・起動できない | 失敗した操作と、出力の末尾 20 行 | +| 2 | `stopped` | 引数の誤り・gws の応答が JSON でない・`slides[].objectId` か `contentUrl` が無い | 読めなかった操作 | +| 3 | `stopped` | gws か curl が無い | — | +| 11 | `gate` | gws が未認証(`gws-check.py` と同じ値)。利用者に `gws auth login` を頼む | 失敗した操作(`result` は `unauthenticated`) | + +- 未認証かどうかは、gws が失敗したときだけ `gws auth status` を 1 回打ち、`credential_source` が `none` かで決める。gws のエラーの文言に頼らない +- `contentUrl` は要求した利用者の権限で開ける一時的な URL で、認証なしで取る + +### npm レジストリ + +pptxgenjs は `package-lock.json` が固定した版を `npm ci` で取る。使用許諾は MIT。 + +## エラー処理 + +| 場合 | 扱い | +| --- | --- | +| Node.js か npm が無い | 導入の手順を示して止まる(`form-slide.md`)。テストは `conftest.py` が既定で失敗にする | +| `theme.json` の知らない項目・形の違う値・項目名でない色 | 終了コード 1 で止まり、項目名か値を出す。pptx は書かない | +| 台本と作ったページ数が合わない | 終了コード 1 で、両方の数と章扉の数を出す。pptx は書かない | +| 台本の番号が欠ける・重なる・区切りが無い | 生成も尺の計算も終了コード 2 で、番号を出す | +| 尺が上限を超える | `script-time.js` が表を出した後に終了コード 1 | +| gws が未認証 | `slides-thumbnails.py` が 11 を返す。`google-workspace` の手順で利用者に認証を頼む | +| サムネイルが取れない | 1 か 2 で止まる。体裁レビューは止めて人へ渡す(`layout-review`) | +| 変換した Google Slides で書体が代わる | サムネイルで見て、差し替えを打ち直す(`system-gdrive.md` の「既知の失敗」) | + +## セキュリティ + +- 生成スクリプト・規約・発表資料に Drive のフォルダ ID・ファイル ID・トークンを書かない。例は `<フォルダID>` の形にし、 + Google Slides の URL は資料の `README.md` に置かず、Pull Request の記録に残す +- gws の認証情報はリポジトリに置かず、`slides-thumbnails.py` も読まない。認証は gws が自分の設定ディレクトリに持つ +- アップロードはフォルダを指定しない(マイドライブの直下、非公開)か、共有範囲を確かめた利用者の非公開フォルダに限る。 + どちらの手も `ignoreDefaultVisibility` を外さない +- 下書き先が `gdrive` でなければ、pptx を Google Drive へ送らない(利用者が指定していないサービスへ資料を送らない) +- `docs/presentations/` は `main` へ入ると GitHub Pages で公開されるため、公開されてよい内容だけを置く + +## 運用 + +| 項目 | 内容 | +| --- | --- | +| 汎用テンプレートの更新の取り込み | 資料の `slides/lib/` を写し直し、`README.md` のハッシュを書き換える。`theme.json` には触れない(I2。手順は `form-slide.md`) | +| 発表資料の追随 | `docs/presentations/` の資料は発表日時点の記録で、汎用テンプレートを変えても写しを取り込み直さない | +| 上げた pptx | 変換の 1 手目で上げた pptx は Drive に残る。消すかは利用者が決める | +| 図の多いページ | pptxgenjs は Mermaid を描かないため、図は枠組みの図形(`box`・`chip`・`arrow`)か画像で組む | +| 書体の代替 | pptx で差し替えた Google Slides の本文が Arial になることがある。サムネイルで見て差し替えを打ち直す(`system-gdrive.md`) | + +## テスト観点 + +汎用テンプレートは `plugins/ndf/skills/release/tests/test_slide_template.py`(部品は `slide_deck_support.py`)、 +発表資料は `tests/test_presentation_decks.py`、サムネイルの取得は +`plugins/ndf/skills/google-workspace/tests/test_slides_thumbnails.py` にある。生成は node で実行し、pptx を zip と XML で読む。 +`.md` の文言は照合しない(構成メモは表の行数と番号だけを数える)。 + +- 汎用テンプレートの見本を生成すると終了コード 0 で、版面が 10 × 5.625 インチ、ページが 3 つ(表紙・章扉・本編)で、本編に表と注があること +- 本編の見出し・罫線・著作権表示・ページ番号・注の位置が手本の座標と一致し、`theme.json` で書体・文字の大きさ・色を変えても動かないこと(I1) +- 書体・全色・著作権表示・ロゴを差し替えた `theme.json` で生成すると、XML の書体名と色が差し替えた値だけになり既定値が残らず、ロゴが枠組みの位置に入ること。`lib/` を写し直しても同じ結果になること(I2・I3) +- 一部の項目だけを書いた `theme.json` では、書いていない項目が既定値のまま残ること +- 知らない項目・知らない色の項目名・`#` 付きの色で終了コード 1 になり、項目名を出し、pptx を書かないこと +- 生成スクリプトに色の値を直接書くと終了コード 1 で止まり、その値を出すこと(I3) +- スピーカーノートが台本の同じ番号の読み上げと一致し、章扉はノートを持たず、章扉の後のページが台本の次の番号を受け、`>` だけの行が段落を分けること(I4・I5) +- ページ番号が章扉も数え、章扉を足しても台本との照合が通ること。台本のページを増やすと終了コード 1 で 3 つの数を出し、pptx を書かないこと(I5) +- 台本の番号が欠ける・重なると、生成と尺の計算がどちらも終了コード 2 で番号を出すこと +- 字数が分かっている台本で、ページごとの字数と秒(350 字/分)と合計が期待どおりで、空白・強調の記号・`>` 以外の行を数えず、`--limit` を下回る値で終了コード 1 になること(I6) +- `docs/presentations/` の生成スクリプトの資料がそれぞれ終了コード 0 で生成でき、章扉を除いたページ数が台本と構成メモの表の行数に等しく、全ページのノートが台本と一致すること +- 資料の生成スクリプトが `./lib/deck-frame` を読み、`slides/lib/` の内容のハッシュが `README.md` に書いた値と一致すること +- 発表資料「独自プラグイン開発の薦め」が台本の 21 ページと章扉 6 つの 27 ページになること +- 偽の gws の前で、`slides-thumbnails.py` がページの ID の順に `p<番号>.png` を保存し、結果 JSON にページ数と保存先が出ること。成功の経路で `gws auth status` を打たないこと +- gws が失敗すると終了コード 1 で gws の出力が `items` に載り、未認証なら 11、引数の誤りなら 2 になること +- 人が見る観点: 規約に書いた gws のコマンド(変換・差し替え・ページの ID・サムネイル)を実際に打った記録と、変換した全ページのサムネイルを見た体裁レビューの記録(文字あふれ・重なりが 0 件)が Pull Request にあること +- 完了判定の観点: `plugins/ndf/manifests/` の Skill の行が増えないこと。差分の追加行に手本のプロジェクトの名前とコーポレートカラーの値、ページの数え方の直訳の和語が出ないこと + +## 関連リンク + +- [`release` の references/form-slide.md](../../plugins/ndf/skills/release/references/form-slide.md)(作り方の手順の正)・[references/distribution-forms.md](../../plugins/ndf/skills/release/references/distribution-forms.md) +- [`release` の assets/slides/](../../plugins/ndf/skills/release/assets/slides/)([lib/deck-frame.js](../../plugins/ndf/skills/release/assets/slides/lib/deck-frame.js)・[lib/script-time.js](../../plugins/ndf/skills/release/assets/slides/lib/script-time.js)・[build-deck.js](../../plugins/ndf/skills/release/assets/slides/build-deck.js)) +- [`design` の references/layout-slide.md](../../plugins/ndf/skills/design/references/layout-slide.md)・[references/layout-common.md](../../plugins/ndf/skills/design/references/layout-common.md) +- [`layout-review` の SKILL.md](../../plugins/ndf/skills/layout-review/SKILL.md)・[`document-systems` の references/system-gdrive.md](../../plugins/ndf/skills/document-systems/references/system-gdrive.md) +- [`google-workspace` の SKILL.md](../../plugins/ndf/skills/google-workspace/SKILL.md)・[scripts/slides-thumbnails.py](../../plugins/ndf/skills/google-workspace/scripts/slides-thumbnails.py)・[`official-skills-autoloader` の SKILL.md](../../plugins/ndf/skills/official-skills-autoloader/SKILL.md) +- [docs/presentations/README.md](../presentations/README.md)(発表資料の置き場と追加の仕方) +- [ndf-google-workspace-gws.md](ndf-google-workspace-gws.md)(gws への一本化と `gws-check.py` の終了コード) +- #2065(この形を決めた Issue) diff --git a/issues/issue-2065-design-decisions.md b/issues/issue-2065-design-decisions.md deleted file mode 100644 index b64096d71..000000000 --- a/issues/issue-2065-design-decisions.md +++ /dev/null @@ -1,163 +0,0 @@ -# #2065 の設計: 決定の記録 - -設計文書は [issue-2065-design.md](issue-2065-design.md) にある。 - -## 決定の記録 - -### 決定 1: Skill の数を増やさないため、既存の 4 つの規約と google-workspace へ足す - -利用者は新しい Skill の前に既存の規約への統合を優先すると決めた。体裁設計(`layout-slide.md`)・生成(`form-slide.md`)・ -変換と描画(`system-gdrive.md` と `google-workspace`)・体裁レビュー(`layout-review`)の分担は今のまま成り立ち、 -足すものはどれかの持ち場に収まる。gws のコマンドの正本は既に `google-workspace` の対応表にあるため、変換と -サムネイルの行もそこへ足す。 - -新しい Skill(例: スライドの作成)を作る案は、同じ手順の持ち場が 2 つになり、既存の 4 つの規約から辿る経路と -重なるため採らない。 - -根拠: Value 6・Value 7(MVV 版 2) - -### 決定 2: すべてのランタイムで同じテンプレートを使うため、汎用テンプレートを release Skill の assets に置く - -Skill のディレクトリは 4 ランタイムへディレクトリごと配られる(Kiro はリンク、agy はリンク、Codex と Claude Code は -プラグインのディレクトリ)。生成の手順を持つ `release` の配下に置けば、手順とテンプレートが同じ版で届く。 -配布先のリポジトリはそこから資料のディレクトリへ写す。 - -`docs/` に置く案は、配布物に含まれず配布先のリポジトリから辿れないため採らない。新しい Skill の配下に置く案は決定 1 で採らない。 - -根拠: Value 5(MVV 版 2) - -### 決定 3: 生成スクリプトの経路を規約で扱えるようにするため、スライドの生成の経路に「生成スクリプトを書く」を決定的な経路として足す - -生成スクリプトは AI が書くが、同じスクリプトと台本と `theme.json` からは同じ pptx が出る。決定的なため、生成物は -保存しなくてよく、正本は生成スクリプトと台本になる。今の「変換器を使う」は正本の Markdown を前提にし、「AI エージェントが -組む」は非決定的を前提にするため、どちらにも入らない。足す先はスライドだけにし、文書・表計算・ページの形の経路は -変えない。 - -「変換器を使う」に含める案は、起点(正本の Markdown の直前の版)と 1 ページの区切り(`##` の見出し)が成り立たない -ため採らない。 - -根拠: Value 6・Value 8(MVV 版 2) - -### 決定 4: 枠組みの更新でプロジェクトの値を失わないため、トーン&マナーは theme.json で上書きし、枠組みは写して書き換えない - -既定値は枠組みのファイルが持ち、プロジェクトは変えたい項目だけを `theme.json` に書く。枠組みの更新は `lib/` を写し直す -だけで、`theme.json` には触れない。座標は枠組みの定数に固定し、トーン&マナーに含めない(I1)。 - -手本のように生成スクリプトの先頭の定数を書き換える案は、枠組みの更新を取り込むたびに書き換えが上書きされるため採らない。 -環境変数か引数で値を渡す案は、資料ごとの値がリポジトリに残らず、同じ資料を作り直せないため採らない。 - -根拠: Value 5(MVV 版 2) - -### 決定 5: 会社色を持たず配布先で同じ見え方にするため、既定の書体を Noto Sans JP、強調の色を 2B6CB0 にし、著作権表示とロゴは既定で描かない - -Noto Sans JP は Google Slides の書体の一覧にあり、変換の後も代替が起きにくい。作業の端末の描画(Noto Sans CJK JP)とも -字形が揃う。強調の色は 1 色に絞る(`layout-slide.md`)。著作権表示とロゴは持ち主によって違うため、既定では描かず、 -`theme.json` で足す。 - -手本の書体と色を既定にする案は会社色になるため採らない。Windows の既定の書体(BIZ UDP ゴシックなど)は Google Slides と -macOS で揃わないため採らない。 - -根拠: Mission・Value 5(MVV 版 2) - -### 決定 6: スピーカーノートを台本と食い違わせないため、枠組みが台本を読んでページ番号でノートを付ける - -生成スクリプトに読み上げを写すと、台本を直したときに片方だけが古くなる。枠組みが台本を読み、ページを作るたびに同じ番号の -読み上げをノートへ付け、保存の前にページ数を照合する(I4・I5)。台本は Markdown の 1 ファイルにし、区切りは台本の -第 7 稿の形(`## <番号>. <見出し>` と `>` の読み上げ)に合わせる。 - -生成スクリプトの各ページで `addNotes` に文を書く案(手本の形)は、台本と 2 か所に同じ文を持つため採らない。 - -根拠: Value 7(MVV 版 2) - -### 決定 7: 台本の読み取りを 1 つにするため、尺の計算を枠組みと同じ JavaScript で持つ - -尺の計算は台本の読み上げを数えるため、ノートの付与と同じ読み取りを使う。Python で別に書くと、同じ形を読む関数が 2 つの言語に -分かれ、片方だけが直る。計算は字数を数えて割るだけの決まった手順なので、スクリプトにする。 - -手本の 1 行の Python を README に書く案は、手順を文書に置き、読み取りを 2 つにするため採らない。 - -根拠: Value 4・Value 6(MVV 版 2) - -### 決定 8: 全ページを決まった手順で見られるようにするため、サムネイルの取得をスクリプトにし、変換と差し替えは対応表のコマンドで打つ - -サムネイルはページの ID を取り、ページごとに API を呼び、返った一時的な URL から画像を取る。ページ数だけ同じ手順を繰り返す -ため、`google-workspace` のスクリプトにする。変換(上げて複製)と差し替えは 1〜2 回打つだけで、アップロード先の共有範囲を -確かめる判断を挟むため、対応表のコマンドのまま AI が打つ。 - -PDF に書き出してから画像にする今の経路は、Google Slides の描画をそのまま見られるサムネイルより手順が多いため、 -Google Slides では採らない(Google ドキュメントには残す)。 - -根拠: Value 4(MVV 版 2) - -### 決定 9: 発表資料を発表日時点の記録にするため、資料は枠組みを写して持ち、汎用テンプレートを直接読まない - -`docs/presentations/` の資料は発表日時点の記録で、以後の構成の変更に追随しない(`AGENTS.md` の「ドキュメント」の表)。 -資料が `plugins/` の枠組みを直接読むと、枠組みを変えたときに過去の資料の生成結果が変わる。写して持つと、配布先と同じ手順を -このリポジトリでも通すことになる。 - -リポジトリの中の相対パスで汎用テンプレートを読む案は、写しを持たずに済むが、記録が後から変わるため採らない。 - -根拠: Value 7・Value 9(MVV 版 2) - -### 決定 10: 成果物を 1 つにするため、pptx をコミットせず Google Slides を成果物にし、公開ページの入口に足さない - -生成は決定的なため pptx は作り直せる(決定 3)。発表に使うのは利用者の Drive の Google Slides で、共有の設定はこの課題の -範囲外である。Pages で公開できる書き出し(PDF・HTML)を持たないため、`index.html` には足さず、 -`docs/presentations/README.md` の資料一覧にだけ足す。 - -pptx か PDF をコミットして `index.html` から開ける案は、社外へ出す前の資料を公開の場所へ置くことになり、公開の判断 -(C5 に準じる)を先取りするため採らない。 - -根拠: Value 1・C5(MVV 版 2) - -### 決定 11: 生成のテストが CI で読み飛ばされないよう、pytest のジョブに Node.js 22 と npm ci を足す - -生成のテストは pptxgenjs を要る。前提のコマンドが無いとき既定で失敗する根の `conftest.py` の仕組みへ `node` を足し、 -CI の pytest のジョブで `actions/setup-node` の 22 と、汎用テンプレートと発表資料の `npm ci` を打つ。生成した pptx は -Python の標準ライブラリ(zip と XML)で検査する。 - -生成のテストを手元だけで回す案は、CI が版面と差し替えの壊れを見逃すため採らない。 - -根拠: Value 3(MVV 版 2) - -### 決定 12: 変換後のスライドを編集できるようにするため、Marp(変換器を使う経路)をスライドの規約とリポジトリから外す - -利用者の決定(2026-10-18)。Marp で変換したスライドは、Google Slides や PowerPoint で開いても文字と図形を直せない。 -発表の直前に 1 文字を直すにも変換の手順を通し直すことになり、資料として致命的である。スライドの規約(`form-slide.md`・ -`layout-slide.md`・`layout-common.md`・`distribution-forms.md`)から変換器の経路を外し、`docs/presentations/README.md`・ -`build.sh`・`AGENTS.md` の Marp の手順を生成スクリプトの方式へ書き換える。`build.sh` は Marp だけを打つため消す。 -2026-08-06 の資料の md・html・pdf は発表日時点の記録として残し、README にはそれが Marp で作った記録であることだけを書く。 - -Marp を残して経路の 1 つにする案は、編集できない成果物を既定の候補に残すため採らない。 - -根拠: Value 1・Value 6(MVV 版 2) - -### 決定 13: スライドの生成の経路を 1 つにするため、python-pptx と「AI エージェントが組む」をスライドから外し、生成スクリプト(pptxgenjs)だけにする - -利用者の決定(2026-10-18)。python-pptx は pptxgenjs に比べて利点が無く、「AI エージェントが組む」は同じ台本から同じ資料が -出ない。スライドの生成の経路は「生成スクリプトを書く(pptxgenjs)」の 1 つにし、決定的なため生成物は保存しなくてよい。 -文書・表計算・ページの形の経路は変えない。`official-skills-autoloader` の対応表は、スライドを新しく作る依頼を `release` の -`form-slide.md` へ回し、公式の `pptx` Skill は既存の .pptx を読む・直す依頼だけに使う。 - -**決定 3 を置き換える。** 決定 3 は今の 2 つの経路に「生成スクリプトを書く」を足して 3 つにしたが、決定 12・13 で残りの -2 つを外し、生成スクリプトの経路だけが残る。設計文書の「構成要素」の値の集合の記述もこの決定に従って読む。 - -根拠: Value 1・Value 6・Value 8(MVV 版 2) - -### 決定 14: 構成を聞き手に見せるため、章扉を台本のページを消費しないページにし、ページの文言を台本の文から起こさない - -利用者の差し戻し(2026-10-18)。発表資料を Google Slides で見て「読みづらい。スライドらしい言葉遣いに改め、章扉を入れる」 -「(内部用語の見出しが)意味が分からない」と指摘した。原因は 2 つある。各ページの文言が台本の文を縮めただけで長く、 -聞き手の知らない内部の語が説明なしに残っていた。章扉が無く、構成が見えなかった。 - -- **章扉はスピーカーノートを持たず、台本の番号を進めない。** 枠組みの `section` は台本のページを消費せず、ページ数の - 照合(I5)からも外れる。ページ番号は章扉も数える。台本は話す内容の正本で、章扉に読み上げは無いため、台本に章扉の - 区切りを置くと、読み上げの無いページを台本に持つことになる -- **ページの文言は台本の文を縮めて載せない。** 1 ページ 1 メッセージにし、見出しはそのページの結論を短く、箱と表は - 短い句か体言止めにする。聞き手が知らない内部の語は言い換えるか、ページの中で一言で説明する。規約は体裁設計 - (`layout-slide.md`)と生成の手順(`form-slide.md`)に置き、体裁レビュー(`layout-review`)が聞き手の目で見る - -章扉を台本の区切りとして持ち、ノートを空にする案は、台本に読み上げの無いページが混ざり、尺の計算と台本の番号が -章扉の数だけずれるため採らない。 - -根拠: Value 6・Value 8(MVV 版 2) diff --git a/issues/issue-2065-design.md b/issues/issue-2065-design.md deleted file mode 100644 index ca6ee7683..000000000 --- a/issues/issue-2065-design.md +++ /dev/null @@ -1,455 +0,0 @@ -# スライド: 作り方の手順が NDF に無く、AI が毎回その場で作り方を組み立てて手本と違う資料になる → 生成スクリプトの汎用テンプレート・構成メモと台本・gws での変換とサムネイル確認を既存の規約から辿れ、その手順で発表資料を作れる(#2065) - -## 目的 - -- **何が壊れているか**: NDF のスライドの規約(`layout-slide.md`・`form-slide.md`・`layout-review`・`system-gdrive.md`)は原則だけを持ち、生成スクリプト・ページの枠組み・トーン&マナー・構成メモ・台本・Google Slides への変換と確認の手順を持たない -- **誰が困るか**: スライドを頼む利用者。AI が毎回その場で作り方を組み立て(2026-10-17 は python-pptx の自作)、手本と違う作りになって差し戻される -- **直すと何が成り立つか**: AI は既存の規約から汎用テンプレートと手順へ辿り、同じ作り方でスライドを作れる。その手順で発表資料「独自スキルプラグイン開発の薦め」(23 ページ)を作って、手順が通ることを示す - -## 適用範囲 - -- **働く範囲**: 配布先のリポジトリでも働く。汎用テンプレートは `release` Skill の配下に置き、4 ランタイムへ Skill のディレクトリごと配る。発表資料はこのリポジトリの `docs/presentations/` だけに置く -- **プロジェクトごとに違うもの**: トーン&マナー(書体・色・文字サイズ・著作権表示・ロゴ)はプロジェクトのファイル(`slides/theme.json`)で受ける。出力先・台本のパス・尺の上限は引数で受ける -- **当たるモード**: `documentation`(出力の形がスライドのとき)。ほかのモードでもスライドを作る作業はこの規約を読む - -## あるべき姿の根拠 - -| 根拠 | 種類 | 何を示すか | -| --- | --- | --- | -| 「slide の作り方が違う。…を参考に。Skill 化した方が良いかも」(2026-10-17) | 利用者の指示の原文 | 手本の作り方(生成スクリプト方式)に揃える。python-pptx の自作を採らない | -| 「新しい Skill を作る前に既存のスライドの規約…への統合を優先する。トーン&マナーは会社色の無い汎用テンプレートを既定にし、版面と枠組みの関数(page/box/note/tbl/section)は…踏襲、プロジェクトごとに差し替えられるようにする」(2026-10-17) | 利用者の指示の原文 | Skill を増やさず既存の規約へ足す。枠組みの座標は手本の値、トーン&マナーは差し替えられる形 | -| 手本の 3 件(要求の「何をしたいか」の表)。2 件の生成スクリプトが同じ値の定数と同じ枠組みの関数を写して持ち、README に同じ gws の変換手順を書いている | 実測(2026-10-17 に読んだ) | 枠組みとトーン&マナーと変換手順は資料ごとに繰り返される。共通の部品にする価値がある | -| `gws drive files copy`(`mimeType` 指定)・`gws slides presentations get`・`gws slides presentations pages getThumbnail` を `--dry-run` で打ち、要求の形(`POST …/files//copy`・`GET …/presentations/`・`GET …/pages/<ページ>/thumbnail`)を確かめた(2026-10-17) | 実測 | 変換と確認の経路が gws の今の版で組める | -| `npm view pptxgenjs version license` → `4.0.1`・`MIT`(2026-10-17) | 実測 | 依存として宣言できる版と使用許諾 | - -要求と受け入れ条件は #2065 の本文にある(コピーは [issue-2065-requirements.md](issue-2065-requirements.md) )。この文書は「どう作るか」だけを扱う。 - -## ドメインモデル - -### コンテキスト - -| コンテキスト | 何の語が 1 つの意味に決まるか | -| --- | --- | -| スライドの作成(`ndf-slide`) | 汎用テンプレート・ページの枠組み・トーン&マナー・生成スクリプト・構成メモ・台本・尺 | -| Google Workspace(`ndf-google-workspace`) | gws の操作・ファイルの ID・変換・サムネイル | - -**スライドの作成が顧客、Google Workspace が供給者の関係(顧客 / 供給者)。** スライドの作成は、変換と -サムネイルの取得を `google-workspace` の操作の対応表とスクリプトに頼み、gws のコマンドを自分の規約に -写さない。供給者は顧客の要求(pptx の変換・同じ URL のままの差し替え・ページごとのサムネイル)を対応表へ足す。 - -### 集約 - -| 集約 | 持ち主(書き換えてよいもの) | 根 | エンティティ | 値オブジェクト | -| --- | --- | --- | --- | --- | -| 汎用テンプレート | NDF の配布物(`release/assets/slides/`)。プロジェクトは写すだけで書き換えない | ページの枠組み(`lib/deck-frame.js`) | — | 枠組みの座標・既定のトーン&マナー | -| 資料 | プロジェクトの資料のディレクトリ(生成の作業をする AI) | 生成スクリプト(`slides/build-deck.js`) | ページ | トーン&マナー(プロジェクトの値)・読み上げ・尺 | -| 変換したスライド | 利用者の Drive(gws を通して操作する) | Google Slides のファイル | ページ(`objectId`) | サムネイル | - -資料は汎用テンプレートを ID(写した時点の `lib/` の内容のハッシュ)で参照し、オブジェクトとして持たない。資料が持つ枠組みは写しであり、 -写した後に資料の側から書き換えない(I2)。 - -### 不変条件 - -| # | 集約 | 条件 | 破れたときの扱い | -| --- | --- | --- | --- | -| I1 | 汎用テンプレート | 枠組みの関数が置く見出し・罫線・ロゴ・著作権表示・ページ番号・注の座標は、トーン&マナーの値に依らず手本と同じ値で固定される | トーン&マナーの項目に座標を持たせない。座標は枠組みのファイルの定数だけが持つ | -| I2 | 資料 | トーン&マナーの差し替えは `slides/theme.json` だけで済み、枠組みのファイル(`slides/lib/`)を書き換えない。枠組みを写し直してもプロジェクトの値が残る | 枠組みを書き換えた資料は、汎用テンプレートの更新を取り込めない。書き換えかどうかは、資料の `slides/lib/` の内容のハッシュを、写した時点の `lib/` の内容のハッシュ(資料の `README.md` に書いた値)と比べて決め、一致しなければ書き換えとみなしてプロジェクトの値を `theme.json` へ移す。NDF の版は基準にしない(版はスプリント単位でしか上がらず、同じ版数のまま develop で `lib/` が変わるため、版では写した元の `lib/` を一意に指せない)。新しい汎用テンプレートの `lib/` を写し直すのは更新の取り込みであり、書き換えとはみなさない。取り込んだら `README.md` のハッシュを写し直した `lib/` の値へ書き換える | -| I3 | 資料 | 生成スクリプトと枠組みの関数の本体に、書体名と色の値を直接書かない。色は `theme.json` の項目名で指す | 直書きが残ると、差し替えた後も既定の値が pptx に残る。テストが落とす | -| I4 | 資料 | スピーカーノートは台本のファイルの読み上げから入れる。生成スクリプトに読み上げを写さない | 写すと台本と食い違う。枠組みが台本を読み込み、ページ番号で対応させる | -| I5 | 資料 | 生成した pptx のページ数から章扉を除いた数は、台本のページ数と等しい。章扉はスピーカーノートを持たず、台本の番号を進めない(決定 14) | 生成スクリプトが終了コード 1 で止まり、台本のページ数と、章扉を除いて作ったページ数と、章扉の数を出す | -| I6 | 資料 | 尺は台本の読み上げの字数を 350 字/分で割った値で、合計はページごとの値の和に等しい | 尺の上限(引数)を超えたら終了コード 1 を返し、構成メモで削るページを決める | -| I7 | 汎用テンプレート・資料 | 汎用テンプレートと資料に、手本の社名・案件名・コーポレートカラーの値・ロゴを入れない | 完了判定で差分の追加行を検索し、1 件でもあれば直す(受け入れ条件 13) | - -### ドメインイベント - -| # | イベント | 発生元 | 受け手 | -| --- | --- | --- | --- | -| E1 | 体裁設計で版面・トーン&マナー・ページの枠組みを決めた | 体裁設計(`design` の `layout-slide.md`) | 生成(`release` の `form-slide.md`) | -| E2 | 汎用テンプレートを写し、トーン&マナーをプロジェクトの値へ差し替えた | 生成 | 生成スクリプト(`theme.json` を読む) | -| E3 | 構成メモと台本を書き、尺を測った | 執筆(構成メモ・台本) | 生成スクリプト(台本を読む)・体裁設計(尺が超えたら削るページを決める) | -| E4 | 生成スクリプトで pptx を作った | 生成スクリプト | 変換(gws) | -| E5 | pptx を Drive へ上げ、Google Slides へ変換した(同じ URL のままの差し替えを含む) | 変換(`google-workspace`) | サムネイルの取得 | -| E6 | ページごとのサムネイルを取り、体裁レビューの記録を残した | 体裁レビュー(`layout-review`) | 差し戻し先(体裁設計・生成・執筆)か、コミット | -| E7 | 生成スクリプト・構成メモ・台本・README をコミットした | 生成の作業をする AI | Pull Request | - -### 用語 - -| 用語 | 意味 | 用語集への反映 | -| --- | --- | --- | -| トーン&マナーのファイル | プロジェクトのトーン&マナーの値を持つ JSON(`slides/theme.json`)。書いた項目だけが汎用テンプレートの既定値を上書きする | 追加(`ndf-slide`) | -| 尺 | 台本の読み上げにかかる時間。読み上げの字数を 350 字/分で割って出す | 追加(`ndf-slide`) | -| 台本 | ページごとの見出しと読み上げの原稿。配分秒数は見出しに付けてよい(任意)。スピーカーノートへ入れる | 意味の変更(`ndf-slide`。配分秒数を任意にした) | - -## 機能一覧 - -| # | 機能 | 誰が使うか | -| --- | --- | --- | -| F1 | 規約から汎用テンプレートと手順へ辿る(体裁設計 → 生成 → 変換 → 体裁レビュー) | スライドを作る AI | -| F2 | 汎用テンプレートを写して生成スクリプトを用意し、表紙・章扉・本編のページを作る | スライドを作る AI | -| F3 | トーン&マナーをプロジェクトの値へ差し替える | スライドを作る AI・プロジェクトの持ち主 | -| F4 | 構成メモと台本を規約の形で書き、台本からスピーカーノートを入れる | スライドを作る AI | -| F5 | 台本の字数と尺をページごとと合計で出し、上限を超えたら知らせる | スライドを作る AI・発表者 | -| F6 | pptx を Google Slides へ変換する(新しく作る・同じ URL のまま差し替える) | スライドを作る AI | -| F7 | Google Slides のページごとのサムネイルを取り、体裁レビューで見る | 体裁レビューをする AI | -| F8 | 発表資料「独自スキルプラグイン開発の薦め」を F1〜F7 の手順で作る | 発表者(利用者) | - -## 構成要素 - -**値の集合(スライドの生成の経路)を 1 つの値に置き換える。** 今の経路は「変換器を使う」「AI エージェントが組む」の 2 つで、 -これを「生成スクリプトを書く」の 1 つにする(決定 12・13。決定 3 を置き換えた)。集合を前提にした規則を、集合の名前と値の名前での検索(`生成の経路`・ -`AI エージェントが組む`・`変換器を使う`・`form-slide`・`layout-slide`)と、新しい経路が通る手順(体裁設計 → 生成 → -取り込み → 体裁レビュー)を読んで集めた。当てはまらない規則は下の表へ載せる。 - -| 要素 | 責務 | 変更の種類 | -| --- | --- | --- | -| 体裁設計の共通規則(`design/references/layout-common.md`) | 生成の経路ごとの渡し方の表に「生成スクリプトを書く → トーン&マナーのファイルとページの枠組み」の行を足す | 変更(経路の集合の規則) | -| スライドの体裁設計(`design/references/layout-slide.md`) | 決める項目の「生成の経路」に生成スクリプトを足し、「トーン&マナー(著作権表示・ロゴ)」「ページの枠組み」の行を足す。生成スクリプトの経路では決めた値を `theme.json` へ書くと示し、`form-slide.md` へ辿らせる | 変更(経路の集合の規則) | -| スライドの生成(`release/references/form-slide.md`) | 経路の表へ「生成スクリプトを書く(決定的)」を足し、起点(生成スクリプトの直前の版)と 1 ページの区切り(台本の `## <番号>.`)を経路ごとに書き分ける。新しい節「生成スクリプトの経路」に資料のファイルの並び・テンプレートの写し方・トーン&マナーの差し替え・構成メモの形・台本の形と尺・生成・変換と確認の順を書く | 変更(経路の集合の規則)+追加 | -| 配布の形の一覧(`release/references/distribution-forms.md`) | 「生成の経路は 2 つ」の行に、スライドは生成スクリプトの経路も持つ(`form-slide.md`)と足す | 変更(経路の集合の規則) | -| 汎用テンプレートの枠組み(`release/assets/slides/lib/deck-frame.js`) | 枠組みの関数(`cover`・`page`・`section`・`box`・`note`・`tbl`・`callout`、表のセル `H`・`C`・`B`)・座標の定数・既定のトーン&マナー・`theme.json` の重ね合わせ・台本の読み込みとページ番号でのノートの付与・ページ数の照合・保存 | 新設 | -| 尺の計算(`release/assets/slides/lib/script-time.js`) | 台本を `deck-frame.js` の読み込みで読み、ページごとと合計の字数と尺を出す。上限を超えたら終了コード 1 | 新設 | -| 汎用テンプレートの見本(`release/assets/slides/build-deck.js` と `script.md`) | 表紙・章扉・本編(表と注を含む)の 3 ページを作る見本。写した後に資料の中身へ書き換える出発点 | 新設 | -| 依存の宣言(`release/assets/slides/package.json`・`package-lock.json`) | pptxgenjs の版を固定する。資料へ写して `npm ci` で入れる | 新設 | -| Google Drive の手順(`document-systems/references/system-gdrive.md`) | 投稿の手段に「pptx を上げて Google Slides へ変換する・同じ URL のまま差し替える」順を、描画して見る手段に「Google Slides はページごとのサムネイル」を書き、コマンドは `google-workspace` の対応表を指す | 変更 | -| gws の操作の対応表(`google-workspace/SKILL.md`) | pptx の変換(`files copy` と `mimeType`)・同じ URL のままの差し替え(`files update --upload`。pptx のあるディレクトリで打つ)・ページの ID の取得(`slides presentations get`)・サムネイルの取得(スクリプト)の行を足す | 変更 | -| サムネイルの取得(`google-workspace/scripts/slides-thumbnails.py`) | Google Slides の全ページの ID を取り、ページごとにサムネイルを取得して PNG を保存し、結果 JSON で保存先を返す | 新設 | -| 体裁レビュー(`layout-review/SKILL.md`) | 描画して見る手段の表の「Google スライド / ドキュメント」の行を分け、Google スライドはページごとのサムネイル(`system-gdrive.md`)とする | 変更 | -| 発表資料の置き場の説明(`docs/presentations/README.md`) | 資料一覧へ発表資料を足し、「新しい資料を追加するとき」に生成スクリプトの資料(ディレクトリの形)を足す | 変更 | -| 発表資料(`docs/presentations/<日付>-skill-plugin-development/`) | README・構成メモ・台本・`slides/`(生成スクリプト・トーン&マナーのファイル・写した枠組み・依存の宣言) | 新設 | -| テストと継続的統合(`release/tests/test_slide_template.py`・`google-workspace/tests/test_slides_thumbnails.py`・`tests/test_presentation_decks.py`・`conftest.py`・`.github/workflows/pytest.yml`・`.gitignore`) | 生成を実行して pptx を検査する。CI に Node.js 22 と `npm ci` を足し、`node` を前提のコマンドに足す。`node_modules/` と生成した pptx を追跡から外す | 新設・変更 | - -**当てはまるため変えない規則。** `layout-review` の「既知の失敗のリストでは足りない」(描画して見る理由は経路に依らない)、 -`document-drafting` と `layout-common.md` の「版面・書体・色をソースへ埋めない」(生成スクリプトの経路では `theme.json` が -受け、I3 がこれを守る)、`layout-common.md` の「図表の種類は生成の経路が決める」(pptxgenjs は Mermaid を描かないため、 -図は図形か画像で組む)、`import.md` の「Markdown → 生成の手段が無い」(Markdown からの変換は今も無い)。 - -### 構成要素図 - -```mermaid -graph TD - subgraph 規約["既存の規約(足す)"] - LC[体裁設計の共通規則] - LS[スライドの体裁設計] - FS[スライドの生成] - DF[配布の形の一覧] - GD[Google Drive の手順] - LR[体裁レビュー] - GW[gws の操作の対応表] - end - subgraph テンプレート["汎用テンプレート(新設)"] - FR[枠組み deck-frame] - ST[尺の計算] - SB[見本 build-deck と台本] - PK[依存の宣言] - end - PR[発表資料の置き場の説明] - subgraph 資料["発表資料(新設)"] - DB[生成スクリプト] - TH[トーン&マナーのファイル] - CP[写した枠組み] - MM[構成メモ] - SC[台本] - end - TS[サムネイルの取得] - T[テストと継続的統合] - LC --> LS --> FS - DF --> FS - FS --> FR - FS --> GD --> GW --> TS - LR --> GD - FR -. 写す .-> CP - PK -. 写す .-> DB - SB --> FR - ST --> FR - DB --> CP - DB --> TH - CP --> SC - MM --> SC - PR --> DB - T --> FR - T --> TS - T --> DB -``` - -### 文脈 - -```mermaid -graph LR - 利用者 --> AI[スライドを作る AI] - AI --> 本体[NDF の規約と汎用テンプレート] - AI --> 資料[プロジェクトの資料] - 資料 --> npm[npm レジストリ pptxgenjs] - AI --> gws[gws] - gws --> Drive[利用者の Google Drive と Google Slides] - 台本の正本[台本の Google ドキュメント] --> AI -``` - -外部の系は npm レジストリ・gws・利用者の Drive・台本の Google ドキュメントで、どれもこの変更では変えない。 - -### 配置 - -```mermaid -graph TD - subgraph 作業の端末 - N[node と pptxgenjs] - P[python3 と gws] - F[作業ディレクトリの pptx と PNG] - end - subgraph Google - D[Drive の非公開の場所] - S[Slides API] - end - N -- pptx を書く --> F - P -- pptx を上げる・変換を頼む --> D - P -- ページの ID とサムネイルを頼む --> S - S -- 一時的な画像の URL --> P - P -- PNG を保存する --> F -``` - -境界をまたぐのは pptx・ページの ID・サムネイルの画像だけである。認証は gws が自分の設定ディレクトリに持ち、 -スクリプトはトークンを読まない(C1)。アップロード先はフォルダを指定しない(非公開)か、共有範囲を確かめた -利用者の既存の非公開フォルダに限る(要求の前提 4、`google-workspace` の手順)。 - -### 置き場所 - -```text -plugins/ndf/skills/ -├── design/references/ -│ ├── layout-common.md # 変更 -│ └── layout-slide.md # 変更 -├── release/ -│ ├── references/ -│ │ ├── distribution-forms.md # 変更 -│ │ └── form-slide.md # 変更 -│ ├── assets/slides/ # 新設(汎用テンプレート) -│ │ ├── build-deck.js -│ │ ├── script.md -│ │ ├── package.json -│ │ ├── package-lock.json -│ │ └── lib/ -│ │ ├── deck-frame.js -│ │ └── script-time.js -│ └── tests/test_slide_template.py # 新設 -├── document-systems/references/system-gdrive.md # 変更 -├── google-workspace/ -│ ├── SKILL.md # 変更 -│ ├── scripts/slides-thumbnails.py # 新設 -│ └── tests/test_slides_thumbnails.py # 新設 -└── layout-review/SKILL.md # 変更 - -docs/presentations/ -├── README.md # 変更 -└── <日付>-skill-plugin-development/ # 新設 - ├── README.md # 成果物・トーン&マナー・写した時点の lib/ の内容のハッシュ・生成と変換の手順・尺の出力 - ├── notes.md # 構成メモ(23 行) - ├── script.md # 台本(第 7 稿の写し) - └── slides/ - ├── build-deck.js - ├── theme.json - ├── package.json - ├── package-lock.json - └── lib/ # release/assets/slides/lib/ の写し - ├── deck-frame.js - └── script-time.js - -tests/test_presentation_decks.py # 新設 -conftest.py・.github/workflows/pytest.yml・.gitignore # 変更 -``` - -検査の手段: `claude plugin validate .`・`python3 scripts/check-skill-frontmatter.py`・`python3 plugins/ndf/scripts/doc-lint.py` -(受け入れ条件 15)と、下のテスト設計の pytest。 - -## 構造 - -`deck-frame.js` が公開する型と関数だけを描く。ページの中身(資料ごとの図形)は描かない。 - -```mermaid -classDiagram - class Theme { - font - colors 項目名と値 - sizes 項目名と pt - copyright - logo - } - class Frame { - <<定数>> - title 0.26 0.15 8.29 0.63 - rule 0.24 0.80 9.52 - logo 8.78 0.24 0.96 0.23 - copyright 0.26 5.18 - pageNo 9.27 5.18 右寄せ - note 0.26 4.88 9.5 0.28 - } - class Script { - pages 番号 見出し 読み上げ 配分秒数 - } - class Deck { - cover(title, sub, meta) - page(title, lead) Slide - section(title, sub) - box(slide, x, y, w, h, fill, line) - note(slide, text) - tbl(slide, rows, opt) - callout(slide, y, h, fill, head, body) - color(name) 値 - save(out) - } - Deck --> Theme : 既定値に theme.json を重ねる - Deck --> Frame : 座標を読む - Deck --> Script : ページ番号でノートを付ける -``` - -- `createDeck({ theme, script, title, author })` が `Deck` を返す。`theme` は `theme.json` のパスか値、`script` は台本のパス(省略するとノートを付けない) -- `fill` は `theme.colors` の項目名で受ける(I3)。項目名でない値を渡したら例外で止める -- 座標は `Frame` の定数だけが持ち、`Theme` は座標を持たない(I1) - -## 入出力の契約 - -### 体裁設計から生成へ渡す値 - -`layout-common.md` の「決めた値の書き先」のとおり、決めた値は設計文書の入出力の契約に書き、生成スクリプトの経路では -`theme.json` へ写す。 - -### トーン&マナーのファイル(`slides/theme.json`) - -書いた項目だけが既定値を上書きする。`colors` と `sizes` は項目ごとに重ね、ほかは値ごと置き換える。知らない項目名は -終了コード 1 で止める(書き損じが既定値のまま通らないようにする)。 - -| 項目 | 型 | 既定値 | 意味 | -| --- | --- | --- | --- | -| `font` | 文字列 | `Noto Sans JP` | 見出しと本文の書体 | -| `colors.accent` | 6 桁の 16 進 | `2B6CB0` | 強調の 1 色(表紙と章扉の帯・アクセントの線) | -| `colors.text` / `colors.ink` / `colors.mute` | 同上 | `000000` / `303030` / `7F7F7F` | 見出しの文字 / 本文の文字 / 注と著作権表示 | -| `colors.rule` | 同上 | `D9D9D9` | 罫線と表の枠 | -| `colors.panel1` / `colors.panel2` | 同上 | `F3F3F3` / `EEEEEE` | 区画の地 | -| `colors.warn` / `colors.caution` | 同上 | `F4CCCC` / `FFF2CC` | 注意を促す地(増加・条件) | -| `colors.header` | 同上 | `303030` | 表の見出し行の地(文字は白) | -| `sizes.title` / `sizes.lead` / `sizes.body` / `sizes.table` / `sizes.note` / `sizes.footer` | pt | `20` / `12` / `10` / `10` / `8` / `9` | 見出し / リード / 本文 / 表 / 注 / 著作権表示とページ番号 | -| `sizes.sectionTitle` / `sizes.sectionSub` / `sizes.coverTitle` / `sizes.coverSub` | pt | `32` / `14` / `28` / `16` | 章扉と表紙 | -| `copyright` | 文字列 | `""` | 著作権表示。空なら描かない | -| `logo` | 文字列か `null` | `null` | ロゴの PNG の、`theme.json` からの相対パス。`null` なら描かない | - -既定値の正本は `deck-frame.js` の既定のトーン&マナーの定数で、規約は項目の意味だけを書き、値を写さない。 - -### 台本(`script.md`) - -| 規則 | 内容 | -| --- | --- | -| ページの区切り | `## <番号>. <見出し>` の行。番号は 1 から欠けずに続く。見出しの末尾に `(<秒>秒)` を付けると配分秒数になる | -| 読み上げ | 区切りの中の `>` で始まる行。`>` だけの行は段落の区切り。スピーカーノートは読み上げの段落を改行でつないだ文 | -| ほかの行 | ページに載せる要素の覚え書き。ノートにも字数にも入れない | -| 最初の区切りより前 | 題・想定・構成の表。読まない | -| 章扉 | 台本に区切りを置かない。生成スクリプトの `section` が作り、ノートを持たず、台本の番号を進めない(決定 14) | -| 失敗 | 区切りが 1 つも無い・番号が欠ける・重なる → 終了コード 2 と、どの番号かを出す | - -### 構成メモ(`notes.md`) - -`## 構成` の節に、構成の考え方(何から逆算し、何を載せず、どこへ回したか)と、次の表を置く。表の行数はページ数と等しい。 - -```markdown -| # | 見出し | 役割 | 根拠 | -| ---: | --- | --- | --- | -| 1 | 表紙 | — | — | -| 2 | <台本の見出し> | <このページで聞き手に何を渡すか。載せる図・表・箇条書き> | <数値と主張の出所> | -``` - -ページに収まらない読み上げの削り方と、尺を超えたときに削るページは同じ文書の節に書く(要求の前提 3)。 - -### コマンド - -| コマンド | 入力 | 出力 | 終了コード | -| --- | --- | --- | --- | -| `node slides/build-deck.js <出力>.pptx []` | 出力のパス。トーン&マナーのファイル(省略時は `slides/theme.json`、無ければ既定値) | pptx | 0 成功 / 1 引数・`theme.json`・ページ数の照合(I5)の失敗 / 2 台本の形の失敗 | -| `node slides/lib/script-time.js <台本> [--wpm 350] [--limit <分>] [--json]` | 台本のパス | 既定は Markdown の表(ページごとの番号・見出し・字数・尺の秒・配分秒数と合計の行)。`--json` は同じ値の JSON | 0 / 1 合計が上限を超えた / 2 台本の形の失敗 | -| `python3 "$SKILL_DIR/scripts/slides-thumbnails.py" <出力のディレクトリ> [--size LARGE]` | Google Slides の ID | `p<番号>.png` をページ順に保存。結果 JSON(`tool`・`status`・`summary`・`items` にページごとの `objectId` とパス・`metrics.pages`) | 0 / 1 gws の失敗(gws の出力を `items` に載せる)/ 2 引数の失敗 / 11 gws が未認証(`gws-check.py` と同じ値) | - -gws の変換と差し替えのコマンドは `google-workspace` の対応表に置く(形は手本の README と同じ。`files update` の -`--upload` は作業ディレクトリの外のファイルを受けないため、pptx のあるディレクトリで打つ)。 - -## 処理の流れ - -```mermaid -sequenceDiagram - participant AI as スライドを作る AI - participant R as 規約(layout-slide → form-slide) - participant T as 汎用テンプレート - participant D as 資料のディレクトリ - participant G as gws と Google - participant L as 体裁レビュー - AI->>R: 体裁設計の項目を決める(E1) - AI->>T: build-deck.js・lib/・package*.json を写す - AI->>D: theme.json を書き、npm ci(E2) - AI->>D: 構成メモと台本を書く - AI->>D: script-time.js で尺を測る(E3) - alt 尺が上限を超える - AI->>D: 構成メモで削るページを決めて台本を直す - end - AI->>D: node build-deck.js で pptx(E4) - AI->>G: 上げて変換、または同じ URL のまま差し替え(E5) - AI->>G: slides-thumbnails.py でページごとの PNG - AI->>L: PNG を見て記録を残す(E6) - alt 文字あふれ・重なり - L-->>AI: 差し戻し(体裁設計・生成・執筆) - end - AI->>D: コミット(E7) -``` - -既にプロジェクトに生成スクリプト(`slides/build-deck.js`)があるときは、汎用テンプレートを写さずにそれに従う -(`form-slide.md` の「対象リポジトリの仕組みを先に探す」と同じ)。 - -## 非機能の実現方式 - -| 大項目 | 要求の条件 | 実現方式 | 確かめ方 | -| --- | --- | --- | --- | -| 運用・保守性 | トーン&マナーの差し替えはプロジェクト側の値だけを書けば済み、汎用テンプレートの更新を取り込むときにプロジェクトの値が上書きされない | プロジェクトの値は `slides/theme.json` だけに置き、枠組みは `slides/lib/` へ写して書き換えない。更新の取り込みは `lib/` の写し直しだけで、`theme.json` に触れない | `theme.json` を置いた資料で `lib/` を写し直して生成し、差し替えた書体と色が pptx に残ることをテストで見る | -| セキュリティ | 生成スクリプト・規約・発表資料に Drive のフォルダ ID・ファイル ID・トークンを書かない。gws の認証情報をリポジトリに置かない(C1) | 規約と README の例は `<フォルダID>` の形にする。Google Slides の ID は引数でだけ受け、発表資料の README には置かない(URL は PR の記録に書く)。スクリプトはトークンを読まない | 完了判定で差分の追加行を `docs.google.com/.*/d/[A-Za-z0-9_-]{20,}` と `"fileId":"[A-Za-z0-9_-]{20,}"` で検索して 0 件 | -| システム環境 | Node.js 22(CI が使う版)と pptxgenjs で動く。依存の宣言の置き方は設計が決める | 依存は汎用テンプレートと資料の `slides/package.json` と `package-lock.json` で pptxgenjs `4.0.1` に固定する。CI の pytest に `actions/setup-node` の 22 と `npm ci` を足す | CI の pytest が Node.js 22 で生成のテストを通す | - -## 決定の記録 - -決定の記録は [issue-2065-design-decisions.md](issue-2065-design-decisions.md) にある(決定 1〜14。決定 3 は決定 12・13 が置き換えた)。 - -## テスト設計 - -| 受け入れ条件・不変条件 | どの振る舞いで縛るか | どう壊したら落ちるべきか | -| --- | --- | --- | -| 受け入れ条件 1 | `plugins/ndf/manifests/*-skills.txt` の行数が develop と同じ(完了判定のコマンド) | manifests に行を足すと差が出る | -| 受け入れ条件 2・9 | `doc-lint.py` が参照切れを見る。`layout-slide.md` → `form-slide.md` → 汎用テンプレートと `system-gdrive.md` → `google-workspace`、`layout-review` → `system-gdrive.md` の経路をレビューで辿る | リンク先のファイル名を変えると `doc-lint.py` が落ちる | -| 受け入れ条件 3 | 汎用テンプレートの見本を生成すると終了コード 0 で、版面が 10 × 5.625 インチ、ページが 3 つ(表紙・章扉・本編)、本編に表と注がある | 版面の指定を外す・章扉を作らない・表を外すと落ちる | -| 受け入れ条件 4・I1 | 本編のページの見出し・罫線・著作権表示・ページ番号・注の位置が手本の座標(インチ)と一致し、`theme.json` で書体と色と文字の大きさを変えても位置が変わらない | 座標の定数を変える・トーン&マナーの値で座標を動かすと落ちる | -| 受け入れ条件 5・I2・I3 | 書体・色・著作権表示・ロゴを差し替えた `theme.json` で生成すると、全ページの XML の書体名と色が差し替えた値だけになり、既定値が残らない。`lib/` を写し直しても同じ結果になる | 枠組みか見本に書体名・色を直書きすると落ちる。`theme.json` の項目を重ねずに丸ごと置き換えると、書いていない既定値が欠けて落ちる | -| `theme.json` の知らない項目 | 知らない項目名を書くと終了コード 1 で、項目名を出す | 知らない項目を読み捨てると落ちる | -| I4・受け入れ条件 11 | 発表資料を生成すると 23 ページすべてにノートがあり、各ノートが `script.md` の同じ番号の読み上げと一致する | ノートを生成スクリプトに写して食い違わせる・番号をずらすと落ちる | -| I5 | 台本のページ数と、章扉を除いて作ったページ数が違うと、生成が終了コード 1 で両方の数と章扉の数を出す。章扉はノートを持たず、章扉の後のページは台本の次の番号の読み上げを受ける。発表資料は章扉を除く 23 ページが台本と一致する | 照合を外す・章扉で台本の番号を進める・章扉にノートを付けると落ちる | -| 台本の形の失敗 | 区切りの番号が欠ける・重なる台本で、生成と尺の計算が終了コード 2 と番号を出す | 欠けた番号を読み飛ばすと落ちる | -| I6・受け入れ条件 7 | 読み上げの字数が分かっている台本で、ページごとの字数と秒(350 字/分)と合計が期待どおりで、合計がページの和に等しい。`--limit` を下回る値にすると終了コード 1 | 空白や強調の記号を字数に数える・`>` 以外の行を数えると落ちる | -| 受け入れ条件 6 | 発表資料の `notes.md` の構成の表が 23 行で、番号が 1〜23(`tests/test_presentation_decks.py` が表を数える) | 行を欠かすと落ちる | -| 受け入れ条件 10 | 発表資料を生成すると終了コード 0 で 23 ページ。生成スクリプトが `./lib/deck-frame.js` を読み、`lib/` が汎用テンプレートの `lib/` と同じ内容で写されている(作った時点で比べる。以後は追随しない) | 枠組みを使わずに組むと落ちる | -| 受け入れ条件 8 | 規約に書いた gws のコマンド(変換・差し替え・ページの ID・サムネイル)を実装の作業で実際に打ち、打ったコマンドと終了コードを実装の PR に残す | — (手作業の記録) | -| サムネイルの取得 | 偽の gws を前にした実行で、ページの ID の順に `p<番号>.png` を保存し、結果 JSON にページ数と保存先が出る。gws が失敗すると終了コード 1 で gws の出力が `items` に載る。未認証は 11 | gws の失敗を成功として返す・ページの順を崩すと落ちる | -| 受け入れ条件 12 | 発表資料を Google Slides へ変換し、23 ページのサムネイルを見た体裁レビューの記録(`layout-review` の形)を PR に残す。差し戻した後のサムネイルで文字あふれと重なりが 0 件 | — (人が見る。承認ゲート 2 で利用者も見る) | -| 受け入れ条件 13・I7 | 完了判定で `git diff develop -- plugins/ docs/presentations/` の追加行を手本の社名・案件名・手本のコーポレートカラーの値で検索して 0 件 | — (完了判定のコマンド) | -| 受け入れ条件 14 | 完了判定で追加・変更した行をページの数え方の和語(受け入れ条件 14 の語)で検索して 0 件 | — (完了判定のコマンド) | -| 受け入れ条件 15 | 受け入れ条件の 5 つのコマンドが終了コード 0。`git diff develop --stat -- docs/presentations/2026-08-06-ai-plugins-intro.*` が空(`build.sh` は決定 12 で消す) | 2026-08-06 の資料に触れると差が出る | - -`.md` の文言を照合するテストは書かない(`AGENTS.md` の DON'T)。`notes.md` の表を数えるのは構成メモの行数(受け入れ条件 6) -の検査であり、文言は照合しない。 - -## 設計の結果 - -| 課題 | 扱い | 取り込み先 | 触るファイル | -| --- | --- | --- | --- | -| #2065 | 実装する | — | `plugins/ndf/skills/design/references/layout-common.md`、`plugins/ndf/skills/design/references/layout-slide.md`、`plugins/ndf/skills/release/references/form-slide.md`、`plugins/ndf/skills/release/references/distribution-forms.md`、`plugins/ndf/skills/release/assets/slides/`、`plugins/ndf/skills/release/tests/`、`plugins/ndf/skills/document-systems/references/system-gdrive.md`、`plugins/ndf/skills/google-workspace/`、`plugins/ndf/skills/layout-review/SKILL.md`、`docs/presentations/README.md`、`docs/presentations/`、`tests/test_presentation_decks.py`、`conftest.py`、`.github/workflows/pytest.yml`、`.gitignore`、`docs/glossary.md`、`docs/glossary/glossary.json` | - -## 未確認のまま残ること - -| 項目 | 内容 | -| --- | --- | -| 発表資料のディレクトリの日付 | 発表日が未定。承認ゲート 1 で利用者が日付を示さなければ、台本を確定した日 `2026-10-17` を使う(`docs/presentations/README.md` の `YYYY-MM-DD-` の形) | -| 発表資料の著作権表示 | 発表資料の `theme.json` の `copyright` の文言(例: `NDF — github.com/devbasex/ai-plugins`)。承認ゲート 1 で利用者が示さなければこの例を使う | -| gws の実際の変換と差し替え | 設計では `--dry-run` で要求の形だけを確かめた。実際に上げて変換・差し替え・サムネイルを取るのは実装の作業で、打ったコマンドと結果を実装の PR に残す(受け入れ条件 8) | -| Noto Sans JP の変換後の見え方 | pptx の書体名 `Noto Sans JP` が Google Slides で代替されずに描かれるかは、変換したサムネイルで確かめる。代替されたら `layout-review` の「書体の代替」の手順で、配布先(Google Slides)で起きる欠けとして生成へ戻し、既定の書体を選び直す | -| サムネイルの一時的な URL の扱い | `getThumbnail` が返す画像の URL を認証なしで取れるかは、実装で 1 度打って確かめる。取れなければ gws の認証付きの取得へ切り替える | -| 台本の写しと正本の一致 | 台本の正本は第 7 稿の Google ドキュメントである。実装でドキュメントをテキストで書き出し、`script.md` の読み上げと突き合わせた結果を PR に残す(要求の前提 3) | -| 図の多いページの組み方 | 台本の 6・8・14 ページなどは図が要る。pptxgenjs は Mermaid を描かないため、図形で組むか画像を貼るかを実装でページごとに決め、構成メモの「役割」に書く | diff --git a/issues/issue-2065-requirements.md b/issues/issue-2065-requirements.md deleted file mode 100644 index f40adf697..000000000 --- a/issues/issue-2065-requirements.md +++ /dev/null @@ -1,189 +0,0 @@ -# #2065: スライドを作る実務の手順(生成スクリプト・ページの枠組み・トーン&マナー・構成メモ・gws での変換と確認)を Skill に取り込む - -正は課題の本文(#2065)で、この文書はその写しである。`spec-copy.py write` で作り直す。手で直さない。 - -## 何をしたいか - -スライド(発表資料・提案資料)を作る実務の手順を NDF の Skill に取り込む。手本は nyle-dx(`/work/nyle-dx` の `edp/slides`・`mdx/security/slides`・`fde/presentation`)の作り方で、次を持つ。 - -| 要素 | nyle-dx での形 | -| --- | --- | -| 生成 | pptxgenjs の生成スクリプト `slides/build-deck.js`。版面 10 × 5.625 インチ(16:9) | -| ページの枠組み | 共通の関数 `page` / `box` / `note` / `tbl` / `section`(見出し・罫線・ロゴ・著作権表示・ページ番号の位置を固定) | -| トーン&マナー | 書体・色・文字サイズを定数で持ち、README に表で書く | -| 構成メモ | ページごとの見出し・役割・根拠の表(`04-presentation-notes.md`)と、読み上げの台本。スピーカーノートへ入れる | -| 変換と確認 | `gws drive +upload` → `gws drive files copy`(mimeType を Google Slides に)で変換し、`gws slides presentations pages getThumbnail` でページごとに見る | - -NDF の今の Skill はスライドの原則(`design/references/layout-slide.md`・`release/references/form-slide.md`・`layout-review`)だけを持ち、上の実務の手順を持たない。 - -## 方針(利用者の決定 2026-10-17) - -- 新しい Skill を作る前に、既存のスライドの規約(`layout-slide.md`・`form-slide.md`・`layout-review`・`document-systems` の `system-gdrive.md`)への統合を優先する -- トーン&マナーは会社色を持たない汎用のテンプレートを既定にし、プロジェクトごとに差し替えられるようにする -- 取り込んだ手順で、発表資料「独自スキルプラグイン開発の薦め」(台本は第 7 稿 https://docs.google.com/document/d/13nNf3sLjMtrp7WZKHPFD_KW-sv-v5xv5kno2pICfP3U/edit )を `docs/presentations/` に作る -- (2026-10-18 追加)Marp(Markdown を変換器でスライドにする経路)はこのプラグインから外す。変換後のスライドが編集できないのは致命的なため。外す範囲は規約とリポジトリの両方: `form-slide.md` 等のスライドの生成の経路から「変換器を使う」を外して生成スクリプトを既定にし、`docs/presentations/` の README・`build.sh`・`AGENTS.md` の Marp の記述を生成スクリプトの方式へ書き換える。2026-08-06 の資料は発表日時点の記録として残す -- (2026-10-18 追加)python-pptx も pptxgenjs に比べて利点が無いため外す。スライドの生成の経路は「生成スクリプトを書く(pptxgenjs)」の 1 つだけにし、「AI エージェントが組む」をスライドから外す(文書・表計算・ページの形の経路は変えない)。`official-skills-autoloader` は「スライドを新しく作る」依頼を `release` の `form-slide.md` へ回し、公式の `pptx` Skill は既存の .pptx を読む・直すときだけに使う - -## 由来 - -2026-10-17 の会話で、python-pptx で独自に組んだ資料に利用者が「slide の作り方が違う。/work/nyle-dx を参考に。Skill 化した方が良いかも」と指摘した。 - ---- - -# 要求と受け入れ条件 - -## 依頼(原文) - -> slide の作り方が違う。/work/nyle-dx を参考に。Skill 化した方が良いかも - -(書き手: 利用者、日付: 2026-10-17。python-pptx で組んだ試作への指摘。起票者が「由来」の節に写した文) - -> 新しい Skill を作る前に既存のスライドの規約(plugins/ndf/skills/design/references/layout-slide.md・release/references/form-slide.md・layout-review・document-systems の system-gdrive.md)への統合を優先する。トーン&マナーは会社色の無い汎用テンプレートを既定にし、版面と枠組みの関数(page/box/note/tbl/section)は nyle-dx を踏襲、プロジェクトごとに差し替えられるようにする - -(書き手: 利用者(2026-10-17 の決定)を AI の起動指示が引継ぎ文書 `.ndf/handoff/issue-2065.md` から写したもの、日付: 2026-10-17) - -> 取り込んだ手順で発表資料「独自スキルプラグイン開発の薦め」(社外の勉強会・登壇向け、23 ページ、台本は第 7 稿 https://docs.google.com/document/d/13nNf3sLjMtrp7WZKHPFD_KW-sv-v5xv5kno2pICfP3U/edit )を docs/presentations/ に作る(README・構成メモ・台本・slides/build-deck.js、Google Slides に変換してサムネイルで確かめる)。これも受け入れ条件に含める - -(書き手: AI の起動指示(引継ぎ文書の利用者の決定「先に Skill 化し、それで発表資料を作る」「置き場は ai-plugins の docs/presentations/」「台本は第 7 稿で確定扱い(23 ページ)」を写したもの)、日付: 2026-10-17) - -> 文言は直訳の和語を避け業界の語にする(枚→ページ・課題→Issue)。事例のプロジェクトは種類で呼び、名前(nyle-dx を含む社名・案件名)を Skill 本文と発表資料に出さない -> -> python-pptx で独自に組む方式は利用者が却下した(pptxgenjs の生成スクリプト方式にする) - -(書き手: AI の起動指示、日付: 2026-10-17。「事例のプロジェクトは種類で呼び名前を出さない」は台本第 7 稿の冒頭にもある利用者の方針、「Skill 本文にも名前を出さない」は起動指示が足した範囲) - -## 起票者の推定 - -| # | 条件 | 推した出所 | この要求での扱い | -| --- | --- | --- | --- | -| S1 | 構成メモに「根拠」の列を持たせ、台本をスピーカーノートへ入れる | 課題の本文の表(手本 `mdx/security/04-presentation-notes.md` と `addNotes` から起票者が抜き出した) | 受け入れ条件 6・7 | -| S2 | 変換は `+upload` → `files copy`(mimeType 指定)、確認は `getThumbnail` の経路で行う | 課題の本文の表(手本の README から) | 受け入れ条件 8・9 | -| S3 | 尺は 350 字/分で測る | 起動指示の材料(手本 `fde/presentation/README.md`) | 受け入れ条件 7 | -| S4 | Skill 本文にも事例のプロジェクト名・社名を出さない | 起動指示(台本の方針は発表資料について言っている) | 受け入れ条件 12 | - -## 目的 - -- AI がスライドを作るとき、毎回その場で作り方を組み立てず(python-pptx の自作など)、NDF の規約に従って、生成スクリプト・ページの枠組み・トーン&マナー・構成メモ・台本・変換と確認の手順をそろえた形で作れるようにする -- その手順を実際に通して、発表資料「独自スキルプラグイン開発の薦め」を作り、手順が通ることを示す - -## 前提 - -- 前提 1: 生成は pptxgenjs の生成スクリプト(Node.js)で行う。python-pptx で組む方式と、AI エージェントがその場で組む方式は採らない(方針の 2026-10-18 追加)。Marp の経路はこの課題で外す(方針の 2026-10-18 追加) -- 前提 2: 汎用テンプレートの版面(10 × 5.625 インチ)と枠組みの関数の座標は手本の値を踏襲する。書体・色・著作権表示の文言・ロゴは会社に由来しない値を既定にする(書体は配布先の環境と Google Slides で使える書体から設計で選ぶ) -- 前提 3: 台本の正本は第 7 稿の Google ドキュメントである。作成時はドキュメントから取得し、手元の写し(会話の作業ディレクトリの `script-v7.md`)と食い違えばドキュメントを採る。台本はページごとの見出しと読み上げを持つが、ページに載せる要素(図・表・箇条書き)は持たないため、ページの中身は作成時に台本から起こし、構成メモの「役割」「根拠」に書く -- 前提 4: Google Slides への変換は、利用者の Drive の非公開の場所(フォルダを指定しないアップロード、または利用者の既存の非公開フォルダ)に置く。共有・公開範囲の設定はこの課題で行わない -- 前提 5: gws は利用者のアカウントで認証済みである(引継ぎ文書)。認証が切れていれば `google-workspace` の手順で利用者に再認証を頼み、変換と確認の受け入れ条件はそれまで未達とする -- 前提 6: `docs/presentations/` は `main` へ入ると GitHub Pages で公開される(`docs/presentations/README.md`)。発表資料は社外向けで、公開されてよい内容だけを置く -- 前提 7: 規約の文言のうち、この課題で追加・変更する行は「枚」を「ページ」にする。触らない行の言い換えはこの課題の範囲外とする - -## 対象範囲 - -含む: -- 既存のスライドの規約(`design/references/layout-slide.md`・`release/references/form-slide.md`・`layout-review`・`document-systems/references/system-gdrive.md`)へ、生成スクリプト・ページの枠組み・トーン&マナー・構成メモ・台本・gws での変換とサムネイル確認の手順を足す -- 会社色を持たない汎用テンプレートの生成スクリプト(pptxgenjs)と、トーン&マナーの値をプロジェクトごとに差し替える手段 -- 台本の字数と尺(350 字/分)を数える手段 -- `docs/presentations/` の発表資料「独自スキルプラグイン開発の薦め」一式(README・構成メモ・台本・`slides/build-deck.js`)と、`docs/presentations/README.md` の資料一覧への追加 -- Google Slides への変換と、全ページのサムネイルによる体裁レビューの記録 - -含まない: -- 新しい Skill の新設(統合で足りないと設計が示した場合だけ、設計 PR で理由を添えて扱う) -- python-pptx・LibreOffice による生成の経路の追加と、既存の Marp 資料(`2026-08-06-ai-plugins-intro` の md・html・pdf)の削除や書き換え -- 発表資料の共有設定・登壇先への提出・`index.html`(公開ページの入口)以外の公開操作 -- 台本の内容の書き直し(第 7 稿を確定として使う。ページに収まらない場合の削り方は前提 3 の範囲で構成メモに書く) -- 規約の既存の行の「枚」の言い換え(前提 7) - -## ドメインイベント - -| # | イベント | 引き金 | 失敗したとき | 順序の前提 | -| --- | --- | --- | --- | --- | -| E1 | 体裁設計で版面・トーン&マナー・ページの枠組みを決めた | スライドを作る依頼 | プロジェクトに既存の資料が無い → 汎用テンプレートの既定値を使う | — | -| E2 | 汎用テンプレートから生成スクリプトを用意し、トーン&マナーをプロジェクトの値へ差し替えた | E1 の決定 | 差し替える値が欠ける → 既定値のまま生成し、欠けた項目を README に書く | E1 | -| E3 | 構成メモ(ページごとの見出し・役割・根拠)と台本を書き、尺を測った | 内容の確定 | 尺が持ち時間を超える → 構成メモで削るページを決める | E1 | -| E4 | 生成スクリプトで pptx を作った | E2・E3 の完了 | Node.js か pptxgenjs が無い → 導入の手順を示して止める | E2・E3 | -| E5 | pptx を Drive へ上げ、Google Slides へ変換した(既存の URL のまま差し替える場合を含む) | E4 の完了 | gws が未認証 → `google-workspace` の手順で利用者に認証を頼んで止める | E4 | -| E6 | ページごとのサムネイルを取り、体裁レビューの記録を残した | E5 の完了 | 文字あふれ・重なり → `layout-review` の差し戻し先(体裁設計・生成・執筆)へ戻す。サムネイルが取れない → 止めて人へ渡す | E5 | -| E7 | 生成スクリプト・構成メモ・台本・README をリポジトリへコミットした | E6 の完了 | — | E6 | - -## 用語 - -| 用語 | 意味 | -| --- | --- | -| トーン&マナー | スライドの書体・色・文字サイズ・著作権表示・ロゴの値の組。プロジェクトごとに差し替える | -| ページの枠組み | 見出し・罫線・ロゴ・著作権表示・ページ番号の位置を固定した、ページを作る共通の関数(`page` / `box` / `note` / `tbl` / `section`) | -| 生成スクリプト | pptx を出力するスクリプト(pptxgenjs の `build-deck.js`)。スライドの正本になる | -| 汎用テンプレート | 会社色を持たないトーン&マナーとページの枠組みを持つ、生成スクリプトの出発点 | -| 構成メモ | スライドのページごとの番号・見出し・役割・根拠の表と、構成の考え方を書いた文書 | -| 台本 | ページごとの読み上げの原稿と配分秒数。スピーカーノートへ入れる | - -## 受け入れ条件 - -- [ ] 1. `plugins/ndf/manifests/` の Skill の行が増えない(新設が要ると設計が判断した場合は、設計 PR に理由がある) -- [ ] 2. `layout-slide.md`・`form-slide.md`・`layout-review`・`system-gdrive.md` のどれかから、汎用テンプレート・トーン&マナーの差し替え・構成メモと台本の形・gws での変換とサムネイル確認の手順へ、リンクで辿れる -- [ ] 3. 汎用テンプレートの生成スクリプトを `node <スクリプト> <出力>.pptx` で実行すると、終了コード 0 で 16:9(10 × 5.625 インチ)の pptx が出る。出た pptx は表紙・章扉・本編(表と注を含む)のページを持つ -- [ ] 4. 汎用テンプレートは `page` / `box` / `note` / `tbl` / `section` の 5 つの関数を持ち、見出し・罫線・著作権表示・ページ番号の位置が手本と同じ座標になる -- [ ] 5. トーン&マナーの値(書体・色・著作権表示の文言・ロゴの有無)を、関数の本体を書き換えずに差し替えられる。値を差し替えて生成した pptx の XML(`ppt/slides/*.xml`)の書体名と色が、差し替えた値になる -- [ ] 6. 構成メモの形(ページごとの番号・見出し・役割・根拠の表)が規約にあり、発表資料の構成メモがその形で 23 行を持つ -- [ ] 7. 台本の字数と尺(350 字/分)を 1 つのコマンドでページごとと合計で出せる。発表資料の台本でそのコマンドを実行した出力が README か構成メモに載る -- [ ] 8. gws で pptx を Drive へ上げて Google Slides へ変換する手順と、既存の Google Slides を同じ URL のまま差し替える手順が規約にあり、規約に書いた各コマンドは書く前にこのリポジトリの作業で実行して確かめてある(実行した記録が設計か実装の PR にある) -- [ ] 9. Google Slides のページごとのサムネイルを取る手順が `layout-review` の描画の手段から辿れる -- [ ] 10. `docs/presentations/` に発表資料「独自スキルプラグイン開発の薦め」の README・構成メモ・台本・`slides/build-deck.js` があり、`node slides/build-deck.js <出力>.pptx` が終了コード 0 で 23 ページの pptx を出す。生成スクリプトは汎用テンプレートの枠組みとトーン&マナーを使う -- [ ] 11. 発表資料の 23 ページすべてにスピーカーノートがあり、その文が台本第 7 稿の各ページの読み上げと一致する -- [ ] 12. 発表資料を Google Slides へ変換し、23 ページすべてのサムネイルを見た体裁レビューの記録(`layout-review` の「見た結果を残す」の形)が PR にある。記録に残った文字あふれ・図の重なりは、差し戻して直した後のサムネイルで 0 件である -- [ ] 13. 追加・変更したファイル(規約・汎用テンプレート・発表資料)に、事例のプロジェクトの名前と社名(`nyle` / `Nyle` / `ナイル` と案件名)と手本のコーポレートカラー `95FF00` が出ない(`git diff develop -- <対象>` の追加行を grep して 0 件) -- [ ] 14. 追加・変更した行に、直訳の和語「枚」が出ない(ページの数え方は「ページ」) -- [ ] 15. 退行しない: `python3 scripts/check-skill-frontmatter.py`・`python3 plugins/ndf/scripts/instructions-check.py --root .`・`python3 plugins/ndf/scripts/doc-lint.py`(PR の差分に対して)・`uv run --frozen --project . --all-extras pytest . -q -n 4`・`claude plugin validate .` がすべて終了コード 0。既存の Marp 資料と `build.sh` に差分が無い -- [ ] 16. スライドの生成の経路から「変換器を使う」(Marp)が外れ、`plugins/` の規約と `docs/presentations/README.md`・`AGENTS.md` に Marp を使う手順が残らない(`git grep -i marp -- plugins/ AGENTS.md` はテストのデータを除いて 0 件。`docs/presentations/README.md` は 2026-08-06 の資料が Marp で作った記録だと示す行だけを残してよい)。`docs/presentations/build.sh` は消すか生成スクリプトの方式へ置き換える。2026-08-06 の資料の md・html・pdf は残す -- [ ] 17. スライドの生成の経路が「生成スクリプトを書く」の 1 つになり、`form-slide.md`・`layout-slide.md`・`layout-common.md`・`distribution-forms.md` にスライドを「AI エージェントが組む」経路と python-pptx が残らない(ほかの形の経路は変わらない)。`official-skills-autoloader` の対応表で、スライドの新規作成は `form-slide.md` へ、公式 `pptx` は既存の .pptx を読む・直す依頼だけへ振り分けられる - -## 非機能の条件 - -| 大項目 | 条件 | -| --- | --- | -| 運用・保守性 | トーン&マナーの差し替えはプロジェクト側の値だけを書けば済み、汎用テンプレートの更新を取り込むときにプロジェクトの値が上書きされない | -| セキュリティ | 生成スクリプト・規約・発表資料に、Drive のフォルダ ID・ファイル ID・トークンを書かない(例は `<フォルダID>` の形にする)。gws の認証情報はリポジトリに置かない(C1) | -| システム環境 | 生成は Node.js 22(CI が使う版)と pptxgenjs で動く。依存の宣言の置き方は設計が決める | - -## 影響 - -| 対象 | 影響 | -| --- | --- | -| 公開インタフェース | 変わらない(Skill の追加・削除・名前の変更が無い。規約の参照先が増える) | -| データ | 無し | -| 既存の振る舞い | スライドを作るときに AI が読む規約に、生成スクリプトと変換・確認の手順が加わる。Marp(変換器)の経路はスライドの規約とリポジトリの手順から外れる | - -## 検証手段 - -| 項目 | 手段 | -| --- | --- | -| 起動 | `node <汎用テンプレート> /tmp/t.pptx`、`node docs/presentations/<資料>/slides/build-deck.js /tmp/d.pptx`(パスは設計が決める) | -| テスト | `uv run --frozen --project . --all-extras pytest . -q -n 4`(生成した pptx のページ数・版面・書体と色の差し替えを確かめるテストを置くかは設計が決める) | -| 静的解析・型検査 | `python3 scripts/check-skill-frontmatter.py`・`python3 plugins/ndf/scripts/instructions-check.py --root .`・`python3 plugins/ndf/scripts/doc-lint.py`・`claude plugin validate .` | -| 手動確認(マージ前) | 実装者が Google Slides へ変換した発表資料の 23 ページのサムネイルを見て、体裁レビューの記録を PR に残す(受け入れ条件 12)。承認ゲート 2 で利用者がサムネイルか Google Slides を見る | -| 手動確認 | 利用者が Google Slides のプレゼンター表示でスピーカーノートが読めることを確かめる(リリース後テスト) | - -## 前提とする取り決め - -| 項目 | 参照先 / 決めたこと | -| --- | --- | -| プロジェクト構造 | Skill の手順は `plugins/ndf/skills/` の既存の規約へ足す(`CLAUDE.md` の「NDF の Skill 構成」)。発表資料は `docs/presentations/`(`AGENTS.md` の「ドキュメント」の表)。汎用テンプレートを Skill の配下に置くか `docs/` に置くかは設計が決める | -| コーディング規約 | Skill の frontmatter は `plugins/ndf/skills/AUTHORING.md`。文書は 1 語 1 意味(Value 8)と用語集。`.md` の文言を照合するテストは書かない(`AGENTS.md` の DON'T) | -| テスト戦略 | 生成スクリプトは実行して出力の pptx を検査する(振る舞いのテスト)。規約の文言は検査しない | - -## 境界 - -| 区分 | 内容 | -| --- | --- | -| 常に行う | 規約に書くコマンドを書く前に実行して確かめる。生成した pptx を Google Slides で描画して見る。既存の検査をすべて通す | -| 確認してから行う | 依存パッケージ(pptxgenjs)の宣言の追加、新しい Skill の新設(いずれも承認ゲート 1 の設計で示す) | -| 行わない | python-pptx での生成、台本の内容の書き直し、発表資料の共有設定、手本のリポジトリ(`/work/nyle-dx`)の変更、手本のロゴ・書体・色の複製 | - -## 未決 - -| 項目 | 誰が決めるか | 期限 | -| --- | --- | --- | -| 汎用テンプレートの置き場(Skill の assets か docs か)と、配布物に含めるか | 設計(承認ゲート 1 で利用者) | 設計 PR | -| トーン&マナーの差し替えの手段(設定ファイル・引数・プロジェクト側の定数のファイルなど) | 設計(承認ゲート 1 で利用者) | 設計 PR | -| 既定の書体と色の値 | 設計 | 設計 PR | -| 尺を数える手段をスクリプトにする場所(Value 4) | 設計 | 設計 PR | -| CI で生成スクリプトを実行するか(Node.js と pptxgenjs の導入) | 設計 | 設計 PR | -| 発表資料のファイル名(`YYYY-MM-DD-` の日付。発表日が未定) | 利用者(承認ゲート 1) | 設計 PR |