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
|
@@ -28,6 +28,42 @@ var AkariEditKernel = (() => {
|
|
|
28
28
|
transitionProgressAt: () => transitionProgressAt
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
// src/transition-vocabulary.ts
|
|
32
|
+
var TRANSITION_VOCABULARY = [
|
|
33
|
+
{ id: "dissolve", xfadeName: "dissolve", labelJa: "\u30C7\u30A3\u30BE\u30EB\u30D6", category: "\u30D5\u30A7\u30FC\u30C9", previewKind: "dissolve", glyph: "D" },
|
|
34
|
+
{ id: "fade", xfadeName: "fade", labelJa: "\u30AF\u30ED\u30B9\u30D5\u30A7\u30FC\u30C9", category: "\u30D5\u30A7\u30FC\u30C9", previewKind: "fade", glyph: "F" },
|
|
35
|
+
{ id: "fade-black", xfadeName: "fadeblack", labelJa: "\u9ED2\u30D5\u30A7\u30FC\u30C9", category: "\u30D5\u30A7\u30FC\u30C9", previewKind: "fade-black", glyph: "B" },
|
|
36
|
+
{ id: "fade-white", xfadeName: "fadewhite", labelJa: "\u767D\u30D5\u30A7\u30FC\u30C9", category: "\u30D5\u30A7\u30FC\u30C9", previewKind: "fade-white", glyph: "W" },
|
|
37
|
+
{ id: "fade-grays", xfadeName: "fadegrays", labelJa: "\u30E2\u30CE\u30AF\u30ED\u30D5\u30A7\u30FC\u30C9", category: "\u30D5\u30A7\u30FC\u30C9", previewKind: "fade-grays", glyph: "G" },
|
|
38
|
+
{ id: "wipe-left", xfadeName: "wipeleft", labelJa: "\u30EF\u30A4\u30D7\uFF08\u5DE6\u3078\uFF09", category: "\u30EF\u30A4\u30D7", previewKind: "wipe-left", glyph: "\u2190" },
|
|
39
|
+
{ id: "wipe-right", xfadeName: "wiperight", labelJa: "\u30EF\u30A4\u30D7\uFF08\u53F3\u3078\uFF09", category: "\u30EF\u30A4\u30D7", previewKind: "wipe-right", glyph: "\u2192" },
|
|
40
|
+
{ id: "wipe-up", xfadeName: "wipeup", labelJa: "\u30EF\u30A4\u30D7\uFF08\u4E0A\u3078\uFF09", category: "\u30EF\u30A4\u30D7", previewKind: "wipe-up", glyph: "\u2191" },
|
|
41
|
+
{ id: "wipe-down", xfadeName: "wipedown", labelJa: "\u30EF\u30A4\u30D7\uFF08\u4E0B\u3078\uFF09", category: "\u30EF\u30A4\u30D7", previewKind: "wipe-down", glyph: "\u2193" },
|
|
42
|
+
{ id: "radial", xfadeName: "radial", labelJa: "\u6642\u8A08\u30EF\u30A4\u30D7", category: "\u30EF\u30A4\u30D7", previewKind: "radial", glyph: "\u25F7" },
|
|
43
|
+
{ id: "slide-left", xfadeName: "slideleft", labelJa: "\u30B9\u30E9\u30A4\u30C9\uFF08\u5DE6\u3078\uFF09", category: "\u30B9\u30E9\u30A4\u30C9", previewKind: "slide-left", glyph: "\u2190" },
|
|
44
|
+
{ id: "slide-right", xfadeName: "slideright", labelJa: "\u30B9\u30E9\u30A4\u30C9\uFF08\u53F3\u3078\uFF09", category: "\u30B9\u30E9\u30A4\u30C9", previewKind: "slide-right", glyph: "\u2192" },
|
|
45
|
+
{ id: "slide-up", xfadeName: "slideup", labelJa: "\u30B9\u30E9\u30A4\u30C9\uFF08\u4E0A\u3078\uFF09", category: "\u30B9\u30E9\u30A4\u30C9", previewKind: "slide-up", glyph: "\u2191" },
|
|
46
|
+
{ id: "slide-down", xfadeName: "slidedown", labelJa: "\u30B9\u30E9\u30A4\u30C9\uFF08\u4E0B\u3078\uFF09", category: "\u30B9\u30E9\u30A4\u30C9", previewKind: "slide-down", glyph: "\u2193" },
|
|
47
|
+
{ id: "cover-left", xfadeName: "coverleft", labelJa: "\u30AB\u30D0\u30FC\uFF08\u5DE6\u3078\uFF09", category: "\u30AB\u30D0\u30FC", previewKind: "cover-left", glyph: "\u2190" },
|
|
48
|
+
{ id: "cover-right", xfadeName: "coverright", labelJa: "\u30AB\u30D0\u30FC\uFF08\u53F3\u3078\uFF09", category: "\u30AB\u30D0\u30FC", previewKind: "cover-right", glyph: "\u2192" },
|
|
49
|
+
{ id: "cover-up", xfadeName: "coverup", labelJa: "\u30AB\u30D0\u30FC\uFF08\u4E0A\u3078\uFF09", category: "\u30AB\u30D0\u30FC", previewKind: "cover-up", glyph: "\u2191" },
|
|
50
|
+
{ id: "cover-down", xfadeName: "coverdown", labelJa: "\u30AB\u30D0\u30FC\uFF08\u4E0B\u3078\uFF09", category: "\u30AB\u30D0\u30FC", previewKind: "cover-down", glyph: "\u2193" },
|
|
51
|
+
{ id: "reveal-left", xfadeName: "revealleft", labelJa: "\u30EA\u30D3\u30FC\u30EB\uFF08\u5DE6\u3078\uFF09", category: "\u30EA\u30D3\u30FC\u30EB", previewKind: "reveal-left", glyph: "\u2190" },
|
|
52
|
+
{ id: "reveal-right", xfadeName: "revealright", labelJa: "\u30EA\u30D3\u30FC\u30EB\uFF08\u53F3\u3078\uFF09", category: "\u30EA\u30D3\u30FC\u30EB", previewKind: "reveal-right", glyph: "\u2192" },
|
|
53
|
+
{ id: "reveal-down", xfadeName: "revealdown", labelJa: "\u4E0A\u304B\u3089\u30EA\u30D3\u30FC\u30EB", category: "\u30EA\u30D3\u30FC\u30EB", previewKind: "reveal-down", glyph: "\u2193" },
|
|
54
|
+
{ id: "reveal-up", xfadeName: "revealup", labelJa: "\u4E0B\u304B\u3089\u30EA\u30D3\u30FC\u30EB", category: "\u30EA\u30D3\u30FC\u30EB", previewKind: "reveal-up", glyph: "\u2191" },
|
|
55
|
+
{ id: "circle-open", xfadeName: "circleopen", labelJa: "\u30B5\u30FC\u30AF\u30EB\uFF08\u958B\u304F\uFF09", category: "\u5F62\u72B6", previewKind: "circle-open", glyph: "\u25CB" },
|
|
56
|
+
{ id: "circle-close", xfadeName: "circleclose", labelJa: "\u30B5\u30FC\u30AF\u30EB\uFF08\u9589\u3058\u308B\uFF09", category: "\u5F62\u72B6", previewKind: "circle-close", glyph: "\u25CF" },
|
|
57
|
+
{ id: "zoom-in", xfadeName: "zoomin", labelJa: "\u30BA\u30FC\u30E0\u30A4\u30F3", category: "\u5909\u5F62", previewKind: "zoom-in", glyph: "\uFF0B" },
|
|
58
|
+
{ id: "squeeze-h", xfadeName: "squeezeh", labelJa: "\u30B9\u30AF\u30A4\u30FC\u30BA\uFF08\u7E26\u3064\u3076\u3057\uFF09", category: "\u5909\u5F62", previewKind: "squeeze-h", glyph: "\u2195" },
|
|
59
|
+
{ id: "squeeze-v", xfadeName: "squeezev", labelJa: "\u30B9\u30AF\u30A4\u30FC\u30BA\uFF08\u6A2A\u3064\u3076\u3057\uFF09", category: "\u5909\u5F62", previewKind: "squeeze-v", glyph: "\u2194" },
|
|
60
|
+
{ id: "blur", xfadeName: "hblur", labelJa: "\u30D6\u30E9\u30FC", category: "\u8CEA\u611F", previewKind: "blur", glyph: "B" },
|
|
61
|
+
{ id: "pixelize", xfadeName: "pixelize", labelJa: "\u30D4\u30AF\u30BB\u30EC\u30FC\u30C8", category: "\u8CEA\u611F", previewKind: "pixelize", glyph: "P" }
|
|
62
|
+
];
|
|
63
|
+
var TRANSITION_TYPE_IDS = TRANSITION_VOCABULARY.map((entry) => entry.id);
|
|
64
|
+
var TRANSITION_CATEGORIES = [...new Set(TRANSITION_VOCABULARY.map((entry) => entry.category))];
|
|
65
|
+
var TRANSITION_BY_ID = Object.fromEntries(TRANSITION_VOCABULARY.map((entry) => [entry.id, entry]));
|
|
66
|
+
|
|
31
67
|
// src/edit-store.ts
|
|
32
68
|
function computeCutTrackSegments(cuts) {
|
|
33
69
|
const cursorByTrack = /* @__PURE__ */ new Map();
|
|
@@ -50,6 +86,32 @@ var AkariEditKernel = (() => {
|
|
|
50
86
|
return segments;
|
|
51
87
|
}
|
|
52
88
|
|
|
89
|
+
// src/cut-adjacency.ts
|
|
90
|
+
var DEFAULT_CUT_ADJACENCY_FPS = 30;
|
|
91
|
+
function effectiveCutFps(fps) {
|
|
92
|
+
return Number.isFinite(fps) && fps > 0 ? fps : DEFAULT_CUT_ADJACENCY_FPS;
|
|
93
|
+
}
|
|
94
|
+
function cutOverlapFrames(earlier, later, fps = DEFAULT_CUT_ADJACENCY_FPS) {
|
|
95
|
+
const resolvedFps = effectiveCutFps(fps);
|
|
96
|
+
return Math.round(earlier.tlEnd * resolvedFps) - Math.round(later.tlStart * resolvedFps);
|
|
97
|
+
}
|
|
98
|
+
var nonNegativeRoom = (value) => value === Number.POSITIVE_INFINITY ? value : Number.isFinite(value) && value > 0 ? value : 0;
|
|
99
|
+
function planTransitionHandleWindow(input) {
|
|
100
|
+
const declaredSeconds = Number.isFinite(input.declaredSeconds) && input.declaredSeconds > 0 ? input.declaredSeconds : 0;
|
|
101
|
+
const effectiveSeconds = Math.max(0, Math.min(
|
|
102
|
+
declaredSeconds,
|
|
103
|
+
2 * nonNegativeRoom(input.outgoingTailRoomSeconds),
|
|
104
|
+
2 * nonNegativeRoom(input.incomingHeadRoomSeconds),
|
|
105
|
+
2 * nonNegativeRoom(input.outgoingDurationSeconds),
|
|
106
|
+
2 * nonNegativeRoom(input.incomingDurationSeconds)
|
|
107
|
+
));
|
|
108
|
+
return {
|
|
109
|
+
effectiveSeconds,
|
|
110
|
+
halfSeconds: effectiveSeconds / 2,
|
|
111
|
+
outcome: effectiveSeconds <= 0 ? "none" : effectiveSeconds < declaredSeconds ? "clamped" : "full"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
53
115
|
// src/timeline-map.ts
|
|
54
116
|
function transitionProgressAt(window, outputT) {
|
|
55
117
|
if (!(window.duration > 0)) return 0;
|
|
@@ -68,10 +130,46 @@ var AkariEditKernel = (() => {
|
|
|
68
130
|
const resolved = trackSegments.map((segment) => ({
|
|
69
131
|
start: segment.at,
|
|
70
132
|
end: segment.end,
|
|
133
|
+
baseStart: segment.at,
|
|
134
|
+
baseEnd: segment.end,
|
|
71
135
|
track: segment.track,
|
|
72
136
|
cut: usableCuts[segment.index],
|
|
73
137
|
cutIndex: usable[segment.index].index
|
|
74
138
|
}));
|
|
139
|
+
const fps = options?.fps ?? DEFAULT_CUT_ADJACENCY_FPS;
|
|
140
|
+
for (let outgoingIndex = 0; outgoingIndex < resolved.length; outgoingIndex++) {
|
|
141
|
+
const outgoing = resolved[outgoingIndex];
|
|
142
|
+
const transition = outgoing.cut.transitionOut;
|
|
143
|
+
if (!transition || !(typeof transition.duration === "number" && Number.isFinite(transition.duration) && transition.duration > 0)) continue;
|
|
144
|
+
const incoming = resolved.slice(outgoingIndex + 1).find((candidate) => candidate.track === outgoing.track);
|
|
145
|
+
if (!incoming || cutOverlapFrames(
|
|
146
|
+
{ tlEnd: outgoing.end },
|
|
147
|
+
{ tlStart: incoming.start },
|
|
148
|
+
fps
|
|
149
|
+
) !== 0) continue;
|
|
150
|
+
const outgoingRoom = options?.handleRoom?.(outgoing.cutIndex);
|
|
151
|
+
const incomingRoom = options?.handleRoom?.(incoming.cutIndex);
|
|
152
|
+
const incomingSpeed = typeof incoming.cut.speed === "number" && incoming.cut.speed > 0 ? incoming.cut.speed : 1;
|
|
153
|
+
const plan = planTransitionHandleWindow({
|
|
154
|
+
declaredSeconds: transition.duration,
|
|
155
|
+
outgoingTailRoomSeconds: outgoingRoom?.tailSeconds ?? Number.POSITIVE_INFINITY,
|
|
156
|
+
incomingHeadRoomSeconds: incomingRoom?.headSeconds ?? incoming.cut.in / incomingSpeed,
|
|
157
|
+
outgoingDurationSeconds: outgoing.baseEnd - outgoing.baseStart,
|
|
158
|
+
incomingDurationSeconds: incoming.baseEnd - incoming.baseStart
|
|
159
|
+
});
|
|
160
|
+
if (plan.effectiveSeconds <= 0) continue;
|
|
161
|
+
const cutPoint = outgoing.end;
|
|
162
|
+
outgoing.end = cutPoint + plan.halfSeconds;
|
|
163
|
+
outgoing.cut = {
|
|
164
|
+
...outgoing.cut,
|
|
165
|
+
transitionOut: { ...transition, duration: plan.effectiveSeconds }
|
|
166
|
+
};
|
|
167
|
+
incoming.start = cutPoint - plan.halfSeconds;
|
|
168
|
+
incoming.cut = {
|
|
169
|
+
...incoming.cut,
|
|
170
|
+
in: Math.max(0, incoming.cut.in - plan.halfSeconds * incomingSpeed)
|
|
171
|
+
};
|
|
172
|
+
}
|
|
75
173
|
const segmentSlice = (entry, start, end, transitionOut = null) => {
|
|
76
174
|
const cut = entry.cut;
|
|
77
175
|
const speed = typeof cut.speed === "number" && cut.speed > 0 ? cut.speed : 1;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@akari-video/matte-rvm",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Robust Video Matting model deployment and raw BGRA inference helper.",
|
|
7
|
+
"main": "src/index.mjs",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.mjs"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"postinstall": "node scripts/fetch-models.mjs",
|
|
13
|
+
"fetch:resnet50": "node scripts/fetch-models.mjs --model resnet50",
|
|
14
|
+
"test": "node --test \"test/*.test.mjs\""
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"onnxruntime-node": "1.29.0"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { createRequire } from "node:module";
|
|
10
|
+
|
|
11
|
+
const { TRANSITION_TYPE_IDS } = createRequire(import.meta.url)("../../edit-store/lib/index.js");
|
|
9
12
|
|
|
10
13
|
const LAYER_KINDS = new Set(["baked", "video", "filter"]);
|
|
11
14
|
const LAYER_BLEND_MODES = new Set([
|
|
@@ -1063,8 +1066,8 @@ function validateTransitionOut(value, label) {
|
|
|
1063
1066
|
fail(`${label} は object である必要があります`);
|
|
1064
1067
|
return;
|
|
1065
1068
|
}
|
|
1066
|
-
if (!
|
|
1067
|
-
fail(`${label}.type は
|
|
1069
|
+
if (!TRANSITION_TYPE_IDS.includes(value.type)) {
|
|
1070
|
+
fail(`${label}.type は ${TRANSITION_TYPE_IDS.join("/")} のいずれかである必要があります`);
|
|
1068
1071
|
}
|
|
1069
1072
|
if (!isFiniteNumber(value.duration) || value.duration <= 0) {
|
|
1070
1073
|
fail(`${label}.duration は 0 より大きい有限数である必要があります`);
|
|
@@ -279,10 +279,10 @@
|
|
|
279
279
|
"additionalProperties": true,
|
|
280
280
|
"required": ["type", "duration"],
|
|
281
281
|
"properties": {
|
|
282
|
-
"type": { "enum": ["dissolve", "fade-black", "fade-white", "reveal-down", "reveal-up"] },
|
|
282
|
+
"type": { "enum": ["dissolve", "fade", "fade-black", "fade-white", "fade-grays", "wipe-left", "wipe-right", "wipe-up", "wipe-down", "radial", "slide-left", "slide-right", "slide-up", "slide-down", "cover-left", "cover-right", "cover-up", "cover-down", "reveal-left", "reveal-right", "reveal-down", "reveal-up", "circle-open", "circle-close", "zoom-in", "squeeze-h", "squeeze-v", "blur", "pixelize"] },
|
|
283
283
|
"duration": { "$ref": "#/$defs/positiveNumber" }
|
|
284
284
|
},
|
|
285
|
-
"$comment": "docs/contract-2026-07-22-render-basics.md #3。v0 は指定されたカット境界のみ xfade 経路(残裁定3)。
|
|
285
|
+
"$comment": "docs/contract-2026-07-22-render-basics.md #3。v0 は指定されたカット境界のみ xfade 経路(残裁定3)。enum は packages/edit-store の正準トランジション語彙と drift test で一致させる。"
|
|
286
286
|
},
|
|
287
287
|
"cutTransform": {
|
|
288
288
|
"type": "object",
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { tmpdir } from 'node:os';
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import test from 'node:test';
|
|
9
|
+
|
|
10
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
11
|
+
|
|
12
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
13
|
+
const schema = JSON.parse(readFileSync(join(packageRoot, 'edit.schema.json'), 'utf8'));
|
|
14
|
+
const validate = new Ajv2020({ allErrors: true, strict: false }).compile(schema);
|
|
15
|
+
const { TRANSITION_TYPE_IDS } = createRequire(import.meta.url)(
|
|
16
|
+
'../../edit-store/lib/index.js'
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
const editFor = type => ({
|
|
20
|
+
version: 0,
|
|
21
|
+
output: { width: 1280, height: 720, fps: 30 },
|
|
22
|
+
source: { path: 'source.mp4', proxy: null },
|
|
23
|
+
cuts: [
|
|
24
|
+
{ in: 0, out: 2, transition_out: { type, duration: 0.5 } },
|
|
25
|
+
{ in: 2, out: 4 },
|
|
26
|
+
],
|
|
27
|
+
overlays: [],
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('正準 29 種は JSON Schema と validate-edit CLI を往復する', () => {
|
|
31
|
+
assert.deepEqual(schema.$defs.transitionOut.properties.type.enum, TRANSITION_TYPE_IDS);
|
|
32
|
+
const root = mkdtempSync(join(tmpdir(), 'akari-transition-schema-'));
|
|
33
|
+
try {
|
|
34
|
+
for (const type of TRANSITION_TYPE_IDS) {
|
|
35
|
+
const edit = editFor(type);
|
|
36
|
+
assert.equal(validate(edit), true, `${type}: ${JSON.stringify(validate.errors)}`);
|
|
37
|
+
const editPath = join(root, `${type}.json`);
|
|
38
|
+
writeFileSync(editPath, `${JSON.stringify(edit)}\n`);
|
|
39
|
+
const executed = spawnSync(process.execPath, [join(packageRoot, 'bin', 'validate-edit.mjs'), editPath], {
|
|
40
|
+
encoding: 'utf8'
|
|
41
|
+
});
|
|
42
|
+
assert.equal(executed.status, 0, `${type}: ${executed.stderr}`);
|
|
43
|
+
}
|
|
44
|
+
} finally {
|
|
45
|
+
rmSync(root, { recursive: true, force: true });
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('未知種別は schema と validate-edit CLI の双方で拒否される', () => {
|
|
50
|
+
const edit = editFor('future-transition');
|
|
51
|
+
assert.equal(validate(edit), false);
|
|
52
|
+
const root = mkdtempSync(join(tmpdir(), 'akari-transition-schema-invalid-'));
|
|
53
|
+
try {
|
|
54
|
+
const editPath = join(root, 'edit.json');
|
|
55
|
+
writeFileSync(editPath, `${JSON.stringify(edit)}\n`);
|
|
56
|
+
const executed = spawnSync(process.execPath, [join(packageRoot, 'bin', 'validate-edit.mjs'), editPath], {
|
|
57
|
+
encoding: 'utf8'
|
|
58
|
+
});
|
|
59
|
+
assert.equal(executed.status, 1);
|
|
60
|
+
assert.match(executed.stderr, /future-transition|いずれか/u);
|
|
61
|
+
} finally {
|
|
62
|
+
rmSync(root, { recursive: true, force: true });
|
|
63
|
+
}
|
|
64
|
+
});
|
|
@@ -214,12 +214,12 @@ test("source.chroma_key.color is required", () => {
|
|
|
214
214
|
assert.match(executed.stderr, /source\.chroma_key\.color は空でない文字列である必要があります/);
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
-
test("cuts[].transition_out.type must be
|
|
217
|
+
test("cuts[].transition_out.type must be one of the canonical transition vocabulary", () => {
|
|
218
218
|
const executed = run("edit-transition-invalid");
|
|
219
219
|
assert.equal(executed.status, 1, executed.stdout);
|
|
220
220
|
assert.match(
|
|
221
221
|
executed.stderr,
|
|
222
|
-
/cuts\[0\]\.transition_out\.type は
|
|
222
|
+
/cuts\[0\]\.transition_out\.type は .*pixelize のいずれかである必要があります/,
|
|
223
223
|
);
|
|
224
224
|
});
|
|
225
225
|
|