akari-video 0.1.38 → 0.1.39
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.
- package/package.json +1 -1
- package/vendor/docs/contract-2026-08-28-gpu-export-v0.md +27 -2
- package/vendor/docs/contract-2026-08-28-osr-export-v0.md +11 -0
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/edit-store/lib/caption-store.js +39 -1
- package/vendor/skills/overlay-authoring/3d.md +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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": {
|
|
@@ -123,11 +123,16 @@ cuts と layers が同時に空のフレームは、出力解像度の黒 1 枚
|
|
|
123
123
|
スプライト合成は通常どおりこの黒い frame-engine canvas の上へ重ねる。
|
|
124
124
|
|
|
125
125
|
3D は engine の時計から得た local seconds を `threeRuntime.render(container, t)` へ直接渡して駆動する。
|
|
126
|
-
GPU 出口は overlay sheet の `__akariSeek` を使用しない。毎コマの DOM animation
|
|
127
|
-
visibility
|
|
126
|
+
GPU 出口は overlay sheet の `__akariSeek` を使用しない。毎コマの DOM animation 同期と全 container の
|
|
127
|
+
visibility 更新を 3D canvas の texture 更新へ持ち込まないためである。sheet の
|
|
128
128
|
`__akariReady` は起動時に 1 回だけ待ち、各 scene が ready でない場合は overlay id と状態を示して
|
|
129
129
|
fail-closed にする。active 区間は最終 compositor の draw へ積むかどうかで決める。
|
|
130
130
|
|
|
131
|
+
**2026-09-04 改訂(issue #53)**: video seek 待ちだけは例外とし、sheet が公開する `__akariSeekVideos(seconds)`
|
|
132
|
+
(`__akariSeek` から切り出した video 部分・OSR と同一実装)を毎コマ、3D 描画の前に呼ぶ。3D 断片の動画テクスチャは
|
|
133
|
+
`<video>` の提示フレームから上がるため、シーク → 提示確定 → 3D 描画 の順序が必要で(`3d.md`)、呼ばないと
|
|
134
|
+
GPU 経路の動画テクスチャは起動時の 0 秒の絵に固定される。シートに `<video>` が無ければ呼ばない。
|
|
135
|
+
|
|
131
136
|
## 4. 読み戻しゼロ
|
|
132
137
|
|
|
133
138
|
製品実行経路は GPU frame surface を CPU へ読む API を使用しない。静的監査は
|
|
@@ -187,6 +192,26 @@ software MP4 SHA はエンコーダが決定論的な場合だけ必須とし、
|
|
|
187
192
|
GPU と OSR の decode 比較は、engine-only 区間の per-frame MAD 1.0 以下、字幕 cue の代表 5 時刻の
|
|
188
193
|
下半分 MAD 1.0 以下、3D 区間 MAD 1.0 以下を固定閾値とする。
|
|
189
194
|
|
|
195
|
+
**2026-09-04 追加(issue #53)— 2 経路で同じでなければならない 4 点**:
|
|
196
|
+
|
|
197
|
+
1. **overlay へ渡す時刻は `frameNumber / fps`**。µs へ丸めてはならない。overlay の `start` は必ず
|
|
198
|
+
`atFrames / fps` なので、丸めると比較が 1 ulp で反転し、カット境界の 1 コマだけ絵が食い違う。
|
|
199
|
+
この `seconds` は時間窓判定・CSS アニメ位相・item keyframes のフレーム番号すべてに流れる。
|
|
200
|
+
2. **時間窓の外の container も毎コマ pause して `currentTime` を書く**。飛ばすと窓の外の断片の CSS アニメが
|
|
201
|
+
壁時計(書き出しは分単位)で走り切り、`animation-fill-mode: both/forwards` の最終姿勢に張り付いたまま
|
|
202
|
+
窓へ入ってくる = 同じ時刻でも直前に何を撮ったかで絵が変わる。OSR の `__akariSyncAnimations` は
|
|
203
|
+
active 判定を持たない。
|
|
204
|
+
3. **DOM ステージのルートに `data-no-timeline`**。断片の規約は
|
|
205
|
+
`[data-akari-active] .x, [data-no-timeline] .x { animation: … }` の 2 アームで、OSR のシートは `#stage` に
|
|
206
|
+
これを持つ。GPU 側に無いと no-timeline アームだけで宣言した断片が GPU でのみ動かない。
|
|
207
|
+
4. **静的スプライトは overlay の `transform` を落とさない**。`.akari-sprite-root` に OSR の
|
|
208
|
+
`.akari-overlay-container` と同じ `translate/scale/rotate` + `transform-origin: center` を宣言する
|
|
209
|
+
(`role: "background"` は両経路とも恒等固定)。
|
|
210
|
+
|
|
211
|
+
あわせて、manifest 生成時に overlay の `start` / `duration` が有限数でなければ fail-closed とする。
|
|
212
|
+
既定値(`?? 0` / `?? duration`)を置くと、欠けたときに「OSR は絶対に出さない・GPU は全尺出す」という
|
|
213
|
+
最悪の非対称になる(OSR は `formatNumber(undefined)` が `"NaN"` を書き、`seconds >= NaN` が常に偽になる)。
|
|
214
|
+
|
|
190
215
|
## 7. receipt
|
|
191
216
|
|
|
192
217
|
`.akari/render.json` は `provenance.engine = "gpu"` と GPU receipt を持つ。GPU receipt は少なくとも
|
|
@@ -117,6 +117,17 @@ ffprobe timeoutは `max(120000, frames × 100)` msとする。尺、フレーム
|
|
|
117
117
|
- `AKARI_OSR_MEMORY_WARN_MIB` / `AKARI_OSR_MEMORY_HARD_STOP_MIB`で正の整数MiBへ上書きでき(絶対値・スケールも下限も上限も受けない)、
|
|
118
118
|
適用値はwarning < hard stopを必須とする。hard stop だけを上書きし既定 warning がそれ以上になるときは warning を hard stop の 75% に追従させる。
|
|
119
119
|
同じ変数を GPU 直結出口(gpu-export)も読む。
|
|
120
|
+
- 書き出しは厳密に前方順で過去フレームを読み直さないため、**評価 plan から外れたカットのデコーダセッションは解放する**
|
|
121
|
+
(`StreamReaper`。frame-engine が `plan.base` / `plan.layers` の `streamId` を集め、最後に使ったフレームから 1 秒ぶんの
|
|
122
|
+
猶予を過ぎたものを `LookaheadFrameSource.releaseStream` で落とす)。解放しないとカット本数ぶんのセッションが最後まで
|
|
123
|
+
積み上がり、RSS が単調に伸びて長尺ほど後ろで hard stop に当たる(2026-09-04 追加・issue #52。
|
|
124
|
+
244 秒 / 7,320 コマの実機報告で 98% 地点・RSS 4.01 GB)。トランジション中の送出カットは plan に載るので残る。
|
|
125
|
+
- receipt / run.json の `memory.decoderSessions` に生存セッション数(`live`)と累計解放数(`released`)を記録する。
|
|
126
|
+
RSS はセッション数に比例するため、ランプの原因を後から突き合わせられるようにする(同・issue #52。
|
|
127
|
+
#28 の時点で比例は分かっていたが記録が無く、再発時にまた手探りになった)。
|
|
128
|
+
- hard stop に当たった GPU 直結出口の失敗は reasonCode `memory-hard-stop` とし、`--engine auto` のときは OSR で
|
|
129
|
+
走り直して完走させる(`FALLBACK_REASONS`。同・issue #52。それまでは成果物ゼロで終わり、前版で出せていたものが
|
|
130
|
+
出せない退行になっていた)。`--engine gpu` 明示は従来どおり fail-closed。
|
|
120
131
|
- 並列予算1 worker = 1 GiBはGPU前提の値である。v0のworker数は1。
|
|
121
132
|
- 10秒ごとにRSSを記録し、ウィンドウ破棄後も採る。
|
|
122
133
|
- 固定Nコマごとのページ再生成は行わない。再生成を許すのはページ境界、renderer crash、watchdog回復時だけである。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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 組み込みモジュールのみ)。 [akari-video npm vendor: bin/akari.mjs is reference-only. These CLI entrypoints are not included in the akari-video npm package. Use `akari doctor --json` and run the path reported in `render_cut.path`. Full installations provide it in a monorepo checkout, ~/.akari/app, /Applications/AKARI Video.app/Contents/Resources/packages, or %LOCALAPPDATA%\\Programs\\@akari-videoshell\\resources\\packages.]",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -296,7 +296,10 @@ function updateCaptionStylePresetInSource(source, captionIds, presetId) {
|
|
|
296
296
|
changed++;
|
|
297
297
|
continue;
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
const shadowed = shadowedPresetStyleKeys(presetId, record.text_style);
|
|
300
|
+
// 同じテンプレの再適用でも、そのテンプレを覆い隠している字幕個別の指定が残っていれば
|
|
301
|
+
// 掃除する仕事が残っている(「変更はありません」で終わらせない)。
|
|
302
|
+
if (hasPreset && record.style_preset === presetId && shadowed.length === 0)
|
|
300
303
|
continue;
|
|
301
304
|
let nextElement;
|
|
302
305
|
if (hasPreset) {
|
|
@@ -317,11 +320,46 @@ function updateCaptionStylePresetInSource(source, captionIds, presetId) {
|
|
|
317
320
|
+ element.text.slice(textStyle.start);
|
|
318
321
|
}
|
|
319
322
|
}
|
|
323
|
+
nextElement = pruneShadowedTextStyle(nextElement, shadowed, captionId);
|
|
320
324
|
output = replaceElement(output, array.openIndex + 1, element, nextElement);
|
|
321
325
|
changed++;
|
|
322
326
|
}
|
|
323
327
|
return { source: output, changed };
|
|
324
328
|
}
|
|
329
|
+
/**
|
|
330
|
+
* そのテンプレが決めるツマミのうち、字幕個別の text_style が上書きしてしまっているキーを挙げる。
|
|
331
|
+
*
|
|
332
|
+
* 合成規則は `{ ...presetStyle, ...text_style }`(caption-style-preset.ts)で **字幕側が強い**。
|
|
333
|
+
* そのため text_style に既定値が丸ごと書かれていると、テンプレを当てても見た目が変わらない
|
|
334
|
+
* (オーナー報告 2026-09-04:「ニュース帯だけ効く」= ニュース風の background だけが text_style に
|
|
335
|
+
* 無いツマミだった)。テンプレを選ぶ操作は「このツマミはテンプレに任せる」という意思表示なので、
|
|
336
|
+
* 適用時に該当キーを落としてテンプレを表に出す。テンプレが決めないツマミ(ドラッグした position /
|
|
337
|
+
* zone / max_characters など)は字幕個別の指定として残す。
|
|
338
|
+
*/
|
|
339
|
+
function shadowedPresetStyleKeys(presetId, textStyle) {
|
|
340
|
+
const preset = Object.prototype.hasOwnProperty.call(textstyle_catalog_1.TEXTSTYLE_CATALOG, presetId)
|
|
341
|
+
? textstyle_catalog_1.TEXTSTYLE_CATALOG[presetId] : undefined;
|
|
342
|
+
if (!preset || textStyle === null || typeof textStyle !== 'object' || Array.isArray(textStyle)) {
|
|
343
|
+
return [];
|
|
344
|
+
}
|
|
345
|
+
const style = textStyle;
|
|
346
|
+
return Object.keys(preset.style)
|
|
347
|
+
.filter(key => Object.prototype.hasOwnProperty.call(style, key));
|
|
348
|
+
}
|
|
349
|
+
/** text_style から指定キーを取り除く。空になったら text_style ごと落とす。 */
|
|
350
|
+
function pruneShadowedTextStyle(element, keys, captionId) {
|
|
351
|
+
if (keys.length === 0) {
|
|
352
|
+
return element;
|
|
353
|
+
}
|
|
354
|
+
const located = locateTopLevelObjectProperty(element, 'text_style', `字幕 ${captionId}`);
|
|
355
|
+
let textStyle = located.text;
|
|
356
|
+
for (const key of keys) {
|
|
357
|
+
textStyle = removeObjectProperty(textStyle, key);
|
|
358
|
+
}
|
|
359
|
+
return Object.keys(JSON.parse(textStyle)).length === 0
|
|
360
|
+
? removeObjectProperty(element, 'text_style')
|
|
361
|
+
: element.slice(0, located.start) + textStyle + element.slice(located.end);
|
|
362
|
+
}
|
|
325
363
|
function insertCaptionLine(source, caption) {
|
|
326
364
|
const parsed = parseCaptions(source);
|
|
327
365
|
if (!normalizeCaption(caption)) {
|
|
@@ -118,6 +118,21 @@ fragment は単一ルートとし、透明 canvas、任意の静的 fallback、
|
|
|
118
118
|
clip を分けるので、1 個のモデルに複数の動きがあるときは `"*"` で束ねる(1 本しか再生しないと
|
|
119
119
|
片方しか動かない)。存在しない clip 名を書いた場合はエラーになる。
|
|
120
120
|
- `materialOverrides` は `{ "<material 名>": { "texture": "<画像または動画の相対パス>" } }` の形で、名前が一致するマテリアルの `emissiveMap` を差し替える。**差し替え先が `emissiveMap` である以上、貼り先の材質が発光しない(glTF の `emissiveFactor` が未設定 = 黒)と「0 × テクスチャ」で何も出ない**(2026-08-14 実害。詳細は後述「発光しない材質には貼れない」)。edit.json のあるディレクトリからの相対 PNG / JPEG / WebP 等、または MP4 / MOV / WebM を指定し、URL や CDN を書かない。該当するマテリアル名がモデル内にない場合は警告して無視される。
|
|
121
|
+
- `textureVar` は画面に映すものをツマミ(CSS カスタムプロパティ)にする任意キー。`"--screen-src"` のような変数名を書き、overlay の `vars` でその変数に相対パスを入れると `texture` の代わりに差し込まれる。空・未設定なら `texture` がそのまま使われる。
|
|
122
|
+
- `textureVar` を使う場合も `texture` は実在する相対パスのままにする。書き出し前の宣言済み入力検査が実ファイルを要求するため、`texture` に `var(--screen-src)` を直接書く形はライブプレビューでは動くが書き出しでは失敗する。
|
|
123
|
+
- `brightness` は任意の発光倍率(0〜4、既定 1)で、差し替えたテクスチャの `emissiveIntensity` に掛かる。`var(--screen-brightness)` のような CSS 変数も書き出しを含めて使える。既定の 1 のときは `emissiveIntensity` に触れず、既存宣言の見た目を維持する。
|
|
124
|
+
- ツマミへ結線する宣言例:
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"materialOverrides": {
|
|
128
|
+
"ScreenMaterial": {
|
|
129
|
+
"texture": "placeholder.png",
|
|
130
|
+
"textureVar": "--screen-src",
|
|
131
|
+
"brightness": "var(--screen-brightness)"
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
121
136
|
- **パスは「edit.json のあるディレクトリ」から。断片の場所からの相対ではない。** `model` も同様。
|
|
122
137
|
断片を `overlays/3d-phone/fragment.html` へ置いたなら `"overlays/3d-phone/model.glb"` と書く
|
|
123
138
|
(`"model.glb"` はプロジェクト直下を探して ENOENT になる)。
|