akari-video 0.1.19 → 0.1.21
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-07-23-analysis-person-matte.md +102 -2
- package/vendor/packages/akari-launcher/package.json +1 -1
- package/vendor/packages/edit-lint/src/edit-lint.mjs +90 -18
- package/vendor/packages/edit-store/lib/cut-adjacency.d.ts +25 -0
- package/vendor/packages/edit-store/lib/cut-adjacency.js +38 -8
- package/vendor/packages/edit-store/lib/edit-store.d.ts +13 -2
- package/vendor/packages/edit-store/lib/edit-store.js +69 -3
- package/vendor/packages/edit-store/lib/index.d.ts +1 -0
- package/vendor/packages/edit-store/lib/index.js +1 -0
- package/vendor/packages/edit-store/lib/internal-model.d.ts +13 -0
- package/vendor/packages/edit-store/lib/internal-model.js +98 -18
- package/vendor/packages/edit-store/lib/migrate/legacy-parse.js +9 -6
- package/vendor/packages/edit-store/lib/timeline-map.d.ts +5 -0
- package/vendor/packages/edit-store/lib/timeline-map.js +40 -0
- package/vendor/packages/edit-store/lib/transition-vocabulary.d.ts +223 -0
- package/vendor/packages/edit-store/lib/transition-vocabulary.js +45 -0
- package/vendor/packages/edit-store/lib/webview-kernel.js +98 -0
- package/vendor/packages/matte-rvm/package.json +22 -0
- package/vendor/packages/schemas/bin/validate-edit.mjs +5 -2
- package/vendor/packages/schemas/edit.schema.json +2 -2
- package/vendor/packages/schemas/test/transition-vocabulary.test.mjs +64 -0
- package/vendor/packages/schemas/test/validate-edit.test.mjs +2 -2
- package/vendor/skills/analyze-footage/bin/person-matte/person-cutout.mjs +453 -0
- package/vendor/skills/analyze-footage/bin/person-matte/person-matte.mjs +163 -48
- package/vendor/skills/analyze-footage/person-matte.md +135 -5
|
@@ -7,10 +7,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.readInternalEdit = readInternalEdit;
|
|
8
8
|
exports.readInternalSources = readInternalSources;
|
|
9
9
|
exports.visualContentEndSeconds = visualContentEndSeconds;
|
|
10
|
+
exports.findCrossTrackLayerEvacuations = findCrossTrackLayerEvacuations;
|
|
10
11
|
exports.projectLegacyEdit = projectLegacyEdit;
|
|
11
12
|
exports.toLegacyTrack = toLegacyTrack;
|
|
12
13
|
exports.derivedLegacyTracks = derivedLegacyTracks;
|
|
13
14
|
const edit_v2_1 = require("./edit-v2");
|
|
15
|
+
const cut_adjacency_1 = require("./cut-adjacency");
|
|
14
16
|
const error_1 = require("./migrate/error");
|
|
15
17
|
/**
|
|
16
18
|
* edit.json v2 を内部表現へ読む。v0/v1 は凍結変換ユニットのみが読む。
|
|
@@ -171,6 +173,7 @@ function readV2Internal(raw) {
|
|
|
171
173
|
// 旧 top-level audio と tracks[] 音声が同居すると、後者に加えてこの fallback も射影される。
|
|
172
174
|
// どちらを優先するかは未裁定なので、旧 fixture の互換挙動を変えず二重計上の可能性を残す。
|
|
173
175
|
addV2AudioItems(tracks, edit.audio, fps, legacyIndexCounters);
|
|
176
|
+
synthesizeHiddenTransitionHandlesForRender(tracks, fps);
|
|
174
177
|
return {
|
|
175
178
|
output: {
|
|
176
179
|
width: edit.output.width,
|
|
@@ -190,6 +193,66 @@ function readV2Internal(raw) {
|
|
|
190
193
|
}
|
|
191
194
|
};
|
|
192
195
|
}
|
|
196
|
+
/**
|
|
197
|
+
* render-cut に加え shell プレビューの summary と Web UI の readRenderEdit も
|
|
198
|
+
* item.declaration を読む。そのため出荷プレビューはこの合成済み実重なりを既存窓として描く。
|
|
199
|
+
* UI / lint が読む item の at/duration/source と legacy.value は生タイムラインのまま保ち、
|
|
200
|
+
* 突き合わせ境界の隠れのりしろだけを declaration 上の物理重なりへ合成して既存
|
|
201
|
+
* xfade/acrossfade と 2 つのプレビューへ渡す。生 cuts を直接読む消費者の隠れのりしろ経路とは
|
|
202
|
+
* packages/edit-store/test/transition-window-path-equivalence.test.mjs で等価性を固定する。
|
|
203
|
+
*/
|
|
204
|
+
function synthesizeHiddenTransitionHandlesForRender(tracks, fps) {
|
|
205
|
+
const speedOf = (item) => {
|
|
206
|
+
const speed = item.declaration.speed;
|
|
207
|
+
return typeof speed === 'number' && Number.isFinite(speed) && speed > 0 ? speed : 1;
|
|
208
|
+
};
|
|
209
|
+
for (const track of tracks) {
|
|
210
|
+
if (track.lane !== 'visual')
|
|
211
|
+
continue;
|
|
212
|
+
const cuts = track.items.filter((item) => item.legacy.collection === 'cuts' && item.source.kind === 'media');
|
|
213
|
+
for (let index = 0; index + 1 < cuts.length; index++) {
|
|
214
|
+
const outgoing = cuts[index];
|
|
215
|
+
const incoming = cuts[index + 1];
|
|
216
|
+
if ((0, cut_adjacency_1.cutOverlapFrames)({ tlEnd: outgoing.at + outgoing.duration }, { tlStart: incoming.at }, fps) !== 0)
|
|
217
|
+
continue;
|
|
218
|
+
const transition = outgoing.declaration.transition_out;
|
|
219
|
+
if (!isRecord(transition)
|
|
220
|
+
|| typeof transition.duration !== 'number'
|
|
221
|
+
|| !Number.isFinite(transition.duration)
|
|
222
|
+
|| transition.duration <= 0)
|
|
223
|
+
continue;
|
|
224
|
+
const incomingSpeed = speedOf(incoming);
|
|
225
|
+
const incomingStill = (0, cut_adjacency_1.isStillImageSourcePath)(incoming.source.path);
|
|
226
|
+
const plan = (0, cut_adjacency_1.planTransitionHandleWindow)({
|
|
227
|
+
declaredSeconds: transition.duration,
|
|
228
|
+
outgoingTailRoomSeconds: Number.POSITIVE_INFINITY,
|
|
229
|
+
incomingHeadRoomSeconds: incomingStill
|
|
230
|
+
? Number.POSITIVE_INFINITY : incoming.source.in / incomingSpeed,
|
|
231
|
+
outgoingDurationSeconds: outgoing.duration,
|
|
232
|
+
incomingDurationSeconds: incoming.duration
|
|
233
|
+
});
|
|
234
|
+
if (plan.effectiveSeconds <= 0)
|
|
235
|
+
continue;
|
|
236
|
+
const outgoingSpeed = speedOf(outgoing);
|
|
237
|
+
outgoing.declaration = {
|
|
238
|
+
...outgoing.declaration,
|
|
239
|
+
out: Number(outgoing.declaration.out) + plan.halfSeconds * outgoingSpeed,
|
|
240
|
+
transition_out: { ...transition, duration: plan.effectiveSeconds }
|
|
241
|
+
};
|
|
242
|
+
incoming.declaration = incomingStill
|
|
243
|
+
? {
|
|
244
|
+
...incoming.declaration,
|
|
245
|
+
at: Number(incoming.declaration.at) - plan.halfSeconds,
|
|
246
|
+
out: Number(incoming.declaration.out) + plan.halfSeconds * incomingSpeed
|
|
247
|
+
}
|
|
248
|
+
: {
|
|
249
|
+
...incoming.declaration,
|
|
250
|
+
at: Number(incoming.declaration.at) - plan.halfSeconds,
|
|
251
|
+
in: Number(incoming.declaration.in) - plan.halfSeconds * incomingSpeed
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
193
256
|
function legacyKindOfV2Track(track, chromaKeyOf, overlappingItemIds) {
|
|
194
257
|
if (!('items' in track)) {
|
|
195
258
|
return 'captions';
|
|
@@ -258,26 +321,16 @@ function needsLayersEngine(item, chromaKeyOf, hasOverlappingSibling = false) {
|
|
|
258
321
|
return true;
|
|
259
322
|
return false;
|
|
260
323
|
}
|
|
261
|
-
|
|
262
|
-
// 別トラック間の同時表示も winner-take-all になり、下段を描画できない。全 visual トラックの
|
|
263
|
-
// items[] を総当りで比較し、半開区間 [at, at+duration) が正の長さで交差する media アイテムを
|
|
264
|
-
// layers へ退避する。終端と開始が接するだけなら交差ではない。同一トラックの交差は両方を
|
|
265
|
-
// layers へ送る。別トラックの交差は、下段を cuts の不透明な基底として残し、上段が全画面不透明
|
|
266
|
-
// ではない宣言を持つときだけ layers へ送る。上段が全画面不透明なら winner-take-all でも同じ絵に
|
|
267
|
-
// なるため、従来の cuts / track-stack 経路を保つ。
|
|
268
|
-
//
|
|
269
|
-
// transition_out は同一トラックの隣接カットが意図的に作る狭い重なりで、cuts/xfade が表現する。
|
|
270
|
-
// その例外は同一トラックのペアだけに適用する。別トラックとの交差は transition の有無にかかわらず
|
|
271
|
-
// 真の同時表示なので layers へ退避する。
|
|
272
|
-
function computeOverlappingItemIds(itemGroups) {
|
|
324
|
+
function analyzeOverlappingItems(itemGroups) {
|
|
273
325
|
const overlapping = new Set();
|
|
274
|
-
const
|
|
326
|
+
const crossTrackEvacuations = [];
|
|
327
|
+
const entries = itemGroups.flatMap((group, trackIndex) => group.items.map(item => ({ item, trackIndex, trackId: group.trackId })));
|
|
275
328
|
for (let i = 0; i < entries.length; i++) {
|
|
276
|
-
const { item: a, trackIndex: aTrackIndex } = entries[i];
|
|
329
|
+
const { item: a, trackIndex: aTrackIndex, trackId: aTrackId } = entries[i];
|
|
277
330
|
if (a.source.kind !== 'media')
|
|
278
331
|
continue;
|
|
279
332
|
for (let j = i + 1; j < entries.length; j++) {
|
|
280
|
-
const { item: b, trackIndex: bTrackIndex } = entries[j];
|
|
333
|
+
const { item: b, trackIndex: bTrackIndex, trackId: bTrackId } = entries[j];
|
|
281
334
|
if (b.source.kind !== 'media')
|
|
282
335
|
continue;
|
|
283
336
|
if (!(a.at < b.at + b.duration && b.at < a.at + a.duration))
|
|
@@ -291,13 +344,40 @@ function computeOverlappingItemIds(itemGroups) {
|
|
|
291
344
|
overlapping.add(b.id);
|
|
292
345
|
}
|
|
293
346
|
else {
|
|
294
|
-
const
|
|
295
|
-
|
|
347
|
+
const upperIsA = aTrackIndex > bTrackIndex;
|
|
348
|
+
const upper = upperIsA ? a : b;
|
|
349
|
+
const lower = upperIsA ? b : a;
|
|
350
|
+
if (needsCrossTrackLayers(upper)) {
|
|
296
351
|
overlapping.add(upper.id);
|
|
352
|
+
crossTrackEvacuations.push({
|
|
353
|
+
itemId: upper.id,
|
|
354
|
+
trackId: upperIsA ? aTrackId : bTrackId,
|
|
355
|
+
causeItemId: lower.id,
|
|
356
|
+
causeTrackId: upperIsA ? bTrackId : aTrackId,
|
|
357
|
+
overlapStartFrames: Math.max(a.at, b.at),
|
|
358
|
+
overlapEndFrames: Math.min(a.at + a.duration, b.at + b.duration)
|
|
359
|
+
});
|
|
360
|
+
}
|
|
297
361
|
}
|
|
298
362
|
}
|
|
299
363
|
}
|
|
300
|
-
return overlapping;
|
|
364
|
+
return { itemIds: overlapping, crossTrackEvacuations };
|
|
365
|
+
}
|
|
366
|
+
function computeOverlappingItemIds(itemGroups) {
|
|
367
|
+
return analyzeOverlappingItems(itemGroups.map((items, index) => ({
|
|
368
|
+
items,
|
|
369
|
+
trackId: String(index)
|
|
370
|
+
}))).itemIds;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* 別 visual track との重なりが原因で upper item が layers へ退避される組を返す。
|
|
374
|
+
* edit-lint と UI は理由文言に必要な相手 id を、この単一定義から得る。
|
|
375
|
+
*/
|
|
376
|
+
function findCrossTrackLayerEvacuations(edit) {
|
|
377
|
+
const parsed = (0, edit_v2_1.readEditV2)(edit);
|
|
378
|
+
return analyzeOverlappingItems(parsed.tracks.flatMap(track => track.lane === 'visual' && 'items' in track
|
|
379
|
+
? [{ items: track.items, trackId: track.id }]
|
|
380
|
+
: [])).crossTrackEvacuations;
|
|
301
381
|
}
|
|
302
382
|
// cuts の winner-take-all が下段を隠してよいのは、上段が全画面を不透明に覆う場合だけ。
|
|
303
383
|
// transform の単位元を明示しただけなら従来経路を維持する。crop / 半透明 / keyframes は、
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseEdit = parseEdit;
|
|
4
|
+
const transition_vocabulary_1 = require("../transition-vocabulary");
|
|
4
5
|
const LAYER_BLEND_MODES = [
|
|
5
6
|
'normal', 'screen', 'multiply', 'add', 'difference',
|
|
6
7
|
'darken', 'lighten', 'overlay', 'hardlight', 'softlight'
|
|
@@ -78,16 +79,18 @@ function parseEdit(source) {
|
|
|
78
79
|
let transitionOut;
|
|
79
80
|
if (rawCut.transition_out !== undefined && rawCut.transition_out !== null) {
|
|
80
81
|
const transition = rawCut.transition_out;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|| transition?.type === '
|
|
85
|
-
|| transition?.type === 'reveal-up';
|
|
82
|
+
// 正準語彙に加え、手編集で先行した非空文字列も読み取りだけは保持する。
|
|
83
|
+
// 書き込み API は isTransitionType で閉じたまま、preview の汎用フォールバックへ渡す。
|
|
84
|
+
const validType = (0, transition_vocabulary_1.isTransitionType)(transition?.type)
|
|
85
|
+
|| (typeof transition?.type === 'string' && transition.type.trim().length > 0);
|
|
86
86
|
const validDuration = typeof transition?.duration === 'number'
|
|
87
87
|
&& Number.isFinite(transition.duration) && transition.duration > 0;
|
|
88
88
|
if (transition && typeof transition === 'object' && !Array.isArray(transition)
|
|
89
89
|
&& validType && validDuration) {
|
|
90
|
-
transitionOut = {
|
|
90
|
+
transitionOut = {
|
|
91
|
+
type: transition.type,
|
|
92
|
+
duration: transition.duration
|
|
93
|
+
};
|
|
91
94
|
}
|
|
92
95
|
else {
|
|
93
96
|
warnings.push(`${index + 1} 番目のクリップの transition_out が不正なため無視します。`);
|
|
@@ -56,6 +56,11 @@ export interface TimelineMapResult {
|
|
|
56
56
|
export declare function transitionProgressAt(window: TimelineTransitionWindow, outputT: number): number;
|
|
57
57
|
export declare function buildTimelineMap(cuts: readonly EditCut[], options?: {
|
|
58
58
|
trackZ?: (track: number) => number;
|
|
59
|
+
fps?: number;
|
|
60
|
+
handleRoom?: (cutIndex: number) => {
|
|
61
|
+
tailSeconds?: number;
|
|
62
|
+
headSeconds?: number;
|
|
63
|
+
} | undefined;
|
|
59
64
|
}): TimelineMapResult;
|
|
60
65
|
/**
|
|
61
66
|
* 出力秒 → ソース秒。トランジション重なり区間(隣接 src が重なる出力時刻)は
|
|
@@ -16,6 +16,7 @@ exports.transitionProgressAt = transitionProgressAt;
|
|
|
16
16
|
exports.buildTimelineMap = buildTimelineMap;
|
|
17
17
|
exports.outputToSource = outputToSource;
|
|
18
18
|
const edit_store_1 = require("./edit-store");
|
|
19
|
+
const cut_adjacency_1 = require("./cut-adjacency");
|
|
19
20
|
function transitionProgressAt(window, outputT) {
|
|
20
21
|
if (!(window.duration > 0))
|
|
21
22
|
return 0;
|
|
@@ -37,10 +38,49 @@ function buildTimelineMap(cuts, options) {
|
|
|
37
38
|
const resolved = trackSegments.map(segment => ({
|
|
38
39
|
start: segment.at,
|
|
39
40
|
end: segment.end,
|
|
41
|
+
baseStart: segment.at,
|
|
42
|
+
baseEnd: segment.end,
|
|
40
43
|
track: segment.track,
|
|
41
44
|
cut: usableCuts[segment.index],
|
|
42
45
|
cutIndex: usable[segment.index].index
|
|
43
46
|
}));
|
|
47
|
+
const fps = options?.fps ?? cut_adjacency_1.DEFAULT_CUT_ADJACENCY_FPS;
|
|
48
|
+
// 隠れのりしろは、フレーム量子化で突き合わせとなる境界にだけ合成する。
|
|
49
|
+
// 実重なり済みの境界は一切変更せず、従来の窓計算へそのまま流す。
|
|
50
|
+
for (let outgoingIndex = 0; outgoingIndex < resolved.length; outgoingIndex++) {
|
|
51
|
+
const outgoing = resolved[outgoingIndex];
|
|
52
|
+
const transition = outgoing.cut.transitionOut;
|
|
53
|
+
if (!transition || !(typeof transition.duration === 'number' && Number.isFinite(transition.duration)
|
|
54
|
+
&& transition.duration > 0))
|
|
55
|
+
continue;
|
|
56
|
+
const incoming = resolved.slice(outgoingIndex + 1).find(candidate => candidate.track === outgoing.track);
|
|
57
|
+
if (!incoming || (0, cut_adjacency_1.cutOverlapFrames)({ tlEnd: outgoing.end }, { tlStart: incoming.start }, fps) !== 0)
|
|
58
|
+
continue;
|
|
59
|
+
const outgoingRoom = options?.handleRoom?.(outgoing.cutIndex);
|
|
60
|
+
const incomingRoom = options?.handleRoom?.(incoming.cutIndex);
|
|
61
|
+
const incomingSpeed = typeof incoming.cut.speed === 'number' && incoming.cut.speed > 0
|
|
62
|
+
? incoming.cut.speed : 1;
|
|
63
|
+
const plan = (0, cut_adjacency_1.planTransitionHandleWindow)({
|
|
64
|
+
declaredSeconds: transition.duration,
|
|
65
|
+
outgoingTailRoomSeconds: outgoingRoom?.tailSeconds ?? Number.POSITIVE_INFINITY,
|
|
66
|
+
incomingHeadRoomSeconds: incomingRoom?.headSeconds ?? incoming.cut.in / incomingSpeed,
|
|
67
|
+
outgoingDurationSeconds: outgoing.baseEnd - outgoing.baseStart,
|
|
68
|
+
incomingDurationSeconds: incoming.baseEnd - incoming.baseStart
|
|
69
|
+
});
|
|
70
|
+
if (plan.effectiveSeconds <= 0)
|
|
71
|
+
continue;
|
|
72
|
+
const cutPoint = outgoing.end;
|
|
73
|
+
outgoing.end = cutPoint + plan.halfSeconds;
|
|
74
|
+
outgoing.cut = {
|
|
75
|
+
...outgoing.cut,
|
|
76
|
+
transitionOut: { ...transition, duration: plan.effectiveSeconds }
|
|
77
|
+
};
|
|
78
|
+
incoming.start = cutPoint - plan.halfSeconds;
|
|
79
|
+
incoming.cut = {
|
|
80
|
+
...incoming.cut,
|
|
81
|
+
in: Math.max(0, incoming.cut.in - plan.halfSeconds * incomingSpeed)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
44
84
|
const segmentSlice = (entry, start, end, transitionOut = null) => {
|
|
45
85
|
const cut = entry.cut;
|
|
46
86
|
const speed = typeof cut.speed === 'number' && cut.speed > 0 ? cut.speed : 1;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edit.json の transition_out.type に使える正準語彙。
|
|
3
|
+
* JSON Schema はリテラル enum を保つため別置きだが、drift test でこの表と一致させる。
|
|
4
|
+
*/
|
|
5
|
+
export declare const TRANSITION_VOCABULARY: readonly [{
|
|
6
|
+
readonly id: "dissolve";
|
|
7
|
+
readonly xfadeName: "dissolve";
|
|
8
|
+
readonly labelJa: "ディゾルブ";
|
|
9
|
+
readonly category: "フェード";
|
|
10
|
+
readonly previewKind: "dissolve";
|
|
11
|
+
readonly glyph: "D";
|
|
12
|
+
}, {
|
|
13
|
+
readonly id: "fade";
|
|
14
|
+
readonly xfadeName: "fade";
|
|
15
|
+
readonly labelJa: "クロスフェード";
|
|
16
|
+
readonly category: "フェード";
|
|
17
|
+
readonly previewKind: "fade";
|
|
18
|
+
readonly glyph: "F";
|
|
19
|
+
}, {
|
|
20
|
+
readonly id: "fade-black";
|
|
21
|
+
readonly xfadeName: "fadeblack";
|
|
22
|
+
readonly labelJa: "黒フェード";
|
|
23
|
+
readonly category: "フェード";
|
|
24
|
+
readonly previewKind: "fade-black";
|
|
25
|
+
readonly glyph: "B";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "fade-white";
|
|
28
|
+
readonly xfadeName: "fadewhite";
|
|
29
|
+
readonly labelJa: "白フェード";
|
|
30
|
+
readonly category: "フェード";
|
|
31
|
+
readonly previewKind: "fade-white";
|
|
32
|
+
readonly glyph: "W";
|
|
33
|
+
}, {
|
|
34
|
+
readonly id: "fade-grays";
|
|
35
|
+
readonly xfadeName: "fadegrays";
|
|
36
|
+
readonly labelJa: "モノクロフェード";
|
|
37
|
+
readonly category: "フェード";
|
|
38
|
+
readonly previewKind: "fade-grays";
|
|
39
|
+
readonly glyph: "G";
|
|
40
|
+
}, {
|
|
41
|
+
readonly id: "wipe-left";
|
|
42
|
+
readonly xfadeName: "wipeleft";
|
|
43
|
+
readonly labelJa: "ワイプ(左へ)";
|
|
44
|
+
readonly category: "ワイプ";
|
|
45
|
+
readonly previewKind: "wipe-left";
|
|
46
|
+
readonly glyph: "←";
|
|
47
|
+
}, {
|
|
48
|
+
readonly id: "wipe-right";
|
|
49
|
+
readonly xfadeName: "wiperight";
|
|
50
|
+
readonly labelJa: "ワイプ(右へ)";
|
|
51
|
+
readonly category: "ワイプ";
|
|
52
|
+
readonly previewKind: "wipe-right";
|
|
53
|
+
readonly glyph: "→";
|
|
54
|
+
}, {
|
|
55
|
+
readonly id: "wipe-up";
|
|
56
|
+
readonly xfadeName: "wipeup";
|
|
57
|
+
readonly labelJa: "ワイプ(上へ)";
|
|
58
|
+
readonly category: "ワイプ";
|
|
59
|
+
readonly previewKind: "wipe-up";
|
|
60
|
+
readonly glyph: "↑";
|
|
61
|
+
}, {
|
|
62
|
+
readonly id: "wipe-down";
|
|
63
|
+
readonly xfadeName: "wipedown";
|
|
64
|
+
readonly labelJa: "ワイプ(下へ)";
|
|
65
|
+
readonly category: "ワイプ";
|
|
66
|
+
readonly previewKind: "wipe-down";
|
|
67
|
+
readonly glyph: "↓";
|
|
68
|
+
}, {
|
|
69
|
+
readonly id: "radial";
|
|
70
|
+
readonly xfadeName: "radial";
|
|
71
|
+
readonly labelJa: "時計ワイプ";
|
|
72
|
+
readonly category: "ワイプ";
|
|
73
|
+
readonly previewKind: "radial";
|
|
74
|
+
readonly glyph: "◷";
|
|
75
|
+
}, {
|
|
76
|
+
readonly id: "slide-left";
|
|
77
|
+
readonly xfadeName: "slideleft";
|
|
78
|
+
readonly labelJa: "スライド(左へ)";
|
|
79
|
+
readonly category: "スライド";
|
|
80
|
+
readonly previewKind: "slide-left";
|
|
81
|
+
readonly glyph: "←";
|
|
82
|
+
}, {
|
|
83
|
+
readonly id: "slide-right";
|
|
84
|
+
readonly xfadeName: "slideright";
|
|
85
|
+
readonly labelJa: "スライド(右へ)";
|
|
86
|
+
readonly category: "スライド";
|
|
87
|
+
readonly previewKind: "slide-right";
|
|
88
|
+
readonly glyph: "→";
|
|
89
|
+
}, {
|
|
90
|
+
readonly id: "slide-up";
|
|
91
|
+
readonly xfadeName: "slideup";
|
|
92
|
+
readonly labelJa: "スライド(上へ)";
|
|
93
|
+
readonly category: "スライド";
|
|
94
|
+
readonly previewKind: "slide-up";
|
|
95
|
+
readonly glyph: "↑";
|
|
96
|
+
}, {
|
|
97
|
+
readonly id: "slide-down";
|
|
98
|
+
readonly xfadeName: "slidedown";
|
|
99
|
+
readonly labelJa: "スライド(下へ)";
|
|
100
|
+
readonly category: "スライド";
|
|
101
|
+
readonly previewKind: "slide-down";
|
|
102
|
+
readonly glyph: "↓";
|
|
103
|
+
}, {
|
|
104
|
+
readonly id: "cover-left";
|
|
105
|
+
readonly xfadeName: "coverleft";
|
|
106
|
+
readonly labelJa: "カバー(左へ)";
|
|
107
|
+
readonly category: "カバー";
|
|
108
|
+
readonly previewKind: "cover-left";
|
|
109
|
+
readonly glyph: "←";
|
|
110
|
+
}, {
|
|
111
|
+
readonly id: "cover-right";
|
|
112
|
+
readonly xfadeName: "coverright";
|
|
113
|
+
readonly labelJa: "カバー(右へ)";
|
|
114
|
+
readonly category: "カバー";
|
|
115
|
+
readonly previewKind: "cover-right";
|
|
116
|
+
readonly glyph: "→";
|
|
117
|
+
}, {
|
|
118
|
+
readonly id: "cover-up";
|
|
119
|
+
readonly xfadeName: "coverup";
|
|
120
|
+
readonly labelJa: "カバー(上へ)";
|
|
121
|
+
readonly category: "カバー";
|
|
122
|
+
readonly previewKind: "cover-up";
|
|
123
|
+
readonly glyph: "↑";
|
|
124
|
+
}, {
|
|
125
|
+
readonly id: "cover-down";
|
|
126
|
+
readonly xfadeName: "coverdown";
|
|
127
|
+
readonly labelJa: "カバー(下へ)";
|
|
128
|
+
readonly category: "カバー";
|
|
129
|
+
readonly previewKind: "cover-down";
|
|
130
|
+
readonly glyph: "↓";
|
|
131
|
+
}, {
|
|
132
|
+
readonly id: "reveal-left";
|
|
133
|
+
readonly xfadeName: "revealleft";
|
|
134
|
+
readonly labelJa: "リビール(左へ)";
|
|
135
|
+
readonly category: "リビール";
|
|
136
|
+
readonly previewKind: "reveal-left";
|
|
137
|
+
readonly glyph: "←";
|
|
138
|
+
}, {
|
|
139
|
+
readonly id: "reveal-right";
|
|
140
|
+
readonly xfadeName: "revealright";
|
|
141
|
+
readonly labelJa: "リビール(右へ)";
|
|
142
|
+
readonly category: "リビール";
|
|
143
|
+
readonly previewKind: "reveal-right";
|
|
144
|
+
readonly glyph: "→";
|
|
145
|
+
}, {
|
|
146
|
+
readonly id: "reveal-down";
|
|
147
|
+
readonly xfadeName: "revealdown";
|
|
148
|
+
readonly labelJa: "上からリビール";
|
|
149
|
+
readonly category: "リビール";
|
|
150
|
+
readonly previewKind: "reveal-down";
|
|
151
|
+
readonly glyph: "↓";
|
|
152
|
+
}, {
|
|
153
|
+
readonly id: "reveal-up";
|
|
154
|
+
readonly xfadeName: "revealup";
|
|
155
|
+
readonly labelJa: "下からリビール";
|
|
156
|
+
readonly category: "リビール";
|
|
157
|
+
readonly previewKind: "reveal-up";
|
|
158
|
+
readonly glyph: "↑";
|
|
159
|
+
}, {
|
|
160
|
+
readonly id: "circle-open";
|
|
161
|
+
readonly xfadeName: "circleopen";
|
|
162
|
+
readonly labelJa: "サークル(開く)";
|
|
163
|
+
readonly category: "形状";
|
|
164
|
+
readonly previewKind: "circle-open";
|
|
165
|
+
readonly glyph: "○";
|
|
166
|
+
}, {
|
|
167
|
+
readonly id: "circle-close";
|
|
168
|
+
readonly xfadeName: "circleclose";
|
|
169
|
+
readonly labelJa: "サークル(閉じる)";
|
|
170
|
+
readonly category: "形状";
|
|
171
|
+
readonly previewKind: "circle-close";
|
|
172
|
+
readonly glyph: "●";
|
|
173
|
+
}, {
|
|
174
|
+
readonly id: "zoom-in";
|
|
175
|
+
readonly xfadeName: "zoomin";
|
|
176
|
+
readonly labelJa: "ズームイン";
|
|
177
|
+
readonly category: "変形";
|
|
178
|
+
readonly previewKind: "zoom-in";
|
|
179
|
+
readonly glyph: "+";
|
|
180
|
+
}, {
|
|
181
|
+
readonly id: "squeeze-h";
|
|
182
|
+
readonly xfadeName: "squeezeh";
|
|
183
|
+
readonly labelJa: "スクイーズ(縦つぶし)";
|
|
184
|
+
readonly category: "変形";
|
|
185
|
+
readonly previewKind: "squeeze-h";
|
|
186
|
+
readonly glyph: "↕";
|
|
187
|
+
}, {
|
|
188
|
+
readonly id: "squeeze-v";
|
|
189
|
+
readonly xfadeName: "squeezev";
|
|
190
|
+
readonly labelJa: "スクイーズ(横つぶし)";
|
|
191
|
+
readonly category: "変形";
|
|
192
|
+
readonly previewKind: "squeeze-v";
|
|
193
|
+
readonly glyph: "↔";
|
|
194
|
+
}, {
|
|
195
|
+
readonly id: "blur";
|
|
196
|
+
readonly xfadeName: "hblur";
|
|
197
|
+
readonly labelJa: "ブラー";
|
|
198
|
+
readonly category: "質感";
|
|
199
|
+
readonly previewKind: "blur";
|
|
200
|
+
readonly glyph: "B";
|
|
201
|
+
}, {
|
|
202
|
+
readonly id: "pixelize";
|
|
203
|
+
readonly xfadeName: "pixelize";
|
|
204
|
+
readonly labelJa: "ピクセレート";
|
|
205
|
+
readonly category: "質感";
|
|
206
|
+
readonly previewKind: "pixelize";
|
|
207
|
+
readonly glyph: "P";
|
|
208
|
+
}];
|
|
209
|
+
export type TransitionDefinition = typeof TRANSITION_VOCABULARY[number];
|
|
210
|
+
export type TransitionType = TransitionDefinition['id'];
|
|
211
|
+
export type TransitionCategory = TransitionDefinition['category'];
|
|
212
|
+
export type TransitionPreviewKind = TransitionDefinition['previewKind'];
|
|
213
|
+
declare const unknownTransitionTypeBrand: unique symbol;
|
|
214
|
+
/** 読み取り側だけが保持する、schema より先行した未知種別。書き込み API には使わない。 */
|
|
215
|
+
export type UnknownTransitionType = string & {
|
|
216
|
+
readonly [unknownTransitionTypeBrand]: true;
|
|
217
|
+
};
|
|
218
|
+
export type ReadableTransitionType = TransitionType | UnknownTransitionType;
|
|
219
|
+
export declare const TRANSITION_TYPE_IDS: readonly TransitionType[];
|
|
220
|
+
export declare const TRANSITION_CATEGORIES: readonly TransitionCategory[];
|
|
221
|
+
export declare const TRANSITION_BY_ID: Readonly<Record<TransitionType, TransitionDefinition>>;
|
|
222
|
+
export declare function isTransitionType(value: unknown): value is TransitionType;
|
|
223
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TRANSITION_BY_ID = exports.TRANSITION_CATEGORIES = exports.TRANSITION_TYPE_IDS = exports.TRANSITION_VOCABULARY = void 0;
|
|
4
|
+
exports.isTransitionType = isTransitionType;
|
|
5
|
+
/**
|
|
6
|
+
* edit.json の transition_out.type に使える正準語彙。
|
|
7
|
+
* JSON Schema はリテラル enum を保つため別置きだが、drift test でこの表と一致させる。
|
|
8
|
+
*/
|
|
9
|
+
exports.TRANSITION_VOCABULARY = [
|
|
10
|
+
{ id: 'dissolve', xfadeName: 'dissolve', labelJa: 'ディゾルブ', category: 'フェード', previewKind: 'dissolve', glyph: 'D' },
|
|
11
|
+
{ id: 'fade', xfadeName: 'fade', labelJa: 'クロスフェード', category: 'フェード', previewKind: 'fade', glyph: 'F' },
|
|
12
|
+
{ id: 'fade-black', xfadeName: 'fadeblack', labelJa: '黒フェード', category: 'フェード', previewKind: 'fade-black', glyph: 'B' },
|
|
13
|
+
{ id: 'fade-white', xfadeName: 'fadewhite', labelJa: '白フェード', category: 'フェード', previewKind: 'fade-white', glyph: 'W' },
|
|
14
|
+
{ id: 'fade-grays', xfadeName: 'fadegrays', labelJa: 'モノクロフェード', category: 'フェード', previewKind: 'fade-grays', glyph: 'G' },
|
|
15
|
+
{ id: 'wipe-left', xfadeName: 'wipeleft', labelJa: 'ワイプ(左へ)', category: 'ワイプ', previewKind: 'wipe-left', glyph: '←' },
|
|
16
|
+
{ id: 'wipe-right', xfadeName: 'wiperight', labelJa: 'ワイプ(右へ)', category: 'ワイプ', previewKind: 'wipe-right', glyph: '→' },
|
|
17
|
+
{ id: 'wipe-up', xfadeName: 'wipeup', labelJa: 'ワイプ(上へ)', category: 'ワイプ', previewKind: 'wipe-up', glyph: '↑' },
|
|
18
|
+
{ id: 'wipe-down', xfadeName: 'wipedown', labelJa: 'ワイプ(下へ)', category: 'ワイプ', previewKind: 'wipe-down', glyph: '↓' },
|
|
19
|
+
{ id: 'radial', xfadeName: 'radial', labelJa: '時計ワイプ', category: 'ワイプ', previewKind: 'radial', glyph: '◷' },
|
|
20
|
+
{ id: 'slide-left', xfadeName: 'slideleft', labelJa: 'スライド(左へ)', category: 'スライド', previewKind: 'slide-left', glyph: '←' },
|
|
21
|
+
{ id: 'slide-right', xfadeName: 'slideright', labelJa: 'スライド(右へ)', category: 'スライド', previewKind: 'slide-right', glyph: '→' },
|
|
22
|
+
{ id: 'slide-up', xfadeName: 'slideup', labelJa: 'スライド(上へ)', category: 'スライド', previewKind: 'slide-up', glyph: '↑' },
|
|
23
|
+
{ id: 'slide-down', xfadeName: 'slidedown', labelJa: 'スライド(下へ)', category: 'スライド', previewKind: 'slide-down', glyph: '↓' },
|
|
24
|
+
{ id: 'cover-left', xfadeName: 'coverleft', labelJa: 'カバー(左へ)', category: 'カバー', previewKind: 'cover-left', glyph: '←' },
|
|
25
|
+
{ id: 'cover-right', xfadeName: 'coverright', labelJa: 'カバー(右へ)', category: 'カバー', previewKind: 'cover-right', glyph: '→' },
|
|
26
|
+
{ id: 'cover-up', xfadeName: 'coverup', labelJa: 'カバー(上へ)', category: 'カバー', previewKind: 'cover-up', glyph: '↑' },
|
|
27
|
+
{ id: 'cover-down', xfadeName: 'coverdown', labelJa: 'カバー(下へ)', category: 'カバー', previewKind: 'cover-down', glyph: '↓' },
|
|
28
|
+
{ id: 'reveal-left', xfadeName: 'revealleft', labelJa: 'リビール(左へ)', category: 'リビール', previewKind: 'reveal-left', glyph: '←' },
|
|
29
|
+
{ id: 'reveal-right', xfadeName: 'revealright', labelJa: 'リビール(右へ)', category: 'リビール', previewKind: 'reveal-right', glyph: '→' },
|
|
30
|
+
{ id: 'reveal-down', xfadeName: 'revealdown', labelJa: '上からリビール', category: 'リビール', previewKind: 'reveal-down', glyph: '↓' },
|
|
31
|
+
{ id: 'reveal-up', xfadeName: 'revealup', labelJa: '下からリビール', category: 'リビール', previewKind: 'reveal-up', glyph: '↑' },
|
|
32
|
+
{ id: 'circle-open', xfadeName: 'circleopen', labelJa: 'サークル(開く)', category: '形状', previewKind: 'circle-open', glyph: '○' },
|
|
33
|
+
{ id: 'circle-close', xfadeName: 'circleclose', labelJa: 'サークル(閉じる)', category: '形状', previewKind: 'circle-close', glyph: '●' },
|
|
34
|
+
{ id: 'zoom-in', xfadeName: 'zoomin', labelJa: 'ズームイン', category: '変形', previewKind: 'zoom-in', glyph: '+' },
|
|
35
|
+
{ id: 'squeeze-h', xfadeName: 'squeezeh', labelJa: 'スクイーズ(縦つぶし)', category: '変形', previewKind: 'squeeze-h', glyph: '↕' },
|
|
36
|
+
{ id: 'squeeze-v', xfadeName: 'squeezev', labelJa: 'スクイーズ(横つぶし)', category: '変形', previewKind: 'squeeze-v', glyph: '↔' },
|
|
37
|
+
{ id: 'blur', xfadeName: 'hblur', labelJa: 'ブラー', category: '質感', previewKind: 'blur', glyph: 'B' },
|
|
38
|
+
{ id: 'pixelize', xfadeName: 'pixelize', labelJa: 'ピクセレート', category: '質感', previewKind: 'pixelize', glyph: 'P' }
|
|
39
|
+
];
|
|
40
|
+
exports.TRANSITION_TYPE_IDS = exports.TRANSITION_VOCABULARY.map(entry => entry.id);
|
|
41
|
+
exports.TRANSITION_CATEGORIES = [...new Set(exports.TRANSITION_VOCABULARY.map(entry => entry.category))];
|
|
42
|
+
exports.TRANSITION_BY_ID = Object.fromEntries(exports.TRANSITION_VOCABULARY.map(entry => [entry.id, entry]));
|
|
43
|
+
function isTransitionType(value) {
|
|
44
|
+
return typeof value === 'string' && Object.prototype.hasOwnProperty.call(exports.TRANSITION_BY_ID, value);
|
|
45
|
+
}
|