akari-video 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +1 -1
  2. package/vendor/.akari-capability-sources.json +8 -0
  3. package/vendor/docs/contract-2026-08-02-setup-remote-v0.md +13 -1
  4. package/vendor/docs/contract-2026-08-11-review-session-ui-events.md +19 -7
  5. package/vendor/docs/contract-2026-08-12-chat-approval-v0.md +99 -0
  6. package/vendor/docs/contract-2026-08-12-color-range-normalization-v0.md +59 -0
  7. package/vendor/docs/contract-2026-08-12-region-filter-layer-v0.md +98 -0
  8. package/vendor/packages/akari-launcher/package.json +1 -1
  9. package/vendor/packages/analysis-report/render-analysis-report.mjs +15 -0
  10. package/vendor/packages/chat-bridge/package.json +14 -0
  11. package/vendor/packages/chat-bridge/src/telegram.mjs +272 -0
  12. package/vendor/packages/overlay-runtime/README.md +48 -16
  13. package/vendor/packages/schemas/analysis.schema.json +9 -0
  14. package/vendor/packages/schemas/bin/validate-asset.mjs +51 -1
  15. package/vendor/packages/schemas/bin/validate-connections.mjs +1 -1
  16. package/vendor/packages/schemas/bin/validate-edit.mjs +41 -3
  17. package/vendor/packages/schemas/connections.schema.json +1 -1
  18. package/vendor/packages/schemas/edit.schema.json +59 -3
  19. package/vendor/packages/schemas/examples/connections-v0-invalid-kind/connections.json +33 -0
  20. package/vendor/packages/schemas/examples/connections-v0-notify-valid/connections.json +36 -0
  21. package/vendor/packages/schemas/examples/edit-layers-filter-invalid-lut-missing-id/edit.json +15 -0
  22. package/vendor/packages/schemas/examples/edit-layers-filter-invalid-missing-filter/edit.json +14 -0
  23. package/vendor/packages/schemas/examples/edit-layers-filter-invalid-src-present/edit.json +16 -0
  24. package/vendor/packages/schemas/examples/edit-layers-filter-invalid-unknown-type/edit.json +15 -0
  25. package/vendor/packages/schemas/examples/edit-layers-filter-invert-valid/edit.json +15 -0
  26. package/vendor/packages/schemas/examples/edit-layers-filter-lut-valid/edit.json +15 -0
  27. package/vendor/packages/schemas/examples/edit-layers-filter-saturation-valid/edit.json +19 -0
  28. package/vendor/packages/schemas/test/analysis-face-contour-pointer.test.mjs +19 -0
  29. package/vendor/packages/schemas/test/edit-layer-filter-schema.test.mjs +65 -0
  30. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-model-missing-glb/scene3d/hero-missing-glb/fragment.html +1 -0
  31. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-model-missing-glb/scene3d/hero-missing-glb/meta.json +23 -0
  32. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-model-missing-glb/scene3d/hero-missing-glb/preview.png +0 -0
  33. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-neither/scene3d/hero-neither/fragment.html +1 -0
  34. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-neither/scene3d/hero-neither/meta.json +23 -0
  35. package/vendor/packages/schemas/test/fixtures/asset/invalid-scene3d-neither/scene3d/hero-neither/preview.png +0 -0
  36. package/vendor/packages/schemas/test/fixtures/asset/valid-scene3d-texts-only/scene3d/hero-texts-only/fragment.html +1 -0
  37. package/vendor/packages/schemas/test/fixtures/asset/valid-scene3d-texts-only/scene3d/hero-texts-only/meta.json +23 -0
  38. package/vendor/packages/schemas/test/fixtures/asset/valid-scene3d-texts-only/scene3d/hero-texts-only/preview.png +0 -0
  39. package/vendor/packages/schemas/test/validate-asset.test.mjs +19 -0
  40. package/vendor/packages/schemas/test/validate-connections.test.mjs +15 -0
  41. package/vendor/skills/analyze-footage/bin/vision-tracks/vision-tracks-helper.swift +24 -8
  42. package/vendor/skills/analyze-footage/bin/vision-tracks/vision-tracks.mjs +1 -0
  43. package/vendor/skills/analyze-footage/references/vision-tracks.schema.json +14 -2
  44. package/vendor/skills/analyze-footage/test/fixtures/vision-tracks/dummy-helper.mjs +3 -0
  45. package/vendor/skills/analyze-footage/test/vision-tracks-assembly.test.mjs +5 -1
  46. package/vendor/skills/analyze-footage/test/vision-tracks-schema.test.mjs +11 -0
  47. package/vendor/skills/compile-review-session/bin/compile-review-session.mjs +25 -0
  48. package/vendor/skills/compile-review-session/bin/core/compiler.mjs +6 -2
  49. package/vendor/skills/compile-review-session/test/compiler.test.mjs +117 -0
  50. package/vendor/skills/overlay-authoring/3d.md +204 -1
  51. package/vendor/skills/setup-chat-approval/SKILL.md +41 -0
  52. package/vendor/skills/setup-chat-approval/bin/doctor.mjs +132 -0
  53. package/vendor/skills/setup-chat-approval/bin/find-chat-id.mjs +68 -0
  54. package/vendor/skills/setup-chat-approval/setup-token.md +70 -0
  55. package/vendor/skills/setup-chat-approval/smoke-test.md +52 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akari-video",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,6 +33,9 @@
