route-graphics 1.44.1 → 1.44.2
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/README.md +1 -3
- package/bin/route-graphics-render.js +5 -615
- package/dist/RouteGraphics.js +178 -669
- package/dist/cli/routeGraphicsCli.js +64 -10
- package/package.json +17 -10
- package/src/cli/browserLaunch.js +0 -5
- package/src/cli/inspectTimeline.js +0 -72
- package/src/cli/inspectTimeline.test.js +0 -135
- package/src/cli/renderConfig.js +0 -519
- package/src/cli/renderVideo.js +0 -627
- package/src/cli/routeGraphicsCli.js +0 -967
- package/src/cli/stateSelection.js +0 -61
|
@@ -745,13 +745,17 @@ var captureVideoWebm = async ({
|
|
|
745
745
|
return;
|
|
746
746
|
}
|
|
747
747
|
const waiterIndex = pendingRenderWaiters.findIndex(
|
|
748
|
-
(waiter2) => payload?.aborted !== true && (waiter2.stateId === payload?.id || waiter2.stateId === void 0)
|
|
748
|
+
(waiter2) => (payload?.failed === true || payload?.aborted !== true) && (waiter2.stateId === payload?.id || waiter2.stateId === void 0)
|
|
749
749
|
);
|
|
750
750
|
if (waiterIndex < 0) {
|
|
751
751
|
return;
|
|
752
752
|
}
|
|
753
753
|
const [waiter] = pendingRenderWaiters.splice(waiterIndex, 1);
|
|
754
|
-
|
|
754
|
+
if (payload?.failed) {
|
|
755
|
+
waiter.reject(payload.error ?? new Error("Render failed."));
|
|
756
|
+
} else {
|
|
757
|
+
waiter.resolve(payload);
|
|
758
|
+
}
|
|
755
759
|
},
|
|
756
760
|
debug: false
|
|
757
761
|
});
|
|
@@ -798,6 +802,8 @@ var captureVideoWebm = async ({
|
|
|
798
802
|
const stateIndex = renderPayload.stateIndexes[renderIndex];
|
|
799
803
|
const state = renderPayload.states[stateIndex];
|
|
800
804
|
const waitForComplete = createRenderCompleteWaiter(state.id);
|
|
805
|
+
void waitForComplete.catch(() => {
|
|
806
|
+
});
|
|
801
807
|
debug("render state start", state.id);
|
|
802
808
|
app.render(state);
|
|
803
809
|
app.render(state);
|
|
@@ -6651,6 +6657,7 @@ Options:
|
|
|
6651
6657
|
PNG options:
|
|
6652
6658
|
--state <index> State index when YAML contains multiple states
|
|
6653
6659
|
--time <ms> Sample animations at a manual time
|
|
6660
|
+
--layout-report <path> Write a JSON layout snapshot beside the PNG
|
|
6654
6661
|
--wait-for-render-complete Wait for renderComplete before capture
|
|
6655
6662
|
|
|
6656
6663
|
MP4 options:
|
|
@@ -6673,7 +6680,12 @@ Timeline inspection options:
|
|
|
6673
6680
|
--compact Emit compact JSON instead of indented JSON
|
|
6674
6681
|
`;
|
|
6675
6682
|
var renderCommandUsage = usage;
|
|
6676
|
-
var PNG_ONLY_OPTIONS = [
|
|
6683
|
+
var PNG_ONLY_OPTIONS = [
|
|
6684
|
+
"stateIndex",
|
|
6685
|
+
"timeMS",
|
|
6686
|
+
"waitForRenderComplete",
|
|
6687
|
+
"layoutReportPath"
|
|
6688
|
+
];
|
|
6677
6689
|
var MP4_ONLY_OPTIONS = [
|
|
6678
6690
|
"stateSelection",
|
|
6679
6691
|
"fps",
|
|
@@ -6686,6 +6698,7 @@ var MP4_ONLY_OPTIONS = [
|
|
|
6686
6698
|
var toOptionName = (propertyName) => ({
|
|
6687
6699
|
stateIndex: "--state",
|
|
6688
6700
|
timeMS: "--time",
|
|
6701
|
+
layoutReportPath: "--layout-report",
|
|
6689
6702
|
waitForRenderComplete: "--wait-for-render-complete",
|
|
6690
6703
|
stateSelection: "--states",
|
|
6691
6704
|
fps: "--fps",
|
|
@@ -6870,6 +6883,10 @@ var parseRouteGraphicsCliArgs = (argv) => {
|
|
|
6870
6883
|
options.stateSelection = readOptionValue(rest, index, token);
|
|
6871
6884
|
index += 1;
|
|
6872
6885
|
break;
|
|
6886
|
+
case "--layout-report":
|
|
6887
|
+
options.layoutReportPath = readOptionValue(rest, index, token);
|
|
6888
|
+
index += 1;
|
|
6889
|
+
break;
|
|
6873
6890
|
case "--time":
|
|
6874
6891
|
options.timeMS = parseIntegerOption(
|
|
6875
6892
|
"Animation time",
|
|
@@ -7141,7 +7158,8 @@ var capturePng = async ({
|
|
|
7141
7158
|
timeMS,
|
|
7142
7159
|
waitForRenderComplete,
|
|
7143
7160
|
timeoutMS,
|
|
7144
|
-
browserExecutablePath
|
|
7161
|
+
browserExecutablePath,
|
|
7162
|
+
includeLayoutReport = false
|
|
7145
7163
|
}) => {
|
|
7146
7164
|
const browser = await chromium2.launch(
|
|
7147
7165
|
getRendererBrowserLaunchOptions(browserExecutablePath)
|
|
@@ -7160,7 +7178,7 @@ var capturePng = async ({
|
|
|
7160
7178
|
await page.goto(origin, {
|
|
7161
7179
|
waitUntil: "domcontentloaded"
|
|
7162
7180
|
});
|
|
7163
|
-
const
|
|
7181
|
+
const capture = await page.evaluate(
|
|
7164
7182
|
async ({ moduleUrl, renderPayload }) => {
|
|
7165
7183
|
const nextFrame = async (count = 2) => {
|
|
7166
7184
|
await new Promise((resolve) => {
|
|
@@ -7197,16 +7215,22 @@ var capturePng = async ({
|
|
|
7197
7215
|
const assetBufferManager = createAssetBufferManager();
|
|
7198
7216
|
let renderCompleteResolve = () => {
|
|
7199
7217
|
};
|
|
7218
|
+
let renderCompleteReject = () => {
|
|
7219
|
+
};
|
|
7220
|
+
let renderFailure;
|
|
7200
7221
|
let renderTimeoutId = null;
|
|
7201
7222
|
let renderCompletePromise = Promise.resolve(null);
|
|
7202
7223
|
if (renderPayload.waitForRenderComplete) {
|
|
7203
7224
|
renderCompletePromise = new Promise((resolve, reject) => {
|
|
7204
7225
|
renderCompleteResolve = resolve;
|
|
7226
|
+
renderCompleteReject = reject;
|
|
7205
7227
|
renderTimeoutId = window.setTimeout(() => {
|
|
7206
7228
|
reject(new Error("Timed out waiting for renderComplete."));
|
|
7207
7229
|
}, renderPayload.timeoutMS);
|
|
7208
7230
|
});
|
|
7209
7231
|
}
|
|
7232
|
+
void renderCompletePromise.catch(() => {
|
|
7233
|
+
});
|
|
7210
7234
|
try {
|
|
7211
7235
|
await app.init({
|
|
7212
7236
|
width: renderPayload.width,
|
|
@@ -7230,6 +7254,10 @@ var capturePng = async ({
|
|
|
7230
7254
|
audio: [soundPlugin].filter(Boolean)
|
|
7231
7255
|
},
|
|
7232
7256
|
eventHandler: (eventName, payload) => {
|
|
7257
|
+
if (eventName === "renderComplete" && payload?.failed) {
|
|
7258
|
+
renderFailure = payload.error ?? new Error("Render failed.");
|
|
7259
|
+
renderCompleteReject(renderFailure);
|
|
7260
|
+
}
|
|
7233
7261
|
if (eventName === "renderComplete" && payload?.aborted !== true) {
|
|
7234
7262
|
renderCompleteResolve(payload);
|
|
7235
7263
|
}
|
|
@@ -7254,7 +7282,10 @@ var capturePng = async ({
|
|
|
7254
7282
|
} catch {
|
|
7255
7283
|
}
|
|
7256
7284
|
await nextFrame(2);
|
|
7257
|
-
|
|
7285
|
+
if (renderFailure) throw renderFailure;
|
|
7286
|
+
const image = app.extractBase64();
|
|
7287
|
+
const layoutReport = renderPayload.includeLayoutReport ? app.getLayoutReport() : null;
|
|
7288
|
+
return { base64: await image, layoutReport };
|
|
7258
7289
|
} finally {
|
|
7259
7290
|
if (renderTimeoutId !== null) {
|
|
7260
7291
|
window.clearTimeout(renderTimeoutId);
|
|
@@ -7272,14 +7303,15 @@ var capturePng = async ({
|
|
|
7272
7303
|
assets: browserAssets,
|
|
7273
7304
|
timeMS: timeMS ?? null,
|
|
7274
7305
|
waitForRenderComplete,
|
|
7275
|
-
timeoutMS
|
|
7306
|
+
timeoutMS,
|
|
7307
|
+
includeLayoutReport
|
|
7276
7308
|
}
|
|
7277
7309
|
}
|
|
7278
7310
|
);
|
|
7279
7311
|
if (pageErrors.length > 0) {
|
|
7280
7312
|
throw new Error(pageErrors.join("\n"));
|
|
7281
7313
|
}
|
|
7282
|
-
return
|
|
7314
|
+
return capture;
|
|
7283
7315
|
} finally {
|
|
7284
7316
|
await browser.close();
|
|
7285
7317
|
}
|
|
@@ -7301,7 +7333,7 @@ var renderPng = async ({
|
|
|
7301
7333
|
}
|
|
7302
7334
|
const settings = normalizeRenderSettings({ cliOptions, definition });
|
|
7303
7335
|
const renderStartedAt = performance2.now();
|
|
7304
|
-
const base64 = await capturePng({
|
|
7336
|
+
const { base64, layoutReport } = await capturePng({
|
|
7305
7337
|
origin,
|
|
7306
7338
|
width: settings.width,
|
|
7307
7339
|
height: settings.height,
|
|
@@ -7311,11 +7343,22 @@ var renderPng = async ({
|
|
|
7311
7343
|
timeMS: cliOptions.timeMS,
|
|
7312
7344
|
waitForRenderComplete: cliOptions.waitForRenderComplete,
|
|
7313
7345
|
timeoutMS: cliOptions.timeoutMS,
|
|
7314
|
-
browserExecutablePath: cliOptions.browserExecutablePath
|
|
7346
|
+
browserExecutablePath: cliOptions.browserExecutablePath,
|
|
7347
|
+
includeLayoutReport: Boolean(cliOptions.layoutReportPath)
|
|
7315
7348
|
});
|
|
7316
7349
|
const renderDurationMS = performance2.now() - renderStartedAt;
|
|
7317
7350
|
const writeStartedAt = performance2.now();
|
|
7318
7351
|
await writePngOutput(outputPath, base64);
|
|
7352
|
+
if (cliOptions.layoutReportPath) {
|
|
7353
|
+
await fsPromises2.mkdir(path4.dirname(cliOptions.layoutReportPath), {
|
|
7354
|
+
recursive: true
|
|
7355
|
+
});
|
|
7356
|
+
await fsPromises2.writeFile(
|
|
7357
|
+
cliOptions.layoutReportPath,
|
|
7358
|
+
`${JSON.stringify(layoutReport, null, 2)}
|
|
7359
|
+
`
|
|
7360
|
+
);
|
|
7361
|
+
}
|
|
7319
7362
|
const writeDurationMS = performance2.now() - writeStartedAt;
|
|
7320
7363
|
return {
|
|
7321
7364
|
inputPath,
|
|
@@ -7342,6 +7385,17 @@ var runRender = async ({ cliOptions, cwd }) => {
|
|
|
7342
7385
|
outputPath: cliOptions.outputPath,
|
|
7343
7386
|
format
|
|
7344
7387
|
});
|
|
7388
|
+
if (cliOptions.layoutReportPath) {
|
|
7389
|
+
cliOptions = {
|
|
7390
|
+
...cliOptions,
|
|
7391
|
+
layoutReportPath: path4.resolve(cwd, cliOptions.layoutReportPath)
|
|
7392
|
+
};
|
|
7393
|
+
if (cliOptions.layoutReportPath === inputPath || cliOptions.layoutReportPath === outputPath) {
|
|
7394
|
+
throw new Error(
|
|
7395
|
+
"Layout report path must differ from the input and PNG output paths."
|
|
7396
|
+
);
|
|
7397
|
+
}
|
|
7398
|
+
}
|
|
7345
7399
|
await ensureBundleExists();
|
|
7346
7400
|
const yamlSource = await fsPromises2.readFile(inputPath, "utf8");
|
|
7347
7401
|
const definition = loadRenderDefinition(yamlSource);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "route-graphics",
|
|
3
|
-
"version": "1.44.
|
|
3
|
+
"version": "1.44.2",
|
|
4
4
|
"description": "A 2D graphics rendering interface that takes JSON input and renders pixels using PixiJS",
|
|
5
5
|
"main": "dist/RouteGraphics.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,12 +27,11 @@
|
|
|
27
27
|
"files": [
|
|
28
28
|
"bin",
|
|
29
29
|
"dist",
|
|
30
|
-
"src/cli",
|
|
31
30
|
"package.json"
|
|
32
31
|
],
|
|
33
32
|
"scripts": {
|
|
34
|
-
"lint": "
|
|
35
|
-
"lint:fix": "
|
|
33
|
+
"lint": "prettier --check src && oxlint src spec scripts bin",
|
|
34
|
+
"lint:fix": "prettier --write src && oxlint --fix src spec scripts bin",
|
|
36
35
|
"prepare": "husky",
|
|
37
36
|
"build": "node ./esbuild.js",
|
|
38
37
|
"benchmark:timeline": "node ./scripts/benchmarkTimeline.mjs",
|
|
@@ -41,30 +40,37 @@
|
|
|
41
40
|
"avt:report": "bun run build && node ./scripts/audioVisualTest.mjs report",
|
|
42
41
|
"render:png": "bun run build && node ./bin/route-graphics-render.js",
|
|
43
42
|
"vt:docker:pull": "docker pull docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0",
|
|
44
|
-
"vt:generate": "bun run build && docker run --rm --user $(id -u):$(id -g) -e RTGL_VT_DEBUG=true -v \"$PWD:/workspace\" docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 rtgl vt generate --wait-event vt:ready",
|
|
45
|
-
"vt:screenshot": "bun run build &&
|
|
43
|
+
"vt:generate": "bun run build:visual && docker run --rm --user $(id -u):$(id -g) -e RTGL_VT_DEBUG=true -v \"$PWD:/workspace\" docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 rtgl vt generate --wait-event vt:ready",
|
|
44
|
+
"vt:screenshot": "bun run build:visual && bun run vt:screenshot:built",
|
|
46
45
|
"vt:docker": "bun run vt:screenshot",
|
|
47
|
-
"vt:report": "bun run
|
|
46
|
+
"vt:report": "bun run build:visual && bun run vt:report:built",
|
|
48
47
|
"vt:accept": "docker run --rm --user $(id -u):$(id -g) -e RTGL_VT_DEBUG=true -v \"$PWD:/workspace\" docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 rtgl vt accept",
|
|
49
48
|
"test": "vitest run",
|
|
50
49
|
"test:layout-report": "node esbuild.js && node scripts/testLayoutReport.mjs",
|
|
51
50
|
"test:webgpu": "bun run build && node ./scripts/testWebGPUShaders.mjs",
|
|
52
51
|
"test:coverage": "vitest run --coverage",
|
|
53
52
|
"test:watch": "vitest",
|
|
54
|
-
"serve": "bunx serve -p 3005 .rettangoli/vt/_site"
|
|
53
|
+
"serve": "bunx serve -p 3005 .rettangoli/vt/_site",
|
|
54
|
+
"build:playground": "node ./esbuild.js playground",
|
|
55
|
+
"build:visual": "node ./esbuild.js visual",
|
|
56
|
+
"build:all": "node ./esbuild.js all",
|
|
57
|
+
"test:runtime": "bun run build && node scripts/testRuntimeLifecycle.mjs",
|
|
58
|
+
"test:package": "node scripts/testPackage.mjs",
|
|
59
|
+
"vt:screenshot:built": "docker run --rm --user $(id -u):$(id -g) -e RTGL_VT_DEBUG=true -e RTGL_VT_CONCURRENCY=${RTGL_VT_CONCURRENCY:-8} -v \"$PWD:/workspace\" docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 rtgl vt screenshot --wait-event vt:ready --concurrency ${RTGL_VT_CONCURRENCY:-8}",
|
|
60
|
+
"vt:report:built": "bun run vt:screenshot:built && docker run --rm --user $(id -u):$(id -g) -e RTGL_VT_DEBUG=true -v \"$PWD:/workspace\" docker.io/han4wluc/rtgl:playwright-v1.57.0-rtgl-v1.1.0 rtgl vt report"
|
|
55
61
|
},
|
|
56
62
|
"dependencies": {
|
|
57
|
-
"@pixi/unsafe-eval": "^7.4.3",
|
|
58
63
|
"@wasm-audio-decoders/ogg-vorbis": "^0.1.20",
|
|
59
64
|
"gsap": "3.15.0",
|
|
60
65
|
"hotkeys-js": "^4.0.0-beta.7",
|
|
61
66
|
"js-yaml": "^4.1.0",
|
|
62
67
|
"ogg-opus-decoder": "^1.7.3",
|
|
63
|
-
"pixi.js": "8.
|
|
68
|
+
"pixi.js": "8.10.2",
|
|
64
69
|
"playwright": "1.57.0"
|
|
65
70
|
},
|
|
66
71
|
"devDependencies": {
|
|
67
72
|
"@vitest/coverage-v8": "^4.0.8",
|
|
73
|
+
"canvas": "3.2.0",
|
|
68
74
|
"esbuild": "^0.25.6",
|
|
69
75
|
"husky": "^9.1.7",
|
|
70
76
|
"jsdom": "^27.0.1",
|
|
@@ -72,6 +78,7 @@
|
|
|
72
78
|
"oxlint": "^1.26.0",
|
|
73
79
|
"pixelmatch": "^5.3.0",
|
|
74
80
|
"pngjs": "^7.0.0",
|
|
81
|
+
"prettier": "3.6.2",
|
|
75
82
|
"puty": "^0.1.2",
|
|
76
83
|
"vitest": "^4.0.8"
|
|
77
84
|
},
|
package/src/cli/browserLaunch.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
import { loadRenderDefinition } from "./renderConfig.js";
|
|
5
|
-
import { normalizeRenderState } from "../util/normalizeRenderState.js";
|
|
6
|
-
import {
|
|
7
|
-
compileAnimationTimelineProgram,
|
|
8
|
-
inspectTimelineProgram,
|
|
9
|
-
} from "../plugins/animations/timeline/inspectProgram.js";
|
|
10
|
-
|
|
11
|
-
export const inspectTimelineDefinition = ({
|
|
12
|
-
definition,
|
|
13
|
-
stateIndex = 0,
|
|
14
|
-
animationId,
|
|
15
|
-
}) => {
|
|
16
|
-
if (!Number.isSafeInteger(stateIndex) || stateIndex < 0) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
"Timeline inspection state index must be a non-negative safe integer.",
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
const rawState = definition.states[stateIndex];
|
|
22
|
-
if (!rawState) {
|
|
23
|
-
throw new Error(
|
|
24
|
-
`State index ${stateIndex} is out of range for ${definition.states.length} states.`,
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
const state = normalizeRenderState(rawState);
|
|
28
|
-
const indexedAnimations = state.animations.map((animation, index) => ({
|
|
29
|
-
animation,
|
|
30
|
-
index,
|
|
31
|
-
}));
|
|
32
|
-
const selected = animationId
|
|
33
|
-
? indexedAnimations.filter(({ animation }) => animation.id === animationId)
|
|
34
|
-
: indexedAnimations;
|
|
35
|
-
if (animationId && selected.length === 0) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`Animation "${animationId}" was not found in state "${state.id ?? stateIndex}".`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
schema: "route.timeline-inspection-set/v1",
|
|
43
|
-
state: { index: stateIndex, id: state.id ?? null },
|
|
44
|
-
animations: selected.map(({ animation, index }) => {
|
|
45
|
-
const sourcePath = `states[${stateIndex}].animations[${index}]`;
|
|
46
|
-
const program = compileAnimationTimelineProgram(animation, {
|
|
47
|
-
sourcePath,
|
|
48
|
-
});
|
|
49
|
-
return {
|
|
50
|
-
normalizedAst: animation,
|
|
51
|
-
...inspectTimelineProgram(program),
|
|
52
|
-
};
|
|
53
|
-
}),
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export const inspectTimelineFile = async ({
|
|
58
|
-
inputPath,
|
|
59
|
-
cwd = process.cwd(),
|
|
60
|
-
stateIndex = 0,
|
|
61
|
-
animationId,
|
|
62
|
-
}) => {
|
|
63
|
-
if (!inputPath)
|
|
64
|
-
throw new Error("Timeline inspection requires an input YAML file.");
|
|
65
|
-
const absolutePath = path.resolve(cwd, inputPath);
|
|
66
|
-
const yamlSource = await fs.readFile(absolutePath, "utf8");
|
|
67
|
-
return inspectTimelineDefinition({
|
|
68
|
-
definition: loadRenderDefinition(yamlSource),
|
|
69
|
-
stateIndex,
|
|
70
|
-
animationId,
|
|
71
|
-
});
|
|
72
|
-
};
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import { inspectTimelineDefinition } from "./inspectTimeline.js";
|
|
4
|
-
import { loadRenderDefinition } from "./renderConfig.js";
|
|
5
|
-
import {
|
|
6
|
-
parseRouteGraphicsCliArgs,
|
|
7
|
-
runRouteGraphicsCli,
|
|
8
|
-
} from "./routeGraphicsCli.js";
|
|
9
|
-
|
|
10
|
-
const source = `
|
|
11
|
-
states:
|
|
12
|
-
- id: demo
|
|
13
|
-
elements: []
|
|
14
|
-
animations:
|
|
15
|
-
- id: move
|
|
16
|
-
targetId: hero
|
|
17
|
-
type: update
|
|
18
|
-
gsap:
|
|
19
|
-
profile: portable-v1
|
|
20
|
-
steps:
|
|
21
|
-
- kind: mark
|
|
22
|
-
name: entrance
|
|
23
|
-
- kind: to
|
|
24
|
-
values: { x: 100 }
|
|
25
|
-
duration: 250
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
describe("timeline inspector", () => {
|
|
29
|
-
it("reports normalized authoring, semantic program, and visualization lanes", () => {
|
|
30
|
-
const result = inspectTimelineDefinition({
|
|
31
|
-
definition: loadRenderDefinition(source),
|
|
32
|
-
stateIndex: 0,
|
|
33
|
-
animationId: "move",
|
|
34
|
-
});
|
|
35
|
-
expect(result.animations[0]).toMatchObject({
|
|
36
|
-
normalizedAst: { id: "move", gsap: { profile: "portable-v1" } },
|
|
37
|
-
summary: { duration: 250, clipCount: 1, frontend: "gsap" },
|
|
38
|
-
visualization: {
|
|
39
|
-
marks: { entrance: 0 },
|
|
40
|
-
lanes: [{ channel: "transform.x", start: 0, duration: 250 }],
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
expect(result.animations[0].semanticSignature).toContain(
|
|
44
|
-
'"schema":"route.timeline/v1"',
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it("parses and runs inspect-timeline without launching a browser", async () => {
|
|
49
|
-
expect(
|
|
50
|
-
parseRouteGraphicsCliArgs([
|
|
51
|
-
"inspect-timeline",
|
|
52
|
-
"scene.yaml",
|
|
53
|
-
"--animation",
|
|
54
|
-
"move",
|
|
55
|
-
"--compact",
|
|
56
|
-
]),
|
|
57
|
-
).toMatchObject({
|
|
58
|
-
command: "inspect-timeline",
|
|
59
|
-
inputPath: "scene.yaml",
|
|
60
|
-
animationId: "move",
|
|
61
|
-
compact: true,
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const stdout = {
|
|
65
|
-
value: "",
|
|
66
|
-
write(value) {
|
|
67
|
-
this.value += value;
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
const stderr = {
|
|
71
|
-
value: "",
|
|
72
|
-
write(value) {
|
|
73
|
-
this.value += value;
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
const exitCode = await runRouteGraphicsCli({
|
|
77
|
-
argv: ["inspect-timeline", "virtual.yaml", "--compact"],
|
|
78
|
-
cwd: "/virtual",
|
|
79
|
-
stdout,
|
|
80
|
-
stderr,
|
|
81
|
-
});
|
|
82
|
-
expect(exitCode).toBe(1);
|
|
83
|
-
expect(stdout.value).toBe("");
|
|
84
|
-
expect(stderr.value).toContain("ENOENT");
|
|
85
|
-
expect(() =>
|
|
86
|
-
parseRouteGraphicsCliArgs([
|
|
87
|
-
"inspect-timeline",
|
|
88
|
-
"scene.yaml",
|
|
89
|
-
"--output",
|
|
90
|
-
"ignored.json",
|
|
91
|
-
]),
|
|
92
|
-
).toThrow("--output is not supported by inspect-timeline");
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it("preserves original animation indexes in source paths when filtering", () => {
|
|
96
|
-
const result = inspectTimelineDefinition({
|
|
97
|
-
definition: loadRenderDefinition(`
|
|
98
|
-
states:
|
|
99
|
-
- elements: []
|
|
100
|
-
animations:
|
|
101
|
-
- id: first
|
|
102
|
-
targetId: one
|
|
103
|
-
type: update
|
|
104
|
-
tween:
|
|
105
|
-
x:
|
|
106
|
-
keyframes: [{ value: 1, duration: 10 }]
|
|
107
|
-
- id: second
|
|
108
|
-
targetId: two
|
|
109
|
-
type: update
|
|
110
|
-
tween:
|
|
111
|
-
x:
|
|
112
|
-
keyframes: [{ value: 2, duration: 10 }]
|
|
113
|
-
`),
|
|
114
|
-
animationId: "second",
|
|
115
|
-
});
|
|
116
|
-
expect(result.animations[0].visualization.lanes[0].sourcePath).toContain(
|
|
117
|
-
"animations[1]",
|
|
118
|
-
);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("compiles the checked-in portable GSAP example", () => {
|
|
122
|
-
const example = fs.readFileSync(
|
|
123
|
-
`${process.cwd()}/examples/portable-gsap.yaml`,
|
|
124
|
-
"utf8",
|
|
125
|
-
);
|
|
126
|
-
const result = inspectTimelineDefinition({
|
|
127
|
-
definition: loadRenderDefinition(example),
|
|
128
|
-
});
|
|
129
|
-
expect(result.animations[0].summary).toMatchObject({
|
|
130
|
-
programId: "card-entrance",
|
|
131
|
-
frontend: "gsap",
|
|
132
|
-
eventCount: 1,
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
});
|