akari-video 1.2.0 → 1.3.0-beta.1
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-beta.1",
|
|
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": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akari-video",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-beta.1",
|
|
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": [
|
|
@@ -340,6 +340,96 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
340
340
|
// テキスト編集で断片 HTML を保存するときに作者の元指定へ戻せるよう、初回値だけ保持する。
|
|
341
341
|
const hitPolicyOriginalPointerEvents = new WeakMap();
|
|
342
342
|
const hitPolicyAppliedContainers = new WeakSet();
|
|
343
|
+
const hitPolicyTimes = new WeakMap();
|
|
344
|
+
const staleHitPolicyContainers = new Set();
|
|
345
|
+
const pausedHitPolicyContainers = new Set();
|
|
346
|
+
let pausedHitPolicyTimer = null;
|
|
347
|
+
let lastPointerHitPolicyRefresh = -Infinity;
|
|
348
|
+
|
|
349
|
+
function hitPolicyOperationBusy() {
|
|
350
|
+
return Boolean(activeEdit || activeDrag || activeResize || activeRotate || activeLine
|
|
351
|
+
|| marqueeFrame || pointerOwner != null);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function schedulePausedHitPolicyRefresh(delay = 120) {
|
|
355
|
+
if (typeof setTimeout !== 'function') return;
|
|
356
|
+
if (pausedHitPolicyTimer !== null) clearTimeout(pausedHitPolicyTimer);
|
|
357
|
+
pausedHitPolicyTimer = setTimeout(flushPausedHitPolicies, delay);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// runtime は可視コンテナの時刻だけを記録する。CSS の読み取りはここでは行わない。
|
|
361
|
+
function markOverlayHitPolicyStale(container, localTimeMs, paused = false, reentered = false,
|
|
362
|
+
animationReady = null) {
|
|
363
|
+
if (!container) return;
|
|
364
|
+
let state = hitPolicyTimes.get(container);
|
|
365
|
+
if (!state) {
|
|
366
|
+
state = { current: localTimeMs, measured: null, paused: null };
|
|
367
|
+
hitPolicyTimes.set(container, state);
|
|
368
|
+
}
|
|
369
|
+
const timeChanged = state.current !== localTimeMs;
|
|
370
|
+
const enteredPause = paused && state.paused !== true;
|
|
371
|
+
state.current = localTimeMs;
|
|
372
|
+
state.paused = paused;
|
|
373
|
+
if (reentered) {
|
|
374
|
+
state.measured = null;
|
|
375
|
+
hitPolicyAppliedContainers.delete(container);
|
|
376
|
+
}
|
|
377
|
+
if (state.measured !== localTimeMs) staleHitPolicyContainers.add(container);
|
|
378
|
+
// pause()/currentTime の pending 補正はこの tick の測定より後に解決し得る。
|
|
379
|
+
// 暫定 apply が stale を消しても、停止後の一回は別の印で必ず残す。
|
|
380
|
+
if (paused && (reentered || timeChanged || enteredPause)) pausedHitPolicyContainers.add(container);
|
|
381
|
+
if (!paused) pausedHitPolicyContainers.delete(container);
|
|
382
|
+
if (paused && pausedHitPolicyContainers.size) {
|
|
383
|
+
// スクラブ中は連続 tick をまとめ、停止後にポインタ無しで確定する。
|
|
384
|
+
schedulePausedHitPolicyRefresh();
|
|
385
|
+
}
|
|
386
|
+
if (paused && (reentered || timeChanged || enteredPause) && animationReady?.then) {
|
|
387
|
+
const expectedState = state;
|
|
388
|
+
animationReady.then(() => {
|
|
389
|
+
if (hitPolicyTimes.get(container) !== expectedState || !state.paused
|
|
390
|
+
|| state.current !== localTimeMs) return;
|
|
391
|
+
// ready 後の currentTime 補正が 120ms の測定より遅れた場合も追い付く。
|
|
392
|
+
const alreadyRefreshed = !pausedHitPolicyContainers.has(container);
|
|
393
|
+
pausedHitPolicyContainers.add(container);
|
|
394
|
+
schedulePausedHitPolicyRefresh(alreadyRefreshed ? 0 : 120);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function flushPausedHitPolicies() {
|
|
400
|
+
pausedHitPolicyTimer = null;
|
|
401
|
+
if (pausedHitPolicyContainers.size === 0) return;
|
|
402
|
+
if (hitPolicyOperationBusy()) {
|
|
403
|
+
// 編集・ジェスチャーが終わるまで印を保持する。
|
|
404
|
+
pausedHitPolicyTimer = setTimeout(flushPausedHitPolicies, 120);
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
refreshStaleHitPolicies(true);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function refreshStaleHitPolicies(includePaused = false) {
|
|
411
|
+
if (hitPolicyOperationBusy()) return false;
|
|
412
|
+
let refreshed = false;
|
|
413
|
+
const candidates = includePaused ? pausedHitPolicyContainers : staleHitPolicyContainers;
|
|
414
|
+
for (const container of candidates) {
|
|
415
|
+
if (includePaused) pausedHitPolicyContainers.delete(container);
|
|
416
|
+
if (!container.isConnected || container.style.visibility === 'hidden') {
|
|
417
|
+
staleHitPolicyContainers.delete(container);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
invalidateOverlayHitPolicy(container);
|
|
421
|
+
applyOverlayHitPolicy(container);
|
|
422
|
+
refreshed = true;
|
|
423
|
+
}
|
|
424
|
+
return refreshed;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function forgetOverlayHitPolicyTracking(container) {
|
|
428
|
+
staleHitPolicyContainers.delete(container);
|
|
429
|
+
pausedHitPolicyContainers.delete(container);
|
|
430
|
+
hitPolicyTimes.delete(container);
|
|
431
|
+
hitPolicyAppliedContainers.delete(container);
|
|
432
|
+
}
|
|
343
433
|
|
|
344
434
|
// overlay_write は操作順を保存する。selftest は今回の書き込みをこの記録から待つ。
|
|
345
435
|
let writeTail = Promise.resolve();
|
|
@@ -982,7 +1072,8 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
982
1072
|
|
|
983
1073
|
// 全画面の外側コンテナと断片ルートは素通しにし、実際に背景・枠・影・文字・置換要素を
|
|
984
1074
|
// 描く可視の子孫だけを拾う。data-akari-hit は最寄りの指定を配下へ継承し、機械判定より
|
|
985
|
-
// 優先する。字幕が 1,000 件級でも全件を走査しないよう、runtime
|
|
1075
|
+
// 優先する。字幕が 1,000 件級でも全件を走査しないよう、runtime は可視コンテナの
|
|
1076
|
+
// 初回・停止後・ポインタ入力時だけ適用し、再生 tick では時刻の印だけを付ける。
|
|
986
1077
|
function fragmentRootCoversContainer(element, container) {
|
|
987
1078
|
const rootRect = element.getBoundingClientRect();
|
|
988
1079
|
const containerRect = container.getBoundingClientRect();
|
|
@@ -1056,6 +1147,9 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
1056
1147
|
|
|
1057
1148
|
for (const root of container.children) visit(root, null, true, true);
|
|
1058
1149
|
hitPolicyAppliedContainers.add(container);
|
|
1150
|
+
const state = hitPolicyTimes.get(container);
|
|
1151
|
+
if (state) state.measured = state.current;
|
|
1152
|
+
staleHitPolicyContainers.delete(container);
|
|
1059
1153
|
updateShapeLineHitProxyWidths();
|
|
1060
1154
|
}
|
|
1061
1155
|
|
|
@@ -1169,6 +1263,34 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
1169
1263
|
}
|
|
1170
1264
|
}
|
|
1171
1265
|
|
|
1266
|
+
// 08-07 裁定: 背景は選択・削除できる。旧矩形フォールバックと違い、stage 面に
|
|
1267
|
+
// 落ちたクリックで、全面を覆って自ら塗るルートだけを拾う。実際のヒット先が
|
|
1268
|
+
// あるときは使わず 4680d90d8 の巻き込みを防ぎ、素通し規約は変えない。
|
|
1269
|
+
function paintedStageOverlayAt(clientX, clientY) {
|
|
1270
|
+
const candidates = [...stage.children]
|
|
1271
|
+
.flatMap((container, index) => {
|
|
1272
|
+
if (!isSelectable(container)) return [];
|
|
1273
|
+
const value = Number.parseFloat(getComputedStyle(container).zIndex);
|
|
1274
|
+
return [{ container, index, zIndex: Number.isFinite(value) ? value : 0 }];
|
|
1275
|
+
})
|
|
1276
|
+
.sort((a, b) => b.zIndex - a.zIndex || b.index - a.index);
|
|
1277
|
+
|
|
1278
|
+
for (const { container } of candidates) {
|
|
1279
|
+
for (const root of container.children) {
|
|
1280
|
+
if (root.hasAttribute("data-akari-interaction") || root.getAttribute("data-akari-hit") === "pass") continue;
|
|
1281
|
+
const style = getComputedStyle(root);
|
|
1282
|
+
if (style.display === "none" || Number(style.opacity) <= 0
|
|
1283
|
+
|| ["hidden", "collapse"].includes(style.visibility)
|
|
1284
|
+
|| !fragmentRootCoversContainer(root, container)
|
|
1285
|
+
|| !drawsOwnContent(root, style)) continue;
|
|
1286
|
+
const rect = root.getBoundingClientRect();
|
|
1287
|
+
if (clientX >= rect.left && clientX <= rect.right
|
|
1288
|
+
&& clientY >= rect.top && clientY <= rect.bottom) return container;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1172
1294
|
function overlayForEvent(event) {
|
|
1173
1295
|
const eventTargetOverlay = findOverlayContainer(event.target);
|
|
1174
1296
|
if (eventTargetOverlay && !isSelectable(eventTargetOverlay)) {
|
|
@@ -1180,6 +1302,11 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
1180
1302
|
) {
|
|
1181
1303
|
return selftestOverlayOverride;
|
|
1182
1304
|
}
|
|
1305
|
+
if (event.target === stage && !eventTargetOverlay
|
|
1306
|
+
&& Number.isFinite(event.clientX) && Number.isFinite(event.clientY)) {
|
|
1307
|
+
const paintedOverlay = paintedStageOverlayAt(event.clientX, event.clientY);
|
|
1308
|
+
if (paintedOverlay) return paintedOverlay;
|
|
1309
|
+
}
|
|
1183
1310
|
return isSelectable(eventTargetOverlay) ? eventTargetOverlay : null;
|
|
1184
1311
|
}
|
|
1185
1312
|
|
|
@@ -3983,6 +4110,7 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
3983
4110
|
|
|
3984
4111
|
function onPointerDown(event) {
|
|
3985
4112
|
if (!interactionEnabled || !canBeginPointerInteraction(pointerOwner)) return;
|
|
4113
|
+
event = correctedHitPolicyEvent(event);
|
|
3986
4114
|
if (event.button !== 0 || activeDrag || activeResize || activeRotate || activeLine) return;
|
|
3987
4115
|
if (selectedId && stage && event.target instanceof Element) {
|
|
3988
4116
|
const bounds = stage.getBoundingClientRect();
|
|
@@ -4833,6 +4961,7 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
4833
4961
|
|
|
4834
4962
|
function onClick(event) {
|
|
4835
4963
|
if (!interactionEnabled || activeEdit) return;
|
|
4964
|
+
event = correctedHitPolicyEvent(event);
|
|
4836
4965
|
const hit = overlayForEvent(event);
|
|
4837
4966
|
// pointerdown already toggled. Do not toggle twice or update the cycle clock.
|
|
4838
4967
|
if (event.shiftKey && clickOrigin?.scopedHit) {
|
|
@@ -5329,11 +5458,73 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
5329
5458
|
for (const type of ["pointerdown", "pointerup", "click", "dblclick"]) {
|
|
5330
5459
|
window.addEventListener(type, passTransparentCanvasEvent, true);
|
|
5331
5460
|
}
|
|
5461
|
+
const correctedHitPolicyEvents = new WeakMap();
|
|
5462
|
+
let redirectedHitPolicyClick = null;
|
|
5463
|
+
function pointerInsideStage(event) {
|
|
5464
|
+
if (!stage || !Number.isFinite(event.clientX) || !Number.isFinite(event.clientY)) return false;
|
|
5465
|
+
const rect = stage.getBoundingClientRect();
|
|
5466
|
+
return event.clientX >= rect.left && event.clientX <= rect.right
|
|
5467
|
+
&& event.clientY >= rect.top && event.clientY <= rect.bottom;
|
|
5468
|
+
}
|
|
5469
|
+
function trustedEventAtTarget(event, target) {
|
|
5470
|
+
// 合成 Event は isTrusted=false になり E2 の焦点を失う。元の信頼済み
|
|
5471
|
+
// イベントを保ったまま、選択処理に見せる target だけ現在の hit-test にする。
|
|
5472
|
+
return new Proxy(event, { get(original, key) {
|
|
5473
|
+
if (key === 'target') return target;
|
|
5474
|
+
const value = Reflect.get(original, key, original);
|
|
5475
|
+
return typeof value === 'function' ? value.bind(original) : value;
|
|
5476
|
+
} });
|
|
5477
|
+
}
|
|
5478
|
+
function correctHitPolicyEvent(event, target) {
|
|
5479
|
+
correctedHitPolicyEvents.set(event, target);
|
|
5480
|
+
// Window capture の後続ホストにも素の HTML hit と同じ target を見せる。
|
|
5481
|
+
// Event 自体は元の信頼済みイベントなので、再生停止や混在選択は一度だけ走る。
|
|
5482
|
+
try { Object.defineProperty(event, 'target', { configurable: true, value: target }); }
|
|
5483
|
+
catch { /* document 側は WeakMap の target へフォールバックする。 */ }
|
|
5484
|
+
}
|
|
5485
|
+
function correctedHitPolicyEvent(event) {
|
|
5486
|
+
const target = correctedHitPolicyEvents.get(event);
|
|
5487
|
+
return target && event.target !== target ? trustedEventAtTarget(event, target) : event;
|
|
5488
|
+
}
|
|
5489
|
+
function stopCorrectedHitPolicyPropagation(event) {
|
|
5490
|
+
// window のホスト捕捉は通し、古い preview-stage への下流だけ止める。
|
|
5491
|
+
if (findOverlayContainer(correctedHitPolicyEvents.get(event))) event.stopPropagation();
|
|
5492
|
+
}
|
|
5493
|
+
window.addEventListener('pointermove', event => {
|
|
5494
|
+
if (!pointerInsideStage(event) || !staleHitPolicyContainers.size
|
|
5495
|
+
|| hitPolicyOperationBusy()) return;
|
|
5496
|
+
const now = performance.now();
|
|
5497
|
+
if (now - lastPointerHitPolicyRefresh < 125) return;
|
|
5498
|
+
if (!refreshStaleHitPolicies()) return;
|
|
5499
|
+
lastPointerHitPolicyRefresh = now;
|
|
5500
|
+
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
5501
|
+
if (target && target !== event.target) correctHitPolicyEvent(event, target);
|
|
5502
|
+
}, true);
|
|
5503
|
+
window.addEventListener('pointerdown', event => {
|
|
5504
|
+
if (event.button !== 0 || !pointerInsideStage(event) || hitPolicyOperationBusy()) return;
|
|
5505
|
+
redirectedHitPolicyClick = null;
|
|
5506
|
+
if (!refreshStaleHitPolicies()) return;
|
|
5507
|
+
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
5508
|
+
if (!target || target === event.target) return;
|
|
5509
|
+
redirectedHitPolicyClick = { x: event.clientX, y: event.clientY };
|
|
5510
|
+
correctHitPolicyEvent(event, target);
|
|
5511
|
+
}, true);
|
|
5512
|
+
window.addEventListener('click', event => {
|
|
5513
|
+
if (!redirectedHitPolicyClick) return;
|
|
5514
|
+
const redirect = redirectedHitPolicyClick;
|
|
5515
|
+
redirectedHitPolicyClick = null;
|
|
5516
|
+
if (Math.hypot(event.clientX - redirect.x, event.clientY - redirect.y) > 6) return;
|
|
5517
|
+
const target = document.elementFromPoint(event.clientX, event.clientY);
|
|
5518
|
+
if (!target || target === event.target) return;
|
|
5519
|
+
correctHitPolicyEvent(event, target);
|
|
5520
|
+
}, true);
|
|
5332
5521
|
listenerRoot.addEventListener('pointermove', updateShapeLineHitProxyWidths, true);
|
|
5333
5522
|
listenerRoot.addEventListener('pointerdown', updateShapeLineHitProxyWidths, true);
|
|
5334
5523
|
window.addEventListener('resize', updateShapeLineHitProxyWidths);
|
|
5335
5524
|
listenerRoot.addEventListener("click", onClick, true);
|
|
5336
5525
|
listenerRoot.addEventListener("pointerdown", onPointerDown, true);
|
|
5526
|
+
listenerRoot.addEventListener("click", stopCorrectedHitPolicyPropagation, true);
|
|
5527
|
+
listenerRoot.addEventListener("pointerdown", stopCorrectedHitPolicyPropagation, true);
|
|
5337
5528
|
listenerRoot.addEventListener("dblclick", onDoubleClick, true);
|
|
5338
5529
|
listenerRoot.addEventListener("blur", onBlur, true);
|
|
5339
5530
|
listenerRoot.addEventListener("input", onEditableInput, true);
|
|
@@ -5444,6 +5635,8 @@ function elementBoxCompanions(style, parentStyle, width, height) {
|
|
|
5444
5635
|
// ㉑ 素通し: overlay-runtime.js の tick() が可視化タイミングで呼ぶ。
|
|
5445
5636
|
applyOverlayHitPolicy,
|
|
5446
5637
|
invalidateOverlayHitPolicy,
|
|
5638
|
+
markOverlayHitPolicyStale,
|
|
5639
|
+
forgetOverlayHitPolicyTracking,
|
|
5447
5640
|
syncOverlayHitRegion,
|
|
5448
5641
|
// Web UI(preview-server)が編集モードを抜けるときに選択枠を畳むための公開口
|
|
5449
5642
|
// (Phase 2-4 一本化。shell では未使用の追加 export で挙動不変)。
|
|
@@ -341,6 +341,7 @@ function createOverlayRuntime(options = {}) {
|
|
|
341
341
|
|
|
342
342
|
function unmount() {
|
|
343
343
|
for (const overlay of mountedOverlays) {
|
|
344
|
+
window.akari.interaction?.forgetOverlayHitPolicyTracking?.(overlay.container);
|
|
344
345
|
for (const animation of overlay.animations ?? []) releaseAnimation(animation);
|
|
345
346
|
for (const runtime of overlayRuntimes(overlay)) runtime.dispose(overlay.container);
|
|
346
347
|
}
|
|
@@ -490,6 +491,7 @@ function createOverlayRuntime(options = {}) {
|
|
|
490
491
|
runtimesVersion: runtimeRegistryVersion,
|
|
491
492
|
keepLayoutWhenHidden,
|
|
492
493
|
hitPolicyPending: false,
|
|
494
|
+
hitPolicyEntry: false,
|
|
493
495
|
// getAnimations({ subtree: true }) の 250ms キャッシュ(tick() 参照)
|
|
494
496
|
animations: undefined,
|
|
495
497
|
animationsAt: 0,
|
|
@@ -574,6 +576,7 @@ function createOverlayRuntime(options = {}) {
|
|
|
574
576
|
}
|
|
575
577
|
mounted.container.style.setProperty("opacity", String(statics.opacity));
|
|
576
578
|
mounted.hitPolicyPending = true;
|
|
579
|
+
mounted.hitPolicyEntry = true;
|
|
577
580
|
mounted.statics = statics;
|
|
578
581
|
mounted.keyframes = Array.isArray(value.keyframes) ? value.keyframes : undefined;
|
|
579
582
|
mounted.fps = finiteNumber(summary?.output?.fps, 30);
|
|
@@ -595,6 +598,7 @@ function createOverlayRuntime(options = {}) {
|
|
|
595
598
|
mounted.animationsAt = 0;
|
|
596
599
|
mounted.animationEndTimes = [];
|
|
597
600
|
mounted.hitPolicyPending = true;
|
|
601
|
+
mounted.hitPolicyEntry = true;
|
|
598
602
|
return true;
|
|
599
603
|
}
|
|
600
604
|
|
|
@@ -636,7 +640,14 @@ function createOverlayRuntime(options = {}) {
|
|
|
636
640
|
// することで、実際に存在する CSS Animation を「今可視のオーバーレイ分だけ」に
|
|
637
641
|
// 抑え、この地雷を踏まない。
|
|
638
642
|
overlay.container.toggleAttribute("data-akari-active", visible);
|
|
643
|
+
if (!visible && !isPlaying && overlay.animations?.length) {
|
|
644
|
+
// 停止中の連続シークが同一描画フレームで外→内へ戻っても、CSS が
|
|
645
|
+
// inactive を一度観測するようにする。これが無いとゲートの off/on が
|
|
646
|
+
// 相殺され、新しい Animation が生成されず初期 opacity 0 に残る。
|
|
647
|
+
void overlay.container.offsetWidth;
|
|
648
|
+
}
|
|
639
649
|
overlay.hitPolicyPending = visible;
|
|
650
|
+
overlay.hitPolicyEntry = visible;
|
|
640
651
|
// getAnimations() のキャッシュ(下記)は可視化フリップで必ず捨てる。ゲート属性の付け外しで
|
|
641
652
|
// CSS animation の顔ぶれが変わるため、可視化直後の tick は引き直す。非表示化でも捨て、
|
|
642
653
|
// 非可視の間 Animation 参照を持ち越さない。
|
|
@@ -650,6 +661,7 @@ function createOverlayRuntime(options = {}) {
|
|
|
650
661
|
overlay.animationsAt = 0;
|
|
651
662
|
overlay.animationEndTimes = [];
|
|
652
663
|
if (!visible) {
|
|
664
|
+
window.akari.interaction?.forgetOverlayHitPolicyTracking?.(overlay.container);
|
|
653
665
|
if (!overlay.keepLayoutWhenHidden) {
|
|
654
666
|
overlay.container.setAttribute(RUNTIME_HIDDEN_ATTRIBUTE, "");
|
|
655
667
|
}
|
|
@@ -762,15 +774,18 @@ function createOverlayRuntime(options = {}) {
|
|
|
762
774
|
runtime.render(overlay.container, localTimeMs / 1000,
|
|
763
775
|
{ syncVideos: true, maxRenderSize, playing: Boolean(playing) });
|
|
764
776
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
777
|
+
const ready = !isPlaying
|
|
778
|
+
? overlay.animations.map(animation => pendingReady.get(animation)).filter(Boolean) : [];
|
|
779
|
+
window.akari.interaction?.markOverlayHitPolicyStale?.(
|
|
780
|
+
overlay.container, localTimeMs, !isPlaying, overlay.hitPolicyEntry,
|
|
781
|
+
ready.length ? Promise.allSettled(ready) : null);
|
|
782
|
+
overlay.hitPolicyEntry = false;
|
|
783
|
+
// 初回の仮判定と有限アニメ終端の確定判定だけをここで適用する。
|
|
784
|
+
// 途中の姿は上の時刻印を使い、停止後またはポインタ入力時に interaction が
|
|
785
|
+
// 必要な可視コンテナだけ測り直す。終端 tick が存在しない断片も停止後に更新される。
|
|
770
786
|
if (overlay.hitPolicyPending) {
|
|
771
787
|
window.akari.interaction?.syncOverlayHitRegion?.(overlay.container);
|
|
772
|
-
//
|
|
773
|
-
// 実質 no-op(暫定適用)。確定姿勢に達した tick で invalidate してから測り直す。
|
|
788
|
+
// 初回以外は WeakSet のガードで no-op。再入場時は時刻印側が解除する。
|
|
774
789
|
window.akari.interaction?.applyOverlayHitPolicy?.(overlay.container);
|
|
775
790
|
if (entryAnimationsSettled(overlay.animationEndTimes, localTimeMs)) {
|
|
776
791
|
window.akari.interaction?.invalidateOverlayHitPolicy?.(overlay.container);
|