33
33
  "docs/contract-2026-08-05-fx-v0.md",
34
34
  "docs/contract-2026-08-11-analysis-vision-tracks-v0.md",
35
35
  "docs/contract-2026-08-11-review-session-ui-events.md",
36
+ "docs/contract-2026-08-12-chat-approval-v0.md",
37
+ "docs/contract-2026-08-12-color-range-normalization-v0.md",
38
+ "docs/contract-2026-08-12-region-filter-layer-v0.md",
36
39
  "packages/akari-launcher/bin/akari.mjs",
37
40
  "packages/akari-launcher/package.json",
38
41
  "packages/akari-launcher/README.md",
@@ -51,6 +54,8 @@
51
54
  "packages/bake-layer/bin/bake-layer.mjs",
52
55
  "packages/bake-layer/package.json",
53
56
  "packages/bake-layer/README.md",
57
+ "packages/chat-bridge/package.json",
58
+ "packages/chat-bridge/src/telegram.mjs",
54
59
  "packages/creator-root/package.json",
55
60
  "packages/decision-cards/package.json",
56
61
  "packages/decision-cards/README.md",
@@ -158,6 +163,9 @@
158
163
  "skills/setup-audio-library/gallery.md",
159
164
  "skills/setup-audio-library/SKILL.md",
160
165
  "skills/setup-audio-library/store-unlock.md",
166
+ "skills/setup-chat-approval/setup-token.md",
167
+ "skills/setup-chat-approval/SKILL.md",
168
+ "skills/setup-chat-approval/smoke-test.md",
161
169
  "skills/setup-library/fetch-and-validate.md",
162
170
  "skills/setup-library/SKILL.md",
163
171
  "skills/setup-library/starter-pack.md",
@@ -118,7 +118,19 @@ OK / 差し戻しを言う」だけ — その閲覧と素材の受け渡しを
118
118
 
119
119
  | 未達 | 状況 |
120
120
  |---|---|
