@a-company/atelier 0.28.2 → 0.29.0
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/dist/{chunk-C5DBTHXB.js → chunk-JPZ4F4PW.js} +44 -2
- package/dist/chunk-JPZ4F4PW.js.map +1 -0
- package/dist/{chunk-LC7ICNMN.js → chunk-JV7RGETS.js} +54 -4
- package/dist/chunk-JV7RGETS.js.map +1 -0
- package/dist/cli.cjs +253 -66
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +109 -9
- package/dist/cli.js.map +1 -1
- package/dist/{dist-6IHF7WA7.js → dist-M67UZGFQ.js} +2 -2
- package/dist/index.cjs +63 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2 -2
- package/dist/mcp.cjs +32 -2
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +32 -2
- package/dist/mcp.js.map +1 -1
- package/package.json +6 -6
- package/dist/chunk-C5DBTHXB.js.map +0 -1
- package/dist/chunk-LC7ICNMN.js.map +0 -1
- /package/dist/{dist-6IHF7WA7.js.map → dist-M67UZGFQ.js.map} +0 -0
package/dist/cli.cjs
CHANGED
|
@@ -420,7 +420,18 @@ function resolveFrame(doc, stateName, frame, overrideDeltas) {
|
|
|
420
420
|
}
|
|
421
421
|
}
|
|
422
422
|
}
|
|
423
|
-
|
|
423
|
+
const resolvedLayer = { id: layer.id, layer, computedProperties };
|
|
424
|
+
if (layer.visual.type === "video") {
|
|
425
|
+
const video = layer.visual;
|
|
426
|
+
const fps = doc.canvas.fps;
|
|
427
|
+
const startFrame = video.startFrame ?? 0;
|
|
428
|
+
const sourceOffset = video.sourceOffset ?? 0;
|
|
429
|
+
const playbackRate = video.playbackRate ?? 1;
|
|
430
|
+
const relativeFrame = Math.max(0, frame - startFrame);
|
|
431
|
+
const sourceTime = relativeFrame / fps * playbackRate + sourceOffset;
|
|
432
|
+
resolvedLayer.videoSourceTime = video.sourceEnd !== void 0 ? Math.min(sourceTime, video.sourceEnd) : sourceTime;
|
|
433
|
+
}
|
|
434
|
+
return resolvedLayer;
|
|
424
435
|
});
|
|
425
436
|
return { frame, stateName, layers: resolvedLayers };
|
|
426
437
|
}
|
|
@@ -1027,6 +1038,14 @@ function renderImage(ctx, eff, imageCache) {
|
|
|
1027
1038
|
}
|
|
1028
1039
|
ctx.drawImage(img, 0, 0, eff.width, eff.height);
|
|
1029
1040
|
}
|
|
1041
|
+
function renderVideo(ctx, eff, sourceTime, provider) {
|
|
1042
|
+
const visual = eff.visual;
|
|
1043
|
+
const src = visual.src;
|
|
1044
|
+
if (!src) return;
|
|
1045
|
+
const frame = provider(src, sourceTime, eff.width, eff.height);
|
|
1046
|
+
if (!frame) return;
|
|
1047
|
+
ctx.drawImage(frame, 0, 0, eff.width, eff.height);
|
|
1048
|
+
}
|
|
1030
1049
|
function renderRef(ctx, eff, opts, _parentDoc) {
|
|
1031
1050
|
const visual = eff.visual;
|
|
1032
1051
|
const resolver = opts?.documentResolver;
|
|
@@ -1124,6 +1143,7 @@ function renderPlaceholder(ctx, eff, label) {
|
|
|
1124
1143
|
function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
1125
1144
|
let imageCache;
|
|
1126
1145
|
let documentResolver;
|
|
1146
|
+
let videoFrameProvider;
|
|
1127
1147
|
let maxRefDepth = 4;
|
|
1128
1148
|
if (optsOrCache && typeof optsOrCache.get === "function") {
|
|
1129
1149
|
imageCache = optsOrCache;
|
|
@@ -1131,6 +1151,7 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1131
1151
|
const opts = optsOrCache;
|
|
1132
1152
|
imageCache = opts.imageCache;
|
|
1133
1153
|
documentResolver = opts.documentResolver;
|
|
1154
|
+
videoFrameProvider = opts.videoFrameProvider;
|
|
1134
1155
|
maxRefDepth = opts.maxRefDepth ?? 4;
|
|
1135
1156
|
}
|
|
1136
1157
|
const { width, height } = doc.canvas;
|
|
@@ -1138,10 +1159,14 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1138
1159
|
ctx.fillRect(0, 0, width, height);
|
|
1139
1160
|
const effMap = /* @__PURE__ */ new Map();
|
|
1140
1161
|
const effList = [];
|
|
1162
|
+
const videoSourceTimeMap = /* @__PURE__ */ new Map();
|
|
1141
1163
|
for (const resolvedLayer of resolvedFrame.layers) {
|
|
1142
1164
|
const eff = buildEffectiveLayer(resolvedLayer, width, height);
|
|
1143
1165
|
effMap.set(resolvedLayer.layer.id, eff);
|
|
1144
1166
|
effList.push(eff);
|
|
1167
|
+
if (resolvedLayer.videoSourceTime !== void 0) {
|
|
1168
|
+
videoSourceTimeMap.set(resolvedLayer.layer.id, resolvedLayer.videoSourceTime);
|
|
1169
|
+
}
|
|
1145
1170
|
}
|
|
1146
1171
|
for (const eff of effList) {
|
|
1147
1172
|
const { layer } = eff;
|
|
@@ -1153,6 +1178,12 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1153
1178
|
iv.src = doc.assets[iv.assetId].src;
|
|
1154
1179
|
}
|
|
1155
1180
|
}
|
|
1181
|
+
if (layer.visual.type === "video") {
|
|
1182
|
+
const vv = eff.visual;
|
|
1183
|
+
if (!vv.src && vv.assetId && doc.assets?.[vv.assetId]) {
|
|
1184
|
+
vv.src = doc.assets[vv.assetId].src;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1156
1187
|
ctx.save();
|
|
1157
1188
|
applyAncestorTransforms(ctx, layer.id, effMap, doc);
|
|
1158
1189
|
ctx.globalAlpha = eff.opacity;
|
|
@@ -1200,6 +1231,11 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1200
1231
|
case "image":
|
|
1201
1232
|
if (imageCache) renderImage(renderCtx, eff, imageCache);
|
|
1202
1233
|
break;
|
|
1234
|
+
case "video":
|
|
1235
|
+
if (videoFrameProvider) {
|
|
1236
|
+
renderVideo(renderCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider);
|
|
1237
|
+
}
|
|
1238
|
+
break;
|
|
1203
1239
|
case "group":
|
|
1204
1240
|
break;
|
|
1205
1241
|
case "ref":
|
|
@@ -1225,6 +1261,9 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1225
1261
|
case "image":
|
|
1226
1262
|
if (imageCache) renderImage(offCtx, eff, imageCache);
|
|
1227
1263
|
break;
|
|
1264
|
+
case "video":
|
|
1265
|
+
if (videoFrameProvider) renderVideo(offCtx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider);
|
|
1266
|
+
break;
|
|
1228
1267
|
case "ref":
|
|
1229
1268
|
renderRef(offCtx, eff, refOpts, doc);
|
|
1230
1269
|
break;
|
|
@@ -1240,6 +1279,9 @@ function renderFrame(ctx, resolvedFrame, doc, optsOrCache) {
|
|
|
1240
1279
|
case "image":
|
|
1241
1280
|
if (imageCache) renderImage(ctx, eff, imageCache);
|
|
1242
1281
|
break;
|
|
1282
|
+
case "video":
|
|
1283
|
+
if (videoFrameProvider) renderVideo(ctx, eff, videoSourceTimeMap.get(layer.id) ?? 0, videoFrameProvider);
|
|
1284
|
+
break;
|
|
1243
1285
|
case "ref":
|
|
1244
1286
|
renderRef(ctx, eff, refOpts, doc);
|
|
1245
1287
|
break;
|
|
@@ -1642,6 +1684,18 @@ var ImageVisualSchema = import_zod7.z.object({
|
|
|
1642
1684
|
spritesheet: SpritesheetConfigSchema.optional(),
|
|
1643
1685
|
frameIndex: import_zod7.z.number().int().min(0).optional()
|
|
1644
1686
|
});
|
|
1687
|
+
var VideoVisualSchema = import_zod7.z.object({
|
|
1688
|
+
type: import_zod7.z.literal("video"),
|
|
1689
|
+
assetId: import_zod7.z.string().min(1, "assetId is required"),
|
|
1690
|
+
src: import_zod7.z.string().optional(),
|
|
1691
|
+
startFrame: import_zod7.z.number().int().min(0).optional(),
|
|
1692
|
+
sourceOffset: import_zod7.z.number().min(0).optional(),
|
|
1693
|
+
sourceEnd: import_zod7.z.number().positive().optional(),
|
|
1694
|
+
playbackRate: import_zod7.z.number().positive().optional(),
|
|
1695
|
+
volume: import_zod7.z.number().min(0).max(1).optional(),
|
|
1696
|
+
muted: import_zod7.z.boolean().optional(),
|
|
1697
|
+
objectFit: import_zod7.z.enum(["contain", "cover", "fill"]).optional()
|
|
1698
|
+
});
|
|
1645
1699
|
var GroupVisualSchema = import_zod7.z.object({
|
|
1646
1700
|
type: import_zod7.z.literal("group")
|
|
1647
1701
|
});
|
|
@@ -1655,6 +1709,7 @@ var VisualSchema = import_zod7.z.discriminatedUnion("type", [
|
|
|
1655
1709
|
ShapeVisualSchema,
|
|
1656
1710
|
TextVisualSchema,
|
|
1657
1711
|
ImageVisualSchema,
|
|
1712
|
+
VideoVisualSchema,
|
|
1658
1713
|
GroupVisualSchema,
|
|
1659
1714
|
RefVisualSchema
|
|
1660
1715
|
]);
|
|
@@ -1774,7 +1829,7 @@ var VariableSchema = import_zod12.z.object({
|
|
|
1774
1829
|
default: import_zod12.z.unknown().optional(),
|
|
1775
1830
|
description: import_zod12.z.string().optional()
|
|
1776
1831
|
});
|
|
1777
|
-
var AssetTypeSchema = import_zod13.z.enum(["image", "svg", "font", "animation", "audio"]);
|
|
1832
|
+
var AssetTypeSchema = import_zod13.z.enum(["image", "svg", "font", "animation", "audio", "video"]);
|
|
1778
1833
|
var AssetSchema = import_zod13.z.object({
|
|
1779
1834
|
type: AssetTypeSchema,
|
|
1780
1835
|
src: import_zod13.z.string().min(1, "Asset src is required"),
|
|
@@ -1785,6 +1840,12 @@ var AssetSchema = import_zod13.z.object({
|
|
|
1785
1840
|
frameCount: import_zod13.z.number().int().positive().optional(),
|
|
1786
1841
|
frameWidth: import_zod13.z.number().positive(),
|
|
1787
1842
|
frameHeight: import_zod13.z.number().positive()
|
|
1843
|
+
}).optional(),
|
|
1844
|
+
videoMeta: import_zod13.z.object({
|
|
1845
|
+
duration: import_zod13.z.number().positive("videoMeta.duration must be positive"),
|
|
1846
|
+
fps: import_zod13.z.number().positive("videoMeta.fps must be positive"),
|
|
1847
|
+
width: import_zod13.z.number().int().positive(),
|
|
1848
|
+
height: import_zod13.z.number().int().positive()
|
|
1788
1849
|
}).optional()
|
|
1789
1850
|
});
|
|
1790
1851
|
var CanvasSchema = import_zod14.z.object({
|
|
@@ -1818,6 +1879,35 @@ function validateDocument(input) {
|
|
|
1818
1879
|
}
|
|
1819
1880
|
return { success: false, errors: formatErrors(result.error) };
|
|
1820
1881
|
}
|
|
1882
|
+
function validateVideoLayer(visual, videoMetaDuration) {
|
|
1883
|
+
const errors = [];
|
|
1884
|
+
if (!visual.assetId) {
|
|
1885
|
+
errors.push({ path: "assetId", message: "assetId is required" });
|
|
1886
|
+
}
|
|
1887
|
+
const sourceOffset = visual.sourceOffset ?? 0;
|
|
1888
|
+
if (visual.sourceEnd !== void 0) {
|
|
1889
|
+
if (visual.sourceEnd <= sourceOffset) {
|
|
1890
|
+
errors.push({
|
|
1891
|
+
path: "sourceEnd",
|
|
1892
|
+
message: `sourceEnd (${visual.sourceEnd}) must be greater than sourceOffset (${sourceOffset})`
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
if (videoMetaDuration !== void 0 && visual.sourceEnd > videoMetaDuration) {
|
|
1896
|
+
errors.push({
|
|
1897
|
+
path: "sourceEnd",
|
|
1898
|
+
message: `sourceEnd (${visual.sourceEnd}) exceeds asset duration (${videoMetaDuration})`
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
if (videoMetaDuration !== void 0 && sourceOffset >= videoMetaDuration) {
|
|
1903
|
+
errors.push({
|
|
1904
|
+
path: "sourceOffset",
|
|
1905
|
+
message: `sourceOffset (${sourceOffset}) is at or beyond asset duration (${videoMetaDuration})`
|
|
1906
|
+
});
|
|
1907
|
+
}
|
|
1908
|
+
if (errors.length > 0) return { success: false, errors };
|
|
1909
|
+
return { success: true, data: visual };
|
|
1910
|
+
}
|
|
1821
1911
|
function parseAtelier(yamlString) {
|
|
1822
1912
|
let parsed;
|
|
1823
1913
|
try {
|
|
@@ -1877,9 +1967,105 @@ function validateCommand(program2) {
|
|
|
1877
1967
|
});
|
|
1878
1968
|
}
|
|
1879
1969
|
|
|
1880
|
-
// src/commands/
|
|
1970
|
+
// src/commands/lint.ts
|
|
1881
1971
|
var import_node_fs2 = require("fs");
|
|
1882
1972
|
var import_node_path2 = require("path");
|
|
1973
|
+
init_dist2();
|
|
1974
|
+
function lintFile(filePath) {
|
|
1975
|
+
const absPath = (0, import_node_path2.resolve)(filePath);
|
|
1976
|
+
let content;
|
|
1977
|
+
try {
|
|
1978
|
+
content = (0, import_node_fs2.readFileSync)(absPath, "utf-8");
|
|
1979
|
+
} catch {
|
|
1980
|
+
return {
|
|
1981
|
+
file: absPath,
|
|
1982
|
+
valid: false,
|
|
1983
|
+
gates: [
|
|
1984
|
+
{
|
|
1985
|
+
gate: "^valid-document",
|
|
1986
|
+
pass: false,
|
|
1987
|
+
errors: [`Cannot read file: ${absPath}`]
|
|
1988
|
+
}
|
|
1989
|
+
]
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
const gates = [];
|
|
1993
|
+
const parseResult = parseAtelier(content);
|
|
1994
|
+
if (!parseResult.success) {
|
|
1995
|
+
gates.push({
|
|
1996
|
+
gate: "^valid-document",
|
|
1997
|
+
pass: false,
|
|
1998
|
+
errors: parseResult.errors.map((e) => `${e.path}: ${e.message}`)
|
|
1999
|
+
});
|
|
2000
|
+
return { file: absPath, valid: false, gates };
|
|
2001
|
+
}
|
|
2002
|
+
gates.push({ gate: "^valid-document", pass: true, errors: [] });
|
|
2003
|
+
const doc = parseResult.data;
|
|
2004
|
+
const deltaErrors = [];
|
|
2005
|
+
for (const [stateName, state] of Object.entries(doc.states)) {
|
|
2006
|
+
const overlaps = validateAllDeltas(state.deltas);
|
|
2007
|
+
for (const overlap of overlaps) {
|
|
2008
|
+
deltaErrors.push(`State "${stateName}": ${overlap.message}`);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
gates.push({
|
|
2012
|
+
gate: "^valid-delta",
|
|
2013
|
+
pass: deltaErrors.length === 0,
|
|
2014
|
+
errors: deltaErrors
|
|
2015
|
+
});
|
|
2016
|
+
const videoErrors = [];
|
|
2017
|
+
for (const layer of doc.layers) {
|
|
2018
|
+
if (layer.visual.type !== "video") continue;
|
|
2019
|
+
const visual = layer.visual;
|
|
2020
|
+
const duration = doc.assets?.[visual.assetId]?.videoMeta?.duration;
|
|
2021
|
+
const result = validateVideoLayer(visual, duration);
|
|
2022
|
+
if (!result.success) {
|
|
2023
|
+
for (const err of result.errors) {
|
|
2024
|
+
videoErrors.push(`Layer "${layer.id}" (${err.path}): ${err.message}`);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
gates.push({
|
|
2029
|
+
gate: "^valid-video-layer",
|
|
2030
|
+
pass: videoErrors.length === 0,
|
|
2031
|
+
errors: videoErrors
|
|
2032
|
+
});
|
|
2033
|
+
const valid = gates.every((g) => g.pass);
|
|
2034
|
+
return { file: absPath, valid, gates };
|
|
2035
|
+
}
|
|
2036
|
+
function formatResult(result) {
|
|
2037
|
+
const lines = [];
|
|
2038
|
+
const status = result.valid ? "PASS" : "FAIL";
|
|
2039
|
+
lines.push(`${status} ${result.file}`);
|
|
2040
|
+
for (const gate of result.gates) {
|
|
2041
|
+
const gateStatus = gate.pass ? " \u2713" : " \u2717";
|
|
2042
|
+
lines.push(`${gateStatus} ${gate.gate}`);
|
|
2043
|
+
for (const err of gate.errors) {
|
|
2044
|
+
lines.push(` ${err}`);
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
return lines.join("\n");
|
|
2048
|
+
}
|
|
2049
|
+
function lintCommand(program2) {
|
|
2050
|
+
program2.command("lint <files...>").description(
|
|
2051
|
+
"Lint .atelier files against all gates (^valid-document, ^valid-delta, ^valid-video-layer)"
|
|
2052
|
+
).option("--json", "Output results as JSON array").action((files, opts) => {
|
|
2053
|
+
const results = files.map(lintFile);
|
|
2054
|
+
if (opts.json) {
|
|
2055
|
+
console.log(JSON.stringify(results, null, 2));
|
|
2056
|
+
} else {
|
|
2057
|
+
for (const result of results) {
|
|
2058
|
+
console.log(formatResult(result));
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
const allValid = results.every((r) => r.valid);
|
|
2062
|
+
if (!allValid) process.exit(1);
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
// src/commands/info.ts
|
|
2067
|
+
var import_node_fs3 = require("fs");
|
|
2068
|
+
var import_node_path3 = require("path");
|
|
1883
2069
|
function getInfo(doc) {
|
|
1884
2070
|
return {
|
|
1885
2071
|
name: doc.name,
|
|
@@ -1936,10 +2122,10 @@ function formatInfo(info) {
|
|
|
1936
2122
|
return lines.join("\n");
|
|
1937
2123
|
}
|
|
1938
2124
|
function readAndParse(file) {
|
|
1939
|
-
const absPath = (0,
|
|
2125
|
+
const absPath = (0, import_node_path3.resolve)(file);
|
|
1940
2126
|
let content;
|
|
1941
2127
|
try {
|
|
1942
|
-
content = (0,
|
|
2128
|
+
content = (0, import_node_fs3.readFileSync)(absPath, "utf-8");
|
|
1943
2129
|
} catch {
|
|
1944
2130
|
console.error(`Cannot read file: ${absPath}`);
|
|
1945
2131
|
return process.exit(1);
|
|
@@ -1963,8 +2149,8 @@ function infoCommand(program2) {
|
|
|
1963
2149
|
}
|
|
1964
2150
|
|
|
1965
2151
|
// src/commands/still.ts
|
|
1966
|
-
var
|
|
1967
|
-
var
|
|
2152
|
+
var import_node_fs4 = require("fs");
|
|
2153
|
+
var import_node_path4 = require("path");
|
|
1968
2154
|
init_dist2();
|
|
1969
2155
|
function resolveStill(doc, stateName, frame) {
|
|
1970
2156
|
const stateNames = Object.keys(doc.states);
|
|
@@ -1981,10 +2167,10 @@ function resolveStill(doc, stateName, frame) {
|
|
|
1981
2167
|
return resolveFrame(doc, resolvedStateName, resolvedFrame);
|
|
1982
2168
|
}
|
|
1983
2169
|
function readAndParse2(file) {
|
|
1984
|
-
const absPath = (0,
|
|
2170
|
+
const absPath = (0, import_node_path4.resolve)(file);
|
|
1985
2171
|
let content;
|
|
1986
2172
|
try {
|
|
1987
|
-
content = (0,
|
|
2173
|
+
content = (0, import_node_fs4.readFileSync)(absPath, "utf-8");
|
|
1988
2174
|
} catch {
|
|
1989
2175
|
console.error(`Cannot read file: ${absPath}`);
|
|
1990
2176
|
return process.exit(1);
|
|
@@ -2035,7 +2221,7 @@ function stillCommand(program2) {
|
|
|
2035
2221
|
if (options.format === "json") {
|
|
2036
2222
|
const json = JSON.stringify(resolved, null, 2);
|
|
2037
2223
|
if (options.output) {
|
|
2038
|
-
(0,
|
|
2224
|
+
(0, import_node_fs4.writeFileSync)((0, import_node_path4.resolve)(options.output), json, "utf-8");
|
|
2039
2225
|
} else {
|
|
2040
2226
|
console.log(json);
|
|
2041
2227
|
}
|
|
@@ -2055,7 +2241,7 @@ function stillCommand(program2) {
|
|
|
2055
2241
|
renderFrame2(ctx, resolved, doc);
|
|
2056
2242
|
const buffer = cvs.toBuffer("image/png");
|
|
2057
2243
|
if (options.output) {
|
|
2058
|
-
(0,
|
|
2244
|
+
(0, import_node_fs4.writeFileSync)((0, import_node_path4.resolve)(options.output), buffer);
|
|
2059
2245
|
} else {
|
|
2060
2246
|
process.stdout.write(buffer);
|
|
2061
2247
|
}
|
|
@@ -2071,18 +2257,18 @@ function stillCommand(program2) {
|
|
|
2071
2257
|
}
|
|
2072
2258
|
|
|
2073
2259
|
// src/commands/render.ts
|
|
2074
|
-
var
|
|
2075
|
-
var
|
|
2260
|
+
var import_node_fs5 = require("fs");
|
|
2261
|
+
var import_node_path5 = require("path");
|
|
2076
2262
|
|
|
2077
2263
|
// src/commands/render-pipeline.ts
|
|
2078
2264
|
var import_node_child_process = require("child_process");
|
|
2079
2265
|
init_dist2();
|
|
2080
2266
|
init_dist3();
|
|
2081
2267
|
async function checkFfmpeg() {
|
|
2082
|
-
return new Promise((
|
|
2268
|
+
return new Promise((resolve11) => {
|
|
2083
2269
|
const proc = (0, import_node_child_process.spawn)("ffmpeg", ["-version"], { stdio: "pipe" });
|
|
2084
|
-
proc.on("error", () =>
|
|
2085
|
-
proc.on("close", (code) =>
|
|
2270
|
+
proc.on("error", () => resolve11(false));
|
|
2271
|
+
proc.on("close", (code) => resolve11(code === 0));
|
|
2086
2272
|
});
|
|
2087
2273
|
}
|
|
2088
2274
|
function buildFfmpegArgs(width, height, fps, format, output) {
|
|
@@ -2162,7 +2348,7 @@ async function preloadImages(doc, loadImage) {
|
|
|
2162
2348
|
for (const src of preloaded.keys()) {
|
|
2163
2349
|
imageCache.load(src);
|
|
2164
2350
|
}
|
|
2165
|
-
await new Promise((
|
|
2351
|
+
await new Promise((resolve11) => process.nextTick(resolve11));
|
|
2166
2352
|
return imageCache;
|
|
2167
2353
|
}
|
|
2168
2354
|
async function renderDocument(doc, opts) {
|
|
@@ -2226,7 +2412,7 @@ async function renderDocument(doc, opts) {
|
|
|
2226
2412
|
const canWrite = ffmpeg.stdin.write(raw);
|
|
2227
2413
|
if (!canWrite) {
|
|
2228
2414
|
await new Promise(
|
|
2229
|
-
(
|
|
2415
|
+
(resolve11) => ffmpeg.stdin.once("drain", resolve11)
|
|
2230
2416
|
);
|
|
2231
2417
|
}
|
|
2232
2418
|
frameIndex++;
|
|
@@ -2239,8 +2425,8 @@ async function renderDocument(doc, opts) {
|
|
|
2239
2425
|
}
|
|
2240
2426
|
}
|
|
2241
2427
|
ffmpeg.stdin.end();
|
|
2242
|
-
const exitCode = await new Promise((
|
|
2243
|
-
ffmpeg.on("close",
|
|
2428
|
+
const exitCode = await new Promise((resolve11) => {
|
|
2429
|
+
ffmpeg.on("close", resolve11);
|
|
2244
2430
|
});
|
|
2245
2431
|
if (exitCode !== 0) {
|
|
2246
2432
|
throw new Error(
|
|
@@ -2259,10 +2445,10 @@ ${stderrOutput.slice(-500)}`
|
|
|
2259
2445
|
|
|
2260
2446
|
// src/commands/render.ts
|
|
2261
2447
|
function readAndParse3(file) {
|
|
2262
|
-
const absPath = (0,
|
|
2448
|
+
const absPath = (0, import_node_path5.resolve)(file);
|
|
2263
2449
|
let content;
|
|
2264
2450
|
try {
|
|
2265
|
-
content = (0,
|
|
2451
|
+
content = (0, import_node_fs5.readFileSync)(absPath, "utf-8");
|
|
2266
2452
|
} catch {
|
|
2267
2453
|
console.error(`Cannot read file: ${absPath}`);
|
|
2268
2454
|
return process.exit(1);
|
|
@@ -2279,7 +2465,7 @@ function readAndParse3(file) {
|
|
|
2279
2465
|
}
|
|
2280
2466
|
function inferFormat(output) {
|
|
2281
2467
|
if (!output) return "mp4";
|
|
2282
|
-
const ext = (0,
|
|
2468
|
+
const ext = (0, import_node_path5.extname)(output).toLowerCase();
|
|
2283
2469
|
if (ext === ".gif") return "gif";
|
|
2284
2470
|
return "mp4";
|
|
2285
2471
|
}
|
|
@@ -2313,12 +2499,12 @@ function renderCommand(program2) {
|
|
|
2313
2499
|
} else {
|
|
2314
2500
|
format = inferFormat(options.output);
|
|
2315
2501
|
}
|
|
2316
|
-
const inputName = (0,
|
|
2502
|
+
const inputName = (0, import_node_path5.basename)(file, (0, import_node_path5.extname)(file));
|
|
2317
2503
|
const output = options.output ?? `${inputName}.${format}`;
|
|
2318
2504
|
const startTime = Date.now();
|
|
2319
2505
|
try {
|
|
2320
2506
|
const result = await renderDocument(doc, {
|
|
2321
|
-
output: (0,
|
|
2507
|
+
output: (0, import_node_path5.resolve)(output),
|
|
2322
2508
|
format,
|
|
2323
2509
|
states: options.state,
|
|
2324
2510
|
onProgress: ({ frame, totalFrames, state, percent }) => {
|
|
@@ -2344,8 +2530,8 @@ function renderCommand(program2) {
|
|
|
2344
2530
|
}
|
|
2345
2531
|
|
|
2346
2532
|
// src/commands/export-svg.ts
|
|
2347
|
-
var
|
|
2348
|
-
var
|
|
2533
|
+
var import_node_fs6 = require("fs");
|
|
2534
|
+
var import_node_path6 = require("path");
|
|
2349
2535
|
|
|
2350
2536
|
// ../svg/dist/index.js
|
|
2351
2537
|
init_dist2();
|
|
@@ -2810,10 +2996,10 @@ function renderRefSVG(eff, visual, _parentDoc, opts, _depth, _visitedRefs) {
|
|
|
2810
2996
|
|
|
2811
2997
|
// src/commands/export-svg.ts
|
|
2812
2998
|
function readAndParse4(file) {
|
|
2813
|
-
const absPath = (0,
|
|
2999
|
+
const absPath = (0, import_node_path6.resolve)(file);
|
|
2814
3000
|
let content;
|
|
2815
3001
|
try {
|
|
2816
|
-
content = (0,
|
|
3002
|
+
content = (0, import_node_fs6.readFileSync)(absPath, "utf-8");
|
|
2817
3003
|
} catch {
|
|
2818
3004
|
console.error(`Cannot read file: ${absPath}`);
|
|
2819
3005
|
return process.exit(1);
|
|
@@ -2855,7 +3041,7 @@ function exportSvgCommand(program2) {
|
|
|
2855
3041
|
xmlDeclaration: options.xmlDeclaration
|
|
2856
3042
|
});
|
|
2857
3043
|
if (options.output) {
|
|
2858
|
-
(0,
|
|
3044
|
+
(0, import_node_fs6.writeFileSync)((0, import_node_path6.resolve)(options.output), svg, "utf-8");
|
|
2859
3045
|
} else {
|
|
2860
3046
|
console.log(svg);
|
|
2861
3047
|
}
|
|
@@ -2868,8 +3054,8 @@ function exportSvgCommand(program2) {
|
|
|
2868
3054
|
}
|
|
2869
3055
|
|
|
2870
3056
|
// src/commands/export-lottie.ts
|
|
2871
|
-
var
|
|
2872
|
-
var
|
|
3057
|
+
var import_node_fs7 = require("fs");
|
|
3058
|
+
var import_node_path7 = require("path");
|
|
2873
3059
|
|
|
2874
3060
|
// ../lottie/dist/index.js
|
|
2875
3061
|
function colorToLottie(color) {
|
|
@@ -3438,10 +3624,10 @@ function exportToLottie(doc, opts) {
|
|
|
3438
3624
|
|
|
3439
3625
|
// src/commands/export-lottie.ts
|
|
3440
3626
|
function readAndParse5(file) {
|
|
3441
|
-
const absPath = (0,
|
|
3627
|
+
const absPath = (0, import_node_path7.resolve)(file);
|
|
3442
3628
|
let content;
|
|
3443
3629
|
try {
|
|
3444
|
-
content = (0,
|
|
3630
|
+
content = (0, import_node_fs7.readFileSync)(absPath, "utf-8");
|
|
3445
3631
|
} catch {
|
|
3446
3632
|
console.error(`Cannot read file: ${absPath}`);
|
|
3447
3633
|
return process.exit(1);
|
|
@@ -3469,7 +3655,7 @@ function exportLottieCommand(program2) {
|
|
|
3469
3655
|
}
|
|
3470
3656
|
const output = JSON.stringify(json, null, 2);
|
|
3471
3657
|
if (options.output) {
|
|
3472
|
-
(0,
|
|
3658
|
+
(0, import_node_fs7.writeFileSync)((0, import_node_path7.resolve)(options.output), output, "utf-8");
|
|
3473
3659
|
} else {
|
|
3474
3660
|
console.log(output);
|
|
3475
3661
|
}
|
|
@@ -3482,8 +3668,8 @@ function exportLottieCommand(program2) {
|
|
|
3482
3668
|
}
|
|
3483
3669
|
|
|
3484
3670
|
// src/commands/assets.ts
|
|
3485
|
-
var
|
|
3486
|
-
var
|
|
3671
|
+
var import_node_fs8 = require("fs");
|
|
3672
|
+
var import_node_path8 = require("path");
|
|
3487
3673
|
function getAssets(doc) {
|
|
3488
3674
|
const assets = doc.assets ?? {};
|
|
3489
3675
|
return Object.entries(assets).map(([assetId, asset]) => {
|
|
@@ -3515,10 +3701,10 @@ function formatAssets(assets) {
|
|
|
3515
3701
|
return lines.join("\n");
|
|
3516
3702
|
}
|
|
3517
3703
|
function readAndParse6(file) {
|
|
3518
|
-
const absPath = (0,
|
|
3704
|
+
const absPath = (0, import_node_path8.resolve)(file);
|
|
3519
3705
|
let content;
|
|
3520
3706
|
try {
|
|
3521
|
-
content = (0,
|
|
3707
|
+
content = (0, import_node_fs8.readFileSync)(absPath, "utf-8");
|
|
3522
3708
|
} catch {
|
|
3523
3709
|
console.error(`Cannot read file: ${absPath}`);
|
|
3524
3710
|
return process.exit(1);
|
|
@@ -3542,8 +3728,8 @@ function assetsCommand(program2) {
|
|
|
3542
3728
|
}
|
|
3543
3729
|
|
|
3544
3730
|
// src/commands/variables.ts
|
|
3545
|
-
var
|
|
3546
|
-
var
|
|
3731
|
+
var import_node_fs9 = require("fs");
|
|
3732
|
+
var import_node_path9 = require("path");
|
|
3547
3733
|
init_dist2();
|
|
3548
3734
|
function getVariables(doc) {
|
|
3549
3735
|
const variables = doc.variables ?? {};
|
|
@@ -3579,10 +3765,10 @@ function formatVariables(info) {
|
|
|
3579
3765
|
return lines.join("\n");
|
|
3580
3766
|
}
|
|
3581
3767
|
function readAndParse7(file) {
|
|
3582
|
-
const absPath = (0,
|
|
3768
|
+
const absPath = (0, import_node_path9.resolve)(file);
|
|
3583
3769
|
let content;
|
|
3584
3770
|
try {
|
|
3585
|
-
content = (0,
|
|
3771
|
+
content = (0, import_node_fs9.readFileSync)(absPath, "utf-8");
|
|
3586
3772
|
} catch {
|
|
3587
3773
|
console.error(`Cannot read file: ${absPath}`);
|
|
3588
3774
|
return process.exit(1);
|
|
@@ -3606,8 +3792,8 @@ function variablesCommand(program2) {
|
|
|
3606
3792
|
}
|
|
3607
3793
|
|
|
3608
3794
|
// src/commands/studio.ts
|
|
3609
|
-
var
|
|
3610
|
-
var
|
|
3795
|
+
var import_node_path10 = require("path");
|
|
3796
|
+
var import_node_fs10 = require("fs");
|
|
3611
3797
|
var import_node_os = require("os");
|
|
3612
3798
|
var import_node_crypto = require("crypto");
|
|
3613
3799
|
var import_node_child_process2 = require("child_process");
|
|
@@ -3616,30 +3802,30 @@ function findAtelierFiles(dir, base = dir) {
|
|
|
3616
3802
|
const results = [];
|
|
3617
3803
|
let entries;
|
|
3618
3804
|
try {
|
|
3619
|
-
entries = (0,
|
|
3805
|
+
entries = (0, import_node_fs10.readdirSync)(dir);
|
|
3620
3806
|
} catch {
|
|
3621
3807
|
return results;
|
|
3622
3808
|
}
|
|
3623
3809
|
for (const entry of entries) {
|
|
3624
3810
|
if (entry === "node_modules" || entry === "dist" || entry === ".git") continue;
|
|
3625
|
-
const full = (0,
|
|
3811
|
+
const full = (0, import_node_path10.join)(dir, entry);
|
|
3626
3812
|
let stat;
|
|
3627
3813
|
try {
|
|
3628
|
-
stat = (0,
|
|
3814
|
+
stat = (0, import_node_fs10.statSync)(full);
|
|
3629
3815
|
} catch {
|
|
3630
3816
|
continue;
|
|
3631
3817
|
}
|
|
3632
3818
|
if (stat.isDirectory()) {
|
|
3633
3819
|
results.push(...findAtelierFiles(full, base));
|
|
3634
3820
|
} else if (entry.endsWith(".atelier")) {
|
|
3635
|
-
results.push((0,
|
|
3821
|
+
results.push((0, import_node_path10.relative)(base, full));
|
|
3636
3822
|
}
|
|
3637
3823
|
}
|
|
3638
3824
|
return results.sort();
|
|
3639
3825
|
}
|
|
3640
3826
|
function isSafePath(filePath) {
|
|
3641
3827
|
if (!filePath || filePath.includes("..") || filePath.startsWith("/")) return false;
|
|
3642
|
-
const resolved = (0,
|
|
3828
|
+
const resolved = (0, import_node_path10.resolve)(process.cwd(), filePath);
|
|
3643
3829
|
return resolved.startsWith(process.cwd());
|
|
3644
3830
|
}
|
|
3645
3831
|
function getInlineHTML() {
|
|
@@ -4093,17 +4279,17 @@ function studioCommand(program2) {
|
|
|
4093
4279
|
process.exit(1);
|
|
4094
4280
|
}
|
|
4095
4281
|
const cwd = process.cwd();
|
|
4096
|
-
const cliPackageDir = (0,
|
|
4282
|
+
const cliPackageDir = (0, import_node_path10.resolve)((0, import_node_path10.dirname)(new URL(import_meta.url).pathname), "..");
|
|
4097
4283
|
const tmpId = (0, import_node_crypto.randomBytes)(4).toString("hex");
|
|
4098
|
-
const tmpDirRaw = (0,
|
|
4099
|
-
(0,
|
|
4100
|
-
const tmpDir = (0,
|
|
4101
|
-
(0,
|
|
4102
|
-
(0,
|
|
4103
|
-
const cliNodeModules = (0,
|
|
4104
|
-
if ((0,
|
|
4284
|
+
const tmpDirRaw = (0, import_node_path10.join)((0, import_node_os.tmpdir)(), `atelier-studio-${tmpId}`);
|
|
4285
|
+
(0, import_node_fs10.mkdirSync)(tmpDirRaw, { recursive: true });
|
|
4286
|
+
const tmpDir = (0, import_node_fs10.realpathSync)(tmpDirRaw);
|
|
4287
|
+
(0, import_node_fs10.writeFileSync)((0, import_node_path10.join)(tmpDir, "index.html"), getInlineHTML());
|
|
4288
|
+
(0, import_node_fs10.writeFileSync)((0, import_node_path10.join)(tmpDir, "main.ts"), getInlineApp(file ?? null));
|
|
4289
|
+
const cliNodeModules = (0, import_node_path10.join)(cliPackageDir, "node_modules");
|
|
4290
|
+
if ((0, import_node_fs10.existsSync)(cliNodeModules)) {
|
|
4105
4291
|
try {
|
|
4106
|
-
(0,
|
|
4292
|
+
(0, import_node_fs10.symlinkSync)(cliNodeModules, (0, import_node_path10.join)(tmpDir, "node_modules"), "dir");
|
|
4107
4293
|
} catch {
|
|
4108
4294
|
}
|
|
4109
4295
|
}
|
|
@@ -4154,10 +4340,10 @@ function studioCommand(program2) {
|
|
|
4154
4340
|
res.end("Invalid path");
|
|
4155
4341
|
return;
|
|
4156
4342
|
}
|
|
4157
|
-
const absPath = (0,
|
|
4343
|
+
const absPath = (0, import_node_path10.resolve)(cwd, filePath);
|
|
4158
4344
|
if (req.method === "GET") {
|
|
4159
4345
|
try {
|
|
4160
|
-
const content = (0,
|
|
4346
|
+
const content = (0, import_node_fs10.readFileSync)(absPath, "utf-8");
|
|
4161
4347
|
res.setHeader("Content-Type", "text/plain");
|
|
4162
4348
|
res.end(content);
|
|
4163
4349
|
} catch {
|
|
@@ -4173,7 +4359,7 @@ function studioCommand(program2) {
|
|
|
4173
4359
|
});
|
|
4174
4360
|
req.on("end", () => {
|
|
4175
4361
|
try {
|
|
4176
|
-
(0,
|
|
4362
|
+
(0, import_node_fs10.writeFileSync)(absPath, body, "utf-8");
|
|
4177
4363
|
res.end("OK");
|
|
4178
4364
|
} catch {
|
|
4179
4365
|
res.statusCode = 500;
|
|
@@ -4190,15 +4376,15 @@ function studioCommand(program2) {
|
|
|
4190
4376
|
res.end("Invalid path");
|
|
4191
4377
|
return;
|
|
4192
4378
|
}
|
|
4193
|
-
const absPath = (0,
|
|
4379
|
+
const absPath = (0, import_node_path10.resolve)(cwd, filePath);
|
|
4194
4380
|
const chunks = [];
|
|
4195
4381
|
req.on("data", (chunk) => {
|
|
4196
4382
|
chunks.push(chunk);
|
|
4197
4383
|
});
|
|
4198
4384
|
req.on("end", () => {
|
|
4199
4385
|
try {
|
|
4200
|
-
(0,
|
|
4201
|
-
(0,
|
|
4386
|
+
(0, import_node_fs10.mkdirSync)((0, import_node_path10.dirname)(absPath), { recursive: true });
|
|
4387
|
+
(0, import_node_fs10.writeFileSync)(absPath, Buffer.concat(chunks));
|
|
4202
4388
|
res.end("OK");
|
|
4203
4389
|
} catch {
|
|
4204
4390
|
res.statusCode = 500;
|
|
@@ -4237,7 +4423,7 @@ function studioCommand(program2) {
|
|
|
4237
4423
|
console.log("\nShutting down...");
|
|
4238
4424
|
server.close();
|
|
4239
4425
|
try {
|
|
4240
|
-
(0,
|
|
4426
|
+
(0, import_node_fs10.rmSync)(tmpDir, { recursive: true, force: true });
|
|
4241
4427
|
} catch {
|
|
4242
4428
|
}
|
|
4243
4429
|
process.exit(0);
|
|
@@ -4253,6 +4439,7 @@ var import_meta2 = {};
|
|
|
4253
4439
|
var program = new import_commander.Command();
|
|
4254
4440
|
program.name("atelier").description("Atelier animation CLI").version((0, import_node_module.createRequire)(import_meta2.url)("../package.json").version);
|
|
4255
4441
|
validateCommand(program);
|
|
4442
|
+
lintCommand(program);
|
|
4256
4443
|
infoCommand(program);
|
|
4257
4444
|
stillCommand(program);
|
|
4258
4445
|
renderCommand(program);
|