akari-video 0.1.45 → 0.1.47
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/.akari-capability-sources.json +1 -0
- package/vendor/docs/contract-2026-08-28-gpu-export-v0.md +3 -0
- package/vendor/docs/contract-2026-08-28-v2-audio-roles-v0.md +11 -0
- package/vendor/docs/contract-2026-08-30-motion-and-keyframes-v0.md +15 -0
- package/vendor/docs/contract-2026-09-06-vgpu-layer-v0.md +166 -0
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/edit-lint/src/edit-lint.mjs +14 -0
- package/vendor/packages/edit-store/lib/audio-schedule.d.ts +1 -0
- package/vendor/packages/edit-store/lib/audio-schedule.js +2 -0
- package/vendor/packages/edit-store/lib/canonical.js +1 -1
- package/vendor/packages/edit-store/lib/edit-v2.d.ts +10 -0
- package/vendor/packages/edit-store/lib/edit-v2.js +9 -2
- package/vendor/packages/edit-store/lib/generated/edit-v2-keys.d.ts +2 -2
- package/vendor/packages/edit-store/lib/generated/edit-v2-keys.js +3 -1
- package/vendor/packages/edit-store/lib/internal-model.js +10 -1
- package/vendor/packages/edit-store/lib/legacy-audio-view.js +1 -0
- package/vendor/packages/edit-store/lib/webview-kernel.js +18 -3
- package/vendor/packages/gpu-export/README.ja.md +2 -0
- package/vendor/packages/gpu-export/README.md +2 -0
- package/vendor/packages/media-bin/src/preview-audio-sidecar.mjs +89 -14
- package/vendor/packages/media-bin/test/preview-audio-slot-order.test.mjs +306 -5
- package/vendor/packages/overlay-runtime/README.md +60 -0
- package/vendor/packages/schemas/edit.schema.json +6 -2
- package/vendor/packages/schemas/engine-capabilities.json +3 -1
- package/vendor/packages/schemas/test/edit-v2-schema.test.mjs +26 -0
- package/vendor/packages/schemas/test/engine-capabilities.test.mjs +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
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": {
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"docs/contract-2026-09-03-clip-adjust-v0.md",
|
|
65
65
|
"docs/contract-2026-09-03-preview-playback-rate-v1.md",
|
|
66
66
|
"docs/contract-2026-09-05-clip-adjust-v1.md",
|
|
67
|
+
"docs/contract-2026-09-06-vgpu-layer-v0.md",
|
|
67
68
|
"packages/akari-launcher/package.json",
|
|
68
69
|
"packages/akari-launcher/README.md",
|
|
69
70
|
"packages/akari-tools/package.json",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|---|---|---|
|
|
22
22
|
| `same` | はい | 静的 HTML は起動時、対応済み字幕は unit の初回活性時に 1 回だけスプライト化する |
|
|
23
23
|
| `three` | はい | JSON の宣言型 3D scene と描画先 canvas を持つ overlay。毎コマ Three.js canvas を更新し、登場表現は `three-scene-entrance-curve`、`three-scene-entrance-sampled`、または `three-scene-sampled-composite` で処理する |
|
|
24
|
+
| `vgpu` | はい | pure な `data-akari-vgpu-scene` を WebGPU canvas に描き、毎コマスプライトへ転送する([vgpu v0 契約](./contract-2026-09-06-vgpu-layer-v0.md)) |
|
|
24
25
|
| `degraded` | いいえ | raster 自体は可能でも live DOM と同じ時間変化を保証できない |
|
|
25
26
|
| `unsupported` | いいえ | v0 の表現範囲外であり、正しい完成画を生成できない |
|
|
26
27
|
|
|
@@ -320,6 +321,8 @@ CSS 3D は次の 3 群に分けて判定する。
|
|
|
320
321
|
子孫の描画域が画面上で交差し、手前の要素が DOM 上で先に描かれる矛盾対を検出した場合は警告するが、
|
|
321
322
|
fail-closed にはしない。
|
|
322
323
|
|
|
324
|
+
vgpu の理由語彙は `vgpu-scene-canvas-direct`、`vgpu-stateful-unsupported`、`vgpu-invalid-declaration`、`vgpu-condition:<条件をカンマ連結>`([vgpu v0 契約](./contract-2026-09-06-vgpu-layer-v0.md))。
|
|
325
|
+
|
|
323
326
|
次の条件は fail-closed のまま `degraded` とし、receipt に overlay id、理由、検出条件を全件残す。
|
|
324
327
|
|
|
325
328
|
- `iframe`、`object`、`embed` の埋め込み context。
|
|
@@ -128,6 +128,17 @@ ms へ換算し、絶対値で集計する。全 59 点の最大は 16.667 ms、
|
|
|
128
128
|
書き出しはこの speech 鍵を消費する。プレビューサーバーへ speech 鍵を渡す配線は同契約の範囲外で、
|
|
129
129
|
配線されるまでは narration 鍵だけへ劣化する。
|
|
130
130
|
|
|
131
|
+
`tracks[].items[].source`(`kind: 'media'`)の `gain_db`(-60〜12・省略時 0)と
|
|
132
|
+
`mute`(boolean・省略時 false)で、カットごとに埋め込み音声を減衰 / ミュートできる。
|
|
133
|
+
`mute: true` は speech 宣言そのものを作らず、プレビューのサイドカー要求も PCM 化のコストも消える。
|
|
134
|
+
書き出しは無音区間で尺を保つ。キー無しの既定値は従来と完全同一で、既存案件の出力は変わらない。
|
|
135
|
+
|
|
136
|
+
### 6.1 トラック単位の `tracks[].muted`
|
|
137
|
+
|
|
138
|
+
`muted?: boolean` は省略時 false。visual トラックの `muted: true` は cut の埋め込み音声を anullsrc に置き換え、尺は保つ(video layer は対象外)。
|
|
139
|
+
audio トラックの `muted: true` は item を書き出し・プレビューの mix から除外し、ducking の対象からも外れる。
|
|
140
|
+
トラックの `hidden` / `locked` は従来どおり storage 側で保持し、edit.json には出ない。
|
|
141
|
+
|
|
131
142
|
## 7. 速度変更した台詞のピッチ保持サイドカー
|
|
132
143
|
|
|
133
144
|
`speed` が 1 以外の撮影素材の台詞は、Web Audio の `playbackRate` による近似から外す。
|
|
@@ -44,6 +44,21 @@ updated: 2026-08-30
|
|
|
44
44
|
- HTML 部品の L0 は既存どおり `vars`(CSS 変数 `--anim-duration / stagger / distance / easing / delay`)。`motion` は native アイテム(telop / media / caption / group)用
|
|
45
45
|
- グループの `motion` は子全体にかかる(グループ = 小さなコンポジション)
|
|
46
46
|
|
|
47
|
+
- **実装状態(2026-09-06)**: frame-engine の layer / cut 評価で `motion` を描画する。シェルプレビュー / gpu / osr の 3 出口で同じ評価を使う
|
|
48
|
+
- `amount` の既定値は次表。`scale` / `pulse` は倍率に対する差分(0.2 = 20%)、`spin` は回転方向(±1)
|
|
49
|
+
|
|
50
|
+
| プリセット | `amount` の既定値 |
|
|
51
|
+
|---|---|
|
|
52
|
+
| `slide-up` / `slide-down` / `slide-left` / `slide-right` | 40 px |
|
|
53
|
+
| `scale` | 0.2 |
|
|
54
|
+
| `pulse` | 0.05 |
|
|
55
|
+
| `float` | 6 px |
|
|
56
|
+
| `spin` | 1(回転方向)|
|
|
57
|
+
|
|
58
|
+
- 合成は **keyframes の結果(未指定なら静的値)に motion を合成する 1 段**。`in` / `out` / `loop` の `dx` / `dy` / `rotate` は加算、`scale` と `opacity` は乗算、`reveal`(wipe)は交差
|
|
59
|
+
- `wipe` は crop 窓の中の表示率 `reveal` で表し、隠れた部分は完全透過。閉じた端点でも crop の幅・高さは `Number.EPSILON` 以上を保ち、opacity 0 で完全透過にする
|
|
60
|
+
- `duration` / `period` が 0 以下・非有限、または未知 preset の席は描画で無視する。未知 preset は席ごとに lint warning `motion.unknown-preset`(path は `.motion.in` / `.motion.out` / `.motion.loop`)
|
|
61
|
+
|
|
47
62
|
## 2. L1 キーフレーム — `keyframes` の一般化
|
|
48
63
|
|
|
49
64
|
### 2.1 形(1 つだけ: 点形)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
lifecycle: accepted
|
|
3
|
+
date: 2026-09-06
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# vgpu レイヤー v0 契約
|
|
7
|
+
|
|
8
|
+
## 1. 適用範囲
|
|
9
|
+
|
|
10
|
+
`data-akari-vgpu-scene` に宣言した WebGPU のフルスクリーン fragment パスを、
|
|
11
|
+
`window.akari.vgpuRuntime` が外部から渡された時刻で描く。vgpu 0.4.0 は vendor 同梱し、
|
|
12
|
+
実行時の依存取得は行わない。Three.js と同じ overlay sheet に置き、GPU 書き出しでは
|
|
13
|
+
canvas を SpriteCompositor に登録する。毎コマ `render` の直後に `updateSprite` する。
|
|
14
|
+
WebGPU canvas の提示面は一時的なので、描画せずに前回の canvas を転送してはならない。
|
|
15
|
+
CPU への画素読み戻しはこの経路に追加しない。ブラウザ内部のゼロコピーを保証するものではない。
|
|
16
|
+
|
|
17
|
+
## 2. 宣言スキーマ
|
|
18
|
+
|
|
19
|
+
断片に次の script をちょうど 1 個置く。canvas は任意で、省略時はランタイムが作成する。
|
|
20
|
+
|
|
21
|
+
```html
|
|
22
|
+
<canvas></canvas>
|
|
23
|
+
<script type="application/json" data-akari-vgpu-scene>
|
|
24
|
+
{
|
|
25
|
+
"version": 0,
|
|
26
|
+
"mode": "pure",
|
|
27
|
+
"alphaMode": "premultiplied",
|
|
28
|
+
"seed": 0,
|
|
29
|
+
"uniforms": { "speed": 1 },
|
|
30
|
+
"passes": [{
|
|
31
|
+
"id": "main",
|
|
32
|
+
"wgsl": "struct Params { speed: f32 }; @group(0) @binding(1) var<uniform> params: Params; @fragment fn fs_main(@builtin(position) p: vec4f) -> @location(0) vec4f { let uv = akari_uv(p); return vec4f(uv, 0.5 + 0.5 * sin(akari.time * params.speed), 1.0); }",
|
|
33
|
+
"inputs": [],
|
|
34
|
+
"scale": 1
|
|
35
|
+
}]
|
|
36
|
+
}
|
|
37
|
+
</script>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| 項目 | 制約・既定値 |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `version` | 必須、数値 `0` のみ |
|
|
43
|
+
| `mode` | 必須、`pure` のみ。`stateful` は予約語で拒否 |
|
|
44
|
+
| `alphaMode` | 省略時 `premultiplied`。それ以外は拒否。シェーダー出力の RGB も alpha 乗算済みにする |
|
|
45
|
+
| `seed` | 任意の有限数。省略時 `0` |
|
|
46
|
+
| `uniforms` | 任意の plain object。値は有限数、または長さ 2〜4 の有限数配列。省略時 `{}` |
|
|
47
|
+
| `passes` | 必須、1 個以上の配列 |
|
|
48
|
+
| `passes[].id` | 必須、`^[A-Za-z0-9_-]+$`、一意 |
|
|
49
|
+
| `passes[].wgsl` | 必須、空白だけではない WGSL 文字列 |
|
|
50
|
+
| `passes[].inputs` | 先行パス id の文字列配列、最大 8 個。省略時 `[]`。自己参照・前方参照不可 |
|
|
51
|
+
| `passes[].scale` | 正の有限数、省略時 `1`。最終パスでは無視する |
|
|
52
|
+
|
|
53
|
+
未知のトップレベルキー・pass キー、不正 JSON、不正な値は `readDescriptor` が TypeError にする。
|
|
54
|
+
`uniforms` のキーは WGSL `Params` のメンバーに対応し、断片が
|
|
55
|
+
`@group(0) @binding(1) var<uniform> params: Params;` を自分で宣言する。
|
|
56
|
+
型は `f32` / `vec2f` / `vec3f` / `vec4f`。params 宣言のないパスには params を set しない。
|
|
57
|
+
未宣言名・未束縛・WGSL コンパイルエラーは vgpu の検証を通じて失敗する。
|
|
58
|
+
|
|
59
|
+
`pure` は「出力が指定時刻・seed・uniforms の純関数」の authoring 契約である。
|
|
60
|
+
任意時刻へ直接シークでき、前回描画結果への feedback はない。任意の WGSL の数学的な純粋性を
|
|
61
|
+
静的に証明するものではない。時刻を進める時計や乱数源を断片へ提供しない。
|
|
62
|
+
|
|
63
|
+
## 3. 固定 prelude とパス
|
|
64
|
+
|
|
65
|
+
各パスのソース先頭に次を付加する。
|
|
66
|
+
|
|
67
|
+
```wgsl
|
|
68
|
+
struct AkariUniforms { time: f32, aspect: f32, width: f32, height: f32, seed: f32, pad: vec3f };
|
|
69
|
+
@group(0) @binding(0) var<uniform> akari: AkariUniforms;
|
|
70
|
+
fn akari_uv(pos: vec4f) -> vec2f { return pos.xy / vec2f(akari.pad.x, akari.pad.y); }
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
入力があるパスには、入力数だけ texture 宣言と、共通 sampler 宣言を続ける。断片側で重複宣言しない。
|
|
74
|
+
|
|
75
|
+
```wgsl
|
|
76
|
+
@group(1) @binding(0) var input_0: texture_2d<f32>;
|
|
77
|
+
// input_1 ... input_7 は必要な個数だけ binding 1 ... 7 に宣言
|
|
78
|
+
@group(1) @binding(8) var input_sampler: sampler;
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
パスは配列順に、1 回の `frame(gpu, f => ...)` で直列描画する。
|
|
82
|
+
最後のパスだけが surface、それ以前は `scale` 倍のオフスクリーン target へ描く。
|
|
83
|
+
`input_i` には参照先 target の `color` を渡す。resize 後は新しい texture を再束縛する。
|
|
84
|
+
`effect.draw(surface)` は使用しない(0.4.0 の surface は `frame` の `pass` で描く)。
|
|
85
|
+
|
|
86
|
+
`akari.width/height` は常に等倍出力の container 実寸で、`aspect = width / height`。
|
|
87
|
+
**`pad` は予約した形を維持しつつ実値を運ぶ**: x/y は当該パスの描画バッファ実幅・実高、z は previewScale。
|
|
88
|
+
最終パスの x/y は canvas 実寸、中間パスはさらに pass.scale を掛けた target 実寸。
|
|
89
|
+
固定 struct を変えず、`@builtin(position)` のピクセル座標を解像度に依存せず正規化するための裁定補足である。
|
|
90
|
+
断片は `akari_uv(position)`、または vgpu の頂点段が供給する左上原点の `@location(0) uv` を使う。
|
|
91
|
+
`position.xy / vec2f(akari.width, akari.height)` は縮小時に構図が変わるので使わない。
|
|
92
|
+
|
|
93
|
+
## 4. API・解像度・ツマミ
|
|
94
|
+
|
|
95
|
+
- `probe()` はページで 1 回だけ `init()` し、同じ Promise を返す。64×64 一時 surface に 2 コマ描画し、
|
|
96
|
+
GPU queue 完了と検証完了を待つ。device lost を初期化直後から監視し、一時 surface を破棄する。
|
|
97
|
+
成功値は `{ ok: true, adapter: { vendor, architecture }, ms }`。情報取得不可の文字列は空文字。
|
|
98
|
+
- `render(container, localTimeSeconds, { previewScale })` は同期描画。時刻の源は引数のみ。
|
|
99
|
+
未初期化時は probe を開始して loading のまま戻る。書き出しホストは必ず先に probe を await する。
|
|
100
|
+
描画の同期エラーは `VGPU-RENDER:` を投げ、以後その container は no-op とする。
|
|
101
|
+
書き出しホストは inspect の error も確認し、空の層を成功扱いしない。
|
|
102
|
+
- `inspect(container)` は `{ status, adapter, passes, previewScale, drawCount, deviceLost }`。
|
|
103
|
+
status は `idle`(宣言なし)、`loading`、`ready`、`error`。passes は構築したパス数。
|
|
104
|
+
- `dispose(container)` は surface・target と自動作成 canvas を破棄する。共有 device は維持する。
|
|
105
|
+
- `readDescriptor(container)` は宣言なしなら null、宣言不正なら TypeError。
|
|
106
|
+
|
|
107
|
+
previewScale は辺あたり倍率で、未指定 `1`。推奨値は `1` / `0.5` / `0.25` だが、
|
|
108
|
+
実装は有限数 `0 < s <= 1` を受け付ける。範囲外は警告 1 回で `1` にする。
|
|
109
|
+
preview-server の既定は `PREVIEW_VGPU_SCALE = 0.5`。書き出しは options を渡さず常に `1`。
|
|
110
|
+
canvas の CSS は absolute / inset 0 / width・height 100% / display block に固定する。
|
|
111
|
+
内部画素だけが減り、位置・大きさ・時刻・ツマミは変わらない。描画寸法は丸め、最小 1 px。
|
|
112
|
+
container が 0 サイズなら前回寸法を使い、前回もなければ描画しない。
|
|
113
|
+
GPU 合成側は container の解決済み配置変換をスプライトへ渡し、プレビューの位置と拡縮を維持する。
|
|
114
|
+
|
|
115
|
+
`--vgpu-<key>` が container の CSS にある場合は uniforms より優先する。
|
|
116
|
+
数値または空白・カンマ区切りのベクトルを読み、宣言と同じ要素数で全部有限数の場合だけ採用する。
|
|
117
|
+
不一致はキーごとに警告 1 回で宣言値を使う。既存の `vars` からそのまま設定できる。
|
|
118
|
+
|
|
119
|
+
## 5. 適格性と receipt
|
|
120
|
+
|
|
121
|
+
`item-keyframes` の後、three-only 判定の前に vgpu 判定を置く。
|
|
122
|
+
検出条件は `vgpu-runtime`、canvas があればその次に `three-or-canvas-runtime`。
|
|
123
|
+
|
|
124
|
+
| 分類 | 理由 |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `vgpu` | `vgpu-scene-canvas-direct`: pure 宣言が妥当で、他条件が canvas 由来だけ |
|
|
127
|
+
| `degraded` | `vgpu-stateful-unsupported`: stateful |
|
|
128
|
+
| `degraded` | `vgpu-invalid-declaration`: JSON・version・mode・スキーマ不正 |
|
|
129
|
+
| `degraded` | `vgpu-condition:<条件をカンマ連結>`: 他の動的条件や外部参照を含む |
|
|
130
|
+
|
|
131
|
+
3D 宣言が同居する場合は、優先して
|
|
132
|
+
`vgpu-condition:three-or-canvas-runtime(data-akari-3d-scene)` とする。
|
|
133
|
+
その後、他条件、宣言検証の順に判定する。JSON はちょうど 1 宣言だけを受け付ける。
|
|
134
|
+
`forceDegraded` は pure の vgpu 分類を変更しない。degraded になった vgpu は既存の規則どおり
|
|
135
|
+
`forced-dom:<元理由>` で DOM 強制の対象となり、eligible は false のまま残る。
|
|
136
|
+
|
|
137
|
+
`summary.vgpu` は件数が 1 以上のときだけ追加する。`spriteManifest.vgpu` は常に配列で、
|
|
138
|
+
各要素は `{ id, start, duration, index, z }`。overlay sheet は three と vgpu のいずれかがある場合だけ作る。
|
|
139
|
+
receipt の `gpu.vgpu` は run に vgpu があるときだけ、次の形で追加する。
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{ "overlays": 2, "adapter": { "vendor": "apple", "architecture": "metal-3" },
|
|
143
|
+
"previewScale": null, "deviceLost": false, "probeMs": 12.5 }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
overlays は有限非負整数、adapter は文字列、previewScale は数値または null、
|
|
147
|
+
deviceLost は boolean、probeMs は有限非負数または null に正規化する。
|
|
148
|
+
summary と receipt を条件付きにしたのは、vgpu を使わない既存 fixture・receipt を byte/deep-equal で保つため。
|
|
149
|
+
vgpu 不在の overlay sheet には新しい script や seek 文を一切挿入しない。
|
|
150
|
+
|
|
151
|
+
## 6. fail-loud と v0 の限界
|
|
152
|
+
|
|
153
|
+
- WebGPU 未提供・adapter null・初期化/試験描画失敗は `VGPU-UNAVAILABLE:` で probe を reject。
|
|
154
|
+
- device lost 後の render は `VGPU-DEVICE-LOST:` で throw。復帰や別 device への切り替えは行わない。
|
|
155
|
+
- `auto` でも `VGPU-` を含む失敗は OSR へフォールバックせずそのまま伝播する。
|
|
156
|
+
- プレビューは失敗を捕捉し `[data-akari-vgpu-fallback]`(任意、断片の既定 display:none)を表示して、
|
|
157
|
+
console.warn を 1 回出す。他のプレビューは続行する。
|
|
158
|
+
|
|
159
|
+
CLI の `--engine legacy` は既に廃止され、引数処理で拒否される。
|
|
160
|
+
その CLI のエラーを変更せず、`renderProject(..., { engine: 'legacy' })` の API 直呼びには
|
|
161
|
+
vgpu 宣言を検出した時点で `vgpu overlays require --engine gpu` を返す。これが元裁定の
|
|
162
|
+
「engine 解決後の legacy 拒否」と異なる理由は、CLI からその分岐に到達できないためである。
|
|
163
|
+
|
|
164
|
+
stateful・feedback・固定ステップ replay は未対応。OSR は同じ sheet を通すが v0 のパリティ gate 対象外。
|
|
165
|
+
Windows / Linux / 他 GPU は未検証。同一機での 2 走・全コマ SHA 一致は実 GPU の検収で確認する事項であり、
|
|
166
|
+
異機種間の浮動小数点の一致を保証しない。SwiftShader を WebGPU の代替として採用しない。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.47",
|
|
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": [
|
|
@@ -49,6 +49,8 @@ const { captionsHaveRenderableCues, collectFitBasisCandidates } = createRequire(
|
|
|
49
49
|
|
|
50
50
|
const VERSION = 1;
|
|
51
51
|
const EPSILON = 1e-6;
|
|
52
|
+
const MOTION_IN_OUT_PRESETS = new Set(["fade", "slide-up", "slide-down", "slide-left", "slide-right", "scale", "wipe"]);
|
|
53
|
+
const MOTION_LOOP_PRESETS = new Set(["pulse", "float", "spin"]);
|
|
52
54
|
const REPOSITORY_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../..");
|
|
53
55
|
const CAPTIONS_SCHEMA = JSON.parse(readFileSync(
|
|
54
56
|
new URL("../../schemas/captions.schema.json", import.meta.url),
|
|
@@ -1073,6 +1075,18 @@ function validateEditV2(edit, findings) {
|
|
|
1073
1075
|
});
|
|
1074
1076
|
}
|
|
1075
1077
|
if (isRecord(item.motion)) {
|
|
1078
|
+
for (const seat of ["in", "out", "loop"]) {
|
|
1079
|
+
const entry = item.motion[seat];
|
|
1080
|
+
const presets = seat === "loop" ? MOTION_LOOP_PRESETS : MOTION_IN_OUT_PRESETS;
|
|
1081
|
+
if (isRecord(entry) && typeof entry.preset === "string" && !presets.has(entry.preset)) {
|
|
1082
|
+
addFinding(findings, {
|
|
1083
|
+
severity: "warning",
|
|
1084
|
+
check: "motion.unknown-preset",
|
|
1085
|
+
message: `unknown motion ${seat} preset: ${entry.preset}; ignored when rendering`,
|
|
1086
|
+
path: `${itemPath}.motion.${seat}`,
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1076
1090
|
const inDuration = isRecord(item.motion.in) && Number.isInteger(item.motion.in.duration)
|
|
1077
1091
|
? item.motion.in.duration : 0;
|
|
1078
1092
|
const outDuration = isRecord(item.motion.out) && Number.isInteger(item.motion.out.duration)
|
|
@@ -299,6 +299,8 @@ function projectSpeechDeclarations(cuts, options) {
|
|
|
299
299
|
const cut = normalizedCuts[segment.cutIndex];
|
|
300
300
|
if (!cut || typeof cut.src !== 'string' || !cut.src)
|
|
301
301
|
continue;
|
|
302
|
+
if (cut.mute === true)
|
|
303
|
+
continue;
|
|
302
304
|
const speed = finitePositive(cut.speed) ? cut.speed : 1;
|
|
303
305
|
const segmentIn = typeof segment.in === 'number' ? segment.in : cut.in;
|
|
304
306
|
const cutTimelineStart = segment.outStart - (segmentIn - cut.in) / speed;
|
|
@@ -9,7 +9,7 @@ const ITEM_KEY_ORDER = [
|
|
|
9
9
|
'blend', 'crop', 'perspective', 'motion', 'animator', 'keyframes', 'source', 'items'
|
|
10
10
|
];
|
|
11
11
|
const EDIT_KEY_ORDER = ['version', 'output', 'sources', 'audio', 'tracks'];
|
|
12
|
-
const TRACK_KEY_ORDER = ['id', 'lane', 'name', 'items', 'content'];
|
|
12
|
+
const TRACK_KEY_ORDER = ['id', 'lane', 'name', 'muted', 'items', 'content'];
|
|
13
13
|
const CAPTION_KEY_ORDER = [
|
|
14
14
|
'id', 'start', 'end', 'text', 'speaker', 'sourceRef', 'edited', 'time_domain', 'text_style'
|
|
15
15
|
];
|
|
@@ -91,6 +91,10 @@ export interface MediaSourceV2 {
|
|
|
91
91
|
freeze?: Record<string, unknown> | null;
|
|
92
92
|
fx?: unknown[];
|
|
93
93
|
speed?: number;
|
|
94
|
+
/** 埋め込み音声(speech)の音量 dB。-60〜12・省略時 0。 */
|
|
95
|
+
gain_db?: number;
|
|
96
|
+
/** 埋め込み音声(speech)のミュート。省略時 false。 */
|
|
97
|
+
mute?: boolean;
|
|
94
98
|
chroma_key?: Record<string, unknown> | null;
|
|
95
99
|
}
|
|
96
100
|
export interface AudioMediaSourceV2 {
|
|
@@ -321,12 +325,16 @@ export interface VisualItemsTrackV2 {
|
|
|
321
325
|
id: string;
|
|
322
326
|
lane: 'visual';
|
|
323
327
|
name?: string;
|
|
328
|
+
/** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */
|
|
329
|
+
muted?: boolean;
|
|
324
330
|
items: ItemV2[];
|
|
325
331
|
}
|
|
326
332
|
export interface AudioItemsTrackV2 {
|
|
327
333
|
id: string;
|
|
328
334
|
lane: 'audio';
|
|
329
335
|
name?: string;
|
|
336
|
+
/** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */
|
|
337
|
+
muted?: boolean;
|
|
330
338
|
items: AudioMediaItemV2[];
|
|
331
339
|
}
|
|
332
340
|
export type ItemsTrackV2 = VisualItemsTrackV2 | AudioItemsTrackV2;
|
|
@@ -334,6 +342,8 @@ export interface ContentTrackV2 {
|
|
|
334
342
|
id: string;
|
|
335
343
|
lane: LaneV2;
|
|
336
344
|
name?: string;
|
|
345
|
+
/** トラックの音声をミュート。visual は cut の埋め込み音声、audio は item を書き出し・プレビューから除外。 */
|
|
346
|
+
muted?: boolean;
|
|
337
347
|
content: CaptionTrackContentV2;
|
|
338
348
|
}
|
|
339
349
|
export type TrackV2 = ItemsTrackV2 | ContentTrackV2;
|
|
@@ -120,7 +120,7 @@ function validateEditSource(value, index, ids) {
|
|
|
120
120
|
function validateTrack(value, index, trackIds, itemIds, sourceIds) {
|
|
121
121
|
const path = `edit.json.tracks[${index}]`;
|
|
122
122
|
requireRecord(value, path);
|
|
123
|
-
requireExactKeys(value, new Set(['id', 'lane', 'name', 'items', 'content']), path);
|
|
123
|
+
requireExactKeys(value, new Set(['id', 'lane', 'name', 'muted', 'items', 'content']), path);
|
|
124
124
|
requireText(value.id, `${path}.id`);
|
|
125
125
|
if (trackIds.has(value.id))
|
|
126
126
|
throw invalid(`${path}.id`, `track id が重複しています: ${value.id}`);
|
|
@@ -131,6 +131,9 @@ function validateTrack(value, index, trackIds, itemIds, sourceIds) {
|
|
|
131
131
|
if (hasOwn(value, 'name') && typeof value.name !== 'string') {
|
|
132
132
|
throw invalid(`${path}.name`, '文字列である必要があります');
|
|
133
133
|
}
|
|
134
|
+
if (hasOwn(value, 'muted') && typeof value.muted !== 'boolean') {
|
|
135
|
+
throw invalid(`${path}.muted`, 'boolean である必要があります');
|
|
136
|
+
}
|
|
134
137
|
const hasItems = hasOwn(value, 'items');
|
|
135
138
|
const hasContent = hasOwn(value, 'content');
|
|
136
139
|
if (hasItems === hasContent) {
|
|
@@ -302,7 +305,7 @@ function validateItemSource(value, path, sourceIds) {
|
|
|
302
305
|
switch (value.kind) {
|
|
303
306
|
case 'media':
|
|
304
307
|
requireExactKeys(value, new Set([
|
|
305
|
-
'kind', 'src', 'in', 'out', 'framing', 'transition_out', 'freeze', 'fx', 'speed', 'chroma_key'
|
|
308
|
+
'kind', 'src', 'in', 'out', 'framing', 'transition_out', 'freeze', 'fx', 'speed', 'chroma_key', 'gain_db', 'mute'
|
|
306
309
|
]), path);
|
|
307
310
|
requireText(value.src, `${path}.src`);
|
|
308
311
|
if (!sourceIds.has(value.src))
|
|
@@ -319,6 +322,10 @@ function validateItemSource(value, path, sourceIds) {
|
|
|
319
322
|
throw invalid(`${path}.fx`, '配列である必要があります');
|
|
320
323
|
if (hasOwn(value, 'speed'))
|
|
321
324
|
requirePositiveNumber(value.speed, `${path}.speed`);
|
|
325
|
+
if (hasOwn(value, 'gain_db'))
|
|
326
|
+
requireRange(value.gain_db, -60, 12, `${path}.gain_db`);
|
|
327
|
+
if (hasOwn(value, 'mute') && typeof value.mute !== 'boolean')
|
|
328
|
+
throw invalid(`${path}.mute`, 'boolean である必要があります');
|
|
322
329
|
return;
|
|
323
330
|
case 'html':
|
|
324
331
|
requireExactKeys(value, new Set(['kind', 'path', 'part', 'style', 'text', 'exclude', 'derivedFrom', 'vars', 'params']), path);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const ITEM_V2_KEYS: readonly ["id", "name", "hidden", "locked", "at", "duration", "anchor", "transform", "opacity", "blend", "crop", "adjust", "perspective", "motion", "animator", "keyframes", "items", "mask", "source", "role", "gain_db", "denoise", "lowcut_hz", "fade_in", "fade_out", "ducking", "duck_db", "duck_attack", "duck_release", "script", "reading", "provenance"];
|
|
2
|
-
export declare const ITEM_SOURCE_V2_KEYS: readonly ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "chroma_key", "pitch_semitones", "formant", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params", "shape", "preset", "baked", "from", "filter", "id"];
|
|
2
|
+
export declare const ITEM_SOURCE_V2_KEYS: readonly ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "gain_db", "mute", "chroma_key", "pitch_semitones", "formant", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params", "shape", "preset", "baked", "from", "filter", "id"];
|
|
3
3
|
export declare const KEYFRAME_V2_KEYS: readonly ["t", "transform", "crop", "perspective", "opacity", "gain_db", "animator", "easing"];
|
|
4
4
|
export declare const MOTION_V0_KEYS: readonly ["in", "out", "loop"];
|
|
5
5
|
export declare const ANIMATOR_V0_KEYS: readonly ["id", "basis", "shape", "start", "end", "offset", "randomize", "amount", "ease"];
|
|
@@ -17,7 +17,7 @@ export declare const ITEM_V2_KEYS_BY_DEFINITION: {
|
|
|
17
17
|
readonly itemV2AudioMedia: readonly ["id", "name", "hidden", "locked", "at", "duration", "role", "source", "gain_db", "denoise", "lowcut_hz", "keyframes", "fade_in", "fade_out", "ducking", "duck_db", "duck_attack", "duck_release", "script", "reading", "provenance"];
|
|
18
18
|
};
|
|
19
19
|
export declare const ITEM_SOURCE_V2_KEYS_BY_DEFINITION: {
|
|
20
|
-
readonly itemSourceMediaV2: readonly ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "chroma_key"];
|
|
20
|
+
readonly itemSourceMediaV2: readonly ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "gain_db", "mute", "chroma_key"];
|
|
21
21
|
readonly itemSourceAudioMediaV2: readonly ["kind", "src", "in", "out", "speed", "pitch_semitones", "formant"];
|
|
22
22
|
readonly itemSourceHtmlV2: readonly ["kind", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params"];
|
|
23
23
|
readonly itemSourceShapeV2: readonly ["kind", "shape", "params"];
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.ITEM_SOURCE_V2_KEYS_BY_DEFINITION = exports.ITEM_V2_KEYS_BY_DEFINITION = exports.SOURCE_KIND_V2 = exports.MOTION_FILE_V0_KEYS = exports.ANIMATOR_V0_KEYS = exports.MOTION_V0_KEYS = exports.KEYFRAME_V2_KEYS = exports.ITEM_SOURCE_V2_KEYS = exports.ITEM_V2_KEYS = void 0;
|
|
6
6
|
exports.ITEM_V2_KEYS = ["id", "name", "hidden", "locked", "at", "duration", "anchor", "transform", "opacity", "blend", "crop", "adjust", "perspective", "motion", "animator", "keyframes", "items", "mask", "source", "role", "gain_db", "denoise", "lowcut_hz", "fade_in", "fade_out", "ducking", "duck_db", "duck_attack", "duck_release", "script", "reading", "provenance"];
|
|
7
|
-
exports.ITEM_SOURCE_V2_KEYS = ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "chroma_key", "pitch_semitones", "formant", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params", "shape", "preset", "baked", "from", "filter", "id"];
|
|
7
|
+
exports.ITEM_SOURCE_V2_KEYS = ["kind", "src", "in", "out", "framing", "transition_out", "freeze", "fx", "speed", "gain_db", "mute", "chroma_key", "pitch_semitones", "formant", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params", "shape", "preset", "baked", "from", "filter", "id"];
|
|
8
8
|
exports.KEYFRAME_V2_KEYS = ["t", "transform", "crop", "perspective", "opacity", "gain_db", "animator", "easing"];
|
|
9
9
|
exports.MOTION_V0_KEYS = ["in", "out", "loop"];
|
|
10
10
|
exports.ANIMATOR_V0_KEYS = ["id", "basis", "shape", "start", "end", "offset", "randomize", "amount", "ease"];
|
|
@@ -204,6 +204,8 @@ exports.ITEM_SOURCE_V2_KEYS_BY_DEFINITION = {
|
|
|
204
204
|
"freeze",
|
|
205
205
|
"fx",
|
|
206
206
|
"speed",
|
|
207
|
+
"gain_db",
|
|
208
|
+
"mute",
|
|
207
209
|
"chroma_key"
|
|
208
210
|
],
|
|
209
211
|
"itemSourceAudioMediaV2": [
|
|
@@ -227,6 +227,7 @@ function readV2Internal(raw) {
|
|
|
227
227
|
lane: track.lane,
|
|
228
228
|
z: track.z,
|
|
229
229
|
...(track.name !== undefined ? { name: track.name } : {}),
|
|
230
|
+
...(track.muted === undefined ? {} : { muted: track.muted }),
|
|
230
231
|
origin: 'declared',
|
|
231
232
|
...('content' in track ? { content: { from: 'captions.json' } } : {}),
|
|
232
233
|
items,
|
|
@@ -962,6 +963,8 @@ function copyMediaSourceFields(source) {
|
|
|
962
963
|
...(source.freeze !== undefined ? { freeze: source.freeze } : {}),
|
|
963
964
|
...(source.fx !== undefined ? { fx: source.fx } : {}),
|
|
964
965
|
...(source.speed !== undefined ? { speed: source.speed } : {}),
|
|
966
|
+
...(source.gain_db !== undefined ? { gain_db: source.gain_db } : {}),
|
|
967
|
+
...(source.mute !== undefined ? { mute: source.mute } : {}),
|
|
965
968
|
...(source.chroma_key !== undefined ? { chroma_key: source.chroma_key } : {})
|
|
966
969
|
};
|
|
967
970
|
}
|
|
@@ -1085,6 +1088,8 @@ function projectLegacyEdit(internal) {
|
|
|
1085
1088
|
const audioNarration = [];
|
|
1086
1089
|
let audioBgm;
|
|
1087
1090
|
for (const track of internal.tracks) {
|
|
1091
|
+
if (track.lane === 'audio' && track.muted === true)
|
|
1092
|
+
continue;
|
|
1088
1093
|
for (const item of track.items) {
|
|
1089
1094
|
const value = item.legacy.value;
|
|
1090
1095
|
if (value === undefined) {
|
|
@@ -1114,7 +1119,11 @@ function projectLegacyEdit(internal) {
|
|
|
1114
1119
|
layers.push({ index: item.legacy.index, value: value });
|
|
1115
1120
|
break;
|
|
1116
1121
|
default:
|
|
1117
|
-
cuts.push({
|
|
1122
|
+
cuts.push({
|
|
1123
|
+
index: item.legacy.index,
|
|
1124
|
+
value: (track.lane === 'visual' && track.muted === true
|
|
1125
|
+
? { ...value, mute: true } : value)
|
|
1126
|
+
});
|
|
1118
1127
|
break;
|
|
1119
1128
|
}
|
|
1120
1129
|
break;
|
|
@@ -7,6 +7,7 @@ exports.projectLegacyAudioView = projectLegacyAudioView;
|
|
|
7
7
|
*/
|
|
8
8
|
function projectLegacyAudioView(internal) {
|
|
9
9
|
const ordered = internal.tracks
|
|
10
|
+
.filter(track => !(track.lane === 'audio' && track.muted === true))
|
|
10
11
|
.flatMap(track => track.items)
|
|
11
12
|
.filter(item => item.legacy.collection === 'sfx'
|
|
12
13
|
|| item.legacy.collection === 'narration'
|
|
@@ -1437,6 +1437,7 @@ var AkariEditKernel = (() => {
|
|
|
1437
1437
|
if (segment.kind !== "src" || segment.cutIndex === null) continue;
|
|
1438
1438
|
const cut = normalizedCuts[segment.cutIndex];
|
|
1439
1439
|
if (!cut || typeof cut.src !== "string" || !cut.src) continue;
|
|
1440
|
+
if (cut.mute === true) continue;
|
|
1440
1441
|
const speed = finitePositive(cut.speed) ? cut.speed : 1;
|
|
1441
1442
|
const segmentIn = typeof segment.in === "number" ? segment.in : cut.in;
|
|
1442
1443
|
const cutTimelineStart = segment.outStart - (segmentIn - cut.in) / speed;
|
|
@@ -1863,7 +1864,7 @@ var AkariEditKernel = (() => {
|
|
|
1863
1864
|
function validateTrack(value, index, trackIds, itemIds, sourceIds) {
|
|
1864
1865
|
const path = `edit.json.tracks[${index}]`;
|
|
1865
1866
|
requireRecord(value, path);
|
|
1866
|
-
requireExactKeys(value, /* @__PURE__ */ new Set(["id", "lane", "name", "items", "content"]), path);
|
|
1867
|
+
requireExactKeys(value, /* @__PURE__ */ new Set(["id", "lane", "name", "muted", "items", "content"]), path);
|
|
1867
1868
|
requireText(value.id, `${path}.id`);
|
|
1868
1869
|
if (trackIds.has(value.id)) throw invalid(`${path}.id`, `track id \u304C\u91CD\u8907\u3057\u3066\u3044\u307E\u3059: ${value.id}`);
|
|
1869
1870
|
trackIds.add(value.id);
|
|
@@ -1873,6 +1874,9 @@ var AkariEditKernel = (() => {
|
|
|
1873
1874
|
if (hasOwn(value, "name") && typeof value.name !== "string") {
|
|
1874
1875
|
throw invalid(`${path}.name`, "\u6587\u5B57\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
1875
1876
|
}
|
|
1877
|
+
if (hasOwn(value, "muted") && typeof value.muted !== "boolean") {
|
|
1878
|
+
throw invalid(`${path}.muted`, "boolean \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
1879
|
+
}
|
|
1876
1880
|
const hasItems = hasOwn(value, "items");
|
|
1877
1881
|
const hasContent = hasOwn(value, "content");
|
|
1878
1882
|
if (hasItems === hasContent) {
|
|
@@ -2018,7 +2022,9 @@ var AkariEditKernel = (() => {
|
|
|
2018
2022
|
"freeze",
|
|
2019
2023
|
"fx",
|
|
2020
2024
|
"speed",
|
|
2021
|
-
"chroma_key"
|
|
2025
|
+
"chroma_key",
|
|
2026
|
+
"gain_db",
|
|
2027
|
+
"mute"
|
|
2022
2028
|
]), path);
|
|
2023
2029
|
requireText(value.src, `${path}.src`);
|
|
2024
2030
|
if (!sourceIds.has(value.src)) throw invalid(`${path}.src`, `sources[].id \u306B\u5B58\u5728\u3057\u307E\u305B\u3093: ${value.src}`);
|
|
@@ -2030,6 +2036,8 @@ var AkariEditKernel = (() => {
|
|
|
2030
2036
|
}
|
|
2031
2037
|
if (hasOwn(value, "fx") && !Array.isArray(value.fx)) throw invalid(`${path}.fx`, "\u914D\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
2032
2038
|
if (hasOwn(value, "speed")) requirePositiveNumber(value.speed, `${path}.speed`);
|
|
2039
|
+
if (hasOwn(value, "gain_db")) requireRange(value.gain_db, -60, 12, `${path}.gain_db`);
|
|
2040
|
+
if (hasOwn(value, "mute") && typeof value.mute !== "boolean") throw invalid(`${path}.mute`, "boolean \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059");
|
|
2033
2041
|
return;
|
|
2034
2042
|
case "html":
|
|
2035
2043
|
requireExactKeys(value, /* @__PURE__ */ new Set(["kind", "path", "part", "style", "text", "exclude", "derivedFrom", "vars", "params"]), path);
|
|
@@ -2549,6 +2557,7 @@ var AkariEditKernel = (() => {
|
|
|
2549
2557
|
lane: track.lane,
|
|
2550
2558
|
z: track.z,
|
|
2551
2559
|
...track.name !== void 0 ? { name: track.name } : {},
|
|
2560
|
+
...track.muted === void 0 ? {} : { muted: track.muted },
|
|
2552
2561
|
origin: "declared",
|
|
2553
2562
|
..."content" in track ? { content: { from: "captions.json" } } : {},
|
|
2554
2563
|
items,
|
|
@@ -3254,6 +3263,8 @@ var AkariEditKernel = (() => {
|
|
|
3254
3263
|
...source.freeze !== void 0 ? { freeze: source.freeze } : {},
|
|
3255
3264
|
...source.fx !== void 0 ? { fx: source.fx } : {},
|
|
3256
3265
|
...source.speed !== void 0 ? { speed: source.speed } : {},
|
|
3266
|
+
...source.gain_db !== void 0 ? { gain_db: source.gain_db } : {},
|
|
3267
|
+
...source.mute !== void 0 ? { mute: source.mute } : {},
|
|
3257
3268
|
...source.chroma_key !== void 0 ? { chroma_key: source.chroma_key } : {}
|
|
3258
3269
|
};
|
|
3259
3270
|
}
|
|
@@ -3381,6 +3392,7 @@ var AkariEditKernel = (() => {
|
|
|
3381
3392
|
const audioNarration = [];
|
|
3382
3393
|
let audioBgm;
|
|
3383
3394
|
for (const track of internal.tracks) {
|
|
3395
|
+
if (track.lane === "audio" && track.muted === true) continue;
|
|
3384
3396
|
for (const item of track.items) {
|
|
3385
3397
|
const value = item.legacy.value;
|
|
3386
3398
|
if (value === void 0) {
|
|
@@ -3405,7 +3417,10 @@ var AkariEditKernel = (() => {
|
|
|
3405
3417
|
layers.push({ index: item.legacy.index, value });
|
|
3406
3418
|
break;
|
|
3407
3419
|
default:
|
|
3408
|
-
cuts.push({
|
|
3420
|
+
cuts.push({
|
|
3421
|
+
index: item.legacy.index,
|
|
3422
|
+
value: track.lane === "visual" && track.muted === true ? { ...value, mute: true } : value
|
|
3423
|
+
});
|
|
3409
3424
|
break;
|
|
3410
3425
|
}
|
|
3411
3426
|
break;
|
|
@@ -236,3 +236,5 @@ frame-engine bundle は生成物です。`generated/frame-engine.js` を直接
|
|
|
236
236
|
生フレーム hash は隔離した検証専用 module からだけ利用でき、実行時 readback trap とは同時に
|
|
237
237
|
有効化できません。DOM frame 検証は隔離した texture sentinel を使い、選択した settle policy
|
|
238
238
|
(`raf2-paint-event` または `sync-layout`)を receipt に記録します。
|
|
239
|
+
|
|
240
|
+
宣言型 `data-akari-vgpu-scene` は同梱 vgpu 0.4.0 の WebGPU ランタイムで描き、描画直後の canvas を GPU 合成へ渡す。v0 は pure な fragment パス、先行パスの texture 入力、CSS `--vgpu-*` ツマミに対応する。ライブプレビューは辺あたり半解像度、GPU 書き出しは等倍で、配置と時刻を共有する。WebGPU の probe・device 障害は `auto` でも失敗として伝播し OSR へ落とさない。receipt の `gpu.vgpu` は使用時だけ追加する。詳しくは [vgpu v0 契約](../../docs/contract-2026-09-06-vgpu-layer-v0.md)。
|
|
@@ -258,3 +258,5 @@ The frame-engine bundle is generated. Do not edit `generated/frame-engine.js` di
|
|
|
258
258
|
Frame hashing is available only through the isolated verification module and cannot be combined
|
|
259
259
|
with the runtime readback trap. DOM frame verification uses an isolated texture sentinel and
|
|
260
260
|
records the selected settle policy (`raf2-paint-event` or `sync-layout`) in the receipt.
|
|
261
|
+
|
|
262
|
+
Declarative `data-akari-vgpu-scene` overlays use the vendored vgpu 0.4.0 WebGPU runtime and transfer each freshly drawn canvas into the GPU compositor. v0 supports pure fragment passes, earlier-pass texture inputs, and CSS `--vgpu-*` uniforms. Live preview defaults to half resolution per edge; GPU export uses full resolution with the same placement and time. WebGPU probe/device failures are fatal, including in `auto` (no OSR fallback); `gpu.vgpu` is present in receipts only when used. See the [vgpu v0 contract](../../docs/contract-2026-09-06-vgpu-layer-v0.md) (Japanese).
|