121
- | HTTPS | **`tailscale serve` の TLS が未成立**。tailnet 側で HTTPS は有効(`CertDomains` に当該ドメインあり)だが Let's Encrypt の ACME 注文が `invalid` で失敗。上記の実測は tailnet 内の平文 HTTP で代替した(WireGuard 内側のため機密性は保たれるが、secure context を要する機能は使えない)。**平文 HTTP を既定にはしない** |
121
+ | HTTPS | **`tailscale serve` の TLS が未成立**。上記の実測は tailnet 内の平文 HTTP で代替した(WireGuard 内側のため機密性は保たれるが、secure context を要する機能は使えない)。**平文 HTTP を既定にはしない** |
122
+
123
+ **HTTPS 失敗の切り分け結果(2026-08-12)** — スキル側・serve 設定側の不備ではないと確定:
124
+
125
+ - tailnet で HTTPS は有効(`tailscale status --json` の `CertDomains` に当該ドメインあり)
126
+ - serve の設定自体は正常(同じ経路が平文 HTTP では 200 / 0.28 秒で応答する)
127
+ - CAA は発行を許可している(`ts.net` に `issue "letsencrypt.org"`)
128
+ - Let's Encrypt の注文が毎回 `status: invalid`(注文 ID は毎回新規 = レート制限ではなく検証失敗)
129
+ - **`_acme-challenge.<host>.<tailnet>.ts.net` に使い捨て TXT が 5 件累積**していた。
130
+ DNS-01 の検証失敗と符合する(現行トークンが正しく公開されていない疑い)
131
+ - → **tailnet 側(Tailscale の DNS / 制御プレーン)の問題**。再試行を重ねても TXT が増えるだけで
132
+ 好転しないため、打ち切って次の一手に回す。候補: (a) マシン名を変更して
133
+ `_acme-challenge` の名前ごと作り直す(serve URL が変わる)(b) Tailscale サポートに問い合わせる
122
134
 
123
135
  ## 8. 改訂履歴
124
136
 
@@ -48,6 +48,7 @@
48
48
  | `timeline:cut:<n>` | タイムラインのカット(cuts[] index) | `timeline:cut:3` |
49
49
  | `timeline:overlay:<id>` | タイムラインのオーバーレイ | `timeline:overlay:o-0002` |
50
50
  | `asset:<path>` | 素材(プロジェクト相対 or カタログ id) | `asset:assets/broll/city.mp4` |
51
+ | `asset:<category>/<id>` | 素材(カタログ由来カード。key = `<category>/<id>`) | `asset:still/br-typing-laptop` |
51
52
 
52
53
  - **登録機構**: 記録対象の要素は `data-akari-ui="<target-id>"` 属性で opt-in する。
53
54
  クリック解決は capture-phase のリスナー 1 本で行い、**最近傍の登録済み祖先**に丸める。
@@ -80,10 +81,21 @@
80
81
  - 回帰: 新イベント入りの events.jsonl を旧読み手(compile-review-session の手順)が
81
82
  処理してもエラーにならないこと
82
83
 
83
- ## 6. 予約(次段の実装契約で確定)
84
-
85
- - review.json `annotations[].target` への **`ui:<element-id>`** 追加(選択ツール経由の
86
- UI 要素注釈の着地形)。§2 と同一の id 空間を使う
87
- - 書き出し済み MP4 への注釈は新 target 種を作らず既存 `src` 機構で扱う方針(要検証:
88
- プロジェクト外ファイルの src 正規化)
89
- - 音への注釈(`sourceRange` + トラック指定)の形
84
+ ## 6. 注釈の着地契約
85
+
86
+ - review.json `annotations[].target` **`ui:<element-id>`** は、選択ツール経由の UI 要素注釈に
87
+ 使う。§2 と同一の id 空間を使い、たとえばオーバーレイは
88
+ `ui:timeline:overlay:<id>` に着地する
89
+ - render-cut は検証に成功した書き出し成果物を、edit.json v1 の `sources[]` へ自動追記する。
90
+ `path` はプロジェクトルート相対、`proxy` `null` とし、同じ `path` が既にあれば追記しない。
91
+ 既存 id と衝突しない出力 stem 由来の id を使い、既存フィールドと整形は書き換えない。
92
+ edit.json を再読込・パースできない場合は警告だけを残し、書き出し成功を取り消さない。
93
+ v0 は schema 上 `sources` を持てないため自動追記せず、同様に警告する
94
+ - `sources[].path` に一致する動画ファイルを raw preview で開き、そのタブがフォーカスされて
95
+ いる間の注釈は、`src = sources[].id` と raw preview の現在再生位置を source 秒とする
96
+ `sourceT` に着地する。コンポーザーは対象を `🎞 <source id>` チップで表示する。
97
+ 一致しないファイルは従来どおり `src: null` の通常注釈とし、新しい target 種は作らない
98
+ - 音の素材区間は新しい `audio:` target を作らず、`src = sources[].id` と半開区間
99
+ `sourceRange: [start, end)` を使う。BGM 等のオーバーレイ音は既存の `overlay:<id>` または
100
+ `ui:timeline:overlay:<id>` で扱う。音声ファイルは専用 audio preview で開かれるため、raw video
101
+ preview の現在位置接続とは別であり、区間選択 UI は本契約の対象外とする
@@ -0,0 +1,99 @@
1
+ # chat-approval 契約 v0(チャット通知 + ボタン承認)
2
+
3
+ - 日付: 2026-08-12
4
+ - 状態: **v0 ドラフト・要オーナーレビュー**
5
+ - 前提: `contract-2026-08-02-setup-remote-v0.md`(tailnet 限定の閲覧経路。レポート URL の供給元)、
6
+ `contract-2026-07-25-project-structure-v0.md`(承認レポートの実体)、
7
+ `packages/decision-cards/report-helper.mjs`(`decisions.json` の read / write / commit の唯一の実装)、
8
+ `skills/manage-connections`(接続レジストリと credentials の唯一の入口)
9
+ - スコープ: 承認ゲート到達を**チャットへ通知**し、**ボタンのタップだけで**承認を返せるようにする
10
+ - 非スコープ: チャットからの自由文指示、エージェントの起動・操作、素材のチャット搬送、
11
+ 複数チャネル対応(v0 は Telegram 1 本)
12
+
13
+ ## 0. 位置づけ — 一言で言い切る
14
+
15
+ **チャットは配管であって頭脳ではない。** 運ぶのは「できました」という通知・レポートへのリンク・
16
+ 画像・そして**列挙可能な承認の返事**だけ。編集の判断は従来どおり AKARI のパイプラインが持ち、
17
+ 承認の記録は `decisions.json` が持つ。チャット層は SSOT を一切持たない。
18
+
19
+ ## 1. 決定事項
20
+
21
+ | 論点 | 決定 |
22
+ |---|---|
23
+ | 何を足すか | **通知と承認だけ**。エージェントをチャットから起動しない(別契約) |
24
+ | 書き込み経路 | ブリッジは `decisions.json` を**自分で書かない**。report-helper の HTTP API(`POST /api/state` / `POST /api/commit`)を 127.0.0.1 経由で叩く。書き込みの原子性・検証・`0600`・二重確定の 409 は既存実装のまま効く |
25
+ | 受信方式 | **long polling**(`getUpdates`)。公開エンドポイント・webhook・トンネルを作らない(受信口をインターネットに開けない) |
26
+ | 入力語彙 | **閉じた語彙のみ**。`callback_data` が既定の集合に一致するものだけ処理し、自由文は処理しない |
27
+ | チャネル | Telegram のみ(v0)。実装は `packages/chat-bridge/` に置き、後で LINE / Discord を足せる形にする |
28
+
29
+ ## 2. なぜ自由文を入れないか(この契約の中心)
30
+
31
+ 自由文をエージェントへ通すと、`planning`(非公開)の信頼境界契約が扱う prompt injection の
32
+ 窓口がそのまま開く。ボタンの `callback_data` は**発行側が定義した有限集合**であり、
33
+ 受信側は集合に無い値を捨てるだけでよい。v0 はこの性質を設計の土台にする。
34
+
35
+ - 差し戻しは「確定しない + レポートを開くリンクを返す」で表現する。理由の自由記述はレポート側で行う
36
+ - 自由文メッセージを受けたら、処理せず「レポートで操作してください」と定型文を返す
37
+
38
+ ## 3. 安全規律(ハードルール)
39
+
40
+ 1. **トークンを git 管理下・レポート・ログ・会話に出さない。** 置き場は
41
+ `~/.config/akari-video/credentials.env`(`600`)のみ。エージェントは値を読まず、KEY 名だけ案内する
42
+ 2. **チャット ID の許可リストを必須にする。** 登録済み chat ID 以外からの update は
43
+ 一切処理せず破棄する(bot のユーザー名は誰でも到達できるため、これが無いと第三者が承認できる)
44
+ 3. **ブリッジはポートを listen しない。** 送信も受信も outbound の long polling のみ
45
+ 4. **`decisions.json` を直接書かない**(§1 の決定)。report-helper 経由のみ
46
+ 5. **update の重複処理をしない。** `update_id` で冪等化する(Telegram は再配信しうる)
47
+ 6. **送ってよいのはレポートの画像とテキストのみ。** 撮影素材の原本・secrets・パスの内部構造を送らない
48
+ 7. **疎通確認(実機への通知到達 + ボタンで `decisions.json` 更新)が取れるまで完了と言わない**
49
+
50
+ ## 4. 構成要素
51
+
52
+ | 要素 | 置き場 | 役割 |
53
+ |---|---|---|
54
+ | ブリッジ本体 | `packages/chat-bridge/telegram.mjs` | 通知送信 + long polling + report-helper API 呼び出し |
55
+ | セットアップスキル | `skills/setup-chat-approval/` | doctor → BotFather 案内(人間手番)→ chat ID 取得 → 疎通確認。`setup-remote` と同じ型 |
56
+ | 接続登録 | `.akari/connections.json` | `manage-connections` の管轄(§5 の判断待ち) |
57
+
58
+ ### 送るメッセージの形
59
+
60
+ ```
61
+ 🎬 <プロジェクト名> — 承認をお願いします
62
+ <要約 1〜2 行>
63
+ [キーフレーム画像 数枚]
64
+
65
+ [ レポートを開く (URL) ] [ おまかせで確定 ] [ あとで ]
66
+ ```
67
+
68
+ - 「レポートを開く」は URL ボタン(tailnet 限定 URL。Telegram のサーバーからは到達できないため
69
+ リンクプレビューは出ない → `disable_web_page_preview` を付ける)
70
+ - 「おまかせで確定」は全カード既定値のまま `POST /api/commit`(レポート側の `accept-all` と同義)
71
+ - v1 の拡張余地: カードごとに選択肢ボタンを展開する(`data-option` は有限集合なので §2 と両立する)
72
+
73
+ ## 5. 判断待ち — `connections.json` の `kind` 拡張
74
+
75
+ 現行スキーマの `kind` は `genai / image / video / tts / music / sns / analytics` の閉じた enum で、
76
+ **通知系の枠が無い**。`manage-connections` のハードルール 7(レジストリに無い接続を使わない)を
77
+ 守るには、いずれかを選ぶ必要がある:
78
+
79
+ | 案 | 内容 | 評価 |
80
+ |---|---|---|
81
+ | **A. `notify` を enum に追加** | スキーマ + 検証 + 例 + `apps/shell` 側ミラーを更新 | **推奨**。通知は既存のどの kind とも性質が違う(発信ではなく往復)。将来の LINE / Discord も同じ枠に入る |
82
+ | B. 既存の `sns` を流用 | 変更ゼロ | `sns` は「SNS へ投稿する」枠であり、承認の往復とは別物。意味が濁る |
83
+ | C. レジストリに載せない | credentials.env だけで完結 | ハードルール 7 違反。採らない |
84
+
85
+ ## 6. 成果物と受け入れ基準
86
+
87
+ - **L0**: スキル lint / スキーマ検証 / 既存テストが green
88
+ - **L1**: 決定論の単体テスト — 許可外 chat ID の破棄・未知の `callback_data` の破棄・
89
+ `update_id` の冪等化・自由文の非処理・トークンが出力に混じらないこと
90
+ - **L2**: 実機 — スマホへ通知が届き、ボタンのタップで `decisions.json` が更新される
91
+
92
+ ## 7. 将来(非スコープの明示)
93
+
94
+ - カードごとの選択肢ボタン展開(v1)
95
+ - 複数チャネル(LINE / Discord / Slack)
96
+ - チャットからのエージェント起動・自由文指示(信頼境界の別契約が前提。常駐エージェント
97
+ = Hermes 等の検討もここに属する)
98
+ - 承認待ちのエージェント側の再開機構(現状は人間が「続けて」と言う前提。ファイル待ちの
99
+ ポーリングを挟む設計は別途)
@@ -0,0 +1,59 @@
1
+ # Color range normalization v0
2
+
3
+ ## 1. 背景と目的
4
+
5
+ full-range(`color_range=pc` / `yuvj420p`)の入力をそのまま H.264 出力へ伝播させると、配信向けの limited range を期待する再生・検証環境で階調とメタデータが一致しない。本契約は Render の全エンコード工程を limited range(FFmpeg の `tv`)へ正規化し、最終成果物と中間生成物の一貫性を保証する。
6
+
7
+ この不具合の起点と再現条件は [公開 issue #21](https://github.com/AkariLabs/akari-video/issues/21) を参照する。
8
+
9
+ ## 2. 最終出力の保証
10
+
11
+ MP4 / H.264 の最終映像ストリームは次を満たさなければならない。
12
+
13
+ - pixel format は `yuv420p`
14
+ - `color_range` は `tv`(limited range)
15
+
16
+ この組み合わせを AKARI Video の配信標準出力とする。
17
+
18
+ ## 3. 値変換とメタデータの不変条件
19
+
20
+ 色域レンジの正規化は、画素値の変換と映像ストリームへのメタデータのタグ付けを常に対で行う。
21
+
22
+ - 各 video filter chain は出力直前に `scale=out_range=tv` 相当の値変換を行う。
23
+ - 各 H.264 encode は `-color_range tv` 相当のメタデータを付ける。
24
+ - full-range の画素値を残したまま `tv` タグだけを付けることを禁止する。
25
+ - 値だけを limited range へ変換し、タグ付けを省略することも禁止する。
26
+
27
+ 入力がすでに tv range の場合、`scale=out_range=tv` はレンジ変換について no-op として扱う。
28
+
29
+ ## 4. 工程不変
30
+
31
+ cut、tail padding、track stack、layers、overlay composite を含む各エンコード工程の出力フレームは常に tv range とする。これは最終成果物だけでなく、後続工程へ渡す中間生成物にも適用する。
32
+
33
+ 複数ソースの cut では、ソースごとの前処理チェーンで tv range へ正規化してから concat / transition へ入力する。これにより pc / tv range が混在したフレームを同じ concat へ直接渡さない。さらに、LUT や合成後の工程出力も終端で tv range に正規化する。
34
+
35
+ 映像を再エンコードしない audio-only mux と、alpha を運ぶ非 H.264 overlay 中間生成物は本契約の対象外とする。
36
+
37
+ ## 5. Probe と provenance
38
+
39
+ 入力ソースの `pix_fmt` と `color_range` を ffprobe の映像ストリームから取得し、既存の duration、audio 有無、width、height、fps と同じ provenance 情報として記録する。ffprobe が入力の `color_range` を報告しない場合は `null` として記録し、推測値で置き換えない。
40
+
41
+ ## 6. Verify 契約
42
+
43
+ レンダープランの期待値へ `color_range: "tv"` を追加し、official verify は `verify.color-range` を報告する。
44
+
45
+ - 実測 `color_range` が `pc` の場合は error とする。
46
+ - 実測が `tv` の場合は pass とする。
47
+ - ffprobe が `color_range` を報告しない場合は、H.264 の仕様既定(未指定は limited range)に従って tv とみなし pass とする。
48
+
49
+ `verify.pixel-format` の期待値 `yuv420p` は維持し、`verify.color-range` と独立に判定する。
50
+
51
+ ## 7. 予約(今回のスコープ外)
52
+
53
+ 次の事項は別契約で扱い、本契約 v0 では実装しない。
54
+
55
+ - BT.601 から BT.709 などの colorspace 変換
56
+ - `-colorspace` / `-color_primaries` / `-color_trc` による colorspace メタデータの正規化
57
+ - 10bit および HDR 入力の変換、tone mapping、出力形式
58
+
59
+ 本契約の `tv` 正規化は color range のみに限定され、上記の色域・伝達特性変換を暗黙に保証しない。
@@ -0,0 +1,98 @@
1
+ # Region filter layer v0
2
+
3
+ ## 1. 背景
4
+
5
+ finger-frame の中心表現を、別映像の corner-pin 合成だけでなく、指で作った枠の内側だけベース映像自身のルックを切り替える表現へ拡張する。この用途では貼り込み素材を入力せず、ベース映像からフィルター済みの映像を作り、指定 region の内側だけへ戻す。
6
+
7
+ 本書は `edit.json` の additive な拡張である `layers[].kind: "filter"` の v0 契約を定める。
8
+
9
+ ## 2. 意味論
10
+
11
+ - `kind: "filter"` の layer は `src` を持たない。ベース映像以外の貼り込み入力を追加しない。
12
+ - `filter` は region の内側にだけ適用し、region の外側はベース映像をそのまま保つ。
13
+ - layer の発動時間窓は既存どおり `t` と `duration` で表す。
14
+ - `opacity`、`track`、および `keyframes[].perspective` は既存 layer の共通フィールドを再利用する。
15
+ - `src`、`chroma_key`、`blend`、`crop`、`transform` は `kind: "filter"` では使用できない。
16
+
17
+ ## 3. Region source v0
18
+
19
+ v0 の region source は `perspective.corners` の quad である。表現、4 隅の順序、値域、退化四角形の制約は既存の `layerPerspective` をそのまま再利用する。`keyframes[].perspective` がある場合は既存の perspective keyframe 展開規約に従い、時間区間ごとの静的 quad として合成する。
20
+
21
+ ## 4. 凍結インターフェース
22
+
23
+ ```jsonc
24
+ {
25
+ "id": "finger-frame-1",
26
+ "kind": "filter",
27
+ "t": 12.0,
28
+ "duration": 2.4,
29
+ "filter": { "type": "invert" },
30
+ // または { "type": "lut", "id": "<presets/luts の id>", "intensity": 1.0 }
31
+ // または { "type": "saturation", "value": 1.6 }
32
+ "perspective": { "corners": [[0, 0], [1, 0], [0, 1], [1, 1]] },
33
+ "keyframes": [
34
+ {
35
+ "t": 0.1,
36
+ "perspective": { "corners": [[0, 0], [1, 0], [0, 1], [1, 1]] }
37
+ }
38
+ ],
39
+ "opacity": 1.0
40
+ }
41
+ ```
42
+
43
+ `filter` は次の closed union とする。
44
+
45
+ ```jsonc
46
+ {
47
+ "type": "object",
48
+ "required": ["type"],
49
+ "oneOf": [
50
+ {
51
+ "properties": { "type": { "const": "invert" } },
52
+ "required": ["type"],
53
+ "additionalProperties": false
54
+ },
55
+ {
56
+ "properties": {
57
+ "type": { "const": "lut" },
58
+ "id": { "type": "string", "minLength": 1, "pattern": "\\S" },
59
+ "intensity": { "type": "number", "minimum": 0, "maximum": 1 }
60
+ },
61
+ "required": ["type", "id"],
62
+ "additionalProperties": false
63
+ },
64
+ {
65
+ "properties": {
66
+ "type": { "const": "saturation" },
67
+ "value": { "type": "number", "minimum": 0, "maximum": 3 }
68
+ },
69
+ "required": ["type", "value"],
70
+ "additionalProperties": false
71
+ }
72
+ ]
73
+ }
74
+ ```
75
+
76
+ LUT の `intensity` 省略時は `1` として描画する。
77
+
78
+ ## 5. 予約(今回のスコープ外)
79
+
80
+ - region source `mask`: ピクセル単位のマットを region として使用する予約。v0 では schema、CLI、renderer のいずれにも実装しない。
81
+ - filter type `"pixelate"`: face-mosaic の将来の移行先として予約する。v0 の closed union には含めず、指定された場合は拒否する。
82
+
83
+ 予約名は現在利用可能であることを意味しない。
84
+
85
+ ## 6. Additive 原則
86
+
87
+ この契約は既存の `kind: "baked"` / `kind: "video"` に対する additive な拡張である。既存 kind の必須フィールド、合成順、フィルターチェーン、examples / fixtures の妥当性と出力は変更しない。filter layer を含まない既存入力は従来とバイト等価に扱う。
88
+
89
+ ## 7. 実装対応
90
+
91
+ - `packages/render-cut/src/layers.mjs`: ベース映像の split、ルック適用、白 quad mask、`maskedmerge` による region 内合成を行う。filter layer は追加の `-i` を作らない。
92
+ - `packages/akari-tools/bin/finger-frame.mjs`: `--kind filter --filter invert|lut:<id>|saturation:<value>` から、既存と同じ gesture window と corner keyframes を持つ layer を生成する。
93
+
94
+ ## 8. 検証
95
+
96
+ L0 では schemas、akari-tools、render-cut の各 `node --test`、docs-sync、既存 baked / video の非回帰を確認する。ffmpeg コマンド生成テストは filter layer が追加 `-i` を作らず、3 種の filter と perspective keyframe 展開が決定論的なグラフを生成することを確認する。
97
+
98
+ 12 秒 window の実素材による invert / LUT の見た目、所要時間、入力数の実測は別途実施し、検証報告へ記録する。
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akari-video",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "AKARI Video launcher CLI — start an AI-edited video project from any directory: scaffold, connection check, then hand over to Claude Code (or opencode). AKARI Video を opencode や Claude Code で、どのディレクトリからでも始めるための `akari` ランチャー CLI。接続確認(doctor)→ 未セットアップならプロジェクト雛形を作成 → AI エージェントを起動する。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -135,6 +135,21 @@ function validateAnalysisStructure(analysis, label) {
135
135
  ) {
136
136
  errors.push("tracks.person_matte は string か null である必要があります");
137
137
  }
138
+ for (const field of ["face_landmarks", "hand_pose"]) {
139
+ if (!hasOwn(analysis.tracks, field)) continue;
140
+ const pointer = analysis.tracks[field];
141
+ if (!isRecord(pointer) || !isNonEmptyString(pointer.path) || !(Number(pointer.sample_fps) > 0)) {
142
+ errors.push(`tracks.${field} は path(空でない文字列)・sample_fps(正数) を持つ object である必要があります`);
143
+ continue;
144
+ }
145
+ if (hasOwn(pointer, "features") && (
146
+ !Array.isArray(pointer.features)
147
+ || pointer.features.some((feature) => !isNonEmptyString(feature))
148
+ || new Set(pointer.features).size !== pointer.features.length
149
+ )) {
150
+ errors.push(`tracks.${field}.features は重複のない空でない文字列配列である必要があります`);
151
+ }
152
+ }
138
153
  }
139
154
  for (const [index, kf] of (analysis.keyframes || []).entries()) {
140
155
  if (!isRecord(kf)) {
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@akari-video/chat-bridge",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "承認ゲートの通知 + ボタン承認ブリッジ v0(Telegram)。decisions.json は report-helper の HTTP API 経由でのみ更新し、ポートは listen しない。外部 npm 依存ゼロ(Node.js 組み込みモジュールのみ)。",
6
+ "type": "module",
7
+ "bin": {
8
+ "akari-chat-bridge": "src/telegram.mjs"
9
+ },
10
+ "scripts": {
11
+ "start": "node src/telegram.mjs",
12
+ "test": "node --test"
13
+ }
14
+ }