@koda-sl/baker-cli 0.123.0-dev.31b784126 → 0.123.0-dev.4a85b9f30
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 +4 -61
- package/dist/{chunk-Q3K5TXC6.js → chunk-43KBQLP5.js} +324 -365
- package/dist/chunk-43KBQLP5.js.map +1 -0
- package/dist/cli.js +1262 -1983
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.d.ts +0 -6
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-Q3K5TXC6.js.map +0 -1
|
@@ -3214,7 +3214,7 @@ var Engine = class {
|
|
|
3214
3214
|
log: this.log,
|
|
3215
3215
|
signal: opts.signal
|
|
3216
3216
|
};
|
|
3217
|
-
const preparedForExec =
|
|
3217
|
+
const preparedForExec = def.location === "local" ? { ...prepared, resolvedInputs: await this.materializeLocalInputs(prepared.resolvedInputs) } : prepared;
|
|
3218
3218
|
const { parsedInputs, parsedParams } = parseNodeArgs(def, preparedForExec, node.id, node.type);
|
|
3219
3219
|
const result = await invokeExecute(def, parsedInputs, parsedParams, ctx, node.id, node.type);
|
|
3220
3220
|
const elapsed = Date.now() - t0;
|
|
@@ -3336,9 +3336,6 @@ async function invokeExecute(def, parsedInputs, parsedParams, ctx, nodeId, nodeT
|
|
|
3336
3336
|
throw new NodeExecutionError(nodeId, nodeType, { kind: "local", cause: e });
|
|
3337
3337
|
}
|
|
3338
3338
|
}
|
|
3339
|
-
function needsLocalMaterialization(def) {
|
|
3340
|
-
return def.location === "local" && !def.passthroughRefs;
|
|
3341
|
-
}
|
|
3342
3339
|
function pickFinalOutput(canvas, outputs) {
|
|
3343
3340
|
if (canvas.output) {
|
|
3344
3341
|
const node = outputs[canvas.output.node];
|
|
@@ -3354,7 +3351,7 @@ function computeNeedsLocalBytes(canvas, graph, registry) {
|
|
|
3354
3351
|
const needs = /* @__PURE__ */ new Set();
|
|
3355
3352
|
for (const [consumerId, deps] of graph) {
|
|
3356
3353
|
const def = registry.get(typeById.get(consumerId) ?? "");
|
|
3357
|
-
if (def?.location !== "local"
|
|
3354
|
+
if (def?.location !== "local") continue;
|
|
3358
3355
|
for (const dep of deps) needs.add(dep);
|
|
3359
3356
|
}
|
|
3360
3357
|
return needs;
|
|
@@ -4685,56 +4682,19 @@ var audioTimelineNode = defineNode({
|
|
|
4685
4682
|
}
|
|
4686
4683
|
});
|
|
4687
4684
|
|
|
4688
|
-
// src/engine/nodes/local/collect.ts
|
|
4689
|
-
import { z as z7 } from "zod";
|
|
4690
|
-
var collectNode = defineNode({
|
|
4691
|
-
id: "collect",
|
|
4692
|
-
version: "1.0.0",
|
|
4693
|
-
category: "data",
|
|
4694
|
-
location: "local",
|
|
4695
|
-
passthroughRefs: true,
|
|
4696
|
-
summary: "Gather images from multiple upstream nodes into one ordered array \u2014 the standard terminal for multi-variant canvases whose final output is several images.",
|
|
4697
|
-
when_to_use: "Point the canvas `output` at this node when several independent branches (e.g. one image_generate per scene/variant) must ALL be finals. Wire `inputs.images` as an array of refs like `$ref:gen_billboard_03.images#0` \u2014 each final inherits its producer node id as its label (or set `params.labels` to override), so variants stay identifiable in the dashboard and selection.",
|
|
4698
|
-
inputs: z7.object({ images: z7.array(ImageRef).min(1) }).strict(),
|
|
4699
|
-
params: z7.object({ labels: z7.array(z7.string().min(1)).min(1).optional() }).strict(),
|
|
4700
|
-
outputs: z7.object({ images: z7.array(ImageRef).min(1) }).strict(),
|
|
4701
|
-
outputKinds: { images: "image" },
|
|
4702
|
-
cost: () => ({ credits: 0, seconds_estimate: 0 }),
|
|
4703
|
-
// Arity is only knowable at validate time when `images` is a literal array;
|
|
4704
|
-
// a single `$ref:` string to an upstream array output defers to runtime.
|
|
4705
|
-
validateExtra: ({ rawParams, rawInputs }) => {
|
|
4706
|
-
const labels = rawParams?.labels;
|
|
4707
|
-
if (!Array.isArray(labels)) return [];
|
|
4708
|
-
if (new Set(labels).size !== labels.length) {
|
|
4709
|
-
return [{ path: "params.labels", message: "labels must be unique \u2014 each names one output variant" }];
|
|
4710
|
-
}
|
|
4711
|
-
const images = rawInputs?.images;
|
|
4712
|
-
if (Array.isArray(images) && labels.length !== images.length) {
|
|
4713
|
-
return [
|
|
4714
|
-
{
|
|
4715
|
-
path: "params.labels",
|
|
4716
|
-
message: `labels has ${labels.length} entries but ${images.length} images are wired \u2014 provide one label per image`
|
|
4717
|
-
}
|
|
4718
|
-
];
|
|
4719
|
-
}
|
|
4720
|
-
return [];
|
|
4721
|
-
},
|
|
4722
|
-
execute: ({ inputs }) => Promise.resolve({ images: inputs.images })
|
|
4723
|
-
});
|
|
4724
|
-
|
|
4725
4685
|
// src/engine/nodes/local/ffmpeg.ts
|
|
4726
|
-
import { z as
|
|
4686
|
+
import { z as z7 } from "zod";
|
|
4727
4687
|
var FFMPEG_BIN2 = "ffmpeg";
|
|
4728
|
-
var OutputDecl =
|
|
4729
|
-
kind:
|
|
4730
|
-
ext:
|
|
4688
|
+
var OutputDecl = z7.object({
|
|
4689
|
+
kind: z7.enum(["image", "video", "audio"]),
|
|
4690
|
+
ext: z7.string().min(1).max(8)
|
|
4731
4691
|
}).strict();
|
|
4732
|
-
var FfmpegParams =
|
|
4733
|
-
args:
|
|
4734
|
-
outputs:
|
|
4692
|
+
var FfmpegParams = z7.object({
|
|
4693
|
+
args: z7.array(z7.string()).min(1),
|
|
4694
|
+
outputs: z7.record(z7.string(), OutputDecl).default({})
|
|
4735
4695
|
}).strict();
|
|
4736
|
-
var FfmpegInputs =
|
|
4737
|
-
var FfmpegOutputs =
|
|
4696
|
+
var FfmpegInputs = z7.record(z7.string(), z7.unknown());
|
|
4697
|
+
var FfmpegOutputs = z7.record(z7.string(), z7.custom());
|
|
4738
4698
|
var ffmpegNode = defineNode({
|
|
4739
4699
|
id: "ffmpeg",
|
|
4740
4700
|
version: "2.0.0",
|
|
@@ -4765,7 +4725,7 @@ import { mkdtemp as mkdtemp3, rm as rm3, writeFile as writeFile3 } from "fs/prom
|
|
|
4765
4725
|
import { createRequire } from "module";
|
|
4766
4726
|
import { tmpdir as tmpdir3 } from "os";
|
|
4767
4727
|
import path6 from "path";
|
|
4768
|
-
import { z as
|
|
4728
|
+
import { z as z8 } from "zod";
|
|
4769
4729
|
|
|
4770
4730
|
// src/engine/nodes/local/lib/assets.ts
|
|
4771
4731
|
import { copyFile as copyFile3, readFile as readFile4 } from "fs/promises";
|
|
@@ -4801,15 +4761,15 @@ var DEFAULT_SPECIMEN = [
|
|
|
4801
4761
|
"abcdefghijklmnopqrstuvwxyz",
|
|
4802
4762
|
`0123456789 !?&@#$%().,:;'"-`
|
|
4803
4763
|
].join("\n");
|
|
4804
|
-
var FontSpecimenParams =
|
|
4805
|
-
text:
|
|
4806
|
-
font_size:
|
|
4807
|
-
padding:
|
|
4808
|
-
line_height:
|
|
4809
|
-
max_width:
|
|
4764
|
+
var FontSpecimenParams = z8.object({
|
|
4765
|
+
text: z8.string().min(1).max(2e3).optional().default(DEFAULT_SPECIMEN),
|
|
4766
|
+
font_size: z8.number().int().min(8).max(512).optional().default(72),
|
|
4767
|
+
padding: z8.number().int().min(0).max(512).optional().default(64),
|
|
4768
|
+
line_height: z8.number().min(0.8).max(3).optional().default(1.35),
|
|
4769
|
+
max_width: z8.number().int().min(256).max(4096).optional()
|
|
4810
4770
|
}).strict();
|
|
4811
|
-
var FontSpecimenInputs =
|
|
4812
|
-
var FontSpecimenOutputs =
|
|
4771
|
+
var FontSpecimenInputs = z8.object({ font: FontRef }).loose();
|
|
4772
|
+
var FontSpecimenOutputs = z8.object({ image: ImageRef }).strict();
|
|
4813
4773
|
var DEVICE_SCALE_FACTOR = 2;
|
|
4814
4774
|
var PAGE_TIMEOUT_MS = 3e4;
|
|
4815
4775
|
function escapeHtml(text) {
|
|
@@ -4950,7 +4910,7 @@ import { createRequire as createRequire2 } from "module";
|
|
|
4950
4910
|
import { cpus, tmpdir as tmpdir4 } from "os";
|
|
4951
4911
|
import path11 from "path";
|
|
4952
4912
|
import { promisify as promisify4 } from "util";
|
|
4953
|
-
import { z as
|
|
4913
|
+
import { z as z10 } from "zod";
|
|
4954
4914
|
|
|
4955
4915
|
// src/engine/engine/composition-hash.ts
|
|
4956
4916
|
import { readdir as readdir2, readFile as readFile5, stat as stat4 } from "fs/promises";
|
|
@@ -4988,62 +4948,62 @@ async function collectFiles(root, current) {
|
|
|
4988
4948
|
// src/engine/engine/composition-meta.ts
|
|
4989
4949
|
import { readFile as readFile6 } from "fs/promises";
|
|
4990
4950
|
import path8 from "path";
|
|
4991
|
-
import { z as
|
|
4992
|
-
var InputKind =
|
|
4993
|
-
var InputSpec =
|
|
4951
|
+
import { z as z9 } from "zod";
|
|
4952
|
+
var InputKind = z9.enum(["video", "image", "audio", "json"]);
|
|
4953
|
+
var InputSpec = z9.object({
|
|
4994
4954
|
kind: InputKind,
|
|
4995
|
-
required:
|
|
4955
|
+
required: z9.boolean().optional().default(false),
|
|
4996
4956
|
// Filename the composition's HTML references (e.g. `input.mp4`, `logo.png`).
|
|
4997
4957
|
// Defaults to `<key><ext>` derived from the kind.
|
|
4998
|
-
staged_as:
|
|
4999
|
-
description:
|
|
4958
|
+
staged_as: z9.string().min(1).optional(),
|
|
4959
|
+
description: z9.string().optional()
|
|
5000
4960
|
}).strict();
|
|
5001
4961
|
var ParamSpecBase = {
|
|
5002
|
-
required:
|
|
5003
|
-
description:
|
|
4962
|
+
required: z9.boolean().optional().default(false),
|
|
4963
|
+
description: z9.string().optional()
|
|
5004
4964
|
};
|
|
5005
|
-
var StringParam =
|
|
4965
|
+
var StringParam = z9.object({
|
|
5006
4966
|
...ParamSpecBase,
|
|
5007
|
-
kind:
|
|
5008
|
-
default:
|
|
5009
|
-
enum:
|
|
4967
|
+
kind: z9.literal("string"),
|
|
4968
|
+
default: z9.string().optional(),
|
|
4969
|
+
enum: z9.array(z9.string()).optional()
|
|
5010
4970
|
}).strict();
|
|
5011
|
-
var IntegerParam =
|
|
4971
|
+
var IntegerParam = z9.object({
|
|
5012
4972
|
...ParamSpecBase,
|
|
5013
|
-
kind:
|
|
5014
|
-
default:
|
|
5015
|
-
min:
|
|
5016
|
-
max:
|
|
4973
|
+
kind: z9.literal("integer"),
|
|
4974
|
+
default: z9.number().int().optional(),
|
|
4975
|
+
min: z9.number().int().optional(),
|
|
4976
|
+
max: z9.number().int().optional()
|
|
5017
4977
|
}).strict();
|
|
5018
|
-
var NumberParam =
|
|
4978
|
+
var NumberParam = z9.object({
|
|
5019
4979
|
...ParamSpecBase,
|
|
5020
|
-
kind:
|
|
5021
|
-
default:
|
|
5022
|
-
min:
|
|
5023
|
-
max:
|
|
4980
|
+
kind: z9.literal("number"),
|
|
4981
|
+
default: z9.number().optional(),
|
|
4982
|
+
min: z9.number().optional(),
|
|
4983
|
+
max: z9.number().optional()
|
|
5024
4984
|
}).strict();
|
|
5025
|
-
var BooleanParam =
|
|
4985
|
+
var BooleanParam = z9.object({
|
|
5026
4986
|
...ParamSpecBase,
|
|
5027
|
-
kind:
|
|
5028
|
-
default:
|
|
4987
|
+
kind: z9.literal("boolean"),
|
|
4988
|
+
default: z9.boolean().optional()
|
|
5029
4989
|
}).strict();
|
|
5030
|
-
var ColorParam =
|
|
4990
|
+
var ColorParam = z9.object({
|
|
5031
4991
|
...ParamSpecBase,
|
|
5032
|
-
kind:
|
|
5033
|
-
default:
|
|
4992
|
+
kind: z9.literal("color"),
|
|
4993
|
+
default: z9.string().optional()
|
|
5034
4994
|
}).strict();
|
|
5035
|
-
var ImageParam =
|
|
4995
|
+
var ImageParam = z9.object({
|
|
5036
4996
|
...ParamSpecBase,
|
|
5037
|
-
kind:
|
|
5038
|
-
default:
|
|
4997
|
+
kind: z9.literal("image"),
|
|
4998
|
+
default: z9.string().optional()
|
|
5039
4999
|
}).strict();
|
|
5040
|
-
var JsonParam =
|
|
5000
|
+
var JsonParam = z9.object({
|
|
5041
5001
|
...ParamSpecBase,
|
|
5042
|
-
kind:
|
|
5043
|
-
schema:
|
|
5044
|
-
default:
|
|
5002
|
+
kind: z9.literal("json"),
|
|
5003
|
+
schema: z9.unknown().optional(),
|
|
5004
|
+
default: z9.unknown().optional()
|
|
5045
5005
|
}).strict();
|
|
5046
|
-
var ParamSpec =
|
|
5006
|
+
var ParamSpec = z9.discriminatedUnion("kind", [
|
|
5047
5007
|
StringParam,
|
|
5048
5008
|
IntegerParam,
|
|
5049
5009
|
NumberParam,
|
|
@@ -5052,16 +5012,16 @@ var ParamSpec = z10.discriminatedUnion("kind", [
|
|
|
5052
5012
|
ImageParam,
|
|
5053
5013
|
JsonParam
|
|
5054
5014
|
]);
|
|
5055
|
-
var CompositionMetaSchema =
|
|
5056
|
-
id:
|
|
5057
|
-
title:
|
|
5058
|
-
description:
|
|
5059
|
-
width:
|
|
5060
|
-
height:
|
|
5061
|
-
fps:
|
|
5062
|
-
default_duration:
|
|
5063
|
-
inputs:
|
|
5064
|
-
params:
|
|
5015
|
+
var CompositionMetaSchema = z9.object({
|
|
5016
|
+
id: z9.string().min(1),
|
|
5017
|
+
title: z9.string().min(1),
|
|
5018
|
+
description: z9.string().optional(),
|
|
5019
|
+
width: z9.number().int().positive(),
|
|
5020
|
+
height: z9.number().int().positive(),
|
|
5021
|
+
fps: z9.number().int().positive().default(30),
|
|
5022
|
+
default_duration: z9.number().positive().default(10),
|
|
5023
|
+
inputs: z9.record(z9.string(), InputSpec).default({}),
|
|
5024
|
+
params: z9.record(z9.string(), ParamSpec).default({})
|
|
5065
5025
|
}).strict();
|
|
5066
5026
|
async function loadCompositionMeta(compositionDir) {
|
|
5067
5027
|
const metaPath = path8.join(compositionDir, "meta.json");
|
|
@@ -5089,39 +5049,39 @@ function buildParamsSchema(meta) {
|
|
|
5089
5049
|
for (const [name, spec] of Object.entries(meta.params)) {
|
|
5090
5050
|
shape[name] = buildParamFieldSchema(name, spec);
|
|
5091
5051
|
}
|
|
5092
|
-
return
|
|
5052
|
+
return z9.object(shape).strict();
|
|
5093
5053
|
}
|
|
5094
5054
|
function buildParamFieldSchema(name, spec) {
|
|
5095
5055
|
switch (spec.kind) {
|
|
5096
5056
|
case "string": {
|
|
5097
|
-
const s = spec.enum && spec.enum.length > 0 ?
|
|
5057
|
+
const s = spec.enum && spec.enum.length > 0 ? z9.enum(spec.enum) : z9.string();
|
|
5098
5058
|
return finalize(s, spec.default, spec.required);
|
|
5099
5059
|
}
|
|
5100
5060
|
case "integer": {
|
|
5101
|
-
let s =
|
|
5061
|
+
let s = z9.number().int();
|
|
5102
5062
|
if (spec.min !== void 0) s = s.min(spec.min);
|
|
5103
5063
|
if (spec.max !== void 0) s = s.max(spec.max);
|
|
5104
5064
|
return finalize(s, spec.default, spec.required);
|
|
5105
5065
|
}
|
|
5106
5066
|
case "number": {
|
|
5107
|
-
let s =
|
|
5067
|
+
let s = z9.number();
|
|
5108
5068
|
if (spec.min !== void 0) s = s.min(spec.min);
|
|
5109
5069
|
if (spec.max !== void 0) s = s.max(spec.max);
|
|
5110
5070
|
return finalize(s, spec.default, spec.required);
|
|
5111
5071
|
}
|
|
5112
5072
|
case "boolean":
|
|
5113
|
-
return finalize(
|
|
5073
|
+
return finalize(z9.boolean(), spec.default, spec.required);
|
|
5114
5074
|
case "color": {
|
|
5115
|
-
const s =
|
|
5075
|
+
const s = z9.string().regex(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/, {
|
|
5116
5076
|
message: `param "${name}": must be a 3/6/8-digit hex color (e.g. "#ff0066")`
|
|
5117
5077
|
});
|
|
5118
5078
|
return finalize(s, spec.default, spec.required);
|
|
5119
5079
|
}
|
|
5120
5080
|
case "image":
|
|
5121
|
-
return finalize(
|
|
5081
|
+
return finalize(z9.union([z9.string().min(1), z9.record(z9.string(), z9.unknown())]), spec.default, spec.required);
|
|
5122
5082
|
case "json":
|
|
5123
5083
|
return finalize(
|
|
5124
|
-
|
|
5084
|
+
z9.unknown().refine((v) => v !== void 0, { message: `param "${name}" is required` }),
|
|
5125
5085
|
spec.default,
|
|
5126
5086
|
spec.required
|
|
5127
5087
|
);
|
|
@@ -5421,17 +5381,17 @@ function literalize(value) {
|
|
|
5421
5381
|
// src/engine/nodes/local/hyperframe.ts
|
|
5422
5382
|
var execFileAsync2 = promisify4(execFile4);
|
|
5423
5383
|
var require_2 = createRequire2(import.meta.url);
|
|
5424
|
-
var HyperframeParams =
|
|
5425
|
-
composition:
|
|
5384
|
+
var HyperframeParams = z10.object({
|
|
5385
|
+
composition: z10.string().min(1),
|
|
5426
5386
|
// Output container. mp4 (default) for delivery; webm/mov render WITH
|
|
5427
5387
|
// transparency (alpha) when the composition background is transparent —
|
|
5428
5388
|
// use for motion-graphic overlays dropped into Premiere/AE/Nuke.
|
|
5429
|
-
format:
|
|
5430
|
-
timeout_ms:
|
|
5431
|
-
}).catchall(
|
|
5432
|
-
var HyperframeInputs =
|
|
5433
|
-
var HyperframeOutputs =
|
|
5434
|
-
video:
|
|
5389
|
+
format: z10.enum(["mp4", "webm", "mov"]).optional().default("mp4"),
|
|
5390
|
+
timeout_ms: z10.number().int().positive().optional().default(10 * 60 * 1e3)
|
|
5391
|
+
}).catchall(z10.unknown());
|
|
5392
|
+
var HyperframeInputs = z10.record(z10.string(), z10.custom()).optional().default({});
|
|
5393
|
+
var HyperframeOutputs = z10.object({
|
|
5394
|
+
video: z10.custom()
|
|
5435
5395
|
}).strict();
|
|
5436
5396
|
var NODE_OWNED_PARAM_KEYS = /* @__PURE__ */ new Set(["composition", "format", "timeout_ms"]);
|
|
5437
5397
|
var MIME_BY_FORMAT = {
|
|
@@ -5720,23 +5680,23 @@ import { createRequire as createRequire3 } from "module";
|
|
|
5720
5680
|
import { tmpdir as tmpdir5 } from "os";
|
|
5721
5681
|
import path12 from "path";
|
|
5722
5682
|
import { promisify as promisify5 } from "util";
|
|
5723
|
-
import { z as
|
|
5683
|
+
import { z as z11 } from "zod";
|
|
5724
5684
|
var _execFileAsync = promisify5(execFile5);
|
|
5725
5685
|
var require_3 = createRequire3(import.meta.url);
|
|
5726
|
-
var WaitForSpec =
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5686
|
+
var WaitForSpec = z11.discriminatedUnion("kind", [
|
|
5687
|
+
z11.object({ kind: z11.literal("auto") }),
|
|
5688
|
+
z11.object({ kind: z11.literal("selector"), value: z11.string().min(1) }),
|
|
5689
|
+
z11.object({ kind: z11.literal("function"), value: z11.string().min(1) }),
|
|
5690
|
+
z11.object({ kind: z11.literal("timeout"), ms: z11.number().int().min(0).max(6e4) })
|
|
5731
5691
|
]);
|
|
5732
|
-
var HyperframeSnapshotParams =
|
|
5733
|
-
composition:
|
|
5692
|
+
var HyperframeSnapshotParams = z11.object({
|
|
5693
|
+
composition: z11.string().min(1),
|
|
5734
5694
|
wait_for: WaitForSpec.optional().default({ kind: "auto" }),
|
|
5735
|
-
timeout_ms:
|
|
5736
|
-
}).catchall(
|
|
5737
|
-
var HyperframeSnapshotInputs =
|
|
5738
|
-
var HyperframeSnapshotOutputs =
|
|
5739
|
-
image:
|
|
5695
|
+
timeout_ms: z11.number().int().positive().optional().default(6e4)
|
|
5696
|
+
}).catchall(z11.unknown());
|
|
5697
|
+
var HyperframeSnapshotInputs = z11.record(z11.string(), z11.custom()).optional().default({});
|
|
5698
|
+
var HyperframeSnapshotOutputs = z11.object({
|
|
5699
|
+
image: z11.custom()
|
|
5740
5700
|
}).strict();
|
|
5741
5701
|
var NODE_OWNED_PARAM_KEYS2 = /* @__PURE__ */ new Set(["composition", "wait_for", "timeout_ms"]);
|
|
5742
5702
|
var DEVICE_SCALE_FACTOR2 = 2;
|
|
@@ -5928,18 +5888,18 @@ async function waitForReady(page, waitFor, timeoutMs) {
|
|
|
5928
5888
|
// src/engine/nodes/local/imagemagick.ts
|
|
5929
5889
|
import { execFile as execFile6 } from "child_process";
|
|
5930
5890
|
import { promisify as promisify6 } from "util";
|
|
5931
|
-
import { z as
|
|
5891
|
+
import { z as z12 } from "zod";
|
|
5932
5892
|
var execFileAsync3 = promisify6(execFile6);
|
|
5933
|
-
var OutputDecl2 =
|
|
5934
|
-
kind:
|
|
5935
|
-
ext:
|
|
5893
|
+
var OutputDecl2 = z12.object({
|
|
5894
|
+
kind: z12.enum(["image", "video", "audio"]),
|
|
5895
|
+
ext: z12.string().min(1).max(8)
|
|
5936
5896
|
}).strict();
|
|
5937
|
-
var ImageMagickParams =
|
|
5938
|
-
args:
|
|
5939
|
-
outputs:
|
|
5897
|
+
var ImageMagickParams = z12.object({
|
|
5898
|
+
args: z12.array(z12.string()).min(1),
|
|
5899
|
+
outputs: z12.record(z12.string(), OutputDecl2).default({})
|
|
5940
5900
|
}).strict();
|
|
5941
|
-
var ImageMagickInputs =
|
|
5942
|
-
var ImageMagickOutputs =
|
|
5901
|
+
var ImageMagickInputs = z12.record(z12.string(), z12.unknown());
|
|
5902
|
+
var ImageMagickOutputs = z12.record(z12.string(), z12.custom());
|
|
5943
5903
|
var resolvedBin;
|
|
5944
5904
|
async function resolveBin() {
|
|
5945
5905
|
if (resolvedBin) return resolvedBin;
|
|
@@ -5981,29 +5941,29 @@ var imagemagickNode = defineNode({
|
|
|
5981
5941
|
});
|
|
5982
5942
|
|
|
5983
5943
|
// src/engine/nodes/local/text.ts
|
|
5984
|
-
import { z as
|
|
5944
|
+
import { z as z13 } from "zod";
|
|
5985
5945
|
var textNode = defineNode({
|
|
5986
5946
|
id: "text",
|
|
5987
5947
|
version: "1.0.0",
|
|
5988
5948
|
category: "data",
|
|
5989
5949
|
location: "local",
|
|
5990
5950
|
summary: "A literal text value. Use for prompts, descriptions, copy.",
|
|
5991
|
-
inputs:
|
|
5992
|
-
params:
|
|
5993
|
-
outputs:
|
|
5951
|
+
inputs: z13.object({}).strict(),
|
|
5952
|
+
params: z13.object({ value: z13.string() }).strict(),
|
|
5953
|
+
outputs: z13.object({ text: z13.string() }).strict(),
|
|
5994
5954
|
cost: () => ({ credits: 0, seconds_estimate: 0 }),
|
|
5995
5955
|
execute: ({ params }) => Promise.resolve({ text: params.value })
|
|
5996
5956
|
});
|
|
5997
5957
|
|
|
5998
5958
|
// src/engine/nodes/remote/audioVoiceConvert.ts
|
|
5999
|
-
import { z as
|
|
6000
|
-
var AudioVoiceConvertParams =
|
|
6001
|
-
model:
|
|
5959
|
+
import { z as z14 } from "zod";
|
|
5960
|
+
var AudioVoiceConvertParams = z14.object({
|
|
5961
|
+
model: z14.literal("elevenlabs/eleven_multilingual_sts_v2"),
|
|
6002
5962
|
/** Target voice id. Splice an upstream `voice_select` via `"{{voice_ref}}"`. */
|
|
6003
|
-
voice:
|
|
6004
|
-
output_format:
|
|
5963
|
+
voice: z14.string().min(1),
|
|
5964
|
+
output_format: z14.string().optional(),
|
|
6005
5965
|
/** Strip the source clip's background noise before re-voicing. */
|
|
6006
|
-
remove_background_noise:
|
|
5966
|
+
remove_background_noise: z14.boolean().optional()
|
|
6007
5967
|
}).strict();
|
|
6008
5968
|
var audioVoiceConvertNode = delegated({
|
|
6009
5969
|
id: "audio_voice_convert",
|
|
@@ -6011,44 +5971,44 @@ var audioVoiceConvertNode = delegated({
|
|
|
6011
5971
|
category: "audio",
|
|
6012
5972
|
summary: "Voice Changer / speech-to-speech via ElevenLabs (eleven_multilingual_sts_v2). Re-voices an existing audio clip in a TARGET voice while preserving timing/prosody.",
|
|
6013
5973
|
when_to_use: 'Use to normalize a generator-chosen voice (e.g. a Seedance talking-head clip\'s native audio) into ONE consistent brand voice across every scene \u2014 the cadence is preserved so any lip-sync stays valid. Wire `inputs.voice_ref: $ref:<voice_select>.voice_id` and set `params.voice: "{{voice_ref}}"`.',
|
|
6014
|
-
inputs:
|
|
5974
|
+
inputs: z14.object({
|
|
6015
5975
|
audio: AudioRef,
|
|
6016
5976
|
voice_ref: TextRef.optional()
|
|
6017
5977
|
}).strict(),
|
|
6018
5978
|
params: AudioVoiceConvertParams,
|
|
6019
|
-
outputs:
|
|
5979
|
+
outputs: z14.object({ audio: AudioRef }).strict(),
|
|
6020
5980
|
outputKinds: { audio: "audio" },
|
|
6021
5981
|
cost: () => ({ credits: 1, seconds_estimate: 20 })
|
|
6022
5982
|
});
|
|
6023
5983
|
|
|
6024
5984
|
// src/engine/nodes/remote/dialogue.ts
|
|
6025
|
-
import { z as
|
|
6026
|
-
var DialogueInput =
|
|
6027
|
-
text:
|
|
6028
|
-
voice_id:
|
|
5985
|
+
import { z as z15 } from "zod";
|
|
5986
|
+
var DialogueInput = z15.object({
|
|
5987
|
+
text: z15.string().min(1),
|
|
5988
|
+
voice_id: z15.string().min(1)
|
|
6029
5989
|
});
|
|
6030
5990
|
var DIALOGUE_MODELS = ["elevenlabs/eleven_v3"];
|
|
6031
|
-
var DialogueParams =
|
|
6032
|
-
model:
|
|
5991
|
+
var DialogueParams = z15.object({
|
|
5992
|
+
model: z15.enum(DIALOGUE_MODELS),
|
|
6033
5993
|
/**
|
|
6034
5994
|
* Ordered list of lines, each tagged with the voice that should speak it.
|
|
6035
5995
|
* Up to 10 unique voice_ids; total text across all lines should stay under
|
|
6036
5996
|
* ~2000 characters for best quality (ElevenLabs guidance).
|
|
6037
5997
|
*/
|
|
6038
|
-
inputs:
|
|
6039
|
-
language_code:
|
|
5998
|
+
inputs: z15.array(DialogueInput).min(1).max(50),
|
|
5999
|
+
language_code: z15.string().optional(),
|
|
6040
6000
|
/** ElevenLabs voice/model settings passthrough (e.g. `{ stability: 0.5 }`). */
|
|
6041
|
-
settings:
|
|
6042
|
-
seed:
|
|
6043
|
-
apply_text_normalization:
|
|
6001
|
+
settings: z15.record(z15.string(), z15.unknown()).optional(),
|
|
6002
|
+
seed: z15.number().int().min(0).max(4294967295).optional(),
|
|
6003
|
+
apply_text_normalization: z15.enum(["auto", "on", "off"]).optional(),
|
|
6044
6004
|
/**
|
|
6045
6005
|
* When true, hits `/v1/text-to-dialogue/with-timestamps` and emits a
|
|
6046
6006
|
* separate `timestamps` output — character-level alignment plus
|
|
6047
6007
|
* per-voice segment markers usable for captions, lipsync, or
|
|
6048
6008
|
* beat-matched cuts in ad creatives.
|
|
6049
6009
|
*/
|
|
6050
|
-
with_timestamps:
|
|
6051
|
-
output_format:
|
|
6010
|
+
with_timestamps: z15.boolean().optional(),
|
|
6011
|
+
output_format: z15.enum(ELEVENLABS_OUTPUT_FORMATS).optional()
|
|
6052
6012
|
}).strict().refine((p) => p.inputs.reduce((sum, line) => sum + line.text.length, 0) <= ELEVENLABS_MAX_TEXT_CHARS, {
|
|
6053
6013
|
message: `total dialogue text exceeds ${ELEVENLABS_MAX_TEXT_CHARS} characters`,
|
|
6054
6014
|
path: ["inputs"]
|
|
@@ -6059,9 +6019,9 @@ var dialogueNode = delegated({
|
|
|
6059
6019
|
category: "audio",
|
|
6060
6020
|
summary: "Multi-voice dialogue / VO with ElevenLabs Eleven v3. Each line is tagged with a `voice_id`, so you can render two-character scripts (e.g. ad VO + customer testimonial reaction) in a single call. Setting `with_timestamps: true` adds character-level alignment for caption rendering and lipsync-friendly cuts.",
|
|
6061
6021
|
when_to_use: "Use for any ad creative or website video VO that needs more than narration \u2014 interviews, two-actor scripts, character ads, testimonial reads. For single-voice flat reads the existing `tts` node is cheaper and simpler; reach for `dialogue` when you need multiple speakers in one stitched track or word-level timing for downstream lipsync / captions.",
|
|
6062
|
-
inputs:
|
|
6022
|
+
inputs: z15.object({}).loose(),
|
|
6063
6023
|
params: DialogueParams,
|
|
6064
|
-
outputs:
|
|
6024
|
+
outputs: z15.object({ audio: AudioRef, timestamps: JsonRef.optional() }).strict(),
|
|
6065
6025
|
outputKinds: { audio: "audio", timestamps: "json" },
|
|
6066
6026
|
cost: ({ params }) => {
|
|
6067
6027
|
const chars = params.inputs.reduce((sum, line) => sum + line.text.length, 0);
|
|
@@ -6070,7 +6030,7 @@ var dialogueNode = delegated({
|
|
|
6070
6030
|
});
|
|
6071
6031
|
|
|
6072
6032
|
// src/engine/nodes/remote/image.ts
|
|
6073
|
-
import { z as
|
|
6033
|
+
import { z as z16 } from "zod";
|
|
6074
6034
|
var IMAGE_GENERATE_MODELS2 = [
|
|
6075
6035
|
"openai/gpt-5.4-image-2",
|
|
6076
6036
|
"google/gemini-3.5-flash",
|
|
@@ -6078,16 +6038,16 @@ var IMAGE_GENERATE_MODELS2 = [
|
|
|
6078
6038
|
"google/gemini-3-pro-image-preview",
|
|
6079
6039
|
"recraft/recraft-v4.1-pro-vector"
|
|
6080
6040
|
];
|
|
6081
|
-
var ImageGenerateParams =
|
|
6082
|
-
model:
|
|
6083
|
-
prompt:
|
|
6084
|
-
aspect_ratio:
|
|
6085
|
-
image_size:
|
|
6041
|
+
var ImageGenerateParams = z16.object({
|
|
6042
|
+
model: z16.enum(IMAGE_GENERATE_MODELS2),
|
|
6043
|
+
prompt: z16.string().min(1),
|
|
6044
|
+
aspect_ratio: z16.enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9", "1:4", "4:1", "1:8", "8:1"]).optional(),
|
|
6045
|
+
image_size: z16.enum(["0.5K", "1K", "2K", "4K"]).optional(),
|
|
6086
6046
|
// Recraft v4 vector controls — forwarded into `image_config`. Registry
|
|
6087
6047
|
// rejects them on non-Recraft models.
|
|
6088
|
-
strength:
|
|
6089
|
-
rgb_colors:
|
|
6090
|
-
background_rgb_color:
|
|
6048
|
+
strength: z16.number().min(0).max(1).optional(),
|
|
6049
|
+
rgb_colors: z16.array(z16.array(z16.number().int().min(0).max(255))).optional(),
|
|
6050
|
+
background_rgb_color: z16.array(z16.number().int().min(0).max(255)).optional()
|
|
6091
6051
|
}).strict();
|
|
6092
6052
|
var imageGenerateNode = delegated({
|
|
6093
6053
|
id: "image_generate",
|
|
@@ -6097,22 +6057,22 @@ var imageGenerateNode = delegated({
|
|
|
6097
6057
|
when_to_use: "Use for hero shots, product photography, illustrations, and vector logos. `recraft/recraft-v4.1-pro-vector` for crisp vector / logo work; `openai/gpt-5.4-image-2` for photorealistic; Gemini variants for fast iteration and editing via the `reference` input. `reference` accepts ONE image or an ARRAY of images \u2014 wire several to combine references in a single generation (e.g. a subject sheet + a font specimen + the original ad). Every reference is forwarded to the model in array order.",
|
|
6098
6058
|
// `reference` is one image or an ordered array of images. The backend forwards
|
|
6099
6059
|
// each as a separate `image_url` to the provider (OpenRouter accepts many).
|
|
6100
|
-
inputs:
|
|
6060
|
+
inputs: z16.object({ reference: z16.union([ImageRef, z16.array(ImageRef).min(1)]).optional() }).loose(),
|
|
6101
6061
|
params: ImageGenerateParams,
|
|
6102
|
-
outputs:
|
|
6062
|
+
outputs: z16.object({ images: z16.array(ImageRef).min(1) }).strict(),
|
|
6103
6063
|
outputKinds: { images: "image" },
|
|
6104
6064
|
cost: () => ({ credits: 5, seconds_estimate: 10 })
|
|
6105
6065
|
});
|
|
6106
6066
|
|
|
6107
6067
|
// src/engine/nodes/remote/imageAspectAdapt.ts
|
|
6108
|
-
import { z as
|
|
6068
|
+
import { z as z17 } from "zod";
|
|
6109
6069
|
var ASPECT_ADAPT_MODELS = ["google/gemini-3-pro-image-preview", "google/gemini-3.1-flash-image-preview"];
|
|
6110
6070
|
var ASPECT_ADAPT_FORMATS = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
|
|
6111
|
-
var ImageAspectAdaptParams =
|
|
6112
|
-
model:
|
|
6113
|
-
formats:
|
|
6114
|
-
guidance:
|
|
6115
|
-
image_size:
|
|
6071
|
+
var ImageAspectAdaptParams = z17.object({
|
|
6072
|
+
model: z17.enum(ASPECT_ADAPT_MODELS),
|
|
6073
|
+
formats: z17.array(z17.enum(ASPECT_ADAPT_FORMATS)).min(1).max(6).refine((formats) => new Set(formats).size === formats.length, { message: "formats must be unique" }),
|
|
6074
|
+
guidance: z17.string().min(1).optional(),
|
|
6075
|
+
image_size: z17.enum(["0.5K", "1K", "2K", "4K"]).optional()
|
|
6116
6076
|
}).strict();
|
|
6117
6077
|
var imageAspectAdaptNode = delegated({
|
|
6118
6078
|
id: "image_aspect_adapt",
|
|
@@ -6120,9 +6080,9 @@ var imageAspectAdaptNode = delegated({
|
|
|
6120
6080
|
category: "image",
|
|
6121
6081
|
summary: "Adapt ONE creative into multiple aspect ratios (Meta: 9:16 stories, 1:1 feed, 4:5, 16:9\u2026) in a single step. AI recomposes the layout per format \u2014 identical subject, text, logos, colors, and style; the scene is extended/restructured, never stretched or cropped. Formats that already match the source ratio pass through unchanged at zero cost. Outputs are ordered exactly as `formats`.",
|
|
6122
6082
|
when_to_use: "Use after a hero creative exists (image_generate, ingest, image_search) to fan it out to every placement format \u2014 wire the creative into `source` and list the target ratios in `formats`. Cost is estimated per format; formats matching the source ratio are free pass-throughs. Pick `google/gemini-3.1-flash-image-preview` (Nano Banana flash) while iterating, `google/gemini-3-pro-image-preview` (Nano Banana Pro) for final-quality adaptation.",
|
|
6123
|
-
inputs:
|
|
6083
|
+
inputs: z17.object({ source: ImageRef }).loose(),
|
|
6124
6084
|
params: ImageAspectAdaptParams,
|
|
6125
|
-
outputs:
|
|
6085
|
+
outputs: z17.object({ images: z17.array(ImageRef).min(1) }).strict(),
|
|
6126
6086
|
outputKinds: { images: "image" },
|
|
6127
6087
|
cost: ({ params }) => {
|
|
6128
6088
|
const p = params;
|
|
@@ -6135,12 +6095,12 @@ var imageAspectAdaptNode = delegated({
|
|
|
6135
6095
|
});
|
|
6136
6096
|
|
|
6137
6097
|
// src/engine/nodes/remote/imageBackgroundRemove.ts
|
|
6138
|
-
import { z as
|
|
6139
|
-
var ImageBackgroundRemoveParams =
|
|
6140
|
-
model:
|
|
6141
|
-
model_variant:
|
|
6142
|
-
operating_resolution:
|
|
6143
|
-
mask_only:
|
|
6098
|
+
import { z as z18 } from "zod";
|
|
6099
|
+
var ImageBackgroundRemoveParams = z18.object({
|
|
6100
|
+
model: z18.literal("fal/birefnet-v2").optional().default("fal/birefnet-v2"),
|
|
6101
|
+
model_variant: z18.enum(["General Use (Light)", "General Use (Heavy)", "Matting", "Portrait", "DIS", "HRSOD", "COD"]).optional().default("General Use (Light)"),
|
|
6102
|
+
operating_resolution: z18.enum(["1024x1024", "2048x2048", "2304x2304"]).optional(),
|
|
6103
|
+
mask_only: z18.boolean().optional().default(false)
|
|
6144
6104
|
}).strict();
|
|
6145
6105
|
var imageBackgroundRemoveNode = delegated({
|
|
6146
6106
|
id: "image_background_remove",
|
|
@@ -6148,11 +6108,11 @@ var imageBackgroundRemoveNode = delegated({
|
|
|
6148
6108
|
category: "image",
|
|
6149
6109
|
summary: "Remove the background from an image and return a transparent PNG (or the segmentation mask). Powered by fal.ai `fal-ai/birefnet/v2`.",
|
|
6150
6110
|
when_to_use: "Use to extract subjects from photos for use as overlays in hyperframe compositions, product shots, or compositing pipelines. Set `mask_only:true` to return the binary mask instead of the alpha-cut image.",
|
|
6151
|
-
inputs:
|
|
6111
|
+
inputs: z18.object({
|
|
6152
6112
|
image: ImageRef
|
|
6153
6113
|
}).strict(),
|
|
6154
6114
|
params: ImageBackgroundRemoveParams,
|
|
6155
|
-
outputs:
|
|
6115
|
+
outputs: z18.object({
|
|
6156
6116
|
image: ImageRef,
|
|
6157
6117
|
mask: ImageRef.optional()
|
|
6158
6118
|
}).strict(),
|
|
@@ -6161,7 +6121,7 @@ var imageBackgroundRemoveNode = delegated({
|
|
|
6161
6121
|
});
|
|
6162
6122
|
|
|
6163
6123
|
// src/engine/nodes/remote/imageDescribe.ts
|
|
6164
|
-
import { z as
|
|
6124
|
+
import { z as z19 } from "zod";
|
|
6165
6125
|
var IMAGE_DESCRIBE_MODELS = ["~google/gemini-pro-latest", "~google/gemini-flash-latest"];
|
|
6166
6126
|
var imageDescribeNode = delegated({
|
|
6167
6127
|
id: "image_describe",
|
|
@@ -6169,33 +6129,33 @@ var imageDescribeNode = delegated({
|
|
|
6169
6129
|
category: "vision",
|
|
6170
6130
|
summary: "Reverse-engineer an image into an exhaustive, replication-grade JSON description: who the advertiser is and what they sell (source_context), composition, non-person subjects with expression/treatment, deeply detailed people, brand-identified logos (named by brand, not appearance), camera optics, lighting, color palette WITH per-color brand-ownership (brand vs borrowed-functional) and purpose, materials, visible text, ad signals (proof badges/CTA/price), the persuasion engine (ad_intent), style, post-processing.",
|
|
6171
6131
|
when_to_use: 'Use to turn a reference image into a structured blueprint you can inject into downstream prompts via `{{slot}}` \u2014 e.g. restyle a competitor ad onto your own product, lock a look across a series, or feed exact palette/lighting into image_generate. Purpose-built for market adaptation: logos are identified by brand ("Trustpilot", never "green star"), people and animals carry expression/emotion/intent detail, and each color is tagged brand vs borrowed-functional so a recolor can keep the reds/yellows that do a job. The extraction prompt is baked in; use `focus` to emphasise aspects and `context` to pass known provenance (advertiser, category, market) so source_context and color ownership are grounded. Pick `~google/gemini-pro-latest` for the densest extraction (recommended for ad / market-adaptation passes), `~google/gemini-flash-latest` for cheap/fast passes. The output is rich \u2014 raise `max_tokens` (e.g. 8000+) for dense ads so the JSON isn\'t truncated.',
|
|
6172
|
-
inputs:
|
|
6173
|
-
params:
|
|
6174
|
-
model:
|
|
6175
|
-
focus:
|
|
6176
|
-
context:
|
|
6177
|
-
temperature:
|
|
6178
|
-
max_tokens:
|
|
6132
|
+
inputs: z19.object({ image: ImageRef }).loose(),
|
|
6133
|
+
params: z19.object({
|
|
6134
|
+
model: z19.enum(IMAGE_DESCRIBE_MODELS),
|
|
6135
|
+
focus: z19.string().optional(),
|
|
6136
|
+
context: z19.string().optional(),
|
|
6137
|
+
temperature: z19.number().min(0).max(2).optional(),
|
|
6138
|
+
max_tokens: z19.number().int().positive().optional()
|
|
6179
6139
|
}).strict(),
|
|
6180
|
-
outputs:
|
|
6140
|
+
outputs: z19.object({ description: JsonRef }).strict(),
|
|
6181
6141
|
outputKinds: { description: "json" },
|
|
6182
6142
|
cost: () => ({ credits: 2, seconds_estimate: 10 })
|
|
6183
6143
|
});
|
|
6184
6144
|
|
|
6185
6145
|
// src/engine/nodes/remote/imageReferenceSheet.ts
|
|
6186
|
-
import { z as
|
|
6146
|
+
import { z as z20 } from "zod";
|
|
6187
6147
|
var REFERENCE_SHEET_MODELS = ["google/gemini-3-pro-image-preview", "google/gemini-3.1-flash-image-preview"];
|
|
6188
|
-
var ImageReferenceSheetParams =
|
|
6189
|
-
model:
|
|
6190
|
-
subject_description:
|
|
6148
|
+
var ImageReferenceSheetParams = z20.object({
|
|
6149
|
+
model: z20.enum(REFERENCE_SHEET_MODELS),
|
|
6150
|
+
subject_description: z20.string().min(1),
|
|
6191
6151
|
// `location` = a set/room shown from several camera ANGLES (not a rotated subject),
|
|
6192
6152
|
// so a multi-scene shoot keeps one consistent set.
|
|
6193
|
-
subject_type:
|
|
6194
|
-
views:
|
|
6195
|
-
style:
|
|
6196
|
-
prompt_override:
|
|
6197
|
-
aspect_ratio:
|
|
6198
|
-
image_size:
|
|
6153
|
+
subject_type: z20.enum(["character", "person", "product", "location"]),
|
|
6154
|
+
views: z20.array(z20.string().min(1)).min(2).max(8).optional(),
|
|
6155
|
+
style: z20.string().optional(),
|
|
6156
|
+
prompt_override: z20.string().min(1).optional(),
|
|
6157
|
+
aspect_ratio: z20.enum(["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9", "1:4", "4:1", "1:8", "8:1"]).optional(),
|
|
6158
|
+
image_size: z20.enum(["0.5K", "1K", "2K", "4K"]).optional()
|
|
6199
6159
|
}).strict();
|
|
6200
6160
|
var imageReferenceSheetNode = delegated({
|
|
6201
6161
|
id: "image_reference_sheet",
|
|
@@ -6203,9 +6163,9 @@ var imageReferenceSheetNode = delegated({
|
|
|
6203
6163
|
category: "image",
|
|
6204
6164
|
summary: "Fuse 1\u20136 images of a single subject (person, character, product, or location/set) into ONE multi-view reference sheet \u2014 a labeled grid in consistent style and lighting: a turnaround (FRONT / SIDE / BACK\u2026) for a person/character/product, or several camera angles of the same room (WIDE / REVERSE / DETAIL\u2026) for a location. Curated models: Gemini 3 Pro Image (best fusion + labels), Gemini 3.1 Flash Image (cheap iteration).",
|
|
6205
6165
|
when_to_use: "Use before image_generate / video_generate when a subject must stay consistent across many creatives \u2014 wire the `sheet` output into their `reference` input instead of re-describing the subject per prompt. `subject_description` should be the exact wording you reuse downstream. Pick `google/gemini-3-pro-image-preview` for final 6-view sheets at 2K+, `google/gemini-3.1-flash-image-preview` while iterating.",
|
|
6206
|
-
inputs:
|
|
6166
|
+
inputs: z20.object({ references: z20.array(ImageRef).min(1).max(6) }).loose(),
|
|
6207
6167
|
params: ImageReferenceSheetParams,
|
|
6208
|
-
outputs:
|
|
6168
|
+
outputs: z20.object({ sheet: ImageRef }).strict(),
|
|
6209
6169
|
outputKinds: { sheet: "image" },
|
|
6210
6170
|
cost: ({ params }) => ({
|
|
6211
6171
|
credits: params?.model === "google/gemini-3-pro-image-preview" ? 20 : 5,
|
|
@@ -6214,10 +6174,10 @@ var imageReferenceSheetNode = delegated({
|
|
|
6214
6174
|
});
|
|
6215
6175
|
|
|
6216
6176
|
// src/engine/nodes/remote/imageSearch.ts
|
|
6217
|
-
import { z as
|
|
6218
|
-
var ImageSearchParams =
|
|
6219
|
-
prompt:
|
|
6220
|
-
count:
|
|
6177
|
+
import { z as z21 } from "zod";
|
|
6178
|
+
var ImageSearchParams = z21.object({
|
|
6179
|
+
prompt: z21.string().min(1),
|
|
6180
|
+
count: z21.number().int().min(1).max(20).default(5)
|
|
6221
6181
|
}).strict();
|
|
6222
6182
|
var imageSearchNode = delegated({
|
|
6223
6183
|
id: "image_search",
|
|
@@ -6225,15 +6185,15 @@ var imageSearchNode = delegated({
|
|
|
6225
6185
|
category: "image",
|
|
6226
6186
|
summary: "Agentic image search across Google Images, stock photography (Freepik), and Pinterest. An LLM agent picks the search tools and queries, selects the best matches, and the results are downloaded into canvas assets.",
|
|
6227
6187
|
when_to_use: "Use to gather real-world reference or inspiration images for a prompt (e.g. several photos of an australian shepherd) so a later step or the user can pick the best one. Not for creating new imagery \u2014 use image_generate for that.",
|
|
6228
|
-
inputs:
|
|
6188
|
+
inputs: z21.object({}).loose(),
|
|
6229
6189
|
params: ImageSearchParams,
|
|
6230
|
-
outputs:
|
|
6190
|
+
outputs: z21.object({ images: z21.array(ImageRef).min(1) }).strict(),
|
|
6231
6191
|
outputKinds: { images: "image" },
|
|
6232
6192
|
cost: ({ params }) => ({ credits: Math.ceil(2 + params.count / 2), seconds_estimate: 30 })
|
|
6233
6193
|
});
|
|
6234
6194
|
|
|
6235
6195
|
// src/engine/nodes/remote/imageSelect.ts
|
|
6236
|
-
import { z as
|
|
6196
|
+
import { z as z22 } from "zod";
|
|
6237
6197
|
var IMAGE_SELECT_MODELS = ["~google/gemini-flash-latest", "~google/gemini-pro-latest"];
|
|
6238
6198
|
var imageSelectNode = delegated({
|
|
6239
6199
|
id: "image_select",
|
|
@@ -6241,15 +6201,15 @@ var imageSelectNode = delegated({
|
|
|
6241
6201
|
category: "vision",
|
|
6242
6202
|
summary: "Pick the best `count` images out of 2+ candidates with a vision LLM, judged against a prompt. Outputs a passthrough subset of the input refs (no new pixels) plus the model's comparative reasoning.",
|
|
6243
6203
|
when_to_use: "Use after fanning out several image_generate variants (or any pool of 2+ images) to keep only the strongest before expensive downstream steps \u2014 video generation, reference sheets, final delivery. `count` fixes the output size, so `images#0`\u2026`images#count-1` are always safe to wire. Pick `~google/gemini-flash-latest` for cheap/fast picks and `~google/gemini-pro-latest` for harder aesthetic judgement.",
|
|
6244
|
-
inputs:
|
|
6245
|
-
params:
|
|
6246
|
-
model:
|
|
6247
|
-
prompt:
|
|
6248
|
-
count:
|
|
6249
|
-
temperature:
|
|
6250
|
-
max_tokens:
|
|
6204
|
+
inputs: z22.object({ images: z22.array(ImageRef).min(2) }).loose(),
|
|
6205
|
+
params: z22.object({
|
|
6206
|
+
model: z22.enum(IMAGE_SELECT_MODELS),
|
|
6207
|
+
prompt: z22.string().min(1),
|
|
6208
|
+
count: z22.number().int().min(1).default(1),
|
|
6209
|
+
temperature: z22.number().min(0).max(2).optional(),
|
|
6210
|
+
max_tokens: z22.number().int().positive().optional()
|
|
6251
6211
|
}).strict(),
|
|
6252
|
-
outputs:
|
|
6212
|
+
outputs: z22.object({ images: z22.array(ImageRef).min(1), reasoning: TextRef }).strict(),
|
|
6253
6213
|
outputKinds: { images: "image", reasoning: "text" },
|
|
6254
6214
|
cost: () => ({ credits: 1, seconds_estimate: 5 }),
|
|
6255
6215
|
// Arity is only knowable at validate time when `images` is a literal array
|
|
@@ -6274,34 +6234,34 @@ var imageSelectNode = delegated({
|
|
|
6274
6234
|
});
|
|
6275
6235
|
|
|
6276
6236
|
// src/engine/nodes/remote/music.ts
|
|
6277
|
-
import { z as
|
|
6237
|
+
import { z as z23 } from "zod";
|
|
6278
6238
|
var MUSIC_MODELS = ["elevenlabs/music-v1", "elevenlabs/video-background-music-v1"];
|
|
6279
|
-
var MusicParams =
|
|
6280
|
-
model:
|
|
6239
|
+
var MusicParams = z23.object({
|
|
6240
|
+
model: z23.enum(MUSIC_MODELS),
|
|
6281
6241
|
/** Free-form prompt. Used by `elevenlabs/music-v1` (compose-detailed). */
|
|
6282
|
-
prompt:
|
|
6242
|
+
prompt: z23.string().optional(),
|
|
6283
6243
|
/**
|
|
6284
6244
|
* Structured composition plan (intro / hook / verse / outro sections with
|
|
6285
6245
|
* per-section styles + durations). Mutually exclusive with `prompt`.
|
|
6286
6246
|
*/
|
|
6287
|
-
composition_plan:
|
|
6247
|
+
composition_plan: z23.record(z23.string(), z23.unknown()).optional(),
|
|
6288
6248
|
/** Target length when using `prompt`. 3000–454545ms (capped by the $10 per-node cost limit). */
|
|
6289
|
-
music_length_ms:
|
|
6290
|
-
seed:
|
|
6249
|
+
music_length_ms: z23.number().int().min(3e3).max(ELEVENLABS_MAX_MUSIC_LENGTH_MS).optional(),
|
|
6250
|
+
seed: z23.number().int().optional(),
|
|
6291
6251
|
/** Prompt mode only — forces an instrumental (no vocals) track. */
|
|
6292
|
-
force_instrumental:
|
|
6252
|
+
force_instrumental: z23.boolean().optional(),
|
|
6293
6253
|
/** composition_plan only — honor exact section durations. */
|
|
6294
|
-
respect_sections_durations:
|
|
6254
|
+
respect_sections_durations: z23.boolean().optional(),
|
|
6295
6255
|
/** Emit word-level timestamps alongside the audio. */
|
|
6296
|
-
with_timestamps:
|
|
6256
|
+
with_timestamps: z23.boolean().optional(),
|
|
6297
6257
|
/**
|
|
6298
6258
|
* video-to-music only — short description of the desired score
|
|
6299
6259
|
* ("upbeat synth, fast cuts, 80s") used to bias the model.
|
|
6300
6260
|
*/
|
|
6301
|
-
description:
|
|
6261
|
+
description: z23.string().max(1e3).optional(),
|
|
6302
6262
|
/** video-to-music only — up to 10 style tags. */
|
|
6303
|
-
tags:
|
|
6304
|
-
output_format:
|
|
6263
|
+
tags: z23.array(z23.string()).max(10).optional(),
|
|
6264
|
+
output_format: z23.enum(ELEVENLABS_OUTPUT_FORMATS).optional()
|
|
6305
6265
|
}).strict();
|
|
6306
6266
|
var musicNode = delegated({
|
|
6307
6267
|
id: "music",
|
|
@@ -6309,9 +6269,9 @@ var musicNode = delegated({
|
|
|
6309
6269
|
category: "audio",
|
|
6310
6270
|
summary: "Generate music for ad creatives and website video content. `elevenlabs/music-v1` composes from a text prompt or structured composition plan; `elevenlabs/video-background-music-v1` scores an existing video clip provided via `inputs.video`.",
|
|
6311
6271
|
when_to_use: "Use to produce background music or a full score for video ads, hero-section reels, or any motion content. Prefer the video-to-music model when you already have a cut and want music timed to it; use compose-detailed when you have only a brief or want section-level control (intro / hook / outro). Pair the resulting audio with `video_generate` or `video_lipsync` at compose time.",
|
|
6312
|
-
inputs:
|
|
6272
|
+
inputs: z23.object({ video: VideoRef.optional() }).loose(),
|
|
6313
6273
|
params: MusicParams,
|
|
6314
|
-
outputs:
|
|
6274
|
+
outputs: z23.object({ audio: AudioRef, timestamps: JsonRef.optional() }).strict(),
|
|
6315
6275
|
outputKinds: { audio: "audio", timestamps: "json" },
|
|
6316
6276
|
cost: ({ params }) => {
|
|
6317
6277
|
const seconds = params.music_length_ms ? Math.ceil(params.music_length_ms / 1e3) : 30;
|
|
@@ -6342,25 +6302,25 @@ var musicNode = delegated({
|
|
|
6342
6302
|
});
|
|
6343
6303
|
|
|
6344
6304
|
// src/engine/nodes/remote/soundEffect.ts
|
|
6345
|
-
import { z as
|
|
6305
|
+
import { z as z24 } from "zod";
|
|
6346
6306
|
var SOUND_EFFECT_MODELS = ["elevenlabs/eleven_text_to_sound_v2"];
|
|
6347
|
-
var SoundEffectParams =
|
|
6348
|
-
model:
|
|
6307
|
+
var SoundEffectParams = z24.object({
|
|
6308
|
+
model: z24.enum(SOUND_EFFECT_MODELS),
|
|
6349
6309
|
/** Prompt describing the SFX ("metal door slam", "soft UI tap", "ocean waves"). */
|
|
6350
|
-
text:
|
|
6310
|
+
text: z24.string().min(1),
|
|
6351
6311
|
/**
|
|
6352
6312
|
* Target length in seconds. 0.5–30. Leave unset to let the model pick the
|
|
6353
6313
|
* natural length for the described effect.
|
|
6354
6314
|
*/
|
|
6355
|
-
duration_seconds:
|
|
6315
|
+
duration_seconds: z24.number().min(0.5).max(30).optional(),
|
|
6356
6316
|
/**
|
|
6357
6317
|
* 0–1. Higher = stick closer to the prompt at the cost of variety; lower
|
|
6358
6318
|
* = let the model interpret more freely. Defaults to 0.3 on the provider.
|
|
6359
6319
|
*/
|
|
6360
|
-
prompt_influence:
|
|
6320
|
+
prompt_influence: z24.number().min(0).max(1).optional(),
|
|
6361
6321
|
/** Only valid on `eleven_text_to_sound_v2` — produce a seamless loop. */
|
|
6362
|
-
loop:
|
|
6363
|
-
output_format:
|
|
6322
|
+
loop: z24.boolean().optional(),
|
|
6323
|
+
output_format: z24.enum(ELEVENLABS_OUTPUT_FORMATS).optional()
|
|
6364
6324
|
}).strict();
|
|
6365
6325
|
var soundEffectNode = delegated({
|
|
6366
6326
|
id: "sound_effect",
|
|
@@ -6368,9 +6328,9 @@ var soundEffectNode = delegated({
|
|
|
6368
6328
|
category: "audio",
|
|
6369
6329
|
summary: "Generate short sound effects from a text prompt via ElevenLabs Text-to-Sound. Use for whooshes, impacts, UI clicks, ambient beds, or signature stingers in ad creatives and product videos.",
|
|
6370
6330
|
when_to_use: "Reach for this when you need a punch-in SFX layered against `video_generate` or `hyperframe_render` output \u2014 e.g. a logo whoosh on a hero shot, a click on a CTA cut, a swelling ambient bed under VO. Set `loop: true` for atmospheric beds that need to tile under longer footage; leave `duration_seconds` unset and the model picks a natural length.",
|
|
6371
|
-
inputs:
|
|
6331
|
+
inputs: z24.object({}).loose(),
|
|
6372
6332
|
params: SoundEffectParams,
|
|
6373
|
-
outputs:
|
|
6333
|
+
outputs: z24.object({ audio: AudioRef }).strict(),
|
|
6374
6334
|
outputKinds: { audio: "audio" },
|
|
6375
6335
|
cost: ({ params }) => {
|
|
6376
6336
|
const seconds = params.duration_seconds ?? 5;
|
|
@@ -6379,7 +6339,7 @@ var soundEffectNode = delegated({
|
|
|
6379
6339
|
});
|
|
6380
6340
|
|
|
6381
6341
|
// src/engine/nodes/remote/textGenerate.ts
|
|
6382
|
-
import { z as
|
|
6342
|
+
import { z as z25 } from "zod";
|
|
6383
6343
|
var TEXT_GENERATE_MODELS = ["~google/gemini-flash-latest", "~google/gemini-pro-latest"];
|
|
6384
6344
|
var textGenerateNode = delegated({
|
|
6385
6345
|
id: "text_generate",
|
|
@@ -6387,58 +6347,58 @@ var textGenerateNode = delegated({
|
|
|
6387
6347
|
category: "language",
|
|
6388
6348
|
summary: "Single-turn LLM text generation via OpenRouter. Returns a text response.",
|
|
6389
6349
|
when_to_use: 'Use for any short text generation step in a canvas \u2014 ad copy, hooks, headlines, JSON outputs for downstream nodes. Pick `~google/gemini-flash-latest` for cheap/fast work and `~google/gemini-pro-latest` for harder reasoning. When the output must be JSON for a downstream `{{slot}}` (e.g. the ad-blueprint transform), set `response_format: "json_object"` so the model returns clean JSON with no markdown fences or prose. Set `web_search: true` to let the model search the live web first (OpenRouter `:online`) \u2014 useful when the transform must adapt copy to the target brand\'s real facts (current pricing, the trust signals it actually has) rather than guess.',
|
|
6390
|
-
inputs:
|
|
6391
|
-
params:
|
|
6392
|
-
model:
|
|
6393
|
-
prompt:
|
|
6394
|
-
system:
|
|
6395
|
-
response_format:
|
|
6396
|
-
web_search:
|
|
6397
|
-
temperature:
|
|
6398
|
-
max_tokens:
|
|
6350
|
+
inputs: z25.object({}).loose(),
|
|
6351
|
+
params: z25.object({
|
|
6352
|
+
model: z25.enum(TEXT_GENERATE_MODELS),
|
|
6353
|
+
prompt: z25.string().min(1),
|
|
6354
|
+
system: z25.string().optional(),
|
|
6355
|
+
response_format: z25.enum(["text", "json_object"]).optional(),
|
|
6356
|
+
web_search: z25.boolean().optional(),
|
|
6357
|
+
temperature: z25.number().min(0).max(2).optional(),
|
|
6358
|
+
max_tokens: z25.number().int().positive().optional()
|
|
6399
6359
|
}).strict(),
|
|
6400
|
-
outputs:
|
|
6360
|
+
outputs: z25.object({ text: TextRef }).strict(),
|
|
6401
6361
|
outputKinds: { text: "text" },
|
|
6402
6362
|
cost: () => ({ credits: 1, seconds_estimate: 3 })
|
|
6403
6363
|
});
|
|
6404
6364
|
|
|
6405
6365
|
// src/engine/nodes/remote/tts.ts
|
|
6406
|
-
import { z as
|
|
6366
|
+
import { z as z26 } from "zod";
|
|
6407
6367
|
var TTS_MODELS = ["elevenlabs/eleven_v3"];
|
|
6408
|
-
var TtsVoiceSettings =
|
|
6409
|
-
stability:
|
|
6410
|
-
similarity_boost:
|
|
6411
|
-
style:
|
|
6412
|
-
use_speaker_boost:
|
|
6413
|
-
speed:
|
|
6368
|
+
var TtsVoiceSettings = z26.object({
|
|
6369
|
+
stability: z26.number().min(0).max(1).optional(),
|
|
6370
|
+
similarity_boost: z26.number().min(0).max(1).optional(),
|
|
6371
|
+
style: z26.number().min(0).max(1).optional(),
|
|
6372
|
+
use_speaker_boost: z26.boolean().optional(),
|
|
6373
|
+
speed: z26.number().min(0.25).max(4).optional()
|
|
6414
6374
|
}).strict();
|
|
6415
|
-
var TtsPronunciationLocator =
|
|
6416
|
-
pronunciation_dictionary_id:
|
|
6417
|
-
version_id:
|
|
6375
|
+
var TtsPronunciationLocator = z26.object({
|
|
6376
|
+
pronunciation_dictionary_id: z26.string().min(1),
|
|
6377
|
+
version_id: z26.string().nullable().optional()
|
|
6418
6378
|
}).strict();
|
|
6419
|
-
var TtsParams =
|
|
6420
|
-
model:
|
|
6421
|
-
text:
|
|
6422
|
-
voice:
|
|
6379
|
+
var TtsParams = z26.object({
|
|
6380
|
+
model: z26.enum(TTS_MODELS),
|
|
6381
|
+
text: z26.string().min(1).max(ELEVENLABS_MAX_TEXT_CHARS),
|
|
6382
|
+
voice: z26.string().min(1),
|
|
6423
6383
|
/** Provider output_format (mp3 family only — assets are stored as audio/mpeg). */
|
|
6424
|
-
output_format:
|
|
6425
|
-
seed:
|
|
6384
|
+
output_format: z26.enum(ELEVENLABS_OUTPUT_FORMATS).optional(),
|
|
6385
|
+
seed: z26.number().int().min(0).max(4294967295).optional(),
|
|
6426
6386
|
// Top-level shortcuts; structured form is `voice_settings`.
|
|
6427
|
-
stability:
|
|
6428
|
-
similarity_boost:
|
|
6387
|
+
stability: z26.number().min(0).max(1).optional(),
|
|
6388
|
+
similarity_boost: z26.number().min(0).max(1).optional(),
|
|
6429
6389
|
voice_settings: TtsVoiceSettings.optional(),
|
|
6430
6390
|
/** ISO 639-1 language code. eleven_v3 supports language hints. */
|
|
6431
|
-
language_code:
|
|
6432
|
-
pronunciation_dictionary_locators:
|
|
6433
|
-
apply_text_normalization:
|
|
6391
|
+
language_code: z26.string().optional(),
|
|
6392
|
+
pronunciation_dictionary_locators: z26.array(TtsPronunciationLocator).max(3).optional(),
|
|
6393
|
+
apply_text_normalization: z26.enum(["auto", "on", "off"]).optional(),
|
|
6434
6394
|
/** Currently Japanese-only. Adds latency. */
|
|
6435
|
-
apply_language_text_normalization:
|
|
6395
|
+
apply_language_text_normalization: z26.boolean().optional(),
|
|
6436
6396
|
/**
|
|
6437
6397
|
* When true, hits `/v1/text-to-speech/{voice_id}/with-timestamps` and
|
|
6438
6398
|
* adds a `timestamps` output (character-level alignment) for caption
|
|
6439
6399
|
* rendering, lipsync, and beat-matched cuts.
|
|
6440
6400
|
*/
|
|
6441
|
-
with_timestamps:
|
|
6401
|
+
with_timestamps: z26.boolean().optional()
|
|
6442
6402
|
}).strict();
|
|
6443
6403
|
var ttsNode = delegated({
|
|
6444
6404
|
id: "tts",
|
|
@@ -6446,9 +6406,9 @@ var ttsNode = delegated({
|
|
|
6446
6406
|
category: "audio",
|
|
6447
6407
|
summary: "Single-voice text-to-speech via ElevenLabs Eleven v3. Optional character-level timestamps for caption rendering and beat-matched cuts.",
|
|
6448
6408
|
when_to_use: "Use for single-speaker VO \u2014 ad reads, hero-section narration, product walkthroughs. Reach for `dialogue` when you need multiple voices in one stitched track. Set `with_timestamps: true` when downstream needs character-level alignment (captions, lipsync).",
|
|
6449
|
-
inputs:
|
|
6409
|
+
inputs: z26.object({}).loose(),
|
|
6450
6410
|
params: TtsParams,
|
|
6451
|
-
outputs:
|
|
6411
|
+
outputs: z26.object({ audio: AudioRef, timestamps: JsonRef.optional() }).strict(),
|
|
6452
6412
|
outputKinds: { audio: "audio", timestamps: "json" },
|
|
6453
6413
|
cost: ({ params }) => ({
|
|
6454
6414
|
credits: Math.max(1, Math.ceil(params.text.length * 15e-4)),
|
|
@@ -6457,23 +6417,23 @@ var ttsNode = delegated({
|
|
|
6457
6417
|
});
|
|
6458
6418
|
|
|
6459
6419
|
// src/engine/nodes/remote/video.ts
|
|
6460
|
-
import { z as
|
|
6420
|
+
import { z as z27 } from "zod";
|
|
6461
6421
|
var VIDEO_GENERATE_MODELS = ["bytedance/seedance-2.0", "google/veo-3.1-fast"];
|
|
6462
|
-
var VideoGenerateParams =
|
|
6463
|
-
model:
|
|
6464
|
-
prompt:
|
|
6465
|
-
duration:
|
|
6466
|
-
resolution:
|
|
6422
|
+
var VideoGenerateParams = z27.object({
|
|
6423
|
+
model: z27.enum(VIDEO_GENERATE_MODELS),
|
|
6424
|
+
prompt: z27.string().min(1),
|
|
6425
|
+
duration: z27.number().int().positive().optional(),
|
|
6426
|
+
resolution: z27.string().optional(),
|
|
6467
6427
|
// Union of ratios accepted by at least one curated model (registry gates
|
|
6468
6428
|
// per-model). 3:2/2:3 are deliberately absent: no registered model takes them.
|
|
6469
|
-
aspect_ratio:
|
|
6470
|
-
generate_audio:
|
|
6471
|
-
seed:
|
|
6429
|
+
aspect_ratio: z27.enum(["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "9:21"]).optional(),
|
|
6430
|
+
generate_audio: z27.boolean().optional(),
|
|
6431
|
+
seed: z27.number().int().nonnegative().optional(),
|
|
6472
6432
|
// Veo-only passthroughs (routed via `provider.options.google-vertex.parameters`).
|
|
6473
|
-
negative_prompt:
|
|
6474
|
-
person_generation:
|
|
6475
|
-
enhance_prompt:
|
|
6476
|
-
conditioning_scale:
|
|
6433
|
+
negative_prompt: z27.string().optional(),
|
|
6434
|
+
person_generation: z27.string().optional(),
|
|
6435
|
+
enhance_prompt: z27.boolean().optional(),
|
|
6436
|
+
conditioning_scale: z27.number().optional()
|
|
6477
6437
|
}).strict();
|
|
6478
6438
|
var videoGenerateNode = delegated({
|
|
6479
6439
|
id: "video_generate",
|
|
@@ -6481,23 +6441,23 @@ var videoGenerateNode = delegated({
|
|
|
6481
6441
|
category: "video",
|
|
6482
6442
|
summary: "Generate video for ad creatives. Two curated models: `bytedance/seedance-2.0` (production quality, photorealistic humans via fal.ai) and `google/veo-3.1-fast` (cheap/fast for iteration and tests). Async with polling.",
|
|
6483
6443
|
when_to_use: "Use `bytedance/seedance-2.0` for final ad output (photoreal subjects, image-to-video with first/last frames). Use `google/veo-3.1-fast` while iterating to keep cost low. Each model has different supported durations, resolutions, and aspect ratios \u2014 see the README per-model section.",
|
|
6484
|
-
inputs:
|
|
6444
|
+
inputs: z27.object({
|
|
6485
6445
|
first_frame: ImageRef.optional(),
|
|
6486
6446
|
last_frame: ImageRef.optional(),
|
|
6487
6447
|
reference: ImageRef.optional()
|
|
6488
6448
|
}).loose(),
|
|
6489
6449
|
params: VideoGenerateParams,
|
|
6490
|
-
outputs:
|
|
6450
|
+
outputs: z27.object({ video: VideoRef }).strict(),
|
|
6491
6451
|
outputKinds: { video: "video" },
|
|
6492
6452
|
cost: () => ({ credits: 50, seconds_estimate: 120 })
|
|
6493
6453
|
});
|
|
6494
6454
|
|
|
6495
6455
|
// src/engine/nodes/remote/videoBackgroundRemove.ts
|
|
6496
|
-
import { z as
|
|
6497
|
-
var VideoBackgroundRemoveParams =
|
|
6498
|
-
model:
|
|
6499
|
-
edge_refinement:
|
|
6500
|
-
output_codec:
|
|
6456
|
+
import { z as z28 } from "zod";
|
|
6457
|
+
var VideoBackgroundRemoveParams = z28.object({
|
|
6458
|
+
model: z28.literal("fal/veed-video-background-removal").optional().default("fal/veed-video-background-removal"),
|
|
6459
|
+
edge_refinement: z28.boolean().optional().default(true),
|
|
6460
|
+
output_codec: z28.enum(["vp9", "h264"]).optional().default("vp9")
|
|
6501
6461
|
}).strict();
|
|
6502
6462
|
var videoBackgroundRemoveNode = delegated({
|
|
6503
6463
|
id: "video_background_remove",
|
|
@@ -6505,18 +6465,18 @@ var videoBackgroundRemoveNode = delegated({
|
|
|
6505
6465
|
category: "video",
|
|
6506
6466
|
summary: "Remove the background from a video and return a transparent VP9-with-alpha WebM (or H264 RGB+alpha pair). Drops directly into a hyperframe composition as `<video src='...'>` for chroma-keyed picture-in-picture overlays. Powered by fal.ai `veed/video-background-removal/fast`.",
|
|
6507
6467
|
when_to_use: "Use when you need a talking-head or subject to float over a custom background in a hyperframe composition. Pair with hyperframe_render(composition: screencast-with-talker) for screencast-with-narrator videos. Output is `video/webm` with alpha \u2014 feed straight into `<video src>` in a composition.",
|
|
6508
|
-
inputs:
|
|
6468
|
+
inputs: z28.object({
|
|
6509
6469
|
video: VideoRef
|
|
6510
6470
|
}).strict(),
|
|
6511
6471
|
params: VideoBackgroundRemoveParams,
|
|
6512
|
-
outputs:
|
|
6472
|
+
outputs: z28.object({ video: VideoRef }).strict(),
|
|
6513
6473
|
outputKinds: { video: "video" },
|
|
6514
6474
|
// $0.012 per 30 frames (edge refinement on) — assume ~30fps; refine via fal dashboard.
|
|
6515
6475
|
cost: () => ({ credits: 50, seconds_estimate: 60 })
|
|
6516
6476
|
});
|
|
6517
6477
|
|
|
6518
6478
|
// src/engine/nodes/remote/videoDeconstruct.ts
|
|
6519
|
-
import { z as
|
|
6479
|
+
import { z as z29 } from "zod";
|
|
6520
6480
|
var VIDEO_DECONSTRUCT_MODELS = ["~google/gemini-flash-latest", "~google/gemini-pro-latest"];
|
|
6521
6481
|
var videoDeconstructNode = delegated({
|
|
6522
6482
|
id: "video_deconstruct",
|
|
@@ -6524,34 +6484,34 @@ var videoDeconstructNode = delegated({
|
|
|
6524
6484
|
category: "video",
|
|
6525
6485
|
summary: 'Deconstruct a video into a replication-grade blueprint: scene boundaries, the real start/end frame of every scene (extracted from the video as images), and an exhaustive JSON analysis \u2014 per-scene action detail, camera motion, generation-ready frame/motion prompts, overlay text with full typographic style, floating elements, deeply detailed cast (perceived demographics, ethnicity/skin-tone, styling, market-recasting notes), brand-identified logos (named by brand and what they signal, not by appearance, with on-screen timestamps), dialogue with voice descriptions, music spec, SFX list, plus a word-level transcript. `mode:"index"` is the cheap structure-first pass: scene boundaries + global blueprint only (one LLM call, no frames).',
|
|
6526
6486
|
when_to_use: 'Use to reverse-engineer a reference video (e.g. a competitor ad) so a new canvas can reproduce or remix it scene by scene. Agent loop: (1) optionally run `mode:"index"` to see the structure cheaply (scene count, boundaries, transcript) before planning; (2) run the full deconstruct; (3) read `analysis` and author the reproduction canvas. The blueprint maps 1:1 onto generation nodes: `analysis.scenes[i]` aligns positionally with `start_frames#i`/`end_frames#i`; per scene, `start_frame_prompt`/`end_frame_prompt` feed image_generate (overlay text is excluded from them by contract \u2014 recomposite it from `overlays`), `motion_prompt` + the two frames feed video_generate (first_frame/last_frame), `dialogue[].voice_description` casts tts/dialogue voices, `global.music.music_prompt` feeds music, `sfx[].sound_effect_prompt` feeds sound_effect, and `overlays`/`floating_elements` drive an ffmpeg/hyperframe overlay pass. Long videos (over ~8 min single-shot): run `mode:"index"` first, then several full nodes IN PARALLEL each with a `start_s`/`end_s` window (\u2264480s, snap edges to index scene boundaries), and merge by concatenating `analysis.scenes`; over-length errors include suggested windows. Inject fields into downstream prompts via `{{slot}}`. Pick `~google/gemini-pro-latest` for the densest extraction, `~google/gemini-flash-latest` for cheap/fast passes.',
|
|
6527
|
-
inputs:
|
|
6528
|
-
params:
|
|
6529
|
-
model:
|
|
6530
|
-
mode:
|
|
6531
|
-
language:
|
|
6532
|
-
max_scenes:
|
|
6533
|
-
focus:
|
|
6534
|
-
start_s:
|
|
6535
|
-
end_s:
|
|
6487
|
+
inputs: z29.object({ video: VideoRef }).loose(),
|
|
6488
|
+
params: z29.object({
|
|
6489
|
+
model: z29.enum(VIDEO_DECONSTRUCT_MODELS),
|
|
6490
|
+
mode: z29.enum(["full", "index"]).optional(),
|
|
6491
|
+
language: z29.string().min(2).max(8).optional(),
|
|
6492
|
+
max_scenes: z29.number().int().min(1).max(60).optional(),
|
|
6493
|
+
focus: z29.string().optional(),
|
|
6494
|
+
start_s: z29.number().min(0).optional(),
|
|
6495
|
+
end_s: z29.number().positive().optional(),
|
|
6536
6496
|
// Real visual shot-cut timestamps (absolute seconds), detected locally with
|
|
6537
6497
|
// ffmpeg before the deconstruct. The backend SNAPS its LLM scene boundaries
|
|
6538
6498
|
// onto these and SPLITS any scene that spans one, so a scene's frames never
|
|
6539
6499
|
// straddle a hard cut. `scaffold-video` populates this; omit for LLM-only cuts.
|
|
6540
|
-
shot_cuts:
|
|
6500
|
+
shot_cuts: z29.array(z29.number().min(0)).max(200).optional(),
|
|
6541
6501
|
// The video model's per-clip ceiling (seconds). A shot longer than this is
|
|
6542
6502
|
// split into seamless continuation sub-scenes (shared splice frame), so long
|
|
6543
6503
|
// shots reproduce in full instead of being truncated. `scaffold-video` sets
|
|
6544
6504
|
// the Seedance ceiling (15); omit to disable length splitting.
|
|
6545
|
-
max_clip_s:
|
|
6505
|
+
max_clip_s: z29.number().positive().max(60).optional(),
|
|
6546
6506
|
// Transcript provider for the blueprint's dialogue/transcript. Default
|
|
6547
6507
|
// Groq Whisper; "deepgram" routes to Nova-3 so words carry punctuation.
|
|
6548
|
-
transcriber:
|
|
6508
|
+
transcriber: z29.enum(["groq", "deepgram"]).optional()
|
|
6549
6509
|
}).strict(),
|
|
6550
|
-
outputs:
|
|
6510
|
+
outputs: z29.object({
|
|
6551
6511
|
analysis: JsonRef,
|
|
6552
6512
|
// Absent in mode:"index" (structure only, no Mux frame extraction).
|
|
6553
|
-
start_frames:
|
|
6554
|
-
end_frames:
|
|
6513
|
+
start_frames: z29.array(ImageRef).min(1).optional(),
|
|
6514
|
+
end_frames: z29.array(ImageRef).min(1).optional(),
|
|
6555
6515
|
transcript: JsonRef
|
|
6556
6516
|
}).strict(),
|
|
6557
6517
|
outputKinds: { analysis: "json", start_frames: "image", end_frames: "image", transcript: "json" },
|
|
@@ -6559,22 +6519,22 @@ var videoDeconstructNode = delegated({
|
|
|
6559
6519
|
});
|
|
6560
6520
|
|
|
6561
6521
|
// src/engine/nodes/remote/videoLipsync.ts
|
|
6562
|
-
import { z as
|
|
6563
|
-
var FalLipsyncParams =
|
|
6564
|
-
model:
|
|
6522
|
+
import { z as z30 } from "zod";
|
|
6523
|
+
var FalLipsyncParams = z30.object({
|
|
6524
|
+
model: z30.literal("fal/veed-lipsync")
|
|
6565
6525
|
}).strict();
|
|
6566
|
-
var VideoLipsyncParams =
|
|
6526
|
+
var VideoLipsyncParams = z30.discriminatedUnion("model", [FalLipsyncParams]);
|
|
6567
6527
|
var videoLipsyncNode = delegated({
|
|
6568
6528
|
id: "video_lipsync",
|
|
6569
6529
|
version: "1.0.0",
|
|
6570
6530
|
category: "video",
|
|
6571
6531
|
summary: "Lip-sync a video to an audio track. Currently backed by VEED via fal.ai (`fal/veed-lipsync`). $0.40/min of output.",
|
|
6572
|
-
inputs:
|
|
6532
|
+
inputs: z30.object({
|
|
6573
6533
|
video: VideoRef,
|
|
6574
6534
|
audio: AudioRef
|
|
6575
6535
|
}).strict(),
|
|
6576
6536
|
params: VideoLipsyncParams,
|
|
6577
|
-
outputs:
|
|
6537
|
+
outputs: z30.object({ video: VideoRef }).strict(),
|
|
6578
6538
|
outputKinds: { video: "video" },
|
|
6579
6539
|
cost: () => ({ credits: 20, seconds_estimate: 120 })
|
|
6580
6540
|
});
|
|
@@ -6583,7 +6543,7 @@ var videoLipsyncNode = delegated({
|
|
|
6583
6543
|
import { mkdtemp as mkdtemp6, readFile as readFile10, rm as rm6 } from "fs/promises";
|
|
6584
6544
|
import { tmpdir as tmpdir6 } from "os";
|
|
6585
6545
|
import path13 from "path";
|
|
6586
|
-
import { z as
|
|
6546
|
+
import { z as z31 } from "zod";
|
|
6587
6547
|
|
|
6588
6548
|
// src/engine/nodes/local/lib/ffmpeg.ts
|
|
6589
6549
|
import { execFile as execFile7 } from "child_process";
|
|
@@ -6662,21 +6622,21 @@ ${detail.slice(-4e3)}`);
|
|
|
6662
6622
|
}
|
|
6663
6623
|
|
|
6664
6624
|
// src/engine/nodes/remote/videoTranscribe.ts
|
|
6665
|
-
var VideoTranscribeParams =
|
|
6666
|
-
language:
|
|
6625
|
+
var VideoTranscribeParams = z31.object({
|
|
6626
|
+
language: z31.string().min(2).max(8).optional(),
|
|
6667
6627
|
// Provider choice is explicit (no env-based silent branching). Default Groq
|
|
6668
6628
|
// Whisper; "deepgram" routes to Deepgram Nova-3, which additionally emits a
|
|
6669
6629
|
// `rich` JSON output with punctuated words + paragraph/sentence grouping.
|
|
6670
|
-
transcriber:
|
|
6630
|
+
transcriber: z31.enum(["groq", "deepgram"]).optional()
|
|
6671
6631
|
}).strict();
|
|
6672
|
-
var VideoTranscribeInputs =
|
|
6632
|
+
var VideoTranscribeInputs = z31.object({
|
|
6673
6633
|
video: VideoRef
|
|
6674
6634
|
}).strict();
|
|
6675
|
-
var VideoTranscribeOutputs =
|
|
6676
|
-
transcript:
|
|
6635
|
+
var VideoTranscribeOutputs = z31.object({
|
|
6636
|
+
transcript: z31.custom(),
|
|
6677
6637
|
// Only emitted by the Deepgram path: full punctuated words + paragraph /
|
|
6678
6638
|
// sentence grouping with speaker indices. Absent for the default Groq path.
|
|
6679
|
-
rich:
|
|
6639
|
+
rich: z31.custom().optional()
|
|
6680
6640
|
}).strict();
|
|
6681
6641
|
var AUDIO_EXTRACT_TIMEOUT_MS = 6e4;
|
|
6682
6642
|
var videoTranscribeNode = defineNode({
|
|
@@ -6761,29 +6721,29 @@ async function tryExtractAudio(inputs, ctx) {
|
|
|
6761
6721
|
}
|
|
6762
6722
|
|
|
6763
6723
|
// src/engine/nodes/remote/voiceSelect.ts
|
|
6764
|
-
import { z as
|
|
6724
|
+
import { z as z32 } from "zod";
|
|
6765
6725
|
var voiceSelectNode = delegated({
|
|
6766
6726
|
id: "voice_select",
|
|
6767
6727
|
version: "1.0.0",
|
|
6768
6728
|
category: "audio",
|
|
6769
6729
|
summary: 'Cast an ElevenLabs voice from a natural-language description (e.g. "warm, authoritative female narrator, American accent"). Lists the account\'s voices and ranks them against the brief, emitting the best `voice_id` as a bare-string text asset plus a ranked `candidates` JSON.',
|
|
6770
6730
|
when_to_use: 'Use to turn a voice description (e.g. from a `video_deconstruct` blueprint\'s `voice_description`) into a usable ElevenLabs voice id, then feed it into a `tts` node by wiring `inputs.voice_ref: $ref:<this>.voice_id` and setting `params.voice: "{{voice_ref}}"` \u2014 the engine splices the id in at run time. Review `candidates` (json) to pick a different voice. Optional `gender`/`age`/`accent`/`language` hints sharpen the ranking.',
|
|
6771
|
-
inputs:
|
|
6772
|
-
params:
|
|
6773
|
-
description:
|
|
6774
|
-
gender:
|
|
6775
|
-
age:
|
|
6776
|
-
accent:
|
|
6777
|
-
language:
|
|
6778
|
-
limit:
|
|
6731
|
+
inputs: z32.object({}).loose(),
|
|
6732
|
+
params: z32.object({
|
|
6733
|
+
description: z32.string().min(1),
|
|
6734
|
+
gender: z32.string().optional(),
|
|
6735
|
+
age: z32.string().optional(),
|
|
6736
|
+
accent: z32.string().optional(),
|
|
6737
|
+
language: z32.string().optional(),
|
|
6738
|
+
limit: z32.number().int().min(1).max(20).optional()
|
|
6779
6739
|
}).strict(),
|
|
6780
|
-
outputs:
|
|
6740
|
+
outputs: z32.object({ voice_id: TextRef, candidates: JsonRef }).strict(),
|
|
6781
6741
|
outputKinds: { voice_id: "text", candidates: "json" },
|
|
6782
6742
|
cost: () => ({ credits: 0, seconds_estimate: 5 })
|
|
6783
6743
|
});
|
|
6784
6744
|
|
|
6785
6745
|
// src/engine/schema/catalog.ts
|
|
6786
|
-
import { z as
|
|
6746
|
+
import { z as z33 } from "zod";
|
|
6787
6747
|
function generateCatalog(registry, opts = {}) {
|
|
6788
6748
|
const entries = registry.all().map((def) => {
|
|
6789
6749
|
const cost = def.cost ? safeCost(def) : void 0;
|
|
@@ -6794,9 +6754,9 @@ function generateCatalog(registry, opts = {}) {
|
|
|
6794
6754
|
summary: def.summary,
|
|
6795
6755
|
when_to_use: def.when_to_use,
|
|
6796
6756
|
location: def.location,
|
|
6797
|
-
inputs:
|
|
6798
|
-
params:
|
|
6799
|
-
outputs:
|
|
6757
|
+
inputs: z33.toJSONSchema(def.inputs, { unrepresentable: "any" }),
|
|
6758
|
+
params: z33.toJSONSchema(def.params, { unrepresentable: "any" }),
|
|
6759
|
+
outputs: z33.toJSONSchema(def.outputs, { unrepresentable: "any" }),
|
|
6800
6760
|
cost_estimate_credits: cost?.credits,
|
|
6801
6761
|
runtime_estimate_seconds: cost?.seconds_estimate
|
|
6802
6762
|
};
|
|
@@ -6873,8 +6833,7 @@ var LOCAL_NODES = [
|
|
|
6873
6833
|
imagemagickNode,
|
|
6874
6834
|
videoTranscribeNode,
|
|
6875
6835
|
fontSpecimenNode,
|
|
6876
|
-
audioTimelineNode
|
|
6877
|
-
collectNode
|
|
6836
|
+
audioTimelineNode
|
|
6878
6837
|
];
|
|
6879
6838
|
var REMOTE_NODES = [
|
|
6880
6839
|
textGenerateNode,
|
|
@@ -6955,4 +6914,4 @@ export {
|
|
|
6955
6914
|
defaultRegistry,
|
|
6956
6915
|
createEngineFromEnv
|
|
6957
6916
|
};
|
|
6958
|
-
//# sourceMappingURL=chunk-
|
|
6917
|
+
//# sourceMappingURL=chunk-43KBQLP5.js.map
|