@docyrus/animaguru 0.20.0 → 0.22.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/README.md +25 -0
- package/dist/animaguru.js +266 -252
- package/package.json +1 -1
- package/skills/animaguru/SKILL.md +1 -1
- package/templates/video/src/player.ts +20 -0
- package/templates/video/src/style.css +19 -3
package/dist/animaguru.js
CHANGED
|
@@ -2312,8 +2312,8 @@ var require_lib = __commonJS({
|
|
|
2312
2312
|
if (typeof cb !== "function") {
|
|
2313
2313
|
opts = cb;
|
|
2314
2314
|
cb = null;
|
|
2315
|
-
deferred = new this.Promise(function(
|
|
2316
|
-
deferredResolve =
|
|
2315
|
+
deferred = new this.Promise(function(resolve18, reject) {
|
|
2316
|
+
deferredResolve = resolve18;
|
|
2317
2317
|
deferredReject = reject;
|
|
2318
2318
|
});
|
|
2319
2319
|
}
|
|
@@ -2461,17 +2461,17 @@ var require_lib = __commonJS({
|
|
|
2461
2461
|
if (typeof cb === "function") {
|
|
2462
2462
|
fnx(cb);
|
|
2463
2463
|
} else {
|
|
2464
|
-
return new this.Promise(function(
|
|
2464
|
+
return new this.Promise(function(resolve18, reject) {
|
|
2465
2465
|
if (fnx.length === 1) {
|
|
2466
2466
|
fnx(function(err2, ret) {
|
|
2467
2467
|
if (err2) {
|
|
2468
2468
|
reject(err2);
|
|
2469
2469
|
} else {
|
|
2470
|
-
|
|
2470
|
+
resolve18(ret);
|
|
2471
2471
|
}
|
|
2472
2472
|
});
|
|
2473
2473
|
} else {
|
|
2474
|
-
|
|
2474
|
+
resolve18(fnx());
|
|
2475
2475
|
}
|
|
2476
2476
|
});
|
|
2477
2477
|
}
|
|
@@ -6862,7 +6862,7 @@ var require_pify = __commonJS({
|
|
|
6862
6862
|
"use strict";
|
|
6863
6863
|
var processFn = (fn, options) => function(...args) {
|
|
6864
6864
|
const P = options.promiseModule;
|
|
6865
|
-
return new P((
|
|
6865
|
+
return new P((resolve18, reject) => {
|
|
6866
6866
|
if (options.multiArgs) {
|
|
6867
6867
|
args.push((...result) => {
|
|
6868
6868
|
if (options.errorFirst) {
|
|
@@ -6870,10 +6870,10 @@ var require_pify = __commonJS({
|
|
|
6870
6870
|
reject(result);
|
|
6871
6871
|
} else {
|
|
6872
6872
|
result.shift();
|
|
6873
|
-
|
|
6873
|
+
resolve18(result);
|
|
6874
6874
|
}
|
|
6875
6875
|
} else {
|
|
6876
|
-
|
|
6876
|
+
resolve18(result);
|
|
6877
6877
|
}
|
|
6878
6878
|
});
|
|
6879
6879
|
} else if (options.errorFirst) {
|
|
@@ -6881,11 +6881,11 @@ var require_pify = __commonJS({
|
|
|
6881
6881
|
if (error62) {
|
|
6882
6882
|
reject(error62);
|
|
6883
6883
|
} else {
|
|
6884
|
-
|
|
6884
|
+
resolve18(result);
|
|
6885
6885
|
}
|
|
6886
6886
|
});
|
|
6887
6887
|
} else {
|
|
6888
|
-
args.push(
|
|
6888
|
+
args.push(resolve18);
|
|
6889
6889
|
}
|
|
6890
6890
|
fn.apply(this, args);
|
|
6891
6891
|
});
|
|
@@ -11400,7 +11400,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
11400
11400
|
} catch (err22) {
|
|
11401
11401
|
if (err22 === null || err22.code === "EEXIST") return;
|
|
11402
11402
|
if (err22.code === "ENOENT" && attempt < retries) {
|
|
11403
|
-
await new Promise((
|
|
11403
|
+
await new Promise((resolve18) => setTimeout(resolve18, 0));
|
|
11404
11404
|
continue;
|
|
11405
11405
|
}
|
|
11406
11406
|
throw err22;
|
|
@@ -14616,9 +14616,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14616
14616
|
throw Error("You cannot write to a FIFO that has already been ended!");
|
|
14617
14617
|
}
|
|
14618
14618
|
if (this._waiting) {
|
|
14619
|
-
const
|
|
14619
|
+
const resolve18 = this._waiting;
|
|
14620
14620
|
this._waiting = null;
|
|
14621
|
-
|
|
14621
|
+
resolve18({ value: chunk });
|
|
14622
14622
|
} else {
|
|
14623
14623
|
this._queue.push(chunk);
|
|
14624
14624
|
}
|
|
@@ -14626,9 +14626,9 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14626
14626
|
end() {
|
|
14627
14627
|
this._ended = true;
|
|
14628
14628
|
if (this._waiting) {
|
|
14629
|
-
const
|
|
14629
|
+
const resolve18 = this._waiting;
|
|
14630
14630
|
this._waiting = null;
|
|
14631
|
-
|
|
14631
|
+
resolve18({ done: true });
|
|
14632
14632
|
}
|
|
14633
14633
|
}
|
|
14634
14634
|
destroy(err2) {
|
|
@@ -14647,8 +14647,8 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14647
14647
|
"You cannot call read until the previous call to read has returned!"
|
|
14648
14648
|
);
|
|
14649
14649
|
}
|
|
14650
|
-
return new Promise((
|
|
14651
|
-
this._waiting =
|
|
14650
|
+
return new Promise((resolve18) => {
|
|
14651
|
+
this._waiting = resolve18;
|
|
14652
14652
|
});
|
|
14653
14653
|
}
|
|
14654
14654
|
};
|
|
@@ -14803,7 +14803,7 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14803
14803
|
const acks = [];
|
|
14804
14804
|
let nak = false;
|
|
14805
14805
|
let done = false;
|
|
14806
|
-
return new Promise((
|
|
14806
|
+
return new Promise((resolve18, reject) => {
|
|
14807
14807
|
forAwait2(packetlines, (data) => {
|
|
14808
14808
|
const line = data.toString("utf8").trim();
|
|
14809
14809
|
if (line.startsWith("shallow")) {
|
|
@@ -14830,11 +14830,11 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
14830
14830
|
nak = true;
|
|
14831
14831
|
}
|
|
14832
14832
|
if (done) {
|
|
14833
|
-
stream.error ? reject(stream.error) :
|
|
14833
|
+
stream.error ? reject(stream.error) : resolve18({ shallows, unshallows, acks, nak, packfile, progress });
|
|
14834
14834
|
}
|
|
14835
14835
|
}).finally(() => {
|
|
14836
14836
|
if (!done) {
|
|
14837
|
-
stream.error ? reject(stream.error) :
|
|
14837
|
+
stream.error ? reject(stream.error) : resolve18({ shallows, unshallows, acks, nak, packfile, progress });
|
|
14838
14838
|
}
|
|
14839
14839
|
});
|
|
14840
14840
|
});
|
|
@@ -19761,7 +19761,7 @@ var require_ignore2 = __commonJS({
|
|
|
19761
19761
|
// cli/package.json
|
|
19762
19762
|
var package_default = {
|
|
19763
19763
|
name: "@docyrus/animaguru",
|
|
19764
|
-
version: "0.
|
|
19764
|
+
version: "0.22.0",
|
|
19765
19765
|
description: "Agent-friendly AnimaGuru CLI built with CrustJS",
|
|
19766
19766
|
type: "module",
|
|
19767
19767
|
bin: {
|
|
@@ -24295,8 +24295,8 @@ var version = defineExtension(VERSION).factory((extension, value, options = {})
|
|
|
24295
24295
|
|
|
24296
24296
|
// cli/src/commands.ts
|
|
24297
24297
|
import { spawn as spawn3 } from "node:child_process";
|
|
24298
|
-
import { mkdir as mkdir15, readFile as
|
|
24299
|
-
import { dirname as dirname14, resolve as
|
|
24298
|
+
import { mkdir as mkdir15, readFile as readFile19, writeFile as writeFile16 } from "node:fs/promises";
|
|
24299
|
+
import { dirname as dirname14, resolve as resolve17 } from "node:path";
|
|
24300
24300
|
import { setTimeout as delay6 } from "node:timers/promises";
|
|
24301
24301
|
|
|
24302
24302
|
// node_modules/fflate/esm/index.mjs
|
|
@@ -25339,13 +25339,14 @@ var SPRITE_IMAGE_MODEL_IDS = SPRITE_IMAGE_MODELS.map((m) => m.id);
|
|
|
25339
25339
|
function spriteImageModel(id2) {
|
|
25340
25340
|
return SPRITE_IMAGE_MODELS.find((m) => m.id === id2) ?? SPRITE_IMAGE_MODELS[0];
|
|
25341
25341
|
}
|
|
25342
|
-
var VIDEO_WORKFLOWS = ["image-to-video", "text-to-video", "extend-video", "reference-to-video", "lip-sync", "camera-controls", "insert-video", "recast", "relight", "3d-to-video", "style"];
|
|
25342
|
+
var VIDEO_WORKFLOWS = ["image-to-video", "text-to-video", "extend-video", "reference-to-video", "lip-sync", "camera-controls", "insert-video", "recast", "relight", "3d-to-video", "style", "keyframes-to-video"];
|
|
25343
25343
|
var STUDIO_VIDEO_WORKFLOWS = ["image-to-video", "text-to-video", "extend-video"];
|
|
25344
25344
|
var MEDIA_LENGTH_WORKFLOWS = ["lip-sync", "recast", "relight", "3d-to-video"];
|
|
25345
25345
|
var lengthFromMedia = (workflow) => MEDIA_LENGTH_WORKFLOWS.includes(workflow);
|
|
25346
25346
|
var VIDEO_STYLES = ["vhs", "retro-toon-70s", "low-poly", "hand-drawn", "16bit-pixel"];
|
|
25347
25347
|
var VHS_DAMAGE_LEVELS = ["light", "medium", "heavy"];
|
|
25348
|
-
var VIDEO_RESOLUTIONS = ["480p", "768p", "1080p", "2k"];
|
|
25348
|
+
var VIDEO_RESOLUTIONS = ["480p", "720p", "768p", "1080p", "2k"];
|
|
25349
|
+
var H3_RESOLUTIONS = ["480p", "768p", "1080p", "2k"];
|
|
25349
25350
|
var VIDEO_ASPECT_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
|
|
25350
25351
|
var PROMPT_EXPANSION_MODES = ["disabled", "balanced", "quality"];
|
|
25351
25352
|
var EXTEND_OUTPUTS = ["extended", "continuation"];
|
|
@@ -25359,7 +25360,10 @@ var MAX_RECAST_PEOPLE = 4;
|
|
|
25359
25360
|
var MAX_3D_REFERENCES = 8;
|
|
25360
25361
|
var MAX_CAMERA_KEYFRAMES = 12;
|
|
25361
25362
|
var MAX_CAMERA_TURNS = 32;
|
|
25363
|
+
var MAX_IMAGE_KEYFRAMES = 10;
|
|
25364
|
+
var KEYFRAME_FPS = 24;
|
|
25362
25365
|
var H3_MAX = "minimax/h3-max";
|
|
25366
|
+
var FLUX_3_MAX = "blackforestlabs/flux-3-max";
|
|
25363
25367
|
var h3Endpoints = (route) => ({ "image-to-video": `${route}/image-to-video`, "text-to-video": `${route}/text-to-video`, "extend-video": `${route}/extend-video` });
|
|
25364
25368
|
var SPRITE_VIDEO_MODELS = [
|
|
25365
25369
|
{
|
|
@@ -25388,7 +25392,8 @@ var SPRITE_VIDEO_MODELS = [
|
|
|
25388
25392
|
id: "fal/minimax-h3-max",
|
|
25389
25393
|
label: "MiniMax H3 Max (fal.ai)",
|
|
25390
25394
|
provider: "fal",
|
|
25391
|
-
|
|
25395
|
+
// Every workflow but FLUX 3 Max's keyframes.
|
|
25396
|
+
workflows: VIDEO_WORKFLOWS.filter((w) => w !== "keyframes-to-video"),
|
|
25392
25397
|
endpoints: {
|
|
25393
25398
|
...h3Endpoints(H3_MAX),
|
|
25394
25399
|
"reference-to-video": `${H3_MAX}/reference-to-video`,
|
|
@@ -25402,11 +25407,11 @@ var SPRITE_VIDEO_MODELS = [
|
|
|
25402
25407
|
},
|
|
25403
25408
|
resolutions: ["480p", "768p", "1080p"],
|
|
25404
25409
|
workflowOptions: {
|
|
25405
|
-
"extend-video": { resolutions:
|
|
25406
|
-
"lip-sync": { resolutions:
|
|
25410
|
+
"extend-video": { resolutions: H3_RESOLUTIONS },
|
|
25411
|
+
"lip-sync": { resolutions: H3_RESOLUTIONS, seconds: { min: 5, max: 900, fractional: true } },
|
|
25407
25412
|
"insert-video": { resolutions: ["480p", "768p"], seconds: { min: 5, max: 13, fractional: true }, creditsPerSecond: { "480p": 5, "768p": 6 } },
|
|
25408
25413
|
recast: { resolutions: ["768p", "1080p"], seconds: { min: 5, max: 30, fractional: true }, creditsPerSecond: { "768p": 30, "1080p": 45 } },
|
|
25409
|
-
relight: { resolutions:
|
|
25414
|
+
relight: { resolutions: H3_RESOLUTIONS, seconds: { min: 2.33, max: 15, fractional: true } },
|
|
25410
25415
|
"3d-to-video": { seconds: { min: 1, max: 15, fractional: true } },
|
|
25411
25416
|
style: { resolutions: ["768p"], seconds: { min: 5, max: 15 } }
|
|
25412
25417
|
},
|
|
@@ -25426,7 +25431,7 @@ var SPRITE_VIDEO_MODELS = [
|
|
|
25426
25431
|
workflows: STUDIO_VIDEO_WORKFLOWS,
|
|
25427
25432
|
endpoints: h3Endpoints("minimax/h3-max-turbo"),
|
|
25428
25433
|
resolutions: ["480p", "768p", "1080p"],
|
|
25429
|
-
workflowOptions: { "extend-video": { resolutions:
|
|
25434
|
+
workflowOptions: { "extend-video": { resolutions: H3_RESOLUTIONS } },
|
|
25430
25435
|
modes: ["speed"],
|
|
25431
25436
|
lastFrame: true,
|
|
25432
25437
|
endFrameOnly: true,
|
|
@@ -25435,6 +25440,21 @@ var SPRITE_VIDEO_MODELS = [
|
|
|
25435
25440
|
audio: true,
|
|
25436
25441
|
estimatedCreditsPerSecond: { "480p": { speed: 2.5 }, "768p": { speed: 4 }, "1080p": { speed: 8 }, "2k": { speed: 16 } },
|
|
25437
25442
|
seconds: { min: 1, max: 15, fractional: true }
|
|
25443
|
+
},
|
|
25444
|
+
{
|
|
25445
|
+
id: "fal/flux-3-max",
|
|
25446
|
+
label: "FLUX 3 Max (fal.ai)",
|
|
25447
|
+
provider: "fal",
|
|
25448
|
+
workflows: ["image-to-video", "text-to-video", "keyframes-to-video"],
|
|
25449
|
+
endpoints: { "image-to-video": `${FLUX_3_MAX}/image-to-video`, "text-to-video": `${FLUX_3_MAX}/text-to-video`, "keyframes-to-video": `${FLUX_3_MAX}/keyframes-to-video` },
|
|
25450
|
+
falInputs: "flux",
|
|
25451
|
+
resolutions: ["720p", "1080p"],
|
|
25452
|
+
modes: ["quality"],
|
|
25453
|
+
lastFrame: true,
|
|
25454
|
+
seed: true,
|
|
25455
|
+
promptExpansion: ["balanced", "quality"],
|
|
25456
|
+
estimatedCreditsPerSecond: { "720p": { quality: 17 }, "1080p": { quality: 29 } },
|
|
25457
|
+
seconds: { min: 5, max: 20 }
|
|
25438
25458
|
}
|
|
25439
25459
|
];
|
|
25440
25460
|
var SPRITE_VIDEO_MODEL_IDS = SPRITE_VIDEO_MODELS.map((m) => m.id);
|
|
@@ -30496,7 +30516,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
30496
30516
|
var NONE = 0;
|
|
30497
30517
|
var ASSUMED = 1;
|
|
30498
30518
|
var PROVEN = 2;
|
|
30499
|
-
function isRecursive(inst, stack,
|
|
30519
|
+
function isRecursive(inst, stack, resolve18) {
|
|
30500
30520
|
const cached2 = recursive.get(inst);
|
|
30501
30521
|
if (cached2 !== void 0)
|
|
30502
30522
|
return cached2 ? PROVEN : NONE;
|
|
@@ -30506,7 +30526,7 @@ function isRecursive(inst, stack, resolve17) {
|
|
|
30506
30526
|
let result = NONE;
|
|
30507
30527
|
const check2 = (child) => {
|
|
30508
30528
|
if (result !== PROVEN && child?._zod) {
|
|
30509
|
-
const answer = isRecursive(child, stack,
|
|
30529
|
+
const answer = isRecursive(child, stack, resolve18);
|
|
30510
30530
|
if (answer > result)
|
|
30511
30531
|
result = answer;
|
|
30512
30532
|
}
|
|
@@ -30517,7 +30537,7 @@ function isRecursive(inst, stack, resolve17) {
|
|
|
30517
30537
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
30518
30538
|
if (spread && !desc.enumerable)
|
|
30519
30539
|
continue;
|
|
30520
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
30540
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve18) : NONE;
|
|
30521
30541
|
if (child > answer)
|
|
30522
30542
|
answer = child;
|
|
30523
30543
|
}
|
|
@@ -30581,7 +30601,7 @@ function isRecursive(inst, stack, resolve17) {
|
|
|
30581
30601
|
break;
|
|
30582
30602
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
30583
30603
|
case "lazy": {
|
|
30584
|
-
const inner = def._cachedInner ?? (
|
|
30604
|
+
const inner = def._cachedInner ?? (resolve18 ? inst._zod.innerType : void 0);
|
|
30585
30605
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
30586
30606
|
break;
|
|
30587
30607
|
}
|
|
@@ -45199,6 +45219,12 @@ async function saveWorkspace(origin, workspaceId) {
|
|
|
45199
45219
|
credentials[origin] = { ...saved, workspaceId };
|
|
45200
45220
|
await writeCredentials(credentials);
|
|
45201
45221
|
}
|
|
45222
|
+
async function sessionToken(origin) {
|
|
45223
|
+
const saved = (await readCredentials())[origin];
|
|
45224
|
+
const token3 = process.env.ANIMAGURU_TOKEN ?? (saved && saved.expiresAt > Date.now() ? saved.token : void 0);
|
|
45225
|
+
if (!token3) throw new Error("Sign in with animaguru auth login, or set ANIMAGURU_TOKEN.");
|
|
45226
|
+
return token3;
|
|
45227
|
+
}
|
|
45202
45228
|
var ServiceError = class extends Error {
|
|
45203
45229
|
constructor(status, code, message) {
|
|
45204
45230
|
super(message);
|
|
@@ -45216,12 +45242,7 @@ var Client = class {
|
|
|
45216
45242
|
signal;
|
|
45217
45243
|
origin;
|
|
45218
45244
|
async request(path, options = {}) {
|
|
45219
|
-
|
|
45220
|
-
if (options.authenticated !== false) {
|
|
45221
|
-
const saved = (await readCredentials())[this.origin];
|
|
45222
|
-
token3 = process.env.ANIMAGURU_TOKEN ?? (saved && saved.expiresAt > Date.now() ? saved.token : void 0);
|
|
45223
|
-
if (!token3) throw new Error("Sign in with animaguru auth login, or set ANIMAGURU_TOKEN.");
|
|
45224
|
-
}
|
|
45245
|
+
const token3 = options.authenticated !== false ? await sessionToken(this.origin) : void 0;
|
|
45225
45246
|
const generation = options.method === "POST" && /^\/api\/v1\/sprites\/[^/]+\/(jobs|assets|avatars|avatars\/looks|avatars\/[^/]+\/consent)$/.test(path);
|
|
45226
45247
|
const idempotency = generation ? { "Idempotency-Key": generationRequestId(path, options.body) } : {};
|
|
45227
45248
|
const response = await fetch(`${this.origin}${path}`, {
|
|
@@ -45347,14 +45368,7 @@ var animation_styles_default = {
|
|
|
45347
45368
|
"Masked reveals",
|
|
45348
45369
|
"Speech & beat timing"
|
|
45349
45370
|
],
|
|
45350
|
-
previewCaption: "
|
|
45351
|
-
studyCopy: [
|
|
45352
|
-
"Make",
|
|
45353
|
-
"every",
|
|
45354
|
-
"word",
|
|
45355
|
-
"move.",
|
|
45356
|
-
"TYPE / RHYTHM / EMPHASIS"
|
|
45357
|
-
],
|
|
45371
|
+
previewCaption: "Words slam, mask and split into letters on a 120 bpm beat across four color fields, then settle into a lockup. Drawn entirely in code.",
|
|
45358
45372
|
family: "graphic",
|
|
45359
45373
|
example: false
|
|
45360
45374
|
},
|
|
@@ -45371,11 +45385,7 @@ var animation_styles_default = {
|
|
|
45371
45385
|
"Connected transitions",
|
|
45372
45386
|
"Designed easing"
|
|
45373
45387
|
],
|
|
45374
|
-
previewCaption: "A
|
|
45375
|
-
studyCopy: [
|
|
45376
|
-
"A shape. An idea.",
|
|
45377
|
-
"One connected system."
|
|
45378
|
-
],
|
|
45388
|
+
previewCaption: "A bouncing ball splits and morphs into hills and a sun, a skyline rises, and a cyclist rides into dusk before an iris closes. Every shape is drawn and morphed in code.",
|
|
45379
45389
|
family: "graphic",
|
|
45380
45390
|
example: false
|
|
45381
45391
|
},
|
|
@@ -45392,13 +45402,7 @@ var animation_styles_default = {
|
|
|
45392
45402
|
"Drawn connections",
|
|
45393
45403
|
"Readable drawing holds"
|
|
45394
45404
|
],
|
|
45395
|
-
previewCaption: "
|
|
45396
|
-
studyCopy: [
|
|
45397
|
-
"Draw the connection.",
|
|
45398
|
-
"Imagine",
|
|
45399
|
-
"Connect",
|
|
45400
|
-
"Create"
|
|
45401
|
-
],
|
|
45405
|
+
previewCaption: "A generated hand draws an AnimaGuru-generated marker illustration stroke by stroke, colors it in, titles it and wipes the board clean.",
|
|
45402
45406
|
family: "graphic",
|
|
45403
45407
|
example: false
|
|
45404
45408
|
},
|
|
@@ -45415,13 +45419,7 @@ var animation_styles_default = {
|
|
|
45415
45419
|
"Travelling path markers",
|
|
45416
45420
|
"Controlled camera movement"
|
|
45417
45421
|
],
|
|
45418
|
-
previewCaption: "
|
|
45419
|
-
studyCopy: [
|
|
45420
|
-
"A world, connected.",
|
|
45421
|
-
"Collect",
|
|
45422
|
-
"Shape",
|
|
45423
|
-
"Share"
|
|
45424
|
-
],
|
|
45422
|
+
previewCaption: "An isometric town assembles tile by tile: buildings extrude, trees pop, cars and a train start running and the windows light up at dusk. Built from projected geometry in code.",
|
|
45425
45423
|
family: "technical",
|
|
45426
45424
|
example: false
|
|
45427
45425
|
},
|
|
@@ -45438,14 +45436,7 @@ var animation_styles_default = {
|
|
|
45438
45436
|
"Counted values",
|
|
45439
45437
|
"Comparison highlights"
|
|
45440
45438
|
],
|
|
45441
|
-
previewCaption: "
|
|
45442
|
-
studyCopy: [
|
|
45443
|
-
"Make the comparison clear.",
|
|
45444
|
-
"A",
|
|
45445
|
-
"B",
|
|
45446
|
-
"C",
|
|
45447
|
-
"ILLUSTRATIVE DATA / SAMPLE VALUES"
|
|
45448
|
-
],
|
|
45439
|
+
previewCaption: "A line chart is drawn, counted and annotated, then becomes ranked bars beside a platform donut. Drawn entirely in code from sample values.",
|
|
45449
45440
|
family: "technical",
|
|
45450
45441
|
example: false
|
|
45451
45442
|
},
|
|
@@ -45462,12 +45453,7 @@ var animation_styles_default = {
|
|
|
45462
45453
|
"Parameter changes",
|
|
45463
45454
|
"Semantic transformations"
|
|
45464
45455
|
],
|
|
45465
|
-
previewCaption: "A
|
|
45466
|
-
studyCopy: [
|
|
45467
|
-
"See the relationship.",
|
|
45468
|
-
"radius",
|
|
45469
|
-
"area"
|
|
45470
|
-
],
|
|
45456
|
+
previewCaption: "A unit circle traces a sine wave, then becomes the largest of 90 rotating circles that draw \u03C0. Plotted from a real Fourier series.",
|
|
45471
45457
|
family: "technical",
|
|
45472
45458
|
example: false
|
|
45473
45459
|
},
|
|
@@ -45484,19 +45470,7 @@ var animation_styles_default = {
|
|
|
45484
45470
|
"Bounded zooms",
|
|
45485
45471
|
"State transitions"
|
|
45486
45472
|
],
|
|
45487
|
-
previewCaption: "A
|
|
45488
|
-
studyCopy: [
|
|
45489
|
-
"Focus on what matters.",
|
|
45490
|
-
"CONCEPTUAL INTERFACE",
|
|
45491
|
-
"Workspace",
|
|
45492
|
-
"Overview",
|
|
45493
|
-
"Projects",
|
|
45494
|
-
"Library",
|
|
45495
|
-
"New project",
|
|
45496
|
-
"Project created",
|
|
45497
|
-
"Create your next idea.",
|
|
45498
|
-
"Ready to create"
|
|
45499
|
-
],
|
|
45473
|
+
previewCaption: "A cursor drives a dashboard: a live toggle, hover lift, drag-to-reorder, a modal with typing and loading, then a toast and a phone notification. Every element and interaction is coded.",
|
|
45500
45474
|
family: "technical",
|
|
45501
45475
|
example: false
|
|
45502
45476
|
},
|
|
@@ -45513,10 +45487,7 @@ var animation_styles_default = {
|
|
|
45513
45487
|
"Pose-to-pose timing",
|
|
45514
45488
|
"Gesture & reaction"
|
|
45515
45489
|
],
|
|
45516
|
-
previewCaption: "
|
|
45517
|
-
studyCopy: [
|
|
45518
|
-
"An idea comes to life."
|
|
45519
|
-
],
|
|
45490
|
+
previewCaption: "Pip, a cartoon character drawn and animated in AnimaGuru, walks a generated meadow and hops a log, with a following camera, squash and stretch, and dust on landing.",
|
|
45520
45491
|
family: "character",
|
|
45521
45492
|
example: false
|
|
45522
45493
|
},
|
|
@@ -45533,11 +45504,7 @@ var animation_styles_default = {
|
|
|
45533
45504
|
"Palette accents",
|
|
45534
45505
|
"Pixel transitions"
|
|
45535
45506
|
],
|
|
45536
|
-
previewCaption: "
|
|
45537
|
-
studyCopy: [
|
|
45538
|
-
"SMALL PIXELS.",
|
|
45539
|
-
"BIG POSSIBILITIES."
|
|
45540
|
-
],
|
|
45507
|
+
previewCaption: "Bit, a pixel-art sprite animated in AnimaGuru, runs a side-scrolling level built from generated parallax layers, with coins, sparkles and a score drawn in code.",
|
|
45541
45508
|
family: "character",
|
|
45542
45509
|
example: false
|
|
45543
45510
|
},
|
|
@@ -45554,10 +45521,7 @@ var animation_styles_default = {
|
|
|
45554
45521
|
"Foreground reveals",
|
|
45555
45522
|
"Selective organic motion"
|
|
45556
45523
|
],
|
|
45557
|
-
previewCaption: "
|
|
45558
|
-
studyCopy: [
|
|
45559
|
-
"Let the picture breathe."
|
|
45560
|
-
],
|
|
45524
|
+
previewCaption: "Five AnimaGuru-generated oil-painted planes on a slow dolly, with haze between them, sun rays, drifting pollen and wind in the grass.",
|
|
45561
45525
|
family: "material",
|
|
45562
45526
|
example: false
|
|
45563
45527
|
},
|
|
@@ -45574,13 +45538,8 @@ var animation_styles_default = {
|
|
|
45574
45538
|
"Matched reveals",
|
|
45575
45539
|
"Controlled depth"
|
|
45576
45540
|
],
|
|
45577
|
-
studyCopy: [
|
|
45578
|
-
"Bring the signal forward.",
|
|
45579
|
-
"Concept stage",
|
|
45580
|
-
"One clear focus"
|
|
45581
|
-
],
|
|
45582
45541
|
family: "technical",
|
|
45583
|
-
previewCaption: "
|
|
45542
|
+
previewCaption: "Glass interface panels assemble around a hero card on a reflective stage under sweeping light. Built in code with depth of field and floor reflections.",
|
|
45584
45543
|
example: true
|
|
45585
45544
|
},
|
|
45586
45545
|
"studio-product-reveal": {
|
|
@@ -45596,13 +45555,8 @@ var animation_styles_default = {
|
|
|
45596
45555
|
"Detail close-ups",
|
|
45597
45556
|
"Layered part separation"
|
|
45598
45557
|
],
|
|
45599
|
-
studyCopy: [
|
|
45600
|
-
"Form. Material. Detail.",
|
|
45601
|
-
"Illustrative product",
|
|
45602
|
-
"Light reveals the shape"
|
|
45603
|
-
],
|
|
45604
45558
|
family: "material",
|
|
45605
|
-
previewCaption: "
|
|
45559
|
+
previewCaption: "An unbranded fragrance bottle generated with AnimaGuru turns under a strip light: a macro start, a pull-back, anamorphic glints and a title lockup.",
|
|
45606
45560
|
example: true
|
|
45607
45561
|
},
|
|
45608
45562
|
"risograph-print": {
|
|
@@ -45618,13 +45572,8 @@ var animation_styles_default = {
|
|
|
45618
45572
|
"Registration shifts",
|
|
45619
45573
|
"Held-drawing cadence"
|
|
45620
45574
|
],
|
|
45621
|
-
studyCopy: [
|
|
45622
|
-
"Two inks. More possibilities.",
|
|
45623
|
-
"Separate plates",
|
|
45624
|
-
"Meet in the overprint"
|
|
45625
|
-
],
|
|
45626
45575
|
family: "print",
|
|
45627
|
-
previewCaption: "
|
|
45576
|
+
previewCaption: "An AnimaGuru-generated illustration separated in code into yellow, fluorescent pink and teal drums, then printed pass by pass with riso grain and slight misregistration.",
|
|
45628
45577
|
example: true
|
|
45629
45578
|
},
|
|
45630
45579
|
"halftone-editorial": {
|
|
@@ -45640,13 +45589,8 @@ var animation_styles_default = {
|
|
|
45640
45589
|
"Stamp impacts",
|
|
45641
45590
|
"Layered panel changes"
|
|
45642
45591
|
],
|
|
45643
|
-
studyCopy: [
|
|
45644
|
-
"Give the idea a headline.",
|
|
45645
|
-
"An original print study",
|
|
45646
|
-
"Make the point readable"
|
|
45647
|
-
],
|
|
45648
45592
|
family: "print",
|
|
45649
|
-
previewCaption: "
|
|
45593
|
+
previewCaption: "An AnimaGuru-generated stage photo screened in code into black and orange halftone dots at 45\xB0 and 15\xB0, pulling back from the dots to a magazine spread.",
|
|
45650
45594
|
example: true
|
|
45651
45595
|
},
|
|
45652
45596
|
"silkscreen-poster": {
|
|
@@ -45662,13 +45606,8 @@ var animation_styles_default = {
|
|
|
45662
45606
|
"Layer-by-layer builds",
|
|
45663
45607
|
"Graphic holds"
|
|
45664
45608
|
],
|
|
45665
|
-
studyCopy: [
|
|
45666
|
-
"One ink. One impression.",
|
|
45667
|
-
"Print the composition",
|
|
45668
|
-
"Hold the finished image"
|
|
45669
|
-
],
|
|
45670
45609
|
family: "print",
|
|
45671
|
-
previewCaption: "
|
|
45610
|
+
previewCaption: "AnimaGuru-generated poster art cut into five flat stencils in code and pulled screen by screen with a squeegee, ending on the finished print.",
|
|
45672
45611
|
example: true
|
|
45673
45612
|
},
|
|
45674
45613
|
"art-deco-motion": {
|
|
@@ -45684,13 +45623,8 @@ var animation_styles_default = {
|
|
|
45684
45623
|
"Sequenced lights",
|
|
45685
45624
|
"Mechanical settling"
|
|
45686
45625
|
],
|
|
45687
|
-
studyCopy: [
|
|
45688
|
-
"Geometry catches the light.",
|
|
45689
|
-
"Open from the center",
|
|
45690
|
-
"A measured reveal"
|
|
45691
|
-
],
|
|
45692
45626
|
family: "graphic",
|
|
45693
|
-
previewCaption: "
|
|
45627
|
+
previewCaption: "Gold keylines, stepped arches and a sunburst fan open symmetrically; chevrons and marquee lights run in sequence while a specular sweep crosses the metal. Drawn entirely in code.",
|
|
45694
45628
|
example: true
|
|
45695
45629
|
},
|
|
45696
45630
|
"blueprint-drafting": {
|
|
@@ -45706,13 +45640,8 @@ var animation_styles_default = {
|
|
|
45706
45640
|
"Exploded parts",
|
|
45707
45641
|
"Anchored dimensions"
|
|
45708
45642
|
],
|
|
45709
|
-
studyCopy: [
|
|
45710
|
-
"See how the parts connect.",
|
|
45711
|
-
"Illustrative drawing",
|
|
45712
|
-
"Assemble the relationship"
|
|
45713
|
-
],
|
|
45714
45643
|
family: "technical",
|
|
45715
|
-
previewCaption: "
|
|
45644
|
+
previewCaption: "A drafting point traces an AnimaGuru-generated cyanotype line by line, then dimensions, callouts and a title block are drawn in.",
|
|
45716
45645
|
example: true
|
|
45717
45646
|
},
|
|
45718
45647
|
"holographic-scan": {
|
|
@@ -45728,13 +45657,8 @@ var animation_styles_default = {
|
|
|
45728
45657
|
"Target locking",
|
|
45729
45658
|
"Local part separation"
|
|
45730
45659
|
],
|
|
45731
|
-
studyCopy: [
|
|
45732
|
-
"Scan. Focus. Understand.",
|
|
45733
|
-
"Illustrative part model",
|
|
45734
|
-
"Follow the detail"
|
|
45735
|
-
],
|
|
45736
45660
|
family: "technical",
|
|
45737
|
-
previewCaption: "
|
|
45661
|
+
previewCaption: "A wireframe turbofan grows under a moving scan, locks onto its parts and separates them with callouts. Projected 3D geometry drawn in code.",
|
|
45738
45662
|
example: true
|
|
45739
45663
|
},
|
|
45740
45664
|
"paper-popup": {
|
|
@@ -45750,13 +45674,8 @@ var animation_styles_default = {
|
|
|
45750
45674
|
"Back-to-front arrival",
|
|
45751
45675
|
"Paper-stage transitions"
|
|
45752
45676
|
],
|
|
45753
|
-
studyCopy: [
|
|
45754
|
-
"A flat page gains a world.",
|
|
45755
|
-
"An original paper mechanism",
|
|
45756
|
-
"Fold. Open. Discover."
|
|
45757
|
-
],
|
|
45758
45677
|
family: "paper",
|
|
45759
|
-
previewCaption: "
|
|
45678
|
+
previewCaption: "A book opens and AnimaGuru-generated cardstock layers hinge up from the fold with shadows and spring, while a pull tab lifts the balloon and sun.",
|
|
45760
45679
|
example: true
|
|
45761
45680
|
},
|
|
45762
45681
|
"shadow-theatre": {
|
|
@@ -45772,13 +45691,8 @@ var animation_styles_default = {
|
|
|
45772
45691
|
"Jointed articulation",
|
|
45773
45692
|
"Lamp-distance changes"
|
|
45774
45693
|
],
|
|
45775
|
-
studyCopy: [
|
|
45776
|
-
"A silhouette tells a thousand things.",
|
|
45777
|
-
"Light and carved shape",
|
|
45778
|
-
"Move with the material"
|
|
45779
|
-
],
|
|
45780
45694
|
family: "paper",
|
|
45781
|
-
previewCaption: "
|
|
45695
|
+
previewCaption: "Shadow puppets generated with AnimaGuru perform behind a lit linen screen, finished in code with the cloth's weave, a breathing lamp and a warm glow.",
|
|
45782
45696
|
example: true
|
|
45783
45697
|
},
|
|
45784
45698
|
"engraved-relief-print": {
|
|
@@ -45794,13 +45708,8 @@ var animation_styles_default = {
|
|
|
45794
45708
|
"Progressive hatching",
|
|
45795
45709
|
"Successive impressions"
|
|
45796
45710
|
],
|
|
45797
|
-
studyCopy: [
|
|
45798
|
-
"Every mark has a direction.",
|
|
45799
|
-
"Carve the form",
|
|
45800
|
-
"Pull the impression"
|
|
45801
|
-
],
|
|
45802
45711
|
family: "print",
|
|
45803
|
-
previewCaption: "
|
|
45712
|
+
previewCaption: "A generated woodblock print pulled in order: hatching carved first, then two color impressions rolled into register.",
|
|
45804
45713
|
example: true
|
|
45805
45714
|
},
|
|
45806
45715
|
"ascii-crt": {
|
|
@@ -45816,13 +45725,8 @@ var animation_styles_default = {
|
|
|
45816
45725
|
"Grid-scale reveals",
|
|
45817
45726
|
"Analytic afterglow"
|
|
45818
45727
|
],
|
|
45819
|
-
studyCopy: [
|
|
45820
|
-
"A picture made of characters.",
|
|
45821
|
-
"Signal on the grid",
|
|
45822
|
-
"Pixels become language"
|
|
45823
|
-
],
|
|
45824
45728
|
family: "cinematic",
|
|
45825
|
-
previewCaption: "
|
|
45729
|
+
previewCaption: "An AnimaGuru-generated jellyfish clip rendered as real ASCII on a 128-column green-phosphor terminal, with curvature, glow trails and a typed command.",
|
|
45826
45730
|
example: true
|
|
45827
45731
|
},
|
|
45828
45732
|
"analog-film-tape": {
|
|
@@ -45838,13 +45742,8 @@ var animation_styles_default = {
|
|
|
45838
45742
|
"Deterministic weave",
|
|
45839
45743
|
"Tape-inspired transitions"
|
|
45840
45744
|
],
|
|
45841
|
-
studyCopy: [
|
|
45842
|
-
"A different kind of time.",
|
|
45843
|
-
"Original scene / film variant",
|
|
45844
|
-
"Texture follows the medium"
|
|
45845
|
-
],
|
|
45846
45745
|
family: "cinematic",
|
|
45847
|
-
previewCaption: "
|
|
45746
|
+
previewCaption: "Two generated summer scenes projected at 18 fps, with gate weave, grain, a slipped splice and a film burn.",
|
|
45848
45747
|
example: true
|
|
45849
45748
|
},
|
|
45850
45749
|
"glass-mosaic": {
|
|
@@ -45860,13 +45759,8 @@ var animation_styles_default = {
|
|
|
45860
45759
|
"Moving light bands",
|
|
45861
45760
|
"Identity-preserving rearrangement"
|
|
45862
45761
|
],
|
|
45863
|
-
studyCopy: [
|
|
45864
|
-
"Pieces become a picture.",
|
|
45865
|
-
"Original glass-like mosaic",
|
|
45866
|
-
"Light passes through"
|
|
45867
|
-
],
|
|
45868
45762
|
family: "material",
|
|
45869
|
-
previewCaption: "
|
|
45763
|
+
previewCaption: "An AnimaGuru-generated peacock cut in code into leaded glass pieces that slot in one by one, then lit by a low sun crossing the window.",
|
|
45870
45764
|
example: true
|
|
45871
45765
|
},
|
|
45872
45766
|
"portal-zoom": {
|
|
@@ -45882,13 +45776,8 @@ var animation_styles_default = {
|
|
|
45882
45776
|
"Layered parallax",
|
|
45883
45777
|
"Occluded scene handoffs"
|
|
45884
45778
|
],
|
|
45885
|
-
studyCopy: [
|
|
45886
|
-
"Every frame opens another.",
|
|
45887
|
-
"An original nested world",
|
|
45888
|
-
"Keep the journey continuous"
|
|
45889
|
-
],
|
|
45890
45779
|
family: "cinematic",
|
|
45891
|
-
previewCaption: "
|
|
45780
|
+
previewCaption: "A continuous zoom through four AnimaGuru-generated worlds, each framed inside the last, that ends exactly where it began.",
|
|
45892
45781
|
example: true
|
|
45893
45782
|
},
|
|
45894
45783
|
"photo-footage-editorial": {
|
|
@@ -45904,13 +45793,8 @@ var animation_styles_default = {
|
|
|
45904
45793
|
"Media-wall selection",
|
|
45905
45794
|
"Focused detail reveals"
|
|
45906
45795
|
],
|
|
45907
|
-
studyCopy: [
|
|
45908
|
-
"Give every image its place.",
|
|
45909
|
-
"Original illustrated media cards",
|
|
45910
|
-
"Frame the detail"
|
|
45911
|
-
],
|
|
45912
45796
|
family: "cinematic",
|
|
45913
|
-
previewCaption: "
|
|
45797
|
+
previewCaption: "Six generated photographs on a contact sheet. The circled frame becomes footage, then returns to its strip.",
|
|
45914
45798
|
example: true
|
|
45915
45799
|
},
|
|
45916
45800
|
"stop-motion-objects": {
|
|
@@ -45926,13 +45810,8 @@ var animation_styles_default = {
|
|
|
45926
45810
|
"Physical-looking assembly",
|
|
45927
45811
|
"Held-drawing timing"
|
|
45928
45812
|
],
|
|
45929
|
-
studyCopy: [
|
|
45930
|
-
"Build it one piece at a time.",
|
|
45931
|
-
"Illustrative tactile objects",
|
|
45932
|
-
"Deliberate held poses"
|
|
45933
|
-
],
|
|
45934
45813
|
family: "material",
|
|
45935
|
-
previewCaption: "
|
|
45814
|
+
previewCaption: "Clay footage generated with AnimaGuru, held on twos at 12 fps, with a nudge of the set and a flicker of the lamp between poses.",
|
|
45936
45815
|
example: true
|
|
45937
45816
|
},
|
|
45938
45817
|
"miniature-diorama": {
|
|
@@ -45948,13 +45827,8 @@ var animation_styles_default = {
|
|
|
45948
45827
|
"Elevated camera travel",
|
|
45949
45828
|
"Optional time-lapse activity"
|
|
45950
45829
|
],
|
|
45951
|
-
studyCopy: [
|
|
45952
|
-
"A small world, carefully built.",
|
|
45953
|
-
"An original 2.5D miniature",
|
|
45954
|
-
"Let scale guide the view"
|
|
45955
|
-
],
|
|
45956
45830
|
family: "material",
|
|
45957
|
-
previewCaption: "
|
|
45831
|
+
previewCaption: "A generated harbor model with a slow elevated drift, a focus band on the quay and small time-lapsed activity.",
|
|
45958
45832
|
example: true
|
|
45959
45833
|
},
|
|
45960
45834
|
"sand-drawing": {
|
|
@@ -45970,13 +45844,8 @@ var animation_styles_default = {
|
|
|
45970
45844
|
"Authored reshape paths",
|
|
45971
45845
|
"Material holds"
|
|
45972
45846
|
],
|
|
45973
|
-
studyCopy: [
|
|
45974
|
-
"A shape emerges from grains.",
|
|
45975
|
-
"Original procedural sand study",
|
|
45976
|
-
"Reveal the silhouette"
|
|
45977
|
-
],
|
|
45978
45847
|
family: "material",
|
|
45979
|
-
previewCaption: "
|
|
45848
|
+
previewCaption: "A whale is swept into a seabird on a lit sand table, in one take. Footage generated with AnimaGuru.",
|
|
45980
45849
|
example: true
|
|
45981
45850
|
},
|
|
45982
45851
|
"generative-light-signal": {
|
|
@@ -45992,20 +45861,14 @@ var animation_styles_default = {
|
|
|
45992
45861
|
"Measured cue response",
|
|
45993
45862
|
"Controlled pattern changes"
|
|
45994
45863
|
],
|
|
45995
|
-
studyCopy: [
|
|
45996
|
-
"Turn a signal into movement.",
|
|
45997
|
-
"Original analytic field",
|
|
45998
|
-
"Follow the rhythm"
|
|
45999
|
-
],
|
|
46000
45864
|
family: "graphic",
|
|
46001
|
-
previewCaption: "
|
|
45865
|
+
previewCaption: "Seeded light particles stream along braided ribbons, flaring as timed pulses pass. A seamless loop rendered in code.",
|
|
46002
45866
|
example: true
|
|
46003
45867
|
}
|
|
46004
45868
|
},
|
|
46005
45869
|
browseStyles: "Browse animation styles",
|
|
46006
45870
|
styleCount_one: "{{count}} visual style, guided by your brief",
|
|
46007
45871
|
styleCount_other: "{{count}} visual styles, guided by your brief",
|
|
46008
|
-
previewBrand: "ANIMAGURU / MOTION STUDIES",
|
|
46009
45872
|
families: {
|
|
46010
45873
|
all: "All styles",
|
|
46011
45874
|
graphic: "Graphic & type",
|
|
@@ -46452,6 +46315,7 @@ var cameraKeyframe = external_exports.object({
|
|
|
46452
46315
|
/** Distance from the subject in scene units. */
|
|
46453
46316
|
distance: external_exports.number().gt(0).max(100)
|
|
46454
46317
|
});
|
|
46318
|
+
var imageKeyframe = external_exports.object({ image: blob, seconds: external_exports.number().min(0).max(20) });
|
|
46455
46319
|
var videoAsset = external_exports.object({
|
|
46456
46320
|
name: base.name,
|
|
46457
46321
|
/** Lip-sync and relight take no prompt, and camera-controls, insert-video, recast and 3d-to-video may leave it out. */
|
|
@@ -46478,6 +46342,8 @@ var videoAsset = external_exports.object({
|
|
|
46478
46342
|
referenceVideos: external_exports.array(blob).max(MAX_REFERENCE_VIDEOS).optional(),
|
|
46479
46343
|
/** The camera's path around the reference image: 2–12 keyframes. */
|
|
46480
46344
|
camera: external_exports.array(cameraKeyframe).min(2).max(MAX_CAMERA_KEYFRAMES).optional(),
|
|
46345
|
+
/** Keyframes-to-video: 1–10 images pinned to moments of the clip, each on a frame of its own. */
|
|
46346
|
+
keyframes: external_exports.array(imageKeyframe).min(1).max(MAX_IMAGE_KEYFRAMES).optional(),
|
|
46481
46347
|
/** Seconds into the source where the inserted scene starts, and where the source resumes after it. */
|
|
46482
46348
|
insertAt: external_exports.number().min(1.625).max(60).optional(),
|
|
46483
46349
|
resumeAt: external_exports.number().gt(1.625).max(60).optional(),
|
|
@@ -46521,6 +46387,7 @@ var TAKES = {
|
|
|
46521
46387
|
references: ["reference-to-video", "insert-video", "recast", "3d-to-video"],
|
|
46522
46388
|
referenceVideos: ["reference-to-video", "insert-video"],
|
|
46523
46389
|
camera: ["camera-controls"],
|
|
46390
|
+
keyframes: ["keyframes-to-video"],
|
|
46524
46391
|
insertAt: ["insert-video"],
|
|
46525
46392
|
resumeAt: ["insert-video"],
|
|
46526
46393
|
colorMatch: ["insert-video"],
|
|
@@ -46531,8 +46398,8 @@ var TAKES = {
|
|
|
46531
46398
|
generatedReferences: ["3d-to-video"],
|
|
46532
46399
|
style: ["style"],
|
|
46533
46400
|
damage: ["style"],
|
|
46534
|
-
aspectRatio: ["text-to-video", "extend-video", "reference-to-video", "relight", "style"],
|
|
46535
|
-
promptExpansion: ["image-to-video", "text-to-video", "extend-video", "reference-to-video", "camera-controls", "insert-video"],
|
|
46401
|
+
aspectRatio: ["text-to-video", "extend-video", "reference-to-video", "relight", "style", "keyframes-to-video"],
|
|
46402
|
+
promptExpansion: ["image-to-video", "text-to-video", "extend-video", "reference-to-video", "camera-controls", "insert-video", "keyframes-to-video"],
|
|
46536
46403
|
seed: ALL.filter((w) => w !== "3d-to-video"),
|
|
46537
46404
|
extendOutput: ["extend-video"]
|
|
46538
46405
|
};
|
|
@@ -46543,7 +46410,8 @@ var NEEDS = {
|
|
|
46543
46410
|
recast: ["source", "references", "subjectConsent"],
|
|
46544
46411
|
relight: ["source", "lighting"],
|
|
46545
46412
|
"3d-to-video": ["source"],
|
|
46546
|
-
style: ["style"]
|
|
46413
|
+
style: ["style"],
|
|
46414
|
+
"keyframes-to-video": ["keyframes"]
|
|
46547
46415
|
};
|
|
46548
46416
|
var LABELS = {
|
|
46549
46417
|
reference: "a starting image",
|
|
@@ -46556,6 +46424,7 @@ var LABELS = {
|
|
|
46556
46424
|
references: "reference images",
|
|
46557
46425
|
referenceVideos: "reference videos",
|
|
46558
46426
|
camera: "camera keyframes",
|
|
46427
|
+
keyframes: "keyframe images",
|
|
46559
46428
|
insertAt: "insertAt",
|
|
46560
46429
|
resumeAt: "resumeAt",
|
|
46561
46430
|
colorMatch: "colorMatch",
|
|
@@ -46641,6 +46510,11 @@ function videoChecks(p, ctx) {
|
|
|
46641
46510
|
const travel = p.camera.slice(1).reduce((sum, k, i2) => sum + Math.abs(k.azimuth - p.camera[i2].azimuth), 0);
|
|
46642
46511
|
if (travel > 360 * MAX_CAMERA_TURNS) issue2("camera", `The camera may travel at most ${MAX_CAMERA_TURNS} full turns around the subject.`);
|
|
46643
46512
|
}
|
|
46513
|
+
if (p.keyframes) {
|
|
46514
|
+
const frames = p.keyframes.map((k) => Math.round(k.seconds * KEYFRAME_FPS));
|
|
46515
|
+
if (new Set(frames).size !== frames.length) issue2("keyframes", `Put each keyframe on a frame of its own; the video has ${KEYFRAME_FPS} frames a second.`);
|
|
46516
|
+
if (p.keyframes.some((k) => k.seconds > seconds2)) issue2("keyframes", "Put each keyframe within the video's length.");
|
|
46517
|
+
}
|
|
46644
46518
|
}
|
|
46645
46519
|
var defaultSeconds = (model, workflow) => {
|
|
46646
46520
|
const r = videoSeconds(model, workflow);
|
|
@@ -47112,7 +46986,7 @@ var CLOUD_PART_BYTES = 8 * 1024 * 1024;
|
|
|
47112
46986
|
var CLOUD_MANIFEST_PATH = ".animaguru-cloud.json";
|
|
47113
46987
|
var CLOUD_MANIFEST_MAX_BYTES = 16 * 1024 * 1024;
|
|
47114
46988
|
var CLOUD_MAX_FILES = 5e4;
|
|
47115
|
-
var CLOUD_STORAGE_BYTES = { pro: 20 * 1024 ** 3, team: 100 * 1024 ** 3 };
|
|
46989
|
+
var CLOUD_STORAGE_BYTES = { starter: 5 * 1024 ** 3, pro: 20 * 1024 ** 3, team: 100 * 1024 ** 3 };
|
|
47116
46990
|
var cloudProjectId = external_exports.string().regex(/^prj_[A-Za-z0-9]{8,40}$/, "Use a project ID such as prj_\u2026.");
|
|
47117
46991
|
var sha256Hex = external_exports.string().regex(/^[a-f0-9]{64}$/, "Use a lowercase SHA-256 hex digest.");
|
|
47118
46992
|
var gitObjectId = external_exports.string().regex(/^[a-f0-9]{40}$/, "Use a full 40-character version ID.");
|
|
@@ -47917,6 +47791,7 @@ var extras = {
|
|
|
47917
47791
|
"middle-reference",
|
|
47918
47792
|
"middle-seconds",
|
|
47919
47793
|
"camera",
|
|
47794
|
+
"keyframes",
|
|
47920
47795
|
"insert-at",
|
|
47921
47796
|
"resume-at",
|
|
47922
47797
|
"color-match",
|
|
@@ -47951,11 +47826,16 @@ var regions = (value) => value?.split(";").filter((region) => region.trim()).map
|
|
|
47951
47826
|
if (rest.length || [x2, y, width, height].some((n) => !Number.isFinite(n))) throw new Error(`--mask regions are x,y,width,height in fractions of Image 1, separated by semicolons; "${region.trim()}" is not.`);
|
|
47952
47827
|
return { x: x2, y, width, height };
|
|
47953
47828
|
});
|
|
47954
|
-
var
|
|
47829
|
+
var cameraKeyframes = (value) => value?.split(";").filter((frame) => frame.trim()).map((frame) => {
|
|
47955
47830
|
const [time3, azimuth, elevation, distance, ...rest] = frame.split(",").map((n) => n.trim() ? Number(n) : NaN);
|
|
47956
47831
|
if (rest.length || [time3, azimuth, elevation, distance].some((n) => !Number.isFinite(n))) throw new Error(`--camera keyframes are time,azimuth,elevation,distance (time 0\u20131, angles in degrees), separated by semicolons; "${frame.trim()}" is not.`);
|
|
47957
47832
|
return { time: time3, azimuth, elevation, distance };
|
|
47958
47833
|
});
|
|
47834
|
+
var imageKeyframes = (value) => value?.split(";").filter((frame) => frame.trim()).map((frame) => {
|
|
47835
|
+
const [seconds2, image, ...rest] = frame.split(",").map((part) => part.trim());
|
|
47836
|
+
if (rest.length || !image || !seconds2 || !Number.isFinite(Number(seconds2))) throw new Error(`--keyframes are seconds,image SHA pairs separated by semicolons, e.g. "0,SHA;5,SHA"; "${frame.trim()}" is not.`);
|
|
47837
|
+
return { image, seconds: Number(seconds2) };
|
|
47838
|
+
});
|
|
47959
47839
|
function assetFromFlags(flags) {
|
|
47960
47840
|
if (flags.type === "image" && flags.model) throw new Error("Image models are managed by staff. Omit --model.");
|
|
47961
47841
|
for (const name2 of Object.values(extras).flat()) {
|
|
@@ -47978,7 +47858,8 @@ function assetFromFlags(flags) {
|
|
|
47978
47858
|
referenceVideos: shas(flags["reference-videos"]),
|
|
47979
47859
|
middleReference: flags["middle-reference"],
|
|
47980
47860
|
middleSeconds: flags["middle-seconds"],
|
|
47981
|
-
camera:
|
|
47861
|
+
camera: cameraKeyframes(flags.camera),
|
|
47862
|
+
keyframes: imageKeyframes(flags.keyframes),
|
|
47982
47863
|
insertAt: flags["insert-at"],
|
|
47983
47864
|
resumeAt: flags["resume-at"],
|
|
47984
47865
|
colorMatch: flags["color-match"],
|
|
@@ -48688,8 +48569,8 @@ async function youtubeLogin(options) {
|
|
|
48688
48569
|
let receive;
|
|
48689
48570
|
let fail;
|
|
48690
48571
|
let used = false;
|
|
48691
|
-
const callback = new Promise((
|
|
48692
|
-
receive =
|
|
48572
|
+
const callback = new Promise((resolve18, reject) => {
|
|
48573
|
+
receive = resolve18;
|
|
48693
48574
|
fail = reject;
|
|
48694
48575
|
});
|
|
48695
48576
|
void callback.catch(() => {
|
|
@@ -48727,9 +48608,9 @@ async function youtubeLogin(options) {
|
|
|
48727
48608
|
response.end("Authorization received. Return to your AnimaGuru terminal.");
|
|
48728
48609
|
receive(code);
|
|
48729
48610
|
});
|
|
48730
|
-
await new Promise((
|
|
48611
|
+
await new Promise((resolve18, reject) => {
|
|
48731
48612
|
server.once("error", reject);
|
|
48732
|
-
server.listen(0, "127.0.0.1",
|
|
48613
|
+
server.listen(0, "127.0.0.1", resolve18);
|
|
48733
48614
|
});
|
|
48734
48615
|
const address = server.address();
|
|
48735
48616
|
if (!address || typeof address === "string") throw new Error("Cannot open the local YouTube authorization listener.");
|
|
@@ -48764,7 +48645,7 @@ async function youtubeLogin(options) {
|
|
|
48764
48645
|
clearTimeout(timer);
|
|
48765
48646
|
options.signal?.removeEventListener("abort", abort);
|
|
48766
48647
|
server.closeAllConnections();
|
|
48767
|
-
await new Promise((
|
|
48648
|
+
await new Promise((resolve18) => server.close(() => resolve18()));
|
|
48768
48649
|
}
|
|
48769
48650
|
});
|
|
48770
48651
|
}
|
|
@@ -49868,6 +49749,114 @@ async function referenceGet(client, id2, options) {
|
|
|
49868
49749
|
return report(options.wait ? await finished(client, analysis, options.log) : analysis, options);
|
|
49869
49750
|
}
|
|
49870
49751
|
|
|
49752
|
+
// cli/src/curl.ts
|
|
49753
|
+
import { createWriteStream as createWriteStream2, openAsBlob as openAsBlob2 } from "node:fs";
|
|
49754
|
+
import { readFile as readFile18, unlink as unlink3 } from "node:fs/promises";
|
|
49755
|
+
import { extname as extname4, resolve as resolve16 } from "node:path";
|
|
49756
|
+
import { Readable as Readable2 } from "node:stream";
|
|
49757
|
+
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
49758
|
+
function curlUrl(server, target2) {
|
|
49759
|
+
const origin = serverUrl(server);
|
|
49760
|
+
const url3 = target2.startsWith("/") && !target2.startsWith("//") ? new URL(target2, origin) : URL.canParse(target2) ? new URL(target2) : null;
|
|
49761
|
+
if (!url3 || url3.origin !== origin || url3.username || url3.password) throw new Error(`animaguru curl calls only ${origin}. Pass a path such as /api/v1/me.`);
|
|
49762
|
+
return url3;
|
|
49763
|
+
}
|
|
49764
|
+
function curlHeaders(lines = []) {
|
|
49765
|
+
const headers = new Headers();
|
|
49766
|
+
for (const line of lines) {
|
|
49767
|
+
const colon = line.indexOf(":");
|
|
49768
|
+
const name2 = colon > 0 ? line.slice(0, colon).trim() : "";
|
|
49769
|
+
if (!name2) throw new Error(`Write headers as "Name: value", not "${line}".`);
|
|
49770
|
+
if (/^(authorization|host)$/i.test(name2)) throw new Error(`Leave out the ${name2} header; animaguru curl sends the signed-in session's.`);
|
|
49771
|
+
headers.append(name2, line.slice(colon + 1).trim());
|
|
49772
|
+
}
|
|
49773
|
+
return headers;
|
|
49774
|
+
}
|
|
49775
|
+
var UPLOAD_TYPES = {
|
|
49776
|
+
".mp4": "video/mp4",
|
|
49777
|
+
".webm": "video/webm",
|
|
49778
|
+
".mov": "video/quicktime",
|
|
49779
|
+
".jpg": "image/jpeg",
|
|
49780
|
+
".jpeg": "image/jpeg",
|
|
49781
|
+
".png": "image/png",
|
|
49782
|
+
".webp": "image/webp",
|
|
49783
|
+
".gif": "image/gif",
|
|
49784
|
+
".json": "application/json",
|
|
49785
|
+
".txt": "text/plain"
|
|
49786
|
+
};
|
|
49787
|
+
var isText = (type) => /^(text\/|application\/([\w.+-]*\+)?(json|xml)\b|application\/(javascript|x-www-form-urlencoded)\b)/i.test(type);
|
|
49788
|
+
var readStdin = async () => {
|
|
49789
|
+
const chunks = [];
|
|
49790
|
+
for await (const chunk of process.stdin) chunks.push(Buffer.from(chunk));
|
|
49791
|
+
return Buffer.concat(chunks);
|
|
49792
|
+
};
|
|
49793
|
+
async function bodyValue(value, io) {
|
|
49794
|
+
if (value === "@-") return (io.stdin ?? readStdin)();
|
|
49795
|
+
return value.startsWith("@") ? readFile18(resolve16(value.slice(1))) : value;
|
|
49796
|
+
}
|
|
49797
|
+
var parsesAsJson = (body) => {
|
|
49798
|
+
try {
|
|
49799
|
+
JSON.parse(body.toString());
|
|
49800
|
+
return true;
|
|
49801
|
+
} catch {
|
|
49802
|
+
return false;
|
|
49803
|
+
}
|
|
49804
|
+
};
|
|
49805
|
+
async function curl(options, io) {
|
|
49806
|
+
const url3 = curlUrl(options.server, options.target);
|
|
49807
|
+
const headers = curlHeaders(options.header);
|
|
49808
|
+
if ([options.data, options.json, options.uploadFile].filter((value) => value !== void 0).length > 1) throw new Error("Use one of --data, --json and --upload-file.");
|
|
49809
|
+
let body;
|
|
49810
|
+
if (options.uploadFile !== void 0) {
|
|
49811
|
+
const file2 = resolve16(options.uploadFile);
|
|
49812
|
+
body = await openAsBlob2(file2);
|
|
49813
|
+
if (!headers.has("content-type")) headers.set("Content-Type", UPLOAD_TYPES[extname4(file2).toLowerCase()] ?? "application/octet-stream");
|
|
49814
|
+
} else if (options.json !== void 0) {
|
|
49815
|
+
body = await bodyValue(options.json, io);
|
|
49816
|
+
if (!headers.has("content-type")) headers.set("Content-Type", "application/json");
|
|
49817
|
+
if (!headers.has("accept")) headers.set("Accept", "application/json");
|
|
49818
|
+
} else if (options.data !== void 0) {
|
|
49819
|
+
body = await bodyValue(options.data, io);
|
|
49820
|
+
if (!headers.has("content-type")) headers.set("Content-Type", parsesAsJson(body) ? "application/json" : "application/x-www-form-urlencoded");
|
|
49821
|
+
}
|
|
49822
|
+
headers.set("Authorization", `Bearer ${await sessionToken(url3.origin)}`);
|
|
49823
|
+
if (!headers.has("origin")) headers.set("Origin", url3.origin);
|
|
49824
|
+
const method = (options.request ?? (options.uploadFile !== void 0 ? "PUT" : body !== void 0 ? "POST" : "GET")).toUpperCase();
|
|
49825
|
+
const timeout = AbortSignal.timeout(options.maxTime * 1e3);
|
|
49826
|
+
const response = await fetch(url3, { method, headers, body, redirect: "manual", signal: io.signal ? AbortSignal.any([io.signal, timeout]) : timeout });
|
|
49827
|
+
if (options.include) io.stdout([`HTTP ${response.status} ${response.statusText}`.trim(), ...[...response.headers].map(([name2, value]) => `${name2}: ${value}`), ""].join("\n"));
|
|
49828
|
+
const type = response.headers.get("content-type") ?? "";
|
|
49829
|
+
const failed = options.fail && response.status >= 400;
|
|
49830
|
+
if (options.output !== void 0 && !failed) {
|
|
49831
|
+
const file2 = resolve16(options.output);
|
|
49832
|
+
let bytes = 0;
|
|
49833
|
+
try {
|
|
49834
|
+
await pipeline2(
|
|
49835
|
+
response.body ? Readable2.fromWeb(response.body) : Readable2.from([]),
|
|
49836
|
+
async function* (chunks) {
|
|
49837
|
+
for await (const chunk of chunks) {
|
|
49838
|
+
bytes += chunk.length;
|
|
49839
|
+
yield chunk;
|
|
49840
|
+
}
|
|
49841
|
+
},
|
|
49842
|
+
createWriteStream2(file2, { flags: "wx" })
|
|
49843
|
+
);
|
|
49844
|
+
} catch (error62) {
|
|
49845
|
+
if (error62.code === "EEXIST") throw new Error(`${options.output} already exists; choose another --output.`);
|
|
49846
|
+
await unlink3(file2).catch(() => void 0);
|
|
49847
|
+
throw error62;
|
|
49848
|
+
}
|
|
49849
|
+
io.stdout(JSON.stringify({ status: response.status, contentType: type || null, bytes, file: file2 }));
|
|
49850
|
+
} else if (!response.body || isText(type) || failed) {
|
|
49851
|
+
const text2 = await response.text();
|
|
49852
|
+
if (text2) io.stdout(text2.replace(/\n$/, ""));
|
|
49853
|
+
} else {
|
|
49854
|
+
await response.body.cancel();
|
|
49855
|
+
throw new Error(`The response is ${type || "binary"} (HTTP ${response.status}). Save it with -o FILE.`);
|
|
49856
|
+
}
|
|
49857
|
+
if (failed) throw new Error(`HTTP ${response.status}${response.statusText ? ` ${response.statusText}` : ""} from ${method} ${url3.pathname}.`);
|
|
49858
|
+
}
|
|
49859
|
+
|
|
49871
49860
|
// cli/src/commands.ts
|
|
49872
49861
|
var assetModelIds = [...SPRITE_VIDEO_MODEL_IDS, ...MUSIC_MODELS.map((m) => m.id), ...SPEECH_MODELS.map((m) => m.id), ...SFX_MODELS.map((m) => m.id)];
|
|
49873
49862
|
var assetAuthorizationFlags = [
|
|
@@ -49918,12 +49907,12 @@ var workspaceQuery = async (client) => {
|
|
|
49918
49907
|
async function openBrowser(url3) {
|
|
49919
49908
|
const command = process.platform === "darwin" ? "open" : process.platform === "win32" ? "rundll32" : "xdg-open";
|
|
49920
49909
|
const args = process.platform === "win32" ? ["url.dll,FileProtocolHandler", url3] : [url3];
|
|
49921
|
-
await new Promise((
|
|
49910
|
+
await new Promise((resolve18) => {
|
|
49922
49911
|
const child = spawn3(command, args, { stdio: "ignore", detached: true });
|
|
49923
|
-
child.once("error", () =>
|
|
49912
|
+
child.once("error", () => resolve18());
|
|
49924
49913
|
child.once("spawn", () => {
|
|
49925
49914
|
child.unref();
|
|
49926
|
-
|
|
49915
|
+
resolve18();
|
|
49927
49916
|
});
|
|
49928
49917
|
});
|
|
49929
49918
|
}
|
|
@@ -50024,7 +50013,7 @@ function createCli() {
|
|
|
50024
50013
|
).action(async ({ args, flags, stdout, signal }) => out(stdout, await changeVideoSubtitles(new Client(flags.url, signal), args.id, flags))))).add(defineCommand("delete", { description: "Remove a video and its hosted files" }, (command) => command.args({ name: "id", type: "string", required: true }).flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }, { name: "yes", type: "boolean", required: true }).action(async ({ args, flags, stdout, signal }) => {
|
|
50025
50014
|
if (!flags.yes) throw new Error("Pass --yes to delete the video.");
|
|
50026
50015
|
out(stdout, await new Client(flags.url, signal).request(`/api/v1/videos/${encodeURIComponent(args.id)}`, { method: "DELETE" }));
|
|
50027
|
-
})))).command("cloud", (cloud) => cloud.add(defineCommand("list", { description: "List projects with synced animations in the selected workspace, with plan and storage (Individual Pro and Team)" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).action(async ({ flags, stdout, signal }) => {
|
|
50016
|
+
})))).command("cloud", (cloud) => cloud.add(defineCommand("list", { description: "List projects with synced animations in the selected workspace, with plan and storage (Individual Starter, Individual Pro and Team)" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).action(async ({ flags, stdout, signal }) => {
|
|
50028
50017
|
const client = new Client(flags.url, signal);
|
|
50029
50018
|
out(stdout, await client.request(`/api/v1/cloud${await workspaceQuery(client)}`));
|
|
50030
50019
|
}))).add(defineCommand("link", { description: "Sync this video workspace with a project's animations: --project for an existing project, or a new project in the selected workspace" }, (command) => command.flags(
|
|
@@ -50042,7 +50031,31 @@ function createCli() {
|
|
|
50042
50031
|
}))).add(defineCommand("restore", { description: "Make the folder, or --path parts of it, match an earlier version; push afterwards to save it as the newest" }, (command) => command.args({ name: "version", type: "string", required: true, description: "Version ID or its first characters" }).flags({ name: "dir", type: "string", default: "." }, { name: "path", type: "string", multiple: true, description: "File or folder to restore; repeatable" }, { name: "yes", type: "boolean", description: "Replace unsaved local changes (copies are kept)" }).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await restoreCloud({ dir: flags.dir, version: args.version, paths: flags.path, yes: flags.yes, log: stderr, signal }))))).add(defineCommand("clone", { description: "Download the newest version of a project's animations into a new folder" }, (command) => command.args({ name: "id", type: "string", required: true, description: "Project ID" }, { name: "directory", type: "string", description: "New folder; defaults to the project name" }).flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }).action(async ({ args, flags, stdout, stderr, signal }) => out(stdout, await cloneCloud(new Client(flags.url, signal), { id: args.id, dir: args.directory, log: stderr, signal }))))).add(defineCommand("unlink", { description: "Stop syncing this folder; the project's animations and versions stay" }, (command) => command.flags({ name: "dir", type: "string", default: "." }).action(async ({ flags, stdout }) => out(stdout, await unlinkCloud({ dir: flags.dir }))))).add(defineCommand("delete", { description: "Delete a project's animations with all their versions, drafts and stored files; the project and its assets stay. Requires --yes" }, (command) => command.args({ name: "id", type: "string", required: true, description: "Project ID" }).flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" } }, { name: "yes", type: "boolean", required: true }).action(async ({ args, flags, stdout, signal }) => {
|
|
50043
50032
|
if (!flags.yes) throw new Error("Pass --yes to delete the project's animations and every saved version.");
|
|
50044
50033
|
out(stdout, await new Client(flags.url, signal).request(`/api/v1/cloud/${encodeURIComponent(args.id)}`, { method: "DELETE" }));
|
|
50045
|
-
})))).
|
|
50034
|
+
})))).add(defineCommand("curl", { description: "Call an AnimaGuru API path as the signed-in user with curl's flags; the server and the session's token are added for you. Prints the response body, or saves it with -o" }, (command) => command.args({ name: "path", type: "string", required: true, description: "API path such as /api/v1/me (with any query string), or a full URL on the server" }).flags(
|
|
50035
|
+
{ name: "request", short: "X", type: "string", description: "HTTP method; GET by default, POST with --data or --json, PUT with --upload-file" },
|
|
50036
|
+
{ name: "header", short: "H", type: "string", multiple: true, description: '"Name: value" request header; repeatable. Authorization is added for you' },
|
|
50037
|
+
{ name: "data", short: "d", type: "string", aliases: ["data-binary"], description: "Request body: text, @FILE or @- for standard input. JSON is sent as application/json" },
|
|
50038
|
+
{ name: "json", type: "string", description: "JSON body (text, @FILE or @-) with JSON Content-Type and Accept headers" },
|
|
50039
|
+
{ name: "upload-file", short: "T", type: "string", description: "Stream a file as the body (PUT unless -X); Content-Type follows its extension unless -H sets one" },
|
|
50040
|
+
{ name: "output", short: "o", type: "string", description: "Save the response body to a new file and print a JSON summary; needed for video and images" },
|
|
50041
|
+
{ name: "include", short: "i", type: "boolean", noNegate: true, description: "Print the status line and response headers first" },
|
|
50042
|
+
{ name: "fail", short: "f", type: "boolean", default: true, description: "Exit non-zero on HTTP 4xx and 5xx after printing the body; --no-fail exits 0 like plain curl" },
|
|
50043
|
+
{ name: "silent", short: "s", type: "boolean", noNegate: true, description: "Accepted for curl compatibility; nothing else is printed anyway" },
|
|
50044
|
+
{ name: "max-time", short: "m", type: "number", default: 600, description: "Maximum seconds for the whole request" },
|
|
50045
|
+
{ name: "server", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }
|
|
50046
|
+
).action(async ({ args, flags, stdout, signal }) => curl({
|
|
50047
|
+
server: flags.server,
|
|
50048
|
+
target: args.path,
|
|
50049
|
+
request: flags.request,
|
|
50050
|
+
header: flags.header,
|
|
50051
|
+
data: flags.data,
|
|
50052
|
+
json: flags.json,
|
|
50053
|
+
uploadFile: flags["upload-file"],
|
|
50054
|
+
output: flags.output,
|
|
50055
|
+
include: flags.include,
|
|
50056
|
+
fail: flags.fail,
|
|
50057
|
+
maxTime: flags["max-time"]
|
|
50058
|
+
}, { stdout, signal })))).command("auth", (auth) => auth.add(defineCommand("login", { description: "Approve a browser sign-in and save a seven-day CLI session" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).flags({ name: "browser", type: "boolean", default: true, description: "Open the browser; --no-browser prints the URL only" }).action(async ({ flags, stdout, stderr, signal }) => {
|
|
50046
50059
|
const client = new Client(flags.url, signal);
|
|
50047
50060
|
const device = await client.request("/api/auth/device/code", { method: "POST", authenticated: false, body: { client_id: CLI_CLIENT_ID } });
|
|
50048
50061
|
stderr(`Open ${device.verification_uri_complete}
|
|
@@ -50164,11 +50177,11 @@ Confirm code: ${device.user_code}`);
|
|
|
50164
50177
|
{ name: "name", type: "string", required: true },
|
|
50165
50178
|
{ name: "prompt", type: "string", description: "Description to generate, or verbatim transcript for speech; video lip-sync and relight take none, and camera-controls, insert-video, recast and 3d-to-video may leave it out" },
|
|
50166
50179
|
{ name: "model", type: "string", choices: assetModelIds, description: "Model for the chosen asset type" },
|
|
50167
|
-
{ name: "aspect-ratio", type: "string", choices: [.../* @__PURE__ */ new Set([...IMAGE_ASPECT_RATIOS, "auto", ...VIDEO_ASPECT_RATIOS])], description: "Image: 1:1 (default), 3:2, 2:3, 16:9 or 9:16; a masked edit keeps Image 1's shape. Video from text or a style without --reference: 21:9\u20139:16 (default 16:9). Extension, reference-to-video and
|
|
50180
|
+
{ name: "aspect-ratio", type: "string", choices: [.../* @__PURE__ */ new Set([...IMAGE_ASPECT_RATIOS, "auto", ...VIDEO_ASPECT_RATIOS])], description: "Image: 1:1 (default), 3:2, 2:3, 16:9 or 9:16; a masked edit keeps Image 1's shape. Video from text or a style without --reference: 21:9\u20139:16 (default 16:9). Extension, reference-to-video, relight and keyframes-to-video: auto (default, the inputs' shape) or a ratio to crop to" },
|
|
50168
50181
|
{ name: "transparent", type: "boolean", description: "Image: transparent background" },
|
|
50169
50182
|
{ name: "references", type: "string", description: "Comma-separated blob SHAs of this project's images or sprite art, named Image 1, Image 2\u2026 in the prompt. Image: up to 4 to follow, such as a character sheet. Video: subjects or looks to keep (reference-to-video and insert-video up to 9, 3d-to-video up to 8), or recast's new people, one photo each (up to 4)" },
|
|
50170
50183
|
{ name: "mask", type: "string", description: "Image: edit only these rectangles of Image 1 (the first --references image), as x,y,width,height fractions of its size from the top left, up to 8 separated by semicolons; the rest is kept" },
|
|
50171
|
-
{ name: "workflow", type: "string", choices: VIDEO_WORKFLOWS, description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, as the model's videoProfiles allow" },
|
|
50184
|
+
{ name: "workflow", type: "string", choices: VIDEO_WORKFLOWS, description: "Video: image-to-video (default), text-to-video or extend-video; H3 Max also reference-to-video, lip-sync, camera-controls, insert-video, recast, relight, 3d-to-video and style, FLUX 3 Max keyframes-to-video, as the model's videoProfiles allow" },
|
|
50172
50185
|
{ name: "reference", type: "string", description: "Video: starting image blob SHA from this project's assets or sprites; the speaking face for lip-sync, the image the camera moves around for camera-controls" },
|
|
50173
50186
|
{ name: "end-reference", type: "string", description: "Video: ending image blob SHA; models with endFrameOnly accept it without --reference" },
|
|
50174
50187
|
{ name: "middle-reference", type: "string", description: "Reference-to-video: image blob SHA reached at --middle-seconds; needs --reference and --end-reference, 480p or 768p" },
|
|
@@ -50178,6 +50191,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50178
50191
|
{ name: "audio-references", type: "string", description: "Extension or reference-to-video: up to 3 comma-separated audio asset blob SHAs (2\u201315 s each, 15 s total) guiding the sound; refer to them as Audio 1, Audio 2\u2026 in the prompt" },
|
|
50179
50192
|
{ name: "reference-videos", type: "string", description: "Reference-to-video or insert-video: up to 3 comma-separated video asset blob SHAs (2\u201315 s each, 15 s total) guiding motion, named Video 1, Video 2\u2026 in the prompt" },
|
|
50180
50193
|
{ name: "camera", type: "string", description: 'Camera-controls: 2\u201312 keyframes time,azimuth,elevation,distance (time 0\u20131, angles in degrees, elevation \u221290\u201390) separated by semicolons, e.g. "0,0,0,1;1,90,15,1.2"' },
|
|
50194
|
+
{ name: "keyframes", type: "string", description: 'Keyframes-to-video (FLUX 3 Max): 1\u201310 seconds,image-SHA pairs separated by semicolons, e.g. "0,SHA;2.5,SHA;5,SHA"; each image is reached at its second, on a frame of its own of the 24 fps clip, within --seconds' },
|
|
50181
50195
|
{ name: "insert-at", type: "number", description: "Insert-video: seconds into --source where the new scene starts (1.625\u201360)" },
|
|
50182
50196
|
{ name: "resume-at", type: "number", description: "Insert-video: seconds into --source where it resumes after the scene" },
|
|
50183
50197
|
{ name: "color-match", type: "boolean", description: "Insert-video: match the scene's colors to the source (default on; --no-color-match turns it off)" },
|
|
@@ -50188,10 +50202,10 @@ Confirm code: ${device.user_code}`);
|
|
|
50188
50202
|
{ name: "generated-references", type: "number", description: "3d-to-video without --references: how many reference images it may draw, 1\u20138 (default 2)" },
|
|
50189
50203
|
{ name: "style", type: "string", choices: VIDEO_STYLES, description: "Style workflow: the preset look, at 768p for 5\u201315 whole seconds" },
|
|
50190
50204
|
{ name: "damage", type: "string", choices: VHS_DAMAGE_LEVELS, description: "VHS style: tape damage (fal's default medium)" },
|
|
50191
|
-
{ name: "seconds", type: "number", description: "Video or SFX duration in seconds (default 5); H3 takes fractions (6.5); extensions add this many seconds, insert-video's scene is 5\u201313; lip-sync, recast, relight and 3d-to-video take their input's length; SFX supports 0.5\u201330" },
|
|
50205
|
+
{ name: "seconds", type: "number", description: "Video or SFX duration in seconds (default 5); H3 takes fractions (6.5), FLUX 3 Max 5\u201320 whole seconds; extensions add this many seconds, insert-video's scene is 5\u201313; lip-sync, recast, relight and 3d-to-video take their input's length; SFX supports 0.5\u201330" },
|
|
50192
50206
|
{ name: "resolution", type: "string", choices: VIDEO_RESOLUTIONS, description: "Video resolution supported by the selected model and workflow (default its first)" },
|
|
50193
50207
|
{ name: "mode", type: "string", choices: ["cost", "speed", "quality"], description: "Video generation mode supported by the selected model (default its first)" },
|
|
50194
|
-
{ name: "prompt-expansion", type: "string", choices: PROMPT_EXPANSION_MODES, description: "Video: how much the model may rewrite the prompt (default disabled); extensions treat any other value as on" },
|
|
50208
|
+
{ name: "prompt-expansion", type: "string", choices: PROMPT_EXPANSION_MODES, description: "Video: how much the model may rewrite the prompt (default disabled); extensions treat any other value as on. FLUX 3 Max always reasons about the prompt: quality thoroughly, any other value lightly" },
|
|
50195
50209
|
{ name: "seed", type: "number", description: "Video: seed for repeatable results, where the model takes one" },
|
|
50196
50210
|
{ name: "extend-output", type: "string", choices: EXTEND_OUTPUTS, description: "Extension: extended (default, source plus new footage) or continuation (a 1.625 s overlap, then the new footage)" },
|
|
50197
50211
|
{ name: "voice", type: "string", description: "Gemini voice name or ElevenLabs voice ID (defaults: Kore / George)" },
|
|
@@ -50243,7 +50257,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50243
50257
|
out(stdout, await new Client(flags.url, signal).request(flags.look ? `${avatarsPath(args.id)}/looks/${encodeURIComponent(flags.look)}` : `${avatarsPath(args.id)}/${encodeURIComponent(flags.group)}`, { method: "DELETE" }));
|
|
50244
50258
|
})))).command("jobs", (jobs) => jobs.add(defineCommand("list", { description: "List the latest generation jobs" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).action(async ({ args, flags, stdout, signal }) => out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/jobs`))))).add(defineCommand("submit", { description: "Submit a typed JSON job: character, animate, custom or redraw; spends credits" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).flags(...modelFlags).flags({ name: "file", type: "string", required: true, description: "JSON job file" }, { name: "yes", type: "boolean", required: true, description: "Authorize spending credits" }).action(async ({ args, flags, stdout, signal }) => {
|
|
50245
50259
|
if (!flags.yes) throw new Error("Pass --yes to authorize spending credits.");
|
|
50246
|
-
const body = spriteJobBody.parse({ ...JSON.parse(await
|
|
50260
|
+
const body = spriteJobBody.parse({ ...JSON.parse(await readFile19(flags.file, "utf8")), ...selectedModels(flags) });
|
|
50247
50261
|
out(stdout, await new Client(flags.url, signal).request(`${projectPath(args.id)}/jobs`, { method: "POST", body }));
|
|
50248
50262
|
}))).add(defineCommand("wait", { description: "Wait for a specific job; fail if generation fails or times out" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id, { name: "job", type: "string", required: true }).flags({ name: "timeout", type: "number", default: 600, description: "Maximum seconds to wait" }).action(async ({ args, flags, stdout, signal }) => out(stdout, { job: await waitForJob(new Client(flags.url, signal), args.id, args.job, flags.timeout, signal) }))))).add(defineCommand("models", { description: "Set the default video model for future project jobs" }, (command) => command.flags({ name: "url", type: "string", default: "https://animaguru.com", env: { name: "ANIMAGURU_URL" }, description: "Server origin" }).args(id).flags(...modelFlags).action(async ({ args, flags, stdout, signal }) => {
|
|
50249
50263
|
const body = selectedModels(flags);
|
|
@@ -50258,7 +50272,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50258
50272
|
const extension = flags.file.split(".").at(-1)?.toLowerCase();
|
|
50259
50273
|
const type = extension === "png" ? "image/png" : extension === "jpg" || extension === "jpeg" ? "image/jpeg" : extension === "webp" ? "image/webp" : void 0;
|
|
50260
50274
|
if (!type) throw new Error("Use a PNG, JPEG or WebP image.");
|
|
50261
|
-
const bytes = await
|
|
50275
|
+
const bytes = await readFile19(flags.file);
|
|
50262
50276
|
if (bytes.length > 10 * 1024 * 1024) throw new Error("Image must be at most 10 MB.");
|
|
50263
50277
|
const form = new FormData();
|
|
50264
50278
|
form.set("image", new Blob([bytes], { type }), `reference.${extension}`);
|
|
@@ -50274,7 +50288,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50274
50288
|
if (!file2) throw new Error(`No file at ${args.path} in this project. List them with animaguru files list.`);
|
|
50275
50289
|
if (!/^[a-f0-9]{64}$/.test(file2.sha)) throw new Error("Invalid blob hash in manifest.");
|
|
50276
50290
|
const response = await client.request(`/api/v1/blobs/${encodeURIComponent(manifest.ownerId)}/${file2.sha}`, { raw: true });
|
|
50277
|
-
const path =
|
|
50291
|
+
const path = resolve17(flags.output);
|
|
50278
50292
|
await mkdir15(dirname14(path), { recursive: true });
|
|
50279
50293
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
50280
50294
|
await writeFile16(path, bytes, { flag: "wx" });
|
|
@@ -50289,7 +50303,7 @@ Confirm code: ${device.user_code}`);
|
|
|
50289
50303
|
const response = await client.request(`/api/v1/blobs/${encodeURIComponent(manifest.ownerId)}/${file2.sha}`, { raw: true });
|
|
50290
50304
|
entries[path2] = new Uint8Array(await response.arrayBuffer());
|
|
50291
50305
|
}
|
|
50292
|
-
const path =
|
|
50306
|
+
const path = resolve17(flags.output);
|
|
50293
50307
|
await writeFile16(path, zipSync(entries, { level: 0 }), { flag: "wx" });
|
|
50294
50308
|
out(stdout, { path, files: manifest.files.length });
|
|
50295
50309
|
})))).extend(version(package_default.version, { format: "plain" })).extend(help()).extend(completion());
|