@nodaro/prompts 1.53.1 → 1.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-GRSKB3P7.cjs → chunk-56HWABF5.cjs} +52 -2
- package/dist/chunk-56HWABF5.cjs.map +1 -0
- package/dist/{chunk-EKRO42T3.cjs → chunk-CDNW7O7H.cjs} +77 -5
- package/dist/chunk-CDNW7O7H.cjs.map +1 -0
- package/dist/{chunk-WQ7FWGZ2.js → chunk-IVRSNUYX.js} +50 -3
- package/dist/chunk-IVRSNUYX.js.map +1 -0
- package/dist/{chunk-TYRIHUID.cjs → chunk-NUC5RV4P.cjs} +5 -2
- package/dist/chunk-NUC5RV4P.cjs.map +1 -0
- package/dist/{chunk-RBRCJTDJ.js → chunk-OMRFKG4M.js} +5 -2
- package/dist/chunk-OMRFKG4M.js.map +1 -0
- package/dist/{chunk-XRCK3BCF.cjs → chunk-XUMEDRML.cjs} +52 -10
- package/dist/chunk-XUMEDRML.cjs.map +1 -0
- package/dist/{chunk-PHCYQWJP.js → chunk-YDG3KMCN.js} +52 -10
- package/dist/chunk-YDG3KMCN.js.map +1 -0
- package/dist/{chunk-XR7RAHZI.js → chunk-Z4KWM6DV.js} +77 -5
- package/dist/chunk-Z4KWM6DV.js.map +1 -0
- package/dist/entries/assembly.cjs +24 -24
- package/dist/entries/assembly.d.cts +9 -0
- package/dist/entries/assembly.d.ts +9 -0
- package/dist/entries/assembly.js +1 -1
- package/dist/entries/doctrine.cjs +46 -46
- package/dist/entries/doctrine.js +1 -1
- package/dist/entries/picker-art.cjs +3 -3
- package/dist/entries/picker-art.js +1 -1
- package/dist/entries/presets.cjs +47 -35
- package/dist/entries/presets.d.cts +17 -1
- package/dist/entries/presets.d.ts +17 -1
- package/dist/entries/presets.js +1 -1
- package/dist/index.cjs +120 -108
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -4
- package/package.json +2 -2
- package/src/__tests__/factory-preset-shelves.test.ts +30 -0
- package/src/__tests__/seedance-extend.test.ts +24 -25
- package/src/__tests__/video-reference-features.test.ts +7 -5
- package/src/__tests__/video-reference-seatless-assets.test.ts +132 -0
- package/src/factory-presets/index.ts +2 -0
- package/src/factory-presets/shelves.ts +50 -0
- package/src/picker-art/restyle-previews.ts +3 -0
- package/src/prompt-wizard-categories.ts +12 -3
- package/src/provider-prompt-doctrine.ts +44 -5
- package/src/seatless-assets.ts +141 -0
- package/src/video-reference-resolver.ts +31 -4
- package/dist/chunk-EKRO42T3.cjs.map +0 -1
- package/dist/chunk-GRSKB3P7.cjs.map +0 -1
- package/dist/chunk-PHCYQWJP.js.map +0 -1
- package/dist/chunk-RBRCJTDJ.js.map +0 -1
- package/dist/chunk-TYRIHUID.cjs.map +0 -1
- package/dist/chunk-WQ7FWGZ2.js.map +0 -1
- package/dist/chunk-XR7RAHZI.js.map +0 -1
- package/dist/chunk-XRCK3BCF.cjs.map +0 -1
|
@@ -19,6 +19,9 @@ var RESTYLE_PREVIEWS = {
|
|
|
19
19
|
// Source shot: https://cdn.nodaro.ai/picker-renders/4a70c22d-04f0-4b5a-90d4-e9dd7ddb01c4.mp4
|
|
20
20
|
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5ab33529-ef2a-42bc-a625-d6b1abfeef1c.mp4
|
|
21
21
|
"felt-puppet": { url: "https://cdn.nodaro.ai/picker-renders/3aa3c81b-ba19-4776-becc-e0c47c700699.mp4" },
|
|
22
|
+
// Source shot: https://cdn.nodaro.ai/picker-renders/acf379d4-704b-40e5-a5d2-657341f1278a.mp4
|
|
23
|
+
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d3da4317-461f-4a10-a1e6-3d141fbb7802.mp4
|
|
24
|
+
"low-poly": { url: "https://cdn.nodaro.ai/picker-renders/4a5b1b1a-c3a4-46d4-9623-f57e80fcbb68.mp4", stillAtSeconds: 7 },
|
|
22
25
|
// Source shot: https://cdn.nodaro.ai/picker-renders/b1e77bdc-7c58-4cd8-a2d6-fd49379fee9e.mp4
|
|
23
26
|
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/a9aeca2d-bcd6-477b-80d7-5e6454ee2c25.mp4
|
|
24
27
|
"oil-painting": { url: "https://cdn.nodaro.ai/picker-renders/73c98260-9444-45e7-bccb-040b5d33fb53.mp4" },
|
|
@@ -41,5 +44,5 @@ function restylePreviewStillUrl(preview, width) {
|
|
|
41
44
|
|
|
42
45
|
exports.RESTYLE_PREVIEWS = RESTYLE_PREVIEWS;
|
|
43
46
|
exports.restylePreviewStillUrl = restylePreviewStillUrl;
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
45
|
-
//# sourceMappingURL=chunk-
|
|
47
|
+
//# sourceMappingURL=chunk-NUC5RV4P.cjs.map
|
|
48
|
+
//# sourceMappingURL=chunk-NUC5RV4P.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/picker-art/restyle-previews.ts"],"names":["lookPreviewStillUrl"],"mappings":";;;;;AAsBO,IAAM,gBAAA,GAA6D;AAAA;AAAA;AAAA,EAGxE,KAAA,EAAO,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGjH,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGnG,YAAA,EAAc,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGrG,SAAA,EAAW,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGrH,aAAA,EAAe,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGtG,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGtH,cAAA,EAAgB,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGvG,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGnG,SAAA,EAAW,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGrH,eAAA,EAAiB,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAG3H,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA;AACrB;AAGO,SAAS,sBAAA,CAAuB,SAAyB,KAAA,EAAoC;AAClG,EAAA,OAAOA,qCAAA,CAAoB,OAAA,CAAQ,GAAA,EAAK,KAAA,EAAO,QAAQ,cAAc,CAAA;AACvE","file":"chunk-NUC5RV4P.cjs","sourcesContent":["// Restyle previews: for each art style, a short clip of real footage wiping\n// into that style, for a picker that restyles a video. Keyed by the `style`\n// catalog's option id. An entry exists only for an approved clip: a style\n// without one has no preview here.\n//\n// Each approved style keeps the URLs of its source shot and its generated clip\n// (no wipe) in a comment beside its entry, so the clip can be composed again if\n// the switch animation changes.\n//\n// Separate from LOOK_PREVIEW_SETS.style, whose stills every other art style\n// picker keeps showing. Like every render, a clip lives under picker-renders/\n// on the CDN, a key no user owns; a test holds this.\nimport { lookPreviewStillUrl } from \"./images.js\"\n\n/** One style's preview clip. */\nexport interface RestylePreview {\n readonly url: string\n /** The moment of the clip its still is cut from, for a clip whose usual moment frames it badly. Absent: the usual moment (`lookPreviewStillUrl`). */\n readonly stillAtSeconds?: number\n}\n\n/** Art style id → its restyle preview clip. */\nexport const RESTYLE_PREVIEWS: Readonly<Record<string, RestylePreview>> = {\n // Source shot: https://cdn.nodaro.ai/picker-renders/4054a0e1-af60-47f9-86bd-a78ab93f3800.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/9dc6b337-58b4-4a63-889f-70561a8f1f00.mp4\n anime: { url: \"https://cdn.nodaro.ai/picker-renders/7fbad6e4-023f-4282-ac3d-d186f2cbb37b.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/4ffff922-e807-42cc-a2a0-c66c3a8d492c.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/fca5d96d-ee9c-430e-ba82-2795c0adb8d6.mp4\n claymation: { url: \"https://cdn.nodaro.ai/picker-renders/2916a2f7-114c-4c7e-9be0-5bf229d76133.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/41faaa51-5e77-4097-aa9b-bef6738328b7.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5a28da72-f3ee-49a8-b732-f73e79741b62.mp4\n \"comic-book\": { url: \"https://cdn.nodaro.ai/picker-renders/7a2cd17c-b02f-4ae4-9723-ef48d0eda52a.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/a0ca72d5-1d4e-4f57-be74-ba3ac46dd9bd.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/cf977f6c-e755-4b72-b959-e6b954d631c3.mp4\n cyberpunk: { url: \"https://cdn.nodaro.ai/picker-renders/4868595c-cc88-4f82-b2a4-f33bfafe8198.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/4a70c22d-04f0-4b5a-90d4-e9dd7ddb01c4.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5ab33529-ef2a-42bc-a625-d6b1abfeef1c.mp4\n \"felt-puppet\": { url: \"https://cdn.nodaro.ai/picker-renders/3aa3c81b-ba19-4776-becc-e0c47c700699.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/acf379d4-704b-40e5-a5d2-657341f1278a.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d3da4317-461f-4a10-a1e6-3d141fbb7802.mp4\n \"low-poly\": { url: \"https://cdn.nodaro.ai/picker-renders/4a5b1b1a-c3a4-46d4-9623-f57e80fcbb68.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/b1e77bdc-7c58-4cd8-a2d6-fd49379fee9e.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/a9aeca2d-bcd6-477b-80d7-5e6454ee2c25.mp4\n \"oil-painting\": { url: \"https://cdn.nodaro.ai/picker-renders/73c98260-9444-45e7-bccb-040b5d33fb53.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/d9e12a4a-677e-4e36-8f44-8503f14dd6b8.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d4dad451-802a-4795-9cc3-71ff3ed70c69.mp4\n \"pixar-3d\": { url: \"https://cdn.nodaro.ai/picker-renders/c5ea2111-3283-4f80-ab05-8ab4450946ce.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/71d9ab7a-7396-48ff-8bc3-80454b0edd07.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/b11ab600-ec62-4cb6-82b4-b0006374164b.mp4\n \"pop-art\": { url: \"https://cdn.nodaro.ai/picker-renders/0659dbe5-9dfe-45d8-9abd-6ccf88481dd8.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/f832aab2-5f30-48cc-81dd-e6a4b84128b3.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/67386080-e6f5-4fba-a7bc-cfb6de462804.mp4\n \"toy-figure-3d\": { url: \"https://cdn.nodaro.ai/picker-renders/eaebd242-7e53-4018-ba85-00673e2a9b2b.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/789f4330-660b-42bd-8d11-6e638e8c7c88.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/10471107-b26a-42e9-a3a5-068a42436d3c.mp4\n watercolor: { url: \"https://cdn.nodaro.ai/picker-renders/61a26588-d09a-4959-b677-ee8b32e3281a.mp4\" },\n}\n\n/** A preview clip's still, a frame the CDN cuts from it at the clip's own moment. */\nexport function restylePreviewStillUrl(preview: RestylePreview, width?: number): string | undefined {\n return lookPreviewStillUrl(preview.url, width, preview.stillAtSeconds)\n}\n"]}
|
|
@@ -17,6 +17,9 @@ var RESTYLE_PREVIEWS = {
|
|
|
17
17
|
// Source shot: https://cdn.nodaro.ai/picker-renders/4a70c22d-04f0-4b5a-90d4-e9dd7ddb01c4.mp4
|
|
18
18
|
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5ab33529-ef2a-42bc-a625-d6b1abfeef1c.mp4
|
|
19
19
|
"felt-puppet": { url: "https://cdn.nodaro.ai/picker-renders/3aa3c81b-ba19-4776-becc-e0c47c700699.mp4" },
|
|
20
|
+
// Source shot: https://cdn.nodaro.ai/picker-renders/acf379d4-704b-40e5-a5d2-657341f1278a.mp4
|
|
21
|
+
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d3da4317-461f-4a10-a1e6-3d141fbb7802.mp4
|
|
22
|
+
"low-poly": { url: "https://cdn.nodaro.ai/picker-renders/4a5b1b1a-c3a4-46d4-9623-f57e80fcbb68.mp4", stillAtSeconds: 7 },
|
|
20
23
|
// Source shot: https://cdn.nodaro.ai/picker-renders/b1e77bdc-7c58-4cd8-a2d6-fd49379fee9e.mp4
|
|
21
24
|
// Generated, no wipe: https://cdn.nodaro.ai/picker-renders/a9aeca2d-bcd6-477b-80d7-5e6454ee2c25.mp4
|
|
22
25
|
"oil-painting": { url: "https://cdn.nodaro.ai/picker-renders/73c98260-9444-45e7-bccb-040b5d33fb53.mp4" },
|
|
@@ -38,5 +41,5 @@ function restylePreviewStillUrl(preview, width) {
|
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
export { RESTYLE_PREVIEWS, restylePreviewStillUrl };
|
|
41
|
-
//# sourceMappingURL=chunk-
|
|
42
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
//# sourceMappingURL=chunk-OMRFKG4M.js.map
|
|
45
|
+
//# sourceMappingURL=chunk-OMRFKG4M.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/picker-art/restyle-previews.ts"],"names":[],"mappings":";;;AAsBO,IAAM,gBAAA,GAA6D;AAAA;AAAA;AAAA,EAGxE,KAAA,EAAO,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGjH,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGnG,YAAA,EAAc,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGrG,SAAA,EAAW,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGrH,aAAA,EAAe,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGtG,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGtH,cAAA,EAAgB,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGvG,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA,EAAgF;AAAA;AAAA;AAAA,EAGnG,SAAA,EAAW,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAGrH,eAAA,EAAiB,EAAE,GAAA,EAAK,+EAAA,EAAiF,gBAAgB,CAAA,EAAE;AAAA;AAAA;AAAA,EAG3H,UAAA,EAAY,EAAE,GAAA,EAAK,+EAAA;AACrB;AAGO,SAAS,sBAAA,CAAuB,SAAyB,KAAA,EAAoC;AAClG,EAAA,OAAO,mBAAA,CAAoB,OAAA,CAAQ,GAAA,EAAK,KAAA,EAAO,QAAQ,cAAc,CAAA;AACvE","file":"chunk-OMRFKG4M.js","sourcesContent":["// Restyle previews: for each art style, a short clip of real footage wiping\n// into that style, for a picker that restyles a video. Keyed by the `style`\n// catalog's option id. An entry exists only for an approved clip: a style\n// without one has no preview here.\n//\n// Each approved style keeps the URLs of its source shot and its generated clip\n// (no wipe) in a comment beside its entry, so the clip can be composed again if\n// the switch animation changes.\n//\n// Separate from LOOK_PREVIEW_SETS.style, whose stills every other art style\n// picker keeps showing. Like every render, a clip lives under picker-renders/\n// on the CDN, a key no user owns; a test holds this.\nimport { lookPreviewStillUrl } from \"./images.js\"\n\n/** One style's preview clip. */\nexport interface RestylePreview {\n readonly url: string\n /** The moment of the clip its still is cut from, for a clip whose usual moment frames it badly. Absent: the usual moment (`lookPreviewStillUrl`). */\n readonly stillAtSeconds?: number\n}\n\n/** Art style id → its restyle preview clip. */\nexport const RESTYLE_PREVIEWS: Readonly<Record<string, RestylePreview>> = {\n // Source shot: https://cdn.nodaro.ai/picker-renders/4054a0e1-af60-47f9-86bd-a78ab93f3800.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/9dc6b337-58b4-4a63-889f-70561a8f1f00.mp4\n anime: { url: \"https://cdn.nodaro.ai/picker-renders/7fbad6e4-023f-4282-ac3d-d186f2cbb37b.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/4ffff922-e807-42cc-a2a0-c66c3a8d492c.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/fca5d96d-ee9c-430e-ba82-2795c0adb8d6.mp4\n claymation: { url: \"https://cdn.nodaro.ai/picker-renders/2916a2f7-114c-4c7e-9be0-5bf229d76133.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/41faaa51-5e77-4097-aa9b-bef6738328b7.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5a28da72-f3ee-49a8-b732-f73e79741b62.mp4\n \"comic-book\": { url: \"https://cdn.nodaro.ai/picker-renders/7a2cd17c-b02f-4ae4-9723-ef48d0eda52a.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/a0ca72d5-1d4e-4f57-be74-ba3ac46dd9bd.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/cf977f6c-e755-4b72-b959-e6b954d631c3.mp4\n cyberpunk: { url: \"https://cdn.nodaro.ai/picker-renders/4868595c-cc88-4f82-b2a4-f33bfafe8198.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/4a70c22d-04f0-4b5a-90d4-e9dd7ddb01c4.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/5ab33529-ef2a-42bc-a625-d6b1abfeef1c.mp4\n \"felt-puppet\": { url: \"https://cdn.nodaro.ai/picker-renders/3aa3c81b-ba19-4776-becc-e0c47c700699.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/acf379d4-704b-40e5-a5d2-657341f1278a.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d3da4317-461f-4a10-a1e6-3d141fbb7802.mp4\n \"low-poly\": { url: \"https://cdn.nodaro.ai/picker-renders/4a5b1b1a-c3a4-46d4-9623-f57e80fcbb68.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/b1e77bdc-7c58-4cd8-a2d6-fd49379fee9e.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/a9aeca2d-bcd6-477b-80d7-5e6454ee2c25.mp4\n \"oil-painting\": { url: \"https://cdn.nodaro.ai/picker-renders/73c98260-9444-45e7-bccb-040b5d33fb53.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/d9e12a4a-677e-4e36-8f44-8503f14dd6b8.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/d4dad451-802a-4795-9cc3-71ff3ed70c69.mp4\n \"pixar-3d\": { url: \"https://cdn.nodaro.ai/picker-renders/c5ea2111-3283-4f80-ab05-8ab4450946ce.mp4\" },\n // Source shot: https://cdn.nodaro.ai/picker-renders/71d9ab7a-7396-48ff-8bc3-80454b0edd07.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/b11ab600-ec62-4cb6-82b4-b0006374164b.mp4\n \"pop-art\": { url: \"https://cdn.nodaro.ai/picker-renders/0659dbe5-9dfe-45d8-9abd-6ccf88481dd8.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/f832aab2-5f30-48cc-81dd-e6a4b84128b3.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/67386080-e6f5-4fba-a7bc-cfb6de462804.mp4\n \"toy-figure-3d\": { url: \"https://cdn.nodaro.ai/picker-renders/eaebd242-7e53-4018-ba85-00673e2a9b2b.mp4\", stillAtSeconds: 7 },\n // Source shot: https://cdn.nodaro.ai/picker-renders/789f4330-660b-42bd-8d11-6e638e8c7c88.mp4\n // Generated, no wipe: https://cdn.nodaro.ai/picker-renders/10471107-b26a-42e9-a3a5-068a42436d3c.mp4\n watercolor: { url: \"https://cdn.nodaro.ai/picker-renders/61a26588-d09a-4959-b677-ee8b32e3281a.mp4\" },\n}\n\n/** A preview clip's still, a frame the CDN cuts from it at the clip's own moment. */\nexport function restylePreviewStillUrl(preview: RestylePreview, width?: number): string | undefined {\n return lookPreviewStillUrl(preview.url, width, preview.stillAtSeconds)\n}\n"]}
|
|
@@ -344,7 +344,7 @@ var GROK_IMAGINE_DOCTRINE = {
|
|
|
344
344
|
tips: [
|
|
345
345
|
"Keep prompts simple and direct \u2014 Subject + Action + Setting + Camera + Mood. Grok expands the prompt itself; over-specification fights the expander.",
|
|
346
346
|
"Image-to-video: the input image IS the first frame (composition, identity, and style are preserved) \u2014 describe the MOTION, don't re-describe the still.",
|
|
347
|
-
"Video 1.5: 1-15s (default 8), 480p/720p/1080p
|
|
347
|
+
"Video 1.5: 1-15s (default 8), 480p/720p/1080p; exact start and end frame (one image as both = seamless loop), up to 4 in-between frames. Native audio incl. dialogue \u2014 quote the line to have it spoken.",
|
|
348
348
|
"Aspect ratio applies to text runs (1:1/16:9/9:16/3:2/2:3/auto); a single input image locks the output to the image's own aspect."
|
|
349
349
|
],
|
|
350
350
|
doctrine: `Prompt structure (xAI's guidance is minimal by design \u2014 the model auto-expands prompts):
|
|
@@ -353,18 +353,18 @@ descriptions of static/unchanged parts \u2014 spend the words on what MOVES.
|
|
|
353
353
|
|
|
354
354
|
**Image-to-video (the primary mode)**
|
|
355
355
|
- The input image is the FIRST FRAME, not a loose reference: composition, subject identity, and visual style carry over. Describe motion and camera only ("she turns toward the window as the camera slowly pushes in"); re-describing the still wastes adherence.
|
|
356
|
-
- grok-imagine-video-1.5
|
|
356
|
+
- grok-imagine-video-1.5 takes frames, not loose references: the start frame is the exact FIRST frame, an end frame the exact LAST frame, and the same image wired as both makes a seamless loop. Its Image References are up to 4 IN-BETWEEN frames, in order, placed evenly over the clip at whole seconds (one per second inside it \u2014 a 3s clip takes 2); extra frames are left out. Describe the motion that carries the shot from one frame to the next; the frames cannot be named in the prompt, so refer to them in words ("by the midpoint she has reached the door").
|
|
357
357
|
- grok-i2v with reference images: images are addressed \`@image(n)\` in array order. Your references come first (\`@image(1)\` is your first reference); a wired start frame is appended after them and the platform names it as the opening frame.
|
|
358
358
|
|
|
359
359
|
**Audio (video-1.5)**
|
|
360
|
-
- Native audio generates with the clip \u2014 background music, SFX, and lip-synced dialogue. Quote the spoken line; describe the music/SFX plainly.
|
|
360
|
+
- Native audio generates with the clip \u2014 background music, SFX, and lip-synced dialogue. Quote the spoken line; describe the music/SFX plainly. The platform offers no audio toggle for it \u2014 cue (or exclude) sound in the prompt text.
|
|
361
361
|
|
|
362
362
|
**Durations / tiers**
|
|
363
|
-
- grok-i2v: 6 or 10 seconds. grok-imagine-video-1.5: 1-15 seconds in 1s steps (default 8), 480p (default) / 720p / 1080p. Prompt cap 4096 chars \u2014 but shorter is better here.
|
|
363
|
+
- grok-i2v: 6 or 10 seconds. grok-imagine-video-1.5: 1-15 seconds in 1s steps (default 8), 480p (default) / 720p / 1080p. At 1080p it takes the start frame ALONE \u2014 a run with an end frame, a loop or in-between frames is refused before any credits are held, so use 720p for those. Prompt cap 4096 chars \u2014 but shorter is better here.
|
|
364
364
|
|
|
365
365
|
Sources: KIE Grok Imagine contracts (docs.kie.ai/market/grok-imagine/image-to-video,
|
|
366
366
|
docs.kie.ai/market/grok-imagine/1-5-preview), xAI Grok Imagine 1.5 release notes
|
|
367
|
-
(x.ai/news/grok-imagine-1-5). Captured 2026-08-09.`
|
|
367
|
+
(x.ai/news/grok-imagine-1-5). Captured 2026-08-09; frames and in-between frames 2026-11-11.`
|
|
368
368
|
};
|
|
369
369
|
var WAN_DOCTRINE = {
|
|
370
370
|
providers: ["wan", "wan-i2v", "wan-turbo", "wan-flash", "wan-2.7", "wan-2.7-i2v", "wan-2.7-t2v", "wan-2.7-pro", "wan-videoedit"],
|
|
@@ -513,6 +513,38 @@ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera mov
|
|
|
513
513
|
Source: KIE Kling 4.0 market contracts (docs.kie.ai/market/kling/v4-reference-to-video,
|
|
514
514
|
docs.kie.ai/market/kling/v4-keyframe-to-video), live-probed 2026-10-23.`
|
|
515
515
|
};
|
|
516
|
+
var KLING_4_FLASH_DOCTRINE = {
|
|
517
|
+
providers: ["kling-4-flash"],
|
|
518
|
+
heading: "Kling 4.0 Flash (kling-4-flash)",
|
|
519
|
+
tips: [
|
|
520
|
+
"A start frame alone is the exact opening frame (@first_frame). Beside references it joins the reference images, like kling-4.",
|
|
521
|
+
"References: up to 10 images, 5 videos (2-20s together) and 7 characters (15 in all). Name each: @image_1, @video_1, a character's @Name.",
|
|
522
|
+
"No standalone voice: voice clip N is the voice of wired character N, if that character has 2-4 images (else the clip is dropped); write the character, never @audio_N.",
|
|
523
|
+
"3-20s (default 5), 720p only, native audio always on, no end frame. Prompt cap 8,000 chars. Aspect auto / 16:9 / 9:16 / 1:1 / 21:9 (a start frame alone sets its own shape)."
|
|
524
|
+
],
|
|
525
|
+
doctrine: `Prompt structure (no public Kling 4.0 Flash prompt guide is captured \u2014 the KIE API contract is
|
|
526
|
+
the doctrine source; platform-standard structure applies):
|
|
527
|
+
subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera movement \u2192 style \u2192 constraints.
|
|
528
|
+
|
|
529
|
+
**One model, two endpoints (picked by what is connected)**
|
|
530
|
+
- A start frame with nothing else \u2014 no reference image, no reference video, no character \u2014 runs keyframe-to-video: the frame is the exact opening frame and the clip takes its shape. Name it @first_frame.
|
|
531
|
+
- Anything else \u2014 text only, reference images, reference videos, characters, or a start frame beside any of them \u2014 runs reference-to-video. A start frame there joins the reference images and is named as the opening frame, as on kling-4.
|
|
532
|
+
|
|
533
|
+
**Naming materials in the prompt**
|
|
534
|
+
- @image_1 \u2026 for reference images, @video_1 \u2026 for reference videos, a character by its own name (@Maya). Kling refuses a prompt that names a material the request does not carry; the platform removes the "@" from such a mention so the run still starts.
|
|
535
|
+
- There are no standalone voices. Reference audio clip N becomes the voice of character N, in the order the characters are wired. A character needs 2-4 images to carry a voice: a clip whose character has one image, and any clip past the last character, is dropped (the run still starts). Write who speaks by the character's name ("@Maya says\u2026"), never @audio_1.
|
|
536
|
+
|
|
537
|
+
**Limits**
|
|
538
|
+
- Reference images 10, reference videos 5, characters 7 \u2014 15 in all. Reference videos together must be 2-20 seconds; a longer set is refused before the run starts.
|
|
539
|
+
- No end frame and no in-between frames: describe how the shot ends in words.
|
|
540
|
+
|
|
541
|
+
**Duration, resolution, audio**
|
|
542
|
+
- 3-20 seconds (default 5); 720p only; aspect auto (follows the materials, 16:9 with none) / 16:9 / 9:16 / 1:1 / 21:9. Prompts up to 8,000 characters.
|
|
543
|
+
- Native audio is always generated; keep-original-sound keeps a reference video's own audio. Not yet verified for scripted lines here, so plan key dialogue as a TTS + lip-sync pass.
|
|
544
|
+
|
|
545
|
+
Source: KIE Kling 4.0 Flash market contracts (docs.kie.ai/market/kling/v4-flash-reference-to-video,
|
|
546
|
+
docs.kie.ai/market/kling/v4-flash-keyframe-to-video), read 2026-11-11.`
|
|
547
|
+
};
|
|
516
548
|
var HAPPYHORSE_DOCTRINE = {
|
|
517
549
|
providers: ["happyhorse", "happyhorse-i2v", "happyhorse-ref2v", "happyhorse-edit"],
|
|
518
550
|
heading: "HappyHorse 1.1 (happyhorse, happyhorse-i2v, happyhorse-ref2v)",
|
|
@@ -572,6 +604,7 @@ var PROVIDER_PROMPT_DOCTRINES = [
|
|
|
572
604
|
WAN_3_DOCTRINE,
|
|
573
605
|
VIDU_Q4_DOCTRINE,
|
|
574
606
|
KLING_4_DOCTRINE,
|
|
607
|
+
KLING_4_FLASH_DOCTRINE,
|
|
575
608
|
HAPPYHORSE_DOCTRINE,
|
|
576
609
|
RUNWAY_KIE_DOCTRINE
|
|
577
610
|
];
|
|
@@ -823,6 +856,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
823
856
|
"seedream-5-lite": "Lighter Seedream, faster artistic generation",
|
|
824
857
|
"seedream-5-pro": "Flagship Seedream \u2014 strongest instruction following, 2K via high quality",
|
|
825
858
|
"seedream-5-flash": "Fast, low-cost Seedream 5 \u2014 quick drafts and iteration at 1K or 2K",
|
|
859
|
+
"minimax-h3-image": "MiniMax H3 \u2014 readable text in the picture, up to about 16 MP at 4K, same price at 1K and 2K",
|
|
860
|
+
"seedream-5-5": "Seedream 5.5 \u2014 natural light, materials and skin, dense small text, transparent backgrounds; 1K / 1.5K / 2K",
|
|
826
861
|
"z-image": "Experimental, novel generation approaches",
|
|
827
862
|
"wan-2.7": "Wan 2.7 T2I \u2014 1K/2K/4K, up to 9 ref images",
|
|
828
863
|
"wan-2.7-pro": "Wan 2.7 Pro T2I \u2014 higher quality, 1K/2K/4K",
|
|
@@ -851,6 +886,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
851
886
|
"seedream-5-lite-i2i": "Light artistic transformation",
|
|
852
887
|
"seedream-5-pro-i2i": "Pro-grade instruction-based edits, multi-reference",
|
|
853
888
|
"seedream-5-flash-i2i": "Fast, low-cost Seedream edits \u2014 up to 10 input images",
|
|
889
|
+
"minimax-h3-image-i2i": "MiniMax H3 edits \u2014 up to 16 reference images in one edit, readable text, up to 4K",
|
|
890
|
+
"seedream-5-5-i2i": "Seedream 5.5 edits \u2014 round after round, the rest of the picture untouched; up to 10 input images",
|
|
854
891
|
"flux-kontext": "Character-consistent edits with reference awareness",
|
|
855
892
|
"flux-kontext-max": "Premium character-consistent editing",
|
|
856
893
|
"kontext-multi": "Multi-image Kontext via Replicate \u2014 up to 4 refs",
|
|
@@ -879,6 +916,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
879
916
|
"seedream-5-lite-i2i": "Light artistic transformation",
|
|
880
917
|
"seedream-5-pro-i2i": "Pro-grade instruction-based edits, multi-reference",
|
|
881
918
|
"seedream-5-flash-i2i": "Fast, low-cost Seedream edits \u2014 up to 10 input images",
|
|
919
|
+
"minimax-h3-image-i2i": "MiniMax H3 edits \u2014 up to 16 reference images in one edit, readable text, up to 4K",
|
|
920
|
+
"seedream-5-5-i2i": "Seedream 5.5 edits \u2014 round after round, the rest of the picture untouched; up to 10 input images",
|
|
882
921
|
"flux-kontext": "Character-consistent edits with reference awareness",
|
|
883
922
|
"flux-kontext-max": "Premium character-consistent editing",
|
|
884
923
|
"kontext-multi": "Multi-image Kontext via Replicate \u2014 up to 4 refs",
|
|
@@ -920,7 +959,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
920
959
|
"vidu-q4": "Vidu Q4 \u2014 start frame or up to 15 reference images + 3 MP3 audio refs, native audio, 3\u201316s, 540p\u20134K (image required)",
|
|
921
960
|
"kling-4": "Kling 4.0 \u2014 text, or up to 10 reference images / 5 videos / 7 characters / 3 voices; native audio, 3\u201330s, 720p/1080p",
|
|
922
961
|
"kling-4-keyframes": "Kling 4.0 Keyframes \u2014 start frame, up to 8 in-between frames and an end frame; native audio, 3\u201330s, 720p/1080p",
|
|
923
|
-
"
|
|
962
|
+
"kling-4-flash": "Kling 4.0 Flash \u2014 text, or up to 10 reference images / 5 videos / 7 characters (a voice clip per character); native audio, 3\u201320s, 720p",
|
|
963
|
+
"grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 image-to-video only; exact start and end frame (the same image loops), up to 4 in-between frames; requires an input image"
|
|
924
964
|
},
|
|
925
965
|
"image-to-video": {
|
|
926
966
|
"minimax": "Versatile animation from still images",
|
|
@@ -959,7 +999,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
959
999
|
"vidu-q4": "Vidu Q4 \u2014 animate a start frame, or direct up to 15 reference images + 3 MP3 audio refs; native audio, 3\u201316s, 540p\u20134K",
|
|
960
1000
|
"kling-4": "Kling 4.0 \u2014 a start frame joins up to 10 reference images, 5 videos, 7 characters and 3 voices; native audio, 3\u201330s, 720p/1080p",
|
|
961
1001
|
"kling-4-keyframes": "Kling 4.0 Keyframes \u2014 start frame, up to 8 in-between frames and an end frame; native audio, 3\u201330s, 720p/1080p",
|
|
962
|
-
"
|
|
1002
|
+
"kling-4-flash": "Kling 4.0 Flash \u2014 a start frame alone is the exact opening frame; beside up to 10 reference images, 5 videos and 7 characters it joins them; native audio, 3\u201320s, 720p",
|
|
1003
|
+
"grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 stylized animation, 1\u201315s, 480p/720p/1080p, start + up to 4 in-between + end frames (image required)"
|
|
963
1004
|
},
|
|
964
1005
|
"video-to-video": {
|
|
965
1006
|
"wan": "Style transfer and video transformation",
|
|
@@ -976,7 +1017,8 @@ var PROVIDER_CAPABILITIES = {
|
|
|
976
1017
|
"extend-video": {
|
|
977
1018
|
"veo-extend": "Extend VEO-generated videos",
|
|
978
1019
|
"runway-extend": "Extend Runway-generated videos",
|
|
979
|
-
"seedance-2-extend": "Extend ANY video by URL \u2014 seamless trim-stitched continuation with audio (Seedance 2.
|
|
1020
|
+
"seedance-2-5-extend": "Extend ANY video by URL \u2014 seamless trim-stitched continuation with audio, 4\u201330s added (Seedance 2.5)",
|
|
1021
|
+
"seedance-2-0-extend": "Extend ANY video by URL \u2014 seamless trim-stitched continuation with audio, 4\u201315s added (Seedance 2.0)"
|
|
980
1022
|
},
|
|
981
1023
|
"speech-to-video": {
|
|
982
1024
|
"wan-speech": "Wan 2.2 speech-driven video generation"
|
|
@@ -1118,5 +1160,5 @@ exports.isWizardSupported = isWizardSupported;
|
|
|
1118
1160
|
exports.ownMotionHint = ownMotionHint;
|
|
1119
1161
|
exports.renderScene3DLayoutScopingLine = renderScene3DLayoutScopingLine;
|
|
1120
1162
|
exports.scene3DLayoutVideoCaptions = scene3DLayoutVideoCaptions;
|
|
1121
|
-
//# sourceMappingURL=chunk-
|
|
1122
|
-
//# sourceMappingURL=chunk-
|
|
1163
|
+
//# sourceMappingURL=chunk-XUMEDRML.cjs.map
|
|
1164
|
+
//# sourceMappingURL=chunk-XUMEDRML.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/video-own-motion.ts","../src/entity-prompts.ts","../src/provider-prompt-doctrine.ts","../src/image-reference-doctrine.ts","../src/scene3d-reference-doctrine.ts","../src/prompt-wizard-categories.ts","../src/ad-creative-analysis.ts"],"names":["PLACEHOLDER_CHARACTER_NAME"],"mappings":"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","file":"chunk-XUMEDRML.cjs","sourcesContent":["/**\n * A video node's OWN Motion setting (`motionEnabled` + `motion`) as the clause\n * its prompt carries, e.g. \"dynamic motion\".\n *\n * Only the node types that offer the setting add it: the legacy Image to Video\n * node, and Generate Video in either mode (with or without a start frame). A\n * legacy Text to Video node has no such setting. `nodeType` is the node's REAL\n * type: the editor re-types Generate Video to image-to-video / text-to-video\n * before composing, so a re-typed node must still pass \"generate-video\". The\n * editor applied it only with a start frame while workflow runs applied it\n * always; one rule for both is what keeps them in step.\n *\n * Separate from the Motion node wired into a Settings input, whose clause comes\n * from `getParameterPromptHint` through the cinematography collectors.\n */\nexport const OWN_MOTION_NODE_TYPES: ReadonlySet<string> = new Set([\"image-to-video\", \"generate-video\"])\n\n/**\n * The step the Motion control shows before one is picked, and so the step an\n * enabled setting runs with when none is stored. Ticking the checkbox stores\n * no step, so the prompt used to get nothing while the panel showed Moderate.\n */\nexport const DEFAULT_OWN_MOTION = \"moderate\"\n\nexport function ownMotionHint(nodeType: string, data: Readonly<Record<string, unknown>>): string | undefined {\n if (!OWN_MOTION_NODE_TYPES.has(nodeType) || !data.motionEnabled) return undefined\n const step = typeof data.motion === \"string\" && data.motion ? data.motion : DEFAULT_OWN_MOTION\n return `${step} motion`\n}\n","import { EntityStyle, PLACEHOLDER_CHARACTER_NAME } from \"@nodaro/shared/entities\"\n\nfunction effectiveName(name: string): string | undefined {\n const trimmed = name.trim()\n if (!trimmed || trimmed === PLACEHOLDER_CHARACTER_NAME) return undefined\n return trimmed\n}\n\nexport interface CharacterPromptInput {\n name: string\n description?: string\n gender?: string\n style?: EntityStyle | string\n baseOutfit?: string\n}\n\nexport function buildCharacterPrompt(input: CharacterPromptInput): string {\n const charDesc = [effectiveName(input.name), input.gender, input.description].filter(Boolean).join(\", \")\n const outfitDesc = input.baseOutfit ? `, wearing ${input.baseOutfit}` : \"\"\n const styleDesc = input.style ?? \"realistic\"\n return [\n `${charDesc}${outfitDesc},`,\n `${styleDesc} style, front view, looking at camera,`,\n \"full body portrait, 4k, highly detailed, clean background.\",\n ].join(\" \")\n}\n\nexport interface ObjectPromptInput {\n name: string\n description?: string\n category?: string\n style?: EntityStyle | string\n}\n\nexport function buildObjectPrompt(input: ObjectPromptInput): string {\n const categoryDesc = input.category ?? \"object\"\n const descPart = input.description ? `, ${input.description}` : \"\"\n const styleDesc = input.style ?? \"realistic\"\n return [\n `Single ${categoryDesc} ${input.name}${descPart},`,\n `${styleDesc} art style, front view,`,\n \"4k, highly detailed, white/plain background, no text, no labels, no watermarks, product photography style.\",\n ].join(\" \")\n}\n\nexport interface CreaturePromptInput {\n name: string\n description?: string\n /** Free-text species/type (e.g. \"dragon\", \"wolf\") — the creature delta vs object. */\n species?: string\n category?: string\n style?: EntityStyle | string\n /**\n * Already-rendered clauses of the request's `subject` catalog ids (the\n * platform's `renderSubjectHints`, image surface) — the route renders, this\n * builder only places them: after the prose, before the style line, each\n * once. Absent/empty → byte-identical output.\n */\n subjectHints?: readonly string[]\n}\n\n/**\n * Creature establishing-shot prompt. Mirrors {@link buildObjectPrompt} but leads\n * with the free-text `species` (a dragon/wolf/etc. IS the subject) and frames the\n * subject as a living creature rather than a product. Falls back to \"creature\"\n * when no species is given so the prompt always names a subject.\n */\nexport function buildCreaturePrompt(input: CreaturePromptInput): string {\n const subject = input.species?.trim() || \"creature\"\n const descPart = input.description ? `, ${input.description}` : \"\"\n const hints = [...new Set((input.subjectHints ?? []).filter((h) => h.length > 0))]\n const hintPart = hints.length > 0 ? `, ${hints.join(\", \")}` : \"\"\n const styleDesc = input.style ?? \"realistic\"\n return [\n `Single ${subject}, ${input.name}${descPart}${hintPart},`,\n `${styleDesc} art style, full body, front view,`,\n \"4k, highly detailed, plain background, no text, no labels, no watermarks.\",\n ].join(\" \")\n}\n\nexport interface LocationPromptInput {\n name: string\n description?: string\n category?: string\n style?: EntityStyle | string\n}\n\nexport function buildLocationPrompt(input: LocationPromptInput): string {\n const categoryDesc = input.category ?? \"location\"\n const descPart = input.description ? `, ${input.description}` : \"\"\n const styleDesc = input.style ?? \"realistic\"\n return [\n `${categoryDesc} scene, ${input.name}${descPart},`,\n `${styleDesc} art style,`,\n \"wide establishing shot, 4k, highly detailed, cinematic lighting, no people, no text, no labels, no watermarks.\",\n ].join(\" \")\n}\n\nexport interface LocationRefinePromptInput {\n /**\n * The user's TRANSIENT edit/refine instruction (e.g. \"make it night, add\n * drifting fog\"). Used only to build this one generation's prompt - it is\n * never written back to the location row, so the stored name / description /\n * canonical description stay untouched. This is the deliberate contrast with\n * `LocationPromptInput.description`, which IS the persisted scene description\n * that `buildLocationPrompt` weaves in.\n */\n editPrompt: string\n style?: EntityStyle | string\n}\n\n/**\n * Build a TRANSIENT prompt from a user-supplied edit/refine instruction.\n *\n * Used by `POST /v1/generate-location` when the caller passes `userPrompt`\n * (the studio's \"describe changes\" / sparkle Edit flow). Paired with an i2i\n * `sourceImageUrl` the provider edits the source establishing shot toward the\n * instruction; with no source image it reads as a from-scratch custom scene\n * prompt. Mirrors `characters.generate`'s seed/edit-prompt path, but locations\n * have no stored seed prompt - this output is purely transient and the route\n * persists nothing derived from it back to the row.\n */\nexport function buildLocationRefinePrompt(input: LocationRefinePromptInput): string {\n const instruction = input.editPrompt.trim()\n const styleDesc = input.style ?? \"realistic\"\n return [\n `${instruction},`,\n `${styleDesc} art style, wide establishing shot,`,\n \"4k, highly detailed, cinematic lighting, no text, no labels, no watermarks.\",\n ].join(\" \")\n}\n\nexport interface FacePromptInput {\n name: string\n description?: string\n style?: EntityStyle | string\n}\n\n/**\n * Face prompt uses the \"face-generation\" template (resolved via prompt-templates.ts).\n * Returns the template inputs so callers can call resolveTemplate + applyTemplate.\n */\nexport function buildFaceTemplateInputs(input: FacePromptInput): {\n description: string\n style: string\n} {\n const descParts = [input.name, input.description].filter(Boolean).join(\", \")\n return { description: descParts, style: input.style ?? \"realistic\" }\n}\n\nexport interface CharacterMotionPromptInput {\n name: string\n description?: string\n gender?: string\n style?: EntityStyle | string\n baseOutfit?: string\n motionPrompt: string\n}\n\nexport function buildMotionPrompt(input: CharacterMotionPromptInput): string {\n const charDesc = [effectiveName(input.name), input.gender, input.description].filter(Boolean).join(\", \")\n const outfitDesc = input.baseOutfit ? `, wearing ${input.baseOutfit}` : \"\"\n const styleDesc = input.style ?? \"realistic\"\n const charPart = charDesc ? `${charDesc}${outfitDesc}, ` : \"\"\n return `${charPart}${input.motionPrompt}. ${styleDesc} style.`\n}\n\n/**\n * Input shape for buildLocationMotionPrompt.\n *\n * Mirrors CharacterMotionPromptInput's role. `canonicalDescription` is preferred\n * (LLM-authored from the approved main image) but the helper falls back to\n * category+name if not yet set, and to a generic placeholder if both are absent.\n */\nexport interface LocationMotionPromptInput {\n name: string\n category?: string\n style?: EntityStyle | string\n motionPrompt: string\n canonicalDescription?: string\n}\n\n/**\n * Build the prompt sent to the i2v provider for a location atmosphere clip.\n *\n * Note: character's analog is named `buildMotionPrompt` (historical); location\n * uses the more specific `buildLocationMotionPrompt`.\n */\nexport function buildLocationMotionPrompt(input: LocationMotionPromptInput): string {\n const sceneDesc =\n input.canonicalDescription?.trim() ||\n [input.category, input.name].filter(Boolean).join(\", \").trim() ||\n \"A generic location\"\n return `${sceneDesc}. Camera move: ${input.motionPrompt}. ${input.style ?? \"realistic\"} style. Slow, ambient, cinematic.`\n}\n\n/**\n * Object asset-type enum — the kinds of variant a user can generate off an\n * object's anchor main image. Mirrors the literal accepted by\n * `POST /v1/generate-object-asset` (`backend/src/routes/generate-object-asset.ts`)\n * and consumed by the MCP `generate_object` verb (kind=\"asset\").\n *\n * The `motion` value is reserved for type-system exhaustiveness on the\n * frontend; the route rejects it because motion variants flow through the\n * dedicated `/v1/generate-object-motion` endpoint (worker-side it's a different\n * BullMQ job type). `custom` is the free-form bucket — callers must supply\n * `attachToColumn` explicitly since the worker can't infer it.\n */\nexport interface ObjectMotionPromptInput {\n name: string\n category?: string\n style?: EntityStyle | string\n motionPrompt: string\n canonicalDescription?: string\n seedPromptHint?: string\n}\n\n/**\n * Build the prompt sent to the i2v provider for an object atmosphere/motion clip.\n *\n * Naming note: character's analog is `buildMotionPrompt`; location uses\n * `buildLocationMotionPrompt`; object uses `buildObjectMotionPrompt` to make\n * the entity type explicit at call sites.\n *\n * The `seedPromptHint` is appended verbatim — Phase C's route layer composes\n * wired-picker hints (Material/Animal/Vehicle/Weapon/Furniture) into this\n * field before passing the input. Empty hint = no-op (the trailing dot still\n * reads cleanly: \"...motion. \" not \"...motion. .\").\n */\nexport function buildObjectMotionPrompt(input: ObjectMotionPromptInput): string {\n const objDesc =\n input.canonicalDescription?.trim() ||\n [input.category, input.name].filter(Boolean).join(\", \").trim() ||\n \"A generic object\"\n const baseStyle = input.style ?? \"realistic\"\n const seedSuffix = input.seedPromptHint?.trim()\n ? `. ${input.seedPromptHint.trim()}`\n : \"\"\n return `${objDesc}. Motion: ${input.motionPrompt}. ${baseStyle} style. Smooth, controlled, product-showcase quality${seedSuffix}.`\n}\n","/**\n * Per-provider prompting doctrine — the single source of truth for \"how to\n * prompt model family X well\". Consumed by:\n * 1. backend/src/prompts/prompt-wizard-system.ts (enhance/generate system prompts)\n * 2. backend/scripts/gen-skills (provider-prompting block in video node skills)\n * 3. backend/src/lib/mcp/tools/models.ts (list_models promptTips)\n * 4. compact recipes in MCP tool descriptions point here via get_node_skill\n *\n * Sources, in precedence order (conflicts resolve top-down):\n * Seedance 2.0:\n * - Official BytePlus ModelArk \"Dreamina Seedance 2.0 series prompt guide\"\n * https://docs.byteplus.com/en/docs/ModelArk/2222480\n * - Official BytePlus ModelArk \"Dreamina Seedance 2.5 prompt guide\"\n * https://docs.byteplus.com/en/docs/ModelArk/2607689 — its \"Differences\n * from Seedance 2.0\" section is the authority for every 2.0-vs-2.5 split\n * below (timestamps, multi-view references, aspect ratios, MOV output).\n * - Official launch post https://seed.bytedance.com/en/blog/official-launch-of-seedance-2-0\n * - KIE API docs https://docs.kie.ai/market/bytedance/seedance-2\n * Kling:\n * - Official \"Kling Video 2.6 Audio User Guide\"\n * https://kling.ai/quickstart/klingai-video-26-audio-user-guide\n * - fal.ai \"Kling 3.0 Prompting Guide\" https://blog.fal.ai/kling-3-0-prompting-guide/\n * - KIE API docs https://docs.kie.ai/market/kling/kling-3-0\n * - Live KIE-path dialogue probe 2026-07-16 (scripted lines spoken verbatim,\n * lip-synced, on both kling-2.6 and kling-3.0 with sound=true)\n * MiniMax H3:\n * - KIE API docs https://docs.kie.ai/market/minimax-h3 (text-to-video /\n * image-to-video / reference-to-video — the API contract is the doctrine\n * source: limits, modes, aspect rules, pricing dimensions). No live probe\n * yet — structure guidance mirrors the platform's ordinal-reference\n * conventions rather than vendor style claims.\n */\nexport interface ProviderPromptDoctrine {\n /** MODEL_CATALOG ids this doctrine covers. */\n readonly providers: readonly string[]\n /** Human heading for skill docs, e.g. \"Seedance 2.0 (seedance-2, seedance-2-fast)\". */\n readonly heading: string\n /** Short bullets for compact surfaces (list_models promptTips). ≤220 chars each. */\n readonly tips: readonly string[]\n /** Full markdown doctrine for system prompts and generated skill docs. */\n readonly doctrine: string\n}\n\nconst SEEDANCE_2_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"seedance-2\", \"seedance-2-fast\", \"seedance-2-mini\", \"seedance-2-5\"],\n heading: \"Seedance 2 (seedance-2, seedance-2-fast, seedance-2-mini, seedance-2-5)\",\n tips: [\n \"Storyboard as 'Shot 1: … Shot 2: …'. The 2.0 SKUs ignore timestamps and '(0-3s)' shots are officially unstable there; seedance-2-5 honours integer-second timestamps ('0-3s: …', 'at the 5-second mark').\",\n \"One camera movement per shot; describe actions per body part with degree ('slowly raises a hand'); express emotion as physical detail, never abstract words.\",\n \"Native multi-track audio — cue it inline: (background music), <sound effects>, and quoted dialogue.\",\n \"References go by ordinal (@Image 1, Video 2) in attachment order; earlier = higher priority. Identity = ONE headshot + ONE full-body (multi-view sheets drift on 2.0; 2.5 accepts them). 4-5 assets beats maxing 9/3/3.\",\n \"No negative-prompt parameter — put constraints in the prompt: 'keep it subtitle-free, do not generate a watermark, do not generate a logo'.\",\n \"seedance-2-5 only: one shot runs to 30s (2.0 stops at 15s) — storyboard a whole beat, not a stitch; timestamps work (gap-free, 1s units, don't overpack); refs 30/10/10 but 4-5 assets still gives the best identity.\",\n \"Auto-path formula: Subject → Action → Environment → Camera → Style → Constraints in 60-100 words; ONE camera instruction (chain with 'then'); separate camera motion from subject motion; always add one lighting phrase.\",\n ],\n doctrine: `Prompt structure (front-load what matters most):\nprecise subject → action details → scene/environment → lighting & color tone → camera movement → visual style → image quality → constraints.\n\n**Shots & pacing**\n- Storyboard complex videos as \"Shot 1: … Shot 2: … Shot 3: …\" in event order. TIMESTAMPS ARE VERSION-SPLIT: the 2.0 SKUs (seedance-2 / -fast / -mini) respond to shot numbers only — do NOT attach timestamps there (e.g. \"(0-3s)\"; precise timing is officially unstable on 2.0 and forcing durations can break generation, so let the model pace). seedance-2-5 honours integer-second timestamps — the forms and limits are under \"Generation differences\" below.\n- Per shot cover, in order: camera move or transition, subject action + expression, spatial/position change, audio for that shot.\n- One camera movement type per shot — never ask for push + pan + orbit at once (image instability).\n- Prefer slow, gentle, continuous movements over high-burst action (sprints, big jumps, violent rolls morph). Describe actions per body part with quantified degree: \"slowly raises a hand\", \"pushes hard off the ground\". Chain actions with inertia: \"uses the momentum of the turn to naturally raise an arm\".\n- Express emotion as externalized physical detail, never abstract words: not \"very sad\" but \"lowering the head, shoulders trembling slightly, eyes reddening, fingers clutching the corner of clothing\".\n\n**Generation differences (seedance-2-5 vs the 2.0 SKUs)**\n- A single 2.5 shot runs to 30s, where every 2.0 SKU stops at 15s. Plan a complete 4-6 shot beat inside ONE generation instead of splitting it into two clips and stitching — no seam to hide, and continuity holds because it never leaves the model.\n- 2.5 also takes far more reference material (30 images / 10 videos / 10 audio vs 9/3/3). Treat that as room for COVERAGE — more distinct characters, locations and props in one shot — not as licence to pile refs onto one identity. The \"ONE headshot + ONE full-body, 4-5 assets total\" rule above still produces the best likeness on 2.5.\n- 2.5 renders at 480p/720p/1080p (1080p since 2026-08-17): there is no 4K tier, so route a job that needs 4K to seedance-2 (which has it) or upscale afterwards.\n- With a start frame, 2.5 always derives the output aspect from that frame — an explicit aspect ratio is rejected outright, so compose the frame at the ratio you want.\n- Timestamps (official 2.5 guide, \"Differences from Seedance 2.0\"): 2.0 does not respond to them; 2.5 supports integer-second timestamps in three forms — gap-free intervals (\"0-3s: … 3-7s: … 7-15s: …\" or \"[1s-4s] … [4s-8s] …\"; never leave a hole like \"0-3s … 5-6s\"), time-point control (\"At the 5-second mark, …\"), and relative time (\"After 3 seconds, …\"). Use 1-second units. Too little content in a range lets the model improvise; too much packs in extra cuts or drops beats — budget the seconds. Never use timestamps to drive high-frequency actions (\"shake three times per second\").\n- Multi-view subject images: not recommended on 2.0 (the views read as separate people → twins); supported on 2.5. ONE headshot + ONE full-body remains the safest default on both.\n- Transitions and camera terms on 2.5: state a transition's trigger point AND method in one sentence — \"At the 5-second mark, the camera quickly transitions leftward using a left wipe combined with a natural dissolve.\" Basic shot and camera terms are written directly (push in / pull out / pan / track / orbit / dolly zoom / whip pan / hard cut / dissolve / one-shot / speed ramp); only niche terms need [term + descriptive explanation] — which is exactly what the pickers' compact hint mode emits versus their long hints.\n\n**References (when reference media is attached)**\n- Refer to assets by ordinal in attachment order: \"@Image 1\", \"Video 2\", \"Audio 1\". Asset ORDER is priority — put the most identity-critical asset first. (In the editor, the \\`{image:N:label}\\` / \\`{video:N}\\` / \\`{audio:N}\\` prompt tokens auto-emit this binding — \\`{image:1:person}\\` resolves to \"the person from @image_1\" — so a wired reference and its mention stay in sync. An API caller that passes \\`connectedReferences\\` can instead name a reference by its own id — \\`{ref:<id>}\\` / \\`{ref:<id>:label}\\` — and the platform substitutes the \\`@image_N\\` seat after it has numbered the references, so the client never computes N; a token whose reference was not attached drops to its label or name.)\n- Define each subject once, then reuse the label consistently: 'Define the woman in the red dress in Image 1 as the courier' … 'the courier opens the door'. In multi-character scenes bind every character to its image (\"the man from Image 1 hands the box to the woman from Image 2\") and append: \"do not generate duplicate copies of the same character\".\n- Character identity: ONE close-up headshot + ONE full-body image is ideal. On the 2.0 SKUs do NOT attach multi-view/three-view character sheets — the model reads the views as separate people, causing identity drift and twin duplicates; 2.5 accepts multi-view images (see \"Generation differences\").\n- 4-5 assets total works best (1-2 character images + 1 scene image + 1 camera-movement video + 1 audio clip). Maxing out the 9-image/3-video/3-audio limits degrades feature priority and adherence.\n- Editing/extension instructions name clips directly: \"Extend Video 1 backward…\", \"Remove the chair from Video 1\". Saying \"reference Video 1\" flips the model into reference mode and breaks the edit. Track completion: \"Video 1 + [transition description] + followed by Video 2\" (≤3 clips, ≤15s total).\n\n**Audio (native multi-track: music + ambience + voice, stereo)**\n- Cue the layers separately with the official symbols: full-width parentheses for music (slow jazz piano in the background), angle brackets for sound effects <rain tapping on glass>, and dialogue as quoted speech: the man says \"It's not that bad\". Seedance also accepts curly-brace dialogue, but on Nodaro curly braces are reserved for prompt variables — always use quotes for dialogue here.\n- Mark the language for non-English/Chinese dialogue (\"says in Japanese …\").\n- With a reference voice attached, also describe the timbre in words: \"the low, warm, finely grainy middle-aged male voice of Audio 1\".\n\n**Quality & constraints**\n- Quality tail: \"HD, rich details, cinematic texture, natural colors, stable picture.\"\n- Anti-junk constraints (these official templates ARE negative-form): \"keep it subtitle-free\", \"avoid generating any text or subtitles\", \"do not generate a watermark\", \"do not generate a logo\". Landscape output is markedly less subtitle-prone than portrait — generate 16:9 and crop when portrait text-safety matters.\n- There is NO negative-prompt parameter on Seedance — all constraints belong in the prompt text itself.\n\n**Known weaknesses → workarounds**\n- Text rendering is weak: keep on-screen text to short common words; for exact text or logos, attach the artwork as a reference image and instruct \"the logo from Image N stays in the corner unchanged\".\n- More than 4 referenced people gets unstable: group people into composite images of ≤4 first (image generation), then reference those composites.\n- Repeated extension degrades quality: prefer high-definition reference assets and avoid stacking many continuations.\n\n**Auto-path formula (community-sourced enrichment; captured 2026-08-09)**\n- Six steps IN ORDER, 60-100 words total (longer measurably degrades): Subject → Action → Environment → Camera → Style → Constraints.\n- ONE primary camera instruction per shot. Compound moves chain with \"then\": \"camera slow tracking then subtle rise\" — never two competing verbs. The 8 reliable camera types: push-in, pull-out, pan, tracking, orbit/arc, aerial, handheld, locked-off.\n- SEPARATE camera movement from subject movement — the single biggest quality lever: \"The dancer spins slowly. Camera holds fixed framing.\" — never \"spinning camera around a dancing person\".\n- Pace with human words (slow / gentle / gradual / smooth / controlled) — never fps numbers or f-stops in the basic path.\n- ALWAYS add one lighting phrase (highest-impact single addition): golden hour / rim light / neon glow / backlit / overcast.\n- Bake stability constraints in: \"avoid jitter and bent limbs\", \"avoid temporal flicker\", \"avoid identity drift\".\n- Ban vague adjectives standing alone (\"epic\", \"amazing\", \"beautiful\", bare \"cinematic\") — every adjective needs a concrete noun.\n- Mode notes: i2v — skip subject description (the frame has it), focus on motion, append \"preserve composition and colors\". v2v — describe the style TRANSFORM, keep motion + identity.\n- Advanced (pro path): focal angles in degrees (\"47° normal\", \"29° telephoto\", \"107° wide\"); \"180° shutter\" for filmic motion blur; handheld texture as \"organic shake, micro-drift, subtle dutch\"; \"white balance locked 5200K\"; explicit POSITIVE LOCKS section + \"100% matches the reference\" for identity-critical shots.\n\n**Camera-path control — the magenta-line method (STORYBOARD community technique; the\nmanual pro path for precise trajectories, NOT the auto path)**\n1. Duplicate the start frame; on the COPY draw a thick magenta line + arrowhead — the line is the camera's flight path, the arrow its end point. Keep the clean original.\n2. Attach BOTH frames and declare the guide: \"Image N contains a magenta line and arrow — a hidden camera trajectory guide, NOT part of the scene. Completely remove it: no line, no arrow, no paint, no trail, no reflection.\" Skipping the removal order RENDERS the line.\n3. Command the path: \"one continuous FPV drone glide following the S-shaped curve as closely as possible — do not shortcut. Camera motion is the priority.\" Lock the clean frame as first frame + scene reference; lock the destination frame if wired.\n4. Pace with timing blocks (\"[00:00-00:02] rise over the rooftop … [00:07-00:09] settle on the doorway\") and keep any dialogue SHORT — long lines fight the move.\n5. Assign image-input roles explicitly: first-frame/scene-ref · destination frame · path-guide · 3-6 character-identity refs — and bind identities with @-mentions exactly like the platform's reference pills.`,\n}\n\nconst KLING_AUDIO_DOCTRINE: ProviderPromptDoctrine = {\n // kling-turbo (2.5 Turbo Pro) + kling-master (2.1 Master) are SILENT tiers of\n // the same engine: the structure/motion guidance applies, the Audio block\n // does not (variant note in the doctrine body).\n providers: [\"kling\", \"kling-3.0\", \"kling-3-omni\", \"kling-turbo\", \"kling-master\"],\n heading: \"Kling 2.1 / 2.5 / 2.6 / 3.0 / 3 Omni (kling, kling-3.0, kling-3-omni, kling-turbo, kling-master)\",\n tips: [\n \"Kling speaks scripted dialogue natively with lip sync — quote the line and enable sound: [Anna: warm calm voice]: \\\"We made it.\\\" On kling/kling-3.0 audio raises the credit cost; kling-3-omni includes it.\",\n \"Structure prompts as Scene → character/element → Motion → Audio → style. Put ALL sound in one 'Audio:' block: dialogue in quotes, then SFX and ambience described plainly ('rain tapping on glass, no music').\",\n \"Give each speaker a stable label + voice description and reuse it exactly — [Detective: low raspy voice, tired] — pronouns or renamed speakers break voice binding in multi-character scenes.\",\n \"Tone words in the bracket steer delivery (whispering, crying, fast urgent voice); pace with 'Immediately' / 'after a pause'. 2.6 voices are English/Chinese only; 3.0 adds dialects and code-switching.\",\n \"kling-3.0 wired references become @element_name mentions (handled automatically by the editor); multi-shot mode forces sound ON. Kling 2.6 prompts cap at 1000 chars — keep the Audio block tight.\",\n \"Say what should NOT sound: 'no background music, no other sounds' — otherwise Kling invents a music bed under dialogue.\",\n ],\n doctrine: `Prompt structure: Scene (setting, light) → Character/Element (who, appearance) → Motion (action, camera) → Audio (dialogue / SFX / ambience / music) → Others (style, emotion).\n\n**Dialogue (native speech + lip sync — verified on the KIE path 2026-07-16)**\n- Quote the spoken line and enable the sound toggle; the model bakes the voice AND matching lip movement: the woman says \"The quick brown fox jumps over the lazy dog.\"\n- Prefer labeled dialogue with a voice description: [Character label: voice/tone description]: \"line\". Example: [Exhausted Partner: trembling frustrated voice]: \"You never listen to me.\"\n- Keep character labels unique and reuse them verbatim — never switch to pronouns mid-prompt; the label is what binds a voice to a speaker across lines. Kling 2.6 additionally supports [Character@VoiceName] platform-voice binding.\n- Tone words inside the bracket steer delivery: whispering, crying voice, controlled serious voice, fast urgent voice. Sequence speech with temporal markers (\"Immediately\", \"after a pause\") when two lines must not overlap.\n- Languages: Kling 2.6 outputs English/Chinese voices only (other languages are auto-translated to English). Kling 3.0 supports multiple languages, dialects, accents, and code-switching within one scene — mark the language explicitly (\"says in Japanese …\").\n\n**SFX / ambience / music**\n- Put them in the same Audio block, described plainly: \"Rain tapping softly on the window, distant thunder, no music.\"\n- State exclusions explicitly — \"no background music, no other sounds\" — or the model tends to add a bed under dialogue.\n\n**Toggle + cost**\n- The audio lever is the node's sound toggle (KIE \\`sound\\` param). On kling (2.6) and kling-3.0 enabling audio raises the credit cost (the \\`:audio\\` composite); kling-3.0 generates audio by DEFAULT — pass sound: false for the cheaper silent tier. kling-3-omni (Replicate) includes audio in its flat per-duration rate.\n- Multi-shot kling-3.0 (\\`multi_shots\\`) forces sound ON — budget for the audio rate.\n\n**References & elements (kling-3.0 / omni)**\n- Wired references are injected as \\`kling_elements\\` and MUST be mentioned as @element_name in the prompt — the editor's {image:N} tokens and the server prefixer handle this automatically; when hand-writing prompts, mention every element or it is silently ignored.\n- kling-3-omni is image-to-video only (start frame required) and accepts up to 7 reference images; element voice references (element_input_audio_urls, 5-30s clips) bind a voice to an element.\n\n**Limits**\n- Kling 2.6 prompts cap at 1000 characters — front-load scene + dialogue and trim style tails first. kling-3.0 accepts long prompts.\n- Durations: 2.6 = 5/10s; 3.0/omni = 3-15s. A spoken line needs roughly 1s per 2-3 words — don't script more dialogue than the clip can hold.\n\n**Variant note — kling-turbo (2.5 Turbo Pro) & kling-master (2.1 Master)**\n- SILENT tiers: no audio parameter, so the entire Audio block above does not apply — skip dialogue/SFX cues; the Scene → Character → Motion → Style structure and motion guidance carry over unchanged.\n- Durations 5/10s; kling-turbo takes an end frame (tail_image_url); kling-master is single-image i2v.`,\n}\n\nconst MINIMAX_H3_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"minimax-h3\"],\n heading: \"MiniMax H3 (minimax-h3)\",\n tips: [\n \"Natural-language prompts up to 7000 chars. Front-load what matters: subject → action → scene/environment → lighting → camera move → style. One camera movement per shot.\",\n \"Output 2K (default) or 768P (cheaper tier). Aspect: pure text-to-video needs a concrete ratio (21:9/16:9/4:3/1:1/3:4/9:16); reference runs default to adaptive (match the input).\",\n \"References go by ordinal in attachment order (@Image 1, Video 1) — earlier = higher priority. Caps: 9 images, 3 videos (2-15s each, ≤15s total), 3 audio clips (≤15s total).\",\n \"Reference audio drives speech/lip-sync but never rides alone — pair it with an image or video reference. Audio input is free; the first 5 input images are free, extras bill per image.\",\n \"No negative-prompt parameter — put constraints in the prompt text: 'keep it subtitle-free, do not generate a watermark, do not generate a logo'.\",\n ],\n doctrine: `Prompt structure (front-load what matters most):\nprecise subject → action details → scene/environment → lighting & color tone → camera movement → visual style → image quality → constraints. Prompts are natural language, 1-7000 characters, across all three modes.\n\n**Modes (picked automatically from the wired inputs)**\n- First frame and/or last frame connected, nothing else → exact frame mode (image-to-video): the output opens on the first frame and/or closes on the last. The clip's aspect is inferred from the frame — there is no aspect parameter in this mode.\n- ANY reference connected (image, video, or audio) → reference mode (reference-to-video): frames ride along as reference images with a prompt directive binding them to the opening/closing position. Aspect defaults to adaptive (matches the input); a concrete ratio can be forced.\n- Nothing visual connected → text-to-video. A concrete aspect ratio is required (21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16 — no adaptive); Nodaro renders 16:9 unless one is picked.\n\n**References (when reference media is attached)**\n- Refer to assets by ordinal in attachment order: \"@Image 1\", \"Video 1\", \"Audio 1\". Put the identity-critical asset first. (In the editor, the \\`{image:N:label}\\` / \\`{video:N}\\` / \\`{audio:N}\\` prompt tokens auto-emit this binding, so a wired reference and its mention stay in sync. An API caller that passes \\`connectedReferences\\` can instead write \\`{ref:<id>}\\` / \\`{ref:<id>:label}\\` with the reference's own id — the platform substitutes the \\`@image_N\\` seat after numbering.)\n- Caps: 9 reference images; 3 reference videos, each 2-15s and ≤15s combined; 3 reference audio clips, ≤15s combined. Reference audio cannot be used alone — it must accompany an image or video reference.\n- Define each subject once, then reuse the label consistently (\"the woman from @Image 1 … the woman opens the door\"). A focused set of 4-5 assets beats maxing every cap.\n- Billing note: generated seconds AND reference-video input seconds bill at the same per-second rate; the first 5 input images are free and each extra image adds a small surcharge; audio input is free.\n\n**Audio**\n- Audio is always generated — there is no on/off toggle. With reference audio attached, the model syncs speech to the supplied track (the platform's lip-sync surface routes image + voice line through this mode automatically).\n- Quoted dialogue in the prompt gives the model the line to perform; describe the voice in words when no reference audio is supplied.\n\n**Duration & pacing**\n- 4-15 seconds, integer, default 6. Per-second pricing — a 15s clip costs ~3.7× a 4s clip, so pick the shortest duration that serves the shot.\n- One camera movement type per shot; chain actions with physical, quantified detail (\"slowly raises a hand\", \"pushes hard off the ground\") rather than abstract emotion words.\n\n**Constraints**\n- There is NO negative-prompt parameter — all constraints belong in the prompt text itself: \"keep it subtitle-free, do not generate a watermark, do not generate a logo, stable picture\".`,\n}\n\nconst VEO_31_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"veo3\", \"veo3.1\", \"veo3_lite\", \"veo-1080p\", \"veo-4k\", \"veo-extend\"],\n heading: \"VEO 3.1 — Quality / Fast / Lite (veo3, veo3.1, veo3_lite)\",\n tips: [\n \"Structure prompts as [Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance] — lead with the camera, not the subject (Google's official formula).\",\n \"Dialogue: quote the exact line with attribution — A woman says, \\\"We have to leave now.\\\" (no subtitles). Cue sound as separate lines: SFX: thunder cracks; Ambient noise: quiet hum of a starship bridge.\",\n \"Multi-shot pacing via timestamp blocks: [00:00-00:02] medium shot… [00:02-00:04] reverse shot… — VEO honors per-window actions inside one 8s generation.\",\n \"Negative prompting is positive phrasing: not 'no buildings' but 'a desolate landscape with no buildings or roads'. Keep prompts under ~175 words — longer overloads the generation.\",\n \"Start+end frame: pass both and describe the transition move ('smooth 180-degree arc ending on the POV behind her'). References (ingredients) keep characters/objects consistent and DO generate audio.\",\n ],\n doctrine: `Prompt structure (Google's official Veo 3.1 formula — lead with the camera):\n[Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance].\nExample: \"Medium shot, a tired corporate worker, rubbing his temples in exhaustion, in front of a bulky 1980s computer in a cluttered office late at night, lit by harsh fluorescents and the green monitor glow. Retro aesthetic, 1980s color film, slightly grainy.\"\n\n**Camera vocabulary (use the exact terms)**\n- Movement: dolly shot, tracking shot, crane shot, aerial view, slow pan, POV shot, 180-degree arc shot.\n- Composition: wide shot, medium shot, close-up, extreme close-up, two-shot, low angle, high angle.\n- Lens/focus: shallow depth of field, deep focus, wide-angle lens, macro lens, soft focus.\n\n**Audio (native, multi-track — dialogue / SFX / ambience)**\n- Dialogue: quote the exact line with attribution: The detective says in a weary voice, \"Of all the offices in this town, you had to walk into mine.\" Append \"(no subtitles)\" — VEO otherwise tends to burn captions in.\n- Sound effects on their own line: \"SFX: a crystal wine glass shatters on the marble floor\". Ambient bed: \"Ambient noise: rain against the window, distant traffic\".\n- Sound can drive the visual (\"the sound reverberating through the empty ballroom\") — VEO syncs audio-visual timing.\n\n**Multi-shot timestamp prompting (inside one generation)**\n- Split the clip into [mm:ss-mm:ss] windows, one action per window:\n[00:00-00:02] Medium shot from behind a young explorer walking toward a clearing.\n[00:02-00:04] Reverse shot of her freckled face, eyes widening.\n[00:04-00:08] Wide, high-angle crane shot revealing the ruins below.\n- 4 / 6 / 8 second clips; budget ~2s per window.\n\n**Frames & references**\n- Start + end frame: wire both (imageUrls [start, end]) and describe the camera path between them — \"a smooth 180-degree arc shot, starting front-facing and circling to end on the POV from behind her\".\n- Reference images (ingredients) — **Fast (veo3.1) and Lite (veo3_lite) only**; the Quality SKU (veo3) has no reference-to-video mode at the provider, so wire it with frames alone. Where they are available: attach character/object/scene refs and name them in the prompt (\"using the provided images for the detective and the office, …\"). Reference runs DO generate audio.\n\n**Constraints**\n- Negative prompting works by positive description: write \"a desolate landscape with no buildings or roads\", not \"no buildings\".\n- Keep prompts ≤ ~175 words — beyond that instructions conflict and adherence drops. Resolution 720p/1080p; aspect 16:9 / 9:16.\n\nSources: Google Cloud \"Ultimate prompting guide for Veo 3.1\"\n(cloud.google.com/blog/products/ai-machine-learning/ultimate-prompting-guide-for-veo-3-1),\nKIE VEO API docs (docs.kie.ai/veo3-api/generate-veo-3-video). Captured 2026-08-09.`,\n}\n\nconst GEMINI_OMNI_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"gemini-omni-video\", \"gemini-omni-flash\"],\n heading: \"Gemini Omni (gemini-omni-video, gemini-omni-flash)\",\n tips: [\n \"Multimodal Google video with native audio: text-to-video, image-to-video, and video-edit through the same prompt surface. 4/6/8/10s; 720p/1080p or 4K tier.\",\n \"Structure like the platform default: subject → action → scene → lighting → camera → style. Quote dialogue lines to have them spoken; describe SFX/ambience plainly in the prompt.\",\n \"Text-to-video REQUIRES a concrete aspect ratio (the API hard-rejects a missing one); image runs infer aspect from the input.\",\n \"Reference images ride in image_urls, your references first — bind them by ordinal ('the woman from @image_1'); a wired start frame is appended after them and bound as the opening frame. Video-edit: describe the change.\",\n ],\n doctrine: `Prompt structure (no public Google prompt guide exists for the Omni video endpoint —\nthe API contract is the doctrine source, like MiniMax H3; structure guidance mirrors the\nplatform's ordinal-reference conventions):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Modes (picked from the wired inputs)**\n- Nothing visual → text-to-video. A concrete aspect ratio is REQUIRED — the API hard-rejects a missing one (Nodaro sends the node's ratio; there is no adaptive).\n- Image(s) wired → image-to-video. Your reference images come FIRST, in your order (\\`@image_1\\`, \\`@image_2\\`, …) — bind each in the prompt (\"the woman from @image_1\", \"the interior from @image_2\"); a wired start frame is appended after them and the platform names it as the opening frame.\n- Source video wired → video-edit (served through the same handle): describe the CHANGE (\"replace the daylight with dusk, keep the motion and framing\"), not a full re-description.\n\n**Audio (native)**\n- Audio is generated with the clip. Quote dialogue to have it spoken; describe SFX and ambience plainly (\"rain on glass, low synth bed\"). State exclusions (\"no music\") or a bed may be invented.\n\n**Duration & tiers**\n- 4 / 6 / 8 / 10 seconds. 720p/1080p tier or the pricier 4K tier — pick 4K only when the deliverable needs it (nearly 2× the credits).\n- gemini-omni-flash is the faster/cheaper tier with the identical request surface — same 4/6/8/10s, same 720p/1080p and 4K tiers, same video-edit path. Everything above applies verbatim.\n\nSource: KIE gemini-omni-video market contract (parameters + live behavior probed for the\naspect-ratio hard-reject, see providers/kie/video.ts). Captured 2026-08-09.`,\n}\n\nconst GEMINI_OMNI_12_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"gemini-omni-flash-1-2\"],\n heading: \"Gemini Omni Flash 1.2 (gemini-omni-flash-1-2)\",\n tips: [\n \"Google video with native sound: text-to-video, frames, reference images and video-edit through one prompt surface. Every second from 3 to 15; 360p, 720p, 1080p or 4K.\",\n \"Structure like the platform default: subject → action → scene → lighting → camera → style. Quote dialogue lines to have them spoken; describe SFX and ambience plainly.\",\n \"Only a start frame (and an end frame) wired: they are sent as exact first and last frames. With reference images wired too, frames join the image list after your references and are named in the prompt.\",\n \"Up to 6 reference images: bind them by ordinal ('the woman from @image_1'). No character or voice references on this model. Video-edit: describe the change; the output follows the source clip, up to 15s.\",\n ],\n doctrine: `Prompt structure (no public Google prompt guide exists for this endpoint — the API\ncontract is the doctrine source):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Modes (picked from the wired inputs)**\n- Nothing visual → text-to-video.\n- Start frame alone, or start + end frame → exact frames. First + last holds up to 10s; past that the two frames go by the reference route below.\n- Reference images wired → your images come FIRST, in your order (\\`@image_1\\`, \\`@image_2\\`, …), up to 6. A wired start or end frame is appended after them and the platform names it in the prompt as the opening or closing frame.\n- Source video wired → video-edit: describe the CHANGE, not a full re-description. The output follows the source clip, which is cut to 15s at most. Up to 5 images may ride beside it.\n\n**Audio (native)**\n- Audio is generated with the clip. Quote dialogue to have it spoken; describe SFX and ambience plainly. State exclusions (\"no music\") or a bed may be invented.\n\n**Duration & tiers**\n- Any whole second from 3 to 15. 360p is for drafts; 720p and 1080p are close in price; 4K only when the deliverable needs it.\n\nSource: KIE google/gemini-omni-flash-1-2 market contract. Captured 2026-11-09.`,\n}\n\nconst GROK_IMAGINE_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"grok-i2v\", \"grok-imagine-video-1.5\"],\n heading: \"Grok Imagine (grok-i2v, grok-imagine-video-1.5)\",\n tips: [\n \"Keep prompts simple and direct — Subject + Action + Setting + Camera + Mood. Grok expands the prompt itself; over-specification fights the expander.\",\n \"Image-to-video: the input image IS the first frame (composition, identity, and style are preserved) — describe the MOTION, don't re-describe the still.\",\n \"Video 1.5: 1-15s (default 8), 480p/720p/1080p; exact start and end frame (one image as both = seamless loop), up to 4 in-between frames. Native audio incl. dialogue — quote the line to have it spoken.\",\n \"Aspect ratio applies to text runs (1:1/16:9/9:16/3:2/2:3/auto); a single input image locks the output to the image's own aspect.\",\n ],\n doctrine: `Prompt structure (xAI's guidance is minimal by design — the model auto-expands prompts):\nSubject + Action + Setting + Camera + Lighting/Mood, written simply and directly. Reduce\ndescriptions of static/unchanged parts — spend the words on what MOVES.\n\n**Image-to-video (the primary mode)**\n- The input image is the FIRST FRAME, not a loose reference: composition, subject identity, and visual style carry over. Describe motion and camera only (\"she turns toward the window as the camera slowly pushes in\"); re-describing the still wastes adherence.\n- grok-imagine-video-1.5 takes frames, not loose references: the start frame is the exact FIRST frame, an end frame the exact LAST frame, and the same image wired as both makes a seamless loop. Its Image References are up to 4 IN-BETWEEN frames, in order, placed evenly over the clip at whole seconds (one per second inside it — a 3s clip takes 2); extra frames are left out. Describe the motion that carries the shot from one frame to the next; the frames cannot be named in the prompt, so refer to them in words (\"by the midpoint she has reached the door\").\n- grok-i2v with reference images: images are addressed \\`@image(n)\\` in array order. Your references come first (\\`@image(1)\\` is your first reference); a wired start frame is appended after them and the platform names it as the opening frame.\n\n**Audio (video-1.5)**\n- Native audio generates with the clip — background music, SFX, and lip-synced dialogue. Quote the spoken line; describe the music/SFX plainly. The platform offers no audio toggle for it — cue (or exclude) sound in the prompt text.\n\n**Durations / tiers**\n- grok-i2v: 6 or 10 seconds. grok-imagine-video-1.5: 1-15 seconds in 1s steps (default 8), 480p (default) / 720p / 1080p. At 1080p it takes the start frame ALONE — a run with an end frame, a loop or in-between frames is refused before any credits are held, so use 720p for those. Prompt cap 4096 chars — but shorter is better here.\n\nSources: KIE Grok Imagine contracts (docs.kie.ai/market/grok-imagine/image-to-video,\ndocs.kie.ai/market/grok-imagine/1-5-preview), xAI Grok Imagine 1.5 release notes\n(x.ai/news/grok-imagine-1-5). Captured 2026-08-09; frames and in-between frames 2026-11-11.`,\n}\n\nconst WAN_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"wan\", \"wan-i2v\", \"wan-turbo\", \"wan-flash\", \"wan-2.7\", \"wan-2.7-i2v\", \"wan-2.7-t2v\", \"wan-2.7-pro\", \"wan-videoedit\"],\n heading: \"Wan 2.x (wan, wan-i2v, wan-turbo, wan-2.7 family)\",\n tips: [\n \"Alibaba's official formula: Entity + Scene + Motion (basic) → add Aesthetic control + Stylization (advanced). Image-to-video: Motion + Camera only — the image already defines entity and scene.\",\n \"Sound (2.5+): append a sound description block — voice / sound effects / background music. Avoid scripting EXACT lip-synced lines (official anti-pattern); describe the voice and intent instead.\",\n \"Multi-shot (2.6/2.7): Overall description + shot number + timestamp + per-shot content. For ONE continuous take write 'Generate single shot' (the shot_type parameter is gone in 2.7).\",\n \"References go by 'Image 1' / 'Video 1' (capitalized, with a space). Anti-patterns: naming real people, demanding exact legible text, rapid scene changes in one clip, very long choreography.\",\n \"Style words are strong levers: cyberpunk, claymation, pixel style, felt style, tilt-shift, time-lapse. wan-videoedit: describe the transform, keep motion + identity.\",\n ],\n doctrine: `Prompt structure (Alibaba Model Studio's official formulas):\n- Basic: Entity + Scene + Motion.\n- Advanced: Entity (description) + Scene (description) + Motion (description) + Aesthetic control + Stylization.\n- Image-to-video: Motion + Camera movement ONLY — the wired image already defines entity and scene; re-describing it fights the frame.\n- Sound (2.5/2.6/2.7): … + Sound description (voice / sound effects / background music).\n- Multi-shot (2.6/2.7): Overall description + Shot number + Timestamp + Shot content.\n- Reference-to-video (2.6/2.7): Reference identifier + Action + Scene + optional Lines + optional BGM.\n\n**Camera vocabulary**\npush-in (intimacy/tension), pull-out (scale/isolation), tracking shot, orbit, fixed camera, and compound movements chained sequentially for epic scale.\n\n**Single-shot control (2.7)**\n- The shot_type parameter no longer exists — write \"Generate single shot\" in the prompt to force one continuous take; otherwise 2.7's planner may cut.\n\n**References**\n- English format is \"Image 1\" / \"Video 1\" (capitalized, space-separated) — bind every wired asset by that name or it may be ignored.\n\n**Official anti-patterns (from Alibaba's guide)**\n- Do NOT name specific real people.\n- Do NOT script exact lip-synced dialogue — describe the voice and intent (\"she murmurs a reassurance, warm and low\") instead of demanding word-perfect lips.\n- Avoid rapid scene changes inside a single clip, very long choreographed sequences, and demands for exactly legible on-screen text.\n\n**Stylization**\n- Style words are strong levers: cyberpunk, line-art illustration, felt style, 3D cartoon, pixel style, puppet animation, claymation, black-and-white animation, tilt-shift, time-lapse.\n\nSource: Alibaba Cloud Model Studio — \"Text-to-video / image-to-video prompt guide\"\n(alibabacloud.com/help/en/model-studio/text-to-video-prompt). Captured 2026-08-09.`,\n}\n\n// Wan 3.0 is a SEPARATE doctrine from WAN_DOCTRINE on purpose: Wan 2.x binds\n// references as \"Image 1\" / \"Video 1\" (capitalised, WITH a space) while the Wan\n// 3.0 contract uses \"Image1\" / \"Video1\" / \"Audio1\" (no space), and 3.0's surface\n// (adaptive aspect, boolean audio, 30s, mutually-exclusive frame vs reference\n// modes) is different. Folding them together would ship a token format the model\n// does not use. There is no published Wan 3.0 prompt guide, so the body below is\n// KIE contract facts only — no invented vendor style claims.\nconst WAN_3_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"wan-3\", \"wan-3-prime\"],\n heading: \"Wan 3.0 (wan-3, wan-3-prime)\",\n tips: [\n \"Two INPUT MODES, exclusive on the wire: first/last frame, OR reference mode (images + videos + audio). With any reference wired the platform folds the frame into the references and names it in the prompt.\",\n \"References bind by ordinal token in array order: Image1, Image2, Video1, Audio1 — no space, unlike Wan 2.x's \\\"Image 1\\\". Name every wired asset or it may be ignored.\",\n \"Reference caps: 10 images / 5 videos / 5 audio clips; each video and each audio clip 1-15s, with ≤15s combined per array. With reference videos, input seconds + output duration ≤ 30.\",\n \"2-30 seconds (default 5); 480p/720p/1080p; aspect adaptive (default, matches the input media) or 16:9 / 4:3 / 1:1 / 3:4 / 9:16. Prompt cap 20,000 chars — excess is truncated silently.\",\n \"`audio` is a boolean, ON by default: the clip comes back with an ambient/SFX track. Cue the sound you want in the prompt, or state the exclusion (\\\"no music\\\") — it is not a dialogue guarantee.\",\n \"wan-3-prime is the HIGH-SPEED tier: identical surface and limits, faster turnaround at a higher per-second rate. It is not a quality upgrade — choose it for latency, not for looks.\",\n ],\n doctrine: `Prompt structure (no public Wan 3.0 prompt guide exists — the KIE API contract is the\ndoctrine source, like MiniMax H3 and HappyHorse; platform-standard structure applies):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Modes (mutually exclusive at the provider)**\n- Frame mode: first_frame_url, optionally with last_frame_url, and NO references — the frames anchor the shot exactly, so describe MOTION and camera, not the still.\n- Reference mode: image / video / audio reference arrays. The provider CANNOT take these together with the first/last frame parameters, so when both are wired the platform folds — the frame is appended to the reference images (after the caller's own, ordinals unchanged) and bound in the prompt as the opening/closing frame. Write for reference mode whenever a reference is attached.\n- Text-only runs are supported and are the model's default mode.\n\n**Reference binding**\n- Assets bind by ORDINAL TOKEN in array order: Image1, Image2, …, Video1, …, Audio1, …. Note the format has NO space — Wan 2.x's \"Image 1\" is a different generation and does not apply here.\n- Write the binding into the prompt explicitly (\"Image1 walks into the room described in Image2\"); an unnamed reference may simply be ignored.\n- Caps: up to 10 images, 5 videos, 5 audio clips. Each video and each audio clip must be 1-15s with ≤15s combined per array. Audio should not be the only media input — pair it with an image or a video.\n\n**Duration, resolution, aspect**\n- 2-30 seconds (provider default 5). With reference videos there is an extra ceiling: input video duration + output duration ≤ 30 seconds.\n- 480p / 720p / 1080p. Aspect \"adaptive\" (the default — the model selects the ratio from the input media and intent) or 16:9 / 4:3 / 1:1 / 3:4 / 9:16. There is no 21:9.\n- Prompts accept Chinese and English, up to 20,000 characters; anything beyond is truncated silently, so front-load the load-bearing content.\n\n**Audio**\n- The \"audio\" boolean defaults ON and produces an ambient/SFX track with the clip. Describe the soundscape you want plainly (\"rain on glass, distant traffic\"), or state the exclusion, or turn the toggle off. The contract documents no lip-synced dialogue guarantee — plan spoken lines as a separate TTS + lip-sync pass.\n\n**Tiers**\n- wan-3 and wan-3-prime take identical inputs. Prime trades a higher per-second rate for faster turnaround; it is not documented as a quality tier.\n\nSource: KIE Wan 3.0 market contract (docs.kie.ai/market/wan/3-0-video,\ndocs.kie.ai/market/wan/3-0-video-prime). Captured 2026-09-01.`,\n}\n\n// Vidu Q4 — no public Q4 prompt guide is captured, so like Wan 3.0 / MiniMax H3\n// the body is KIE contract facts plus the platform-standard structure. The\n// contract names references \"reference image 2\" / \"reference audio 1\"; the\n// editor's reference tokens emit the platform-wide `@image_N` / `@audio_N`\n// binding instead (see ref-binding.ts), which is what this doctrine teaches.\nconst VIDU_Q4_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"vidu-q4\"],\n heading: \"Vidu Q4 (vidu-q4)\",\n tips: [\n \"A start frame alone animates that frame (prompt optional). Any reference image or audio switches to reference mode: the prompt is REQUIRED and the start frame joins the reference images.\",\n \"Reference mode: 1-15 images, up to 3 audio clips (MP3 only, 3-12s each). Name each by ordinal — \\\"the man from @image_2 says … in the voice of @audio_1\\\".\",\n \"No text-only runs and no end frame: wire a start frame or at least one reference image.\",\n \"3-16s (default 5); 540p / 720p (default) / 1080p / 2K / 4K; reference runs take 16:9 / 9:16 / 1:1 / 4:3 / 3:4. Prompt cap 20,000 chars.\",\n \"`audio` is ON by default (synchronized sound). Cue the sound you want or state the exclusion; dialogue is not verified here, so plan key lines as a TTS + lip-sync pass.\",\n ],\n doctrine: `Prompt structure (no public Vidu Q4 prompt guide is captured — the KIE API contract is the\ndoctrine source; platform-standard structure applies):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Modes (picked by what is wired)**\n- Start frame only → image-to-video. The frame anchors the shot and its aspect ratio; describe MOTION and camera, not the still. The prompt is optional.\n- Any reference image or reference audio → reference-to-video. The prompt is REQUIRED. A wired start frame cannot be sent as a frame here, so the platform adds it to the reference images (after the caller's own, ordinals unchanged) and names it in the prompt as the opening frame.\n- There is no text-only mode and no first+last frame mode.\n\n**Reference binding**\n- Refer to inputs by ordinal in attachment order. In the editor the reference tokens emit \"@image_N\" / \"@audio_N\" — write the binding explicitly (\"the woman from @image_1 turns to the man from @image_2 and says …, in the voice of @audio_1\").\n- Caps: 1-15 reference images (JPG / PNG / WEBP) and 0-3 reference audio clips. Audio must be MP3, each 3-12 seconds — the platform refuses any other format or length before the run starts.\n\n**Duration, resolution, aspect**\n- 3-16 seconds (default 5). 540p / 720p (default) / 1080p / 2K / 4K.\n- Image-to-video has no aspect setting — the output inherits the start frame's shape. Reference runs take 16:9 (default) / 9:16 / 1:1 / 4:3 / 3:4.\n- Prompts up to 20,000 characters.\n\n**Audio**\n- The \"audio\" boolean defaults ON and generates synchronized sound with the clip (the contract says \"dialogue and sound effects\"). Describe the soundscape plainly or state the exclusion, or turn the toggle off for a silent clip.\n\nSource: KIE Vidu Q4 market contracts (docs.kie.ai/market/vidu-q4/image-to-video,\ndocs.kie.ai/market/vidu-q4/reference-to-video). Captured 2026-10-17.`,\n}\n\n// Kling 4.0 — two KIE endpoints, two ids. No public Kling 4.0 prompt guide is\n// captured, so like Vidu Q4 the body is KIE contract facts plus the\n// platform-standard structure. The provider runner maps the platform's\n// `@image_N` / `@audio_N` tokens and wired characters onto Kling's own names\n// (`@image_1`, `@keyframe_1`, a subject's `@Name`, a voice's `@VoiceN`) and drops\n// the `@` from any mention the request does not declare, which KIE rejects.\nconst KLING_4_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"kling-4\", \"kling-4-keyframes\"],\n heading: \"Kling 4.0 (kling-4, kling-4-keyframes)\",\n tips: [\n \"kling-4: text only, or up to 10 images, 5 videos (2-30s), 7 characters and 3 voices (15 in all). Name each: @image_1, @video_1, a character's @Name, a voice clip @audio_1.\",\n \"kling-4-keyframes: start frame, up to 8 in-between frames (Image References, in order), end frame — @first_frame, @keyframe_1 …, @last_frame. 3s takes 4 frames in all, 9s or longer 10.\",\n \"3-30s (default 5), 720p (default) / 1080p, native audio always on. A reference video lends its camera moves and pacing; keep-original-sound keeps its own audio.\",\n \"Prompt cap 8,000 chars. Aspect auto / 16:9 / 9:16 / 1:1 / 21:9 — Keyframes follows the start frame's shape once a frame is attached.\",\n ],\n doctrine: `Prompt structure (no public Kling 4.0 prompt guide is captured — the KIE API contract is the\ndoctrine source; platform-standard structure applies):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Two models**\n- Kling 4.0 (kling-4) — reference-to-video. With no materials it is plain text-to-video. Materials: up to 10 reference images, 5 reference videos (2-30 seconds each), 7 subjects (characters) and 3 voices, at most 15 together. A wired start frame cannot be a frame here, so the platform adds it to the reference images and names it as the opening frame.\n- Kling 4.0 Keyframes (kling-4-keyframes) — keyframe-to-video. A start frame, up to 8 in-between frames in time order, and an end frame; the story passes through each. With no frame it is text-to-video.\n\n**Naming materials in the prompt**\n- Every material is named with \"@\": @image_1 … for reference images, @video_1 … for reference videos, a character by its own name (@Maya), a voice clip as @audio_1 (sent to Kling as a named voice). Keyframes: @first_frame, @keyframe_1 … @keyframe_8, @last_frame.\n- Kling refuses a prompt that names a material the request does not carry; the platform removes the \"@\" from such a mention so the run still starts — wire the material if the mention matters.\n- Write the binding explicitly: \"@Maya walks through the street from @image_1 and greets the camera in the voice of @audio_1\".\n\n**Keyframe rules**\n- Total frames (start + in-between + end) are capped by duration: 3s → 4, 4s → 5, 5s → 6, 6s → 7, 7s → 8, 8s → 9, 9s or longer → 10. Describe how the shot moves from one frame to the next.\n- Once any frame is attached the output takes the start frame's shape; aspect ratio applies to text-only runs.\n\n**Reference videos**\n- A reference video lends its camera moves and pacing — swap the characters or products in the prompt (\"recreate the camera move of @video_1 with …\"). Keep original sound keeps the clip's own audio; otherwise new sound is generated.\n\n**Duration, resolution, audio**\n- 3-30 seconds (default 5); 720p (default) or 1080p; aspect auto (follows the materials, 16:9 with none) / 16:9 / 9:16 / 1:1 / 21:9. Prompts up to 8,000 characters.\n- Native audio is always generated (the contract cites lip-sync and dialogue in 10+ languages); not yet verified for scripted lines here, so plan key dialogue as a TTS + lip-sync pass.\n\nSource: KIE Kling 4.0 market contracts (docs.kie.ai/market/kling/v4-reference-to-video,\ndocs.kie.ai/market/kling/v4-keyframe-to-video), live-probed 2026-10-23.`,\n}\n\n// Kling 4.0 Flash — one id over KIE's two Flash endpoints, picked by what is\n// wired (a start frame alone → keyframe endpoint; anything else → reference\n// endpoint). KIE contract facts plus the platform-standard structure, as for\n// Kling 4.0. The provider runner names subjects (`@Name`), binds each voice\n// clip to a subject, and drops the `@` from any undeclared mention.\nconst KLING_4_FLASH_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"kling-4-flash\"],\n heading: \"Kling 4.0 Flash (kling-4-flash)\",\n tips: [\n \"A start frame alone is the exact opening frame (@first_frame). Beside references it joins the reference images, like kling-4.\",\n \"References: up to 10 images, 5 videos (2-20s together) and 7 characters (15 in all). Name each: @image_1, @video_1, a character's @Name.\",\n \"No standalone voice: voice clip N is the voice of wired character N, if that character has 2-4 images (else the clip is dropped); write the character, never @audio_N.\",\n \"3-20s (default 5), 720p only, native audio always on, no end frame. Prompt cap 8,000 chars. Aspect auto / 16:9 / 9:16 / 1:1 / 21:9 (a start frame alone sets its own shape).\",\n ],\n doctrine: `Prompt structure (no public Kling 4.0 Flash prompt guide is captured — the KIE API contract is\nthe doctrine source; platform-standard structure applies):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**One model, two endpoints (picked by what is connected)**\n- A start frame with nothing else — no reference image, no reference video, no character — runs keyframe-to-video: the frame is the exact opening frame and the clip takes its shape. Name it @first_frame.\n- Anything else — text only, reference images, reference videos, characters, or a start frame beside any of them — runs reference-to-video. A start frame there joins the reference images and is named as the opening frame, as on kling-4.\n\n**Naming materials in the prompt**\n- @image_1 … for reference images, @video_1 … for reference videos, a character by its own name (@Maya). Kling refuses a prompt that names a material the request does not carry; the platform removes the \"@\" from such a mention so the run still starts.\n- There are no standalone voices. Reference audio clip N becomes the voice of character N, in the order the characters are wired. A character needs 2-4 images to carry a voice: a clip whose character has one image, and any clip past the last character, is dropped (the run still starts). Write who speaks by the character's name (\"@Maya says…\"), never @audio_1.\n\n**Limits**\n- Reference images 10, reference videos 5, characters 7 — 15 in all. Reference videos together must be 2-20 seconds; a longer set is refused before the run starts.\n- No end frame and no in-between frames: describe how the shot ends in words.\n\n**Duration, resolution, audio**\n- 3-20 seconds (default 5); 720p only; aspect auto (follows the materials, 16:9 with none) / 16:9 / 9:16 / 1:1 / 21:9. Prompts up to 8,000 characters.\n- Native audio is always generated; keep-original-sound keeps a reference video's own audio. Not yet verified for scripted lines here, so plan key dialogue as a TTS + lip-sync pass.\n\nSource: KIE Kling 4.0 Flash market contracts (docs.kie.ai/market/kling/v4-flash-reference-to-video,\ndocs.kie.ai/market/kling/v4-flash-keyframe-to-video), read 2026-11-11.`,\n}\n\nconst HAPPYHORSE_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"happyhorse\", \"happyhorse-i2v\", \"happyhorse-ref2v\", \"happyhorse-edit\"],\n heading: \"HappyHorse 1.1 (happyhorse, happyhorse-i2v, happyhorse-ref2v)\",\n tips: [\n \"Any-language prompts up to 5000 chars (2500 Chinese) — excess is silently truncated, so front-load subject → action → scene → camera → style.\",\n \"3-15 seconds per second of billing; 720p or 1080p; ratios 16:9 / 9:16 / 1:1 / 4:3 / 3:4. Pick the shortest duration that serves the shot.\",\n \"ref2v is one of the few true REFERENCE modes on the roster: wired refs keep identity across the clip — bind each reference explicitly in the prompt.\",\n \"No published vendor style guide — the platform's standard structure applies; keep one camera move per shot and quantify motion physically.\",\n ],\n doctrine: `Prompt structure (no public HappyHorse prompt guide exists — the KIE API contract is the\ndoctrine source; platform-standard structure applies):\nsubject → action → scene/environment → lighting → camera movement → style → constraints.\n\n**Contract facts (KIE, per-mode pages)**\n- Prompts: any language, up to 5000 non-Chinese / 2500 Chinese characters — excess is TRUNCATED silently, so put the load-bearing content first.\n- Duration 3-15s (default 5), billed per second. Resolution 720p / 1080p (default). Aspect 16:9 (default) / 9:16 / 1:1 / 4:3 / 3:4.\n- Modes: text-to-video (happyhorse), image-to-video (happyhorse-i2v), reference-to-video (happyhorse-ref2v) — ref2v preserves wired identities; name each reference in the prompt so the binding is explicit, as \\`[Image N]\\` in array order: your references come first (\\`[Image 1]\\` is your first), and a wired start frame is appended after them and named as the opening frame.\n\n**Style guidance (platform-standard, honestly generic)**\n- One camera movement per shot; physical, quantified action (\"slowly raises a hand\") over abstract emotion words; state exclusions (\"no on-screen text, no watermark\") in the prompt.\n\nSource: KIE HappyHorse 1.1 contracts (docs.kie.ai/market/happyhorse/text-to-video,\n…/happyhorse-1-1/image-to-video, …/happyhorse-1-1/reference-to-video). Captured 2026-08-09.`,\n}\n\nconst RUNWAY_KIE_DOCTRINE: ProviderPromptDoctrine = {\n providers: [\"runway-kie\", \"runway-extend\", \"runway-aleph\"],\n heading: \"Runway via KIE (runway-kie)\",\n tips: [\n \"Prompt cap is 1800 chars; KIE's own guidance: be specific about subject, action, style, and setting. No native audio — plan sound as a separate pass.\",\n \"Durations 5 or 10s with a hard trade-off: 10s cannot be 1080p, 1080p cannot exceed 5s — pick per deliverable.\",\n \"Text runs REQUIRE an aspect ratio (16:9/4:3/1:1/3:4/9:16); image runs IGNORE it — the input image dictates output dimensions.\",\n \"Image-to-video treats the image as the anchor frame: describe motion and camera, not the still.\",\n ],\n doctrine: `Prompt structure (KIE contract guidance): \"be specific about subject, action, style, and\nsetting\" — subject → action → scene → camera → style, within the 1800-character cap.\n\n**Contract facts (KIE Runway endpoint)**\n- Duration 5 or 10 seconds; quality 720p or 1080p — 10s@1080p does NOT exist (10s forces 720p; 1080p forces 5s). Choose by deliverable: crisp hero shot → 5s/1080p; longer beat → 10s/720p.\n- Text-to-video REQUIRES aspectRatio (16:9 / 4:3 / 1:1 / 3:4 / 9:16). Image-to-video IGNORES aspectRatio — the input image dictates output dimensions.\n- No audio is generated — score/SFX are a separate pass (merge-video-audio / video-sfx downstream).\n\n**Style guidance**\n- The image input anchors composition and identity — describe the motion (\"she pushes the door open as the camera tracks left\"), not the still.\n- Keep one continuous camera idea per clip; front-load the subject and action.\n\nSource: KIE Runway contract (docs.kie.ai/runway-api/generate-ai-video). Captured 2026-08-09.`,\n}\n\nexport const PROVIDER_PROMPT_DOCTRINES: readonly ProviderPromptDoctrine[] = [\n SEEDANCE_2_DOCTRINE,\n KLING_AUDIO_DOCTRINE,\n MINIMAX_H3_DOCTRINE,\n VEO_31_DOCTRINE,\n GEMINI_OMNI_DOCTRINE,\n GEMINI_OMNI_12_DOCTRINE,\n GROK_IMAGINE_DOCTRINE,\n WAN_DOCTRINE,\n WAN_3_DOCTRINE,\n VIDU_Q4_DOCTRINE,\n KLING_4_DOCTRINE,\n KLING_4_FLASH_DOCTRINE,\n HAPPYHORSE_DOCTRINE,\n RUNWAY_KIE_DOCTRINE,\n]\n\nconst DOCTRINE_BY_PROVIDER: ReadonlyMap<string, ProviderPromptDoctrine> = new Map(\n PROVIDER_PROMPT_DOCTRINES.flatMap((d) => d.providers.map((p) => [p, d] as const)),\n)\n\n/** Full doctrine for a provider id, or undefined when none exists. */\nexport function getPromptDoctrine(providerId: string): ProviderPromptDoctrine | undefined {\n return DOCTRINE_BY_PROVIDER.get(providerId)\n}\n\n/** Compact tips for a provider id ([] when none) — used by list_models. */\nexport function getPromptTips(providerId: string): readonly string[] {\n return DOCTRINE_BY_PROVIDER.get(providerId)?.tips ?? []\n}\n","/**\n * Reference-image prompting doctrine for IMAGE generation — the single source\n * of truth for the `{image:N:label}` token idiom on `generate-image`. Consumed\n * by backend/scripts/gen-skills (the `image-reference-prompting` block in the\n * generate-image node skill), the same way `PROVIDER_PROMPT_DOCTRINES` feeds\n * the video node skills.\n *\n * Unlike the per-provider video doctrines, this is a PLATFORM mechanism: the\n * token grammar and expansion are Nodaro's own (`image-token-pattern.ts` —\n * `IMAGE_TOKEN_PATTERN`; `prompt-builder.ts` — `expandImageRefTokens`), so\n * there is one doctrine, not one per model family.\n *\n * Source of truth for the semantics documented here (verified 2026-08-25):\n * - `IMAGE_TOKEN_PATTERN` = `/\\{image:(\\d+)(?::([^}\\n]+))?\\}/gi`\n * - `expandImageRefTokens`: `{image:N:label}` → `Image N (label)`,\n * `{image:N}` → `Image N`.\n * - A token with no reference at N follows the video resolver's rule\n * (`dropUnwiredImageTokens` in `prompt-builder.ts`): `{image:N:label}` →\n * `label`, a bare `{image:N}` is dropped. Two places keep a token as typed,\n * on purpose: a wired token in a hybrid `Avoid:` line, and the native\n * negative prompt of models with their own negative field (e.g. ideogram-v3).\n * - N is the reference's 1-based position in the assembled reference list\n * (connection order on the `references` handle).\n */\n\nexport interface ImageReferenceDoctrine {\n /** Human heading for skill docs. */\n readonly heading: string\n /** Full markdown doctrine for generated skill docs. */\n readonly doctrine: string\n}\n\nexport const IMAGE_REFERENCE_PROMPT_DOCTRINE: ImageReferenceDoctrine = {\n heading: \"Reference-image prompting ({image:N:label} tokens)\",\n doctrine: `The \\`references\\` handle takes MULTIPLE image producers (upload-image, generate-image, …) wired into one generate-image node. Connection order is the numbering: the first-connected reference is 1. The prompt then binds them with tokens:\n\n- \\`{image:N:label}\\` → expands server-side to \\`Image N (label)\\`, aligned with the numbered reference list sent to the provider.\n- \\`{image:N}\\` → \\`Image N\\` (no role named).\n- A token whose N has no wired reference falls back to its label (\\`{image:3:dog}\\` → \\`dog\\`); a bare \\`{image:N}\\` is dropped. The prompt still runs but binds nothing at N, so check the numbering against what is wired.\n\n**How to compose**\n- The prompt should be little more than tokens plus glue words: \\`{image:1:person} with {image:2:face}\\`. The label tells the model what to TAKE from that image — \\`person\\`, \\`face\\`, \\`background\\`, \\`settings\\`, or a concrete garment/prop name (\\`jacket\\`).\n- Order = priority. Put the identity-critical image first. Swapping the numbers (or the labels) swaps the result — \\`{image:2:person} with {image:1:face}\\` transplants in the opposite direction.\n- Do NOT re-describe what a referenced image already shows; a sentence fighting the reference degrades adherence. Add only what is NEW (pose, lighting, scene) — or better, reference it from another image.\n\n**Core patterns (each is one generate-image node with two wired references)**\n- Identity transplant: \\`{image:1:person} with {image:2:face}\\` — body/outfit/scene from 1, face from 2.\n- Reverse transplant: \\`{image:2:person} with {image:1:face}\\` — same two references, opposite result.\n- Keep the stage, change the star: \\`{image:1:background} with {image:2:person}\\`.\n- Relocation: \\`{image:1:person} in {image:2:settings}\\`.\n- Garment transfer: \\`{image:1:person} Wearing {image:2:jacket} on top, at {image:2:settings}\\` — several labels can pull different things from the SAME image.\n\n**Providers & settings**\n- Multi-reference composition is strongest on the GPT-Image family (\\`gpt-image-2\\`) and the Nano Banana family (\\`nano-banana-pro\\`). Check a model's reference support via \\`list_models\\` before relying on more than one reference.\n- Set an explicit \\`aspectRatio\\` and prefer \\`resolution: \"2K\"\\` for composites — face detail survives the merge better.\n\n**Known pitfall**\n- Person+face composition intermittently trips provider content filters (\"Content policy violation\"). Keep wording neutral (no glamor/body emphasis), and on a rejection rephrase the glue words or swap provider rather than retrying unchanged.`,\n}\n","/**\n * Scene3D layout-reference doctrine — what to tell a video model when a\n * Scene3D render (the clay MP4 from 3D Render Pro or from Render Video over a\n * 3D scene, or a still pulled from one) is attached as a reference.\n *\n * Two rules, both measured on a real scene (2026-09-10 greybox-to-video\n * experiment, `seedance-2-mini`, one variable per run):\n *\n * 1. NEVER send a layout reference without a scoping line. A reference is a\n * style anchor as strongly as it is a composition anchor: unscoped, a\n * greybox in gives a greybox out (run A). One sentence naming what the\n * reference is FOR and what to IGNORE converts the output (run C).\n * 2. EVERY figure that must be photoreal needs its own character reference.\n * Photoreal treatment is granted PER REFERENCED SUBJECT, not globally: a\n * figure with no reference of its own falls back to matching the only\n * reference that depicts it — the greybox (runs D → E). One layout\n * reference plus one character per figure, with two slots left over for a\n * location or style plate, is the budget that converts every figure.\n *\n * This module owns the WORDING. It is content, so it lives here (FSL) and not\n * in `@nodaro/shared`. The platform (`backend/…/scene3d-reference-scoping.ts`)\n * owns the graph walk that decides WHICH reference is a Scene3D render and what\n * it carries; it only ever asks this module for the words.\n *\n * The scoping line is a RAIL CAPTION. The platform already renders one caption\n * per video reference as `@video_N: <caption>.` (`renderReferenceCaptionLines`,\n * the same seat an API caller fills through `referenceVideoCaptions[N]`), so\n * the text built here carries NO leading binding and NO trailing full stop —\n * the renderer supplies both. `renderScene3DLayoutScopingLine` reproduces the\n * rendered form for anything that must quote the line exactly as the model\n * sees it (the Seedance A/B harness, the docs).\n *\n * The line never names the target look (\"photoreal\", \"anime\"): that is the\n * prompt's and the other references' job — rule 2 is what actually buys\n * photoreal figures.\n */\n\n/** What a Scene3D layout reference carries: one frame, or the rendered clip. */\nexport type Scene3DLayoutReferenceCarrier = \"still\" | \"clip\"\n\nexport interface Scene3DLayoutScopingSpec {\n /** One frame (`still`) or the rendered clip (`clip`). */\n readonly carries: Scene3DLayoutReferenceCarrier\n /** Shot count in the composition the reference was rendered from, when\n * known. More than one shot adds the cut points to what the reference is\n * for. Ignored for a still, which is one frame of one shot. */\n readonly shots?: number\n /** Whether the clip includes a camera move. A still never does. */\n readonly includesCameraMotion?: boolean\n}\n\n/**\n * The phrase every scoping line opens with. It is the idempotence key\n * (`hasScene3DLayoutScopingLine`) — a re-run over a prompt that already\n * carries the line for a binding must not add a second one — and it is what an\n * A/B log greps for. Never reword it without migrating the re-run check.\n */\nexport const SCENE3D_LAYOUT_SCOPING_MARKER = \"LAYOUT reference only\"\n\n/**\n * What the reference is FOR — the composition properties that survive a change\n * of look. Geometry properties, deliberately: the experiment's correction to\n * the pipeline doc is that what a layout reference must carry is unambiguous\n * spatial layout, which is a property of geometry, not shading.\n */\nexport const SCENE3D_LAYOUT_SCOPING_FOR = {\n /** Always: where the subjects are and what is in front of what. */\n layout: \"its subject positions and blocking\",\n occlusion: \"its foreground occlusion\",\n framing: \"its framing\",\n cameraAngle: \"its camera angle\",\n /** Clips only. */\n cameraMotion: \"its camera motion\",\n timing: \"its timing\",\n /** Clips with more than one shot. */\n cuts: (shots: number) => `its ${shots} shots and where they cut`,\n} as const\n\n/**\n * What to IGNORE — everything the clay render looks like. Named explicitly,\n * one property at a time, because the model has no other way to know that the\n * grey slabs are placeholders and not the target set dressing.\n */\nexport const SCENE3D_LAYOUT_SCOPING_IGNORE =\n \"Ignore its untextured grey clay placeholder look, its flat placeholder colours, its materials, its lighting and its empty background; none of that is the target look\"\n\n/** Where the look comes from instead. Generic on purpose (see module doc). */\nexport const SCENE3D_LAYOUT_SCOPING_LOOK_SOURCE = \"Take the look from the prompt and from the other references\"\n\n/**\n * Build the scoping caption for one attached Scene3D reference.\n *\n * For a clip with a camera move:\n *\n * `LAYOUT reference only — match its subject positions and blocking, its\n * foreground occlusion, its framing, its camera angle, its camera motion and\n * its timing. Ignore its untextured grey clay placeholder look, its flat\n * placeholder colours, its materials, its lighting and its empty background;\n * none of that is the target look. Take the look from the prompt and from\n * the other references`\n *\n * A still drops the motion, timing and cut clauses: one frame carries none of\n * them, and claiming otherwise would tell the model to match motion it cannot\n * see. No trailing full stop — the rail-caption renderer adds it.\n */\nexport function buildScene3DLayoutScopingLine(spec: Scene3DLayoutScopingSpec): string {\n const matches: string[] = [\n SCENE3D_LAYOUT_SCOPING_FOR.layout,\n SCENE3D_LAYOUT_SCOPING_FOR.occlusion,\n SCENE3D_LAYOUT_SCOPING_FOR.framing,\n SCENE3D_LAYOUT_SCOPING_FOR.cameraAngle,\n ]\n if (spec.carries === \"clip\") {\n if (spec.includesCameraMotion) matches.push(SCENE3D_LAYOUT_SCOPING_FOR.cameraMotion)\n if (typeof spec.shots === \"number\" && Number.isFinite(spec.shots) && spec.shots > 1) {\n matches.push(SCENE3D_LAYOUT_SCOPING_FOR.cuts(Math.floor(spec.shots)))\n }\n matches.push(SCENE3D_LAYOUT_SCOPING_FOR.timing)\n }\n return `${SCENE3D_LAYOUT_SCOPING_MARKER} — match ${joinWithAnd(matches)}. ${SCENE3D_LAYOUT_SCOPING_IGNORE}. ${SCENE3D_LAYOUT_SCOPING_LOOK_SOURCE}`\n}\n\n/** `a, b and c` — the doctrine reads as one sentence, not a list. */\nfunction joinWithAnd(parts: readonly string[]): string {\n if (parts.length <= 1) return parts[0] ?? \"\"\n return `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`\n}\n\n/**\n * The line exactly as the model sees it once the platform has rendered the\n * caption onto its seat: `@video_1: <caption>.` — the same shape\n * `renderReferenceCaptionLines` emits for every rail caption. Use it wherever\n * the rendered form must be quoted verbatim (the A/B harness, the docs); use\n * `buildScene3DLayoutScopingLine` for what to SEND.\n */\nexport function renderScene3DLayoutScopingLine(binding: string, spec: Scene3DLayoutScopingSpec): string {\n return `${binding.trim()}: ${buildScene3DLayoutScopingLine(spec)}.`\n}\n\n/**\n * True when `prompt` already carries a scoping line for `binding`. The check\n * is binding + marker, not the whole caption, so a line an author typed by hand\n * (`@video_1 is a LAYOUT reference only …`) or pasted from the docs still\n * counts as present — the rule is \"one scoping line per reference\", never \"our\n * exact bytes\". Per binding on purpose: `@video_1` scoped says nothing about\n * `@video_2`.\n */\nexport function hasScene3DLayoutScopingLine(prompt: string | undefined, binding: string): boolean {\n if (!prompt) return false\n const b = binding.trim().replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\")\n return new RegExp(`${b}(?::| is an?)\\\\s+${SCENE3D_LAYOUT_SCOPING_MARKER}`).test(prompt)\n}\n\n/**\n * The scoping line the 2026-09-10 experiment's Seedance A/B rerun sends —\n * the clip form, camera move included — computed from the builder so the\n * fixture can never drift from what the platform sends. This is the text an\n * API caller passes as `referenceVideoCaptions[N]` for the Scene3D clip on\n * `referenceVideoUrls[N]`, and what the canvas attaches for it.\n */\nexport const SCENE3D_LAYOUT_REFERENCE_SCOPING_LINE = buildScene3DLayoutScopingLine({\n carries: \"clip\",\n includesCameraMotion: true,\n})\n\n/**\n * Every wording the platform can send, plus the rendered form of each on its\n * usual seat: `clip` on the first video-reference seat, `still` on the first\n * image-reference seat. `clipWithCuts` is a four-shot composition.\n */\nexport const SCENE3D_LAYOUT_REFERENCE_SCOPING_FIXTURE = {\n clip: SCENE3D_LAYOUT_REFERENCE_SCOPING_LINE,\n clipRendered: renderScene3DLayoutScopingLine(\"@video_1\", { carries: \"clip\", includesCameraMotion: true }),\n clipWithCuts: buildScene3DLayoutScopingLine({ carries: \"clip\", shots: 4, includesCameraMotion: true }),\n still: buildScene3DLayoutScopingLine({ carries: \"still\" }),\n stillRendered: renderScene3DLayoutScopingLine(\"@image_1\", { carries: \"still\" }),\n} as const\n\n/**\n * A Scene3D layout reference that has already been LOCATED: what it carries,\n * which seat it landed on, and what that seat is called to the model.\n *\n * Finding these is a graph walk, and the graph differs per engine — the\n * orchestrator holds `SimpleNode`s and run states, the canvas holds React Flow\n * nodes and their own data. Applying the doctrine to them does NOT differ, and\n * that is the half that lives here: the two functions below are the whole of\n * rule 1's application, so a caption cannot mean one thing on a workflow run\n * and another on the same node's Run button.\n */\nexport interface Scene3DLayoutReferenceSeat {\n readonly carries: Scene3DLayoutReferenceCarrier\n /** 0-based seat in the video rail (clip) or the leading image list (still). */\n readonly index: number\n /** `@video_N` / `@image_N`, exactly as the model reads the seat. */\n readonly binding: string\n readonly spec: Scene3DLayoutScopingSpec\n}\n\n/**\n * Rule 1 for clips: the rail-caption array, index-aligned with the reference\n * video list (holes are `\"\"`, which the renderer skips) — the same seat an API\n * caller fills through `referenceVideoCaptions`.\n *\n * `undefined` when there is nothing to add, so a node with no Scene3D\n * reference keeps its prompt byte-identical. A seat the prompt already scopes\n * — by hand, or on a re-run over a stored prompt — gets no second line.\n */\nexport function scene3DLayoutVideoCaptions(\n seats: readonly Scene3DLayoutReferenceSeat[],\n prompt: string | undefined,\n): string[] | undefined {\n const clips = seats.filter((r) => r.carries === \"clip\" && !hasScene3DLayoutScopingLine(prompt, r.binding))\n if (clips.length === 0) return undefined\n const captions: string[] = []\n for (const clip of clips) {\n while (captions.length <= clip.index) captions.push(\"\")\n captions[clip.index] = buildScene3DLayoutScopingLine(clip.spec)\n }\n return captions\n}\n\n/**\n * Rule 1 for stills: an image seat has no caption seat, so the line is appended\n * to the assembled body in the rendered form (`@image_N: <caption>.`) — the\n * same surface a clip's caption renders to. Same idempotence as the captions.\n */\nexport function appendScene3DStillScopingLines(\n prompt: string | undefined,\n seats: readonly Scene3DLayoutReferenceSeat[],\n): string | undefined {\n const stills = seats.filter((r) => r.carries === \"still\" && !hasScene3DLayoutScopingLine(prompt, r.binding))\n if (stills.length === 0) return prompt\n const lines = stills.map((still) => renderScene3DLayoutScopingLine(still.binding, still.spec))\n return prompt ? `${prompt}\\n${lines.join(\"\\n\")}` : lines.join(\"\\n\")\n}\n\n// ---------------------------------------------------------------------------\n// Rule 2 — one character reference per figure\n// ---------------------------------------------------------------------------\n\n/** Rule 2 in user terms. Quoted by the docs and by the warning below. */\nexport const SCENE3D_FIGURE_REFERENCE_RULE =\n \"Every figure that must look real needs its own character reference; a figure without one takes the clay look of the layout reference. Keep two reference slots free for a location or style plate.\"\n\n/** Reference slots to keep free beside the figures — a location or style plate. */\nexport const SCENE3D_FREE_PLATE_SLOTS = 2\n\nexport const SCENE3D_UNREFERENCED_FIGURES_WARNING_CODE = \"scene3d_unreferenced_figures\"\n\nexport interface Scene3DFigureReferenceCheck {\n /** Figures in the composition — `person` entities in a Scene3D v2 plan.\n * `undefined` when the plan cannot say (a v1 plan has no entity roles), in\n * which case there is nothing to warn about. */\n readonly figureCount: number | undefined\n /** Distinct character references attached to the same generation. */\n readonly characterReferenceCount: number\n /** The model's image-reference budget, when known. Lets the message say\n * whether one-per-figure plus the free plate slots even fits. */\n readonly imageReferenceCap?: number\n /** Image seats the layout reference itself occupies: 0 for a clip (it rides\n * the video rail), 1 for a still on an image seat. Default 0. */\n readonly layoutReferenceImageSeats?: number\n}\n\nexport interface Scene3DUnreferencedFiguresWarning {\n readonly code: typeof SCENE3D_UNREFERENCED_FIGURES_WARNING_CODE\n readonly message: string\n readonly figureCount: number\n readonly characterReferenceCount: number\n /** Figures still without a reference of their own. */\n readonly missing: number\n}\n\n/**\n * Rule 2 as a WARNING, never a block: the run still goes out — the user may\n * want clay figures, or be drawing a comparison — but they are told, before\n * they pay to find out, that unreferenced figures will inherit the clay look.\n * Returns `undefined` when there is nothing to say: no figures, an unknown\n * count, or every figure already has a reference.\n */\nexport function buildScene3DUnreferencedFiguresWarning(\n check: Scene3DFigureReferenceCheck,\n): Scene3DUnreferencedFiguresWarning | undefined {\n const figures = check.figureCount\n if (figures === undefined || !Number.isFinite(figures) || figures <= 0) return undefined\n const refs = Math.max(0, Math.floor(check.characterReferenceCount))\n const missing = Math.floor(figures) - refs\n if (missing <= 0) return undefined\n const figureWord = figures === 1 ? \"figure\" : \"figures\"\n const refWord = refs === 1 ? \"character reference is\" : \"character references are\"\n let message =\n `The layout reference shows ${figures} ${figureWord} but ${refs} ${refWord} attached. ` +\n `A figure without its own character reference takes the clay look of the layout reference. ` +\n `Attach one character reference per figure (${missing} more)`\n const cap = check.imageReferenceCap\n if (typeof cap === \"number\" && Number.isFinite(cap) && cap > 0) {\n const seats = Math.max(0, Math.floor(check.layoutReferenceImageSeats ?? 0))\n const spare = cap - seats - figures\n message += spare >= SCENE3D_FREE_PLATE_SLOTS\n ? `; this model takes ${cap} image references, which leaves ${spare} for a location or style plate.`\n : `; this model takes ${cap} image references, so one per figure plus ${SCENE3D_FREE_PLATE_SLOTS} free slots for a location or style plate does not fit — reference the figures that matter most first.`\n } else {\n message += \".\"\n }\n return {\n code: SCENE3D_UNREFERENCED_FIGURES_WARNING_CODE,\n message,\n figureCount: figures,\n characterReferenceCount: refs,\n missing,\n }\n}\n","/**\n * Prompt Wizard — shared types, category definitions, and provider capabilities.\n *\n * Used by the backend (system prompt building) and frontend (type-checking, UI).\n */\n\n// ── Types ──\n\nexport interface WizardCategory {\n readonly key: string\n readonly label: string\n readonly optional?: boolean\n}\n\nexport interface WizardQuestion {\n category: string\n label: string\n options: WizardOption[]\n selected: string | string[] | null\n allowCustom: boolean\n multi?: boolean\n}\n\nexport interface WizardOption {\n value: string\n label: string\n description?: string\n}\n\nexport interface WizardSelection {\n category: string\n value: string\n isCustom: boolean\n}\n\nexport interface RecommendedModel {\n provider: string\n field: string\n label: string\n reason: string\n}\n\nexport interface WizardNodeContext {\n connectedInputTypes?: string[]\n referenceImageCount?: number\n referenceImageUrls?: string[]\n hasSourceVideo?: boolean\n}\n\nexport interface ModelChange {\n field: string\n value: string\n}\n\n// ── Category Definitions ──\n\n// ── Image (generate-image, image-to-image) ──\nexport const IMAGE_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"subject\", label: \"Subject\" },\n { key: \"environment\", label: \"Environment / Setting\" },\n { key: \"lighting\", label: \"Lighting\" },\n { key: \"camera-composition\", label: \"Camera & Composition\" },\n { key: \"style-medium\", label: \"Style / Medium\" },\n { key: \"mood-tone\", label: \"Mood & Tone\" },\n { key: \"details-texture\", label: \"Details / Texture\", optional: true },\n { key: \"what-to-avoid\", label: \"What to Avoid\", optional: true },\n]\n\n// ── Video (text-to-video, image-to-video, video-to-video, motion-transfer, extend-video, speech-to-video) ──\nexport const VIDEO_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"subject-action\", label: \"Subject & Action\" },\n { key: \"environment\", label: \"Environment / Setting\" },\n { key: \"camera-movement\", label: \"Camera Movement\" },\n { key: \"pacing-speed\", label: \"Pacing / Speed\" },\n { key: \"style-look\", label: \"Style / Look\" },\n { key: \"mood-tone\", label: \"Mood & Tone\" },\n]\n\n// ── Music (generate-music, suno-generate) ──\nexport const MUSIC_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"genre-style\", label: \"Genre / Style\" },\n { key: \"mood-energy\", label: \"Mood & Energy\" },\n { key: \"instruments\", label: \"Instruments\" },\n { key: \"tempo\", label: \"Tempo\" },\n { key: \"vocals\", label: \"Vocals\" },\n { key: \"production-style\", label: \"Production Style\" },\n]\n\n// ── Audio / SFX (text-to-audio) ──\nexport const AUDIO_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"sound-type\", label: \"Sound Type\" },\n { key: \"environment\", label: \"Environment\" },\n { key: \"intensity\", label: \"Intensity\" },\n { key: \"texture-quality\", label: \"Texture / Quality\" },\n]\n\n// ── Text / General (text-prompt) ──\nexport const TEXT_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"purpose-intent\", label: \"Purpose / Intent\" },\n { key: \"tone-voice\", label: \"Tone / Voice\" },\n { key: \"audience\", label: \"Audience\" },\n { key: \"length-format\", label: \"Length / Format\" },\n]\n\n// ── LLM Chat (llm-chat) ──\nexport const LLM_CHAT_WIZARD_CATEGORIES: readonly WizardCategory[] = [\n { key: \"task\", label: \"Task / Goal\" },\n { key: \"tone\", label: \"Tone & Style\" },\n { key: \"format\", label: \"Output Format\" },\n { key: \"constraints\", label: \"Constraints\" },\n]\n\n// ── Node Type Mapping ──\n\nconst NODE_TYPE_TO_CATEGORIES: Record<string, readonly WizardCategory[]> = {\n \"llm-chat\": LLM_CHAT_WIZARD_CATEGORIES,\n \"generate-image\": IMAGE_WIZARD_CATEGORIES,\n \"image-to-image\": IMAGE_WIZARD_CATEGORIES,\n \"modify-image\": IMAGE_WIZARD_CATEGORIES,\n \"text-to-video\": VIDEO_WIZARD_CATEGORIES,\n \"image-to-video\": VIDEO_WIZARD_CATEGORIES,\n \"generate-video\": VIDEO_WIZARD_CATEGORIES,\n \"video-to-video\": VIDEO_WIZARD_CATEGORIES,\n \"motion-transfer\": VIDEO_WIZARD_CATEGORIES,\n \"extend-video\": VIDEO_WIZARD_CATEGORIES,\n \"speech-to-video\": VIDEO_WIZARD_CATEGORIES,\n // cinematic-avatar's `prompt` IS a generative prompt (unlike ai-avatar's\n // verbatim `script`), so the wizard applies — see design spec Part B.\n \"cinematic-avatar\": VIDEO_WIZARD_CATEGORIES,\n \"generate-music\": MUSIC_WIZARD_CATEGORIES,\n \"suno-generate\": MUSIC_WIZARD_CATEGORIES,\n // Composite wizard targets: same music form as suno-generate, but the backend\n // system-prompt builder reshapes the OUTPUT per field (not prose):\n // :style → comma-separated Suno *style tags*\n // :negativeStyle → comma-separated tags of styles/sounds to AVOID\n // :lyrics → full sectioned song LYRICS ([Verse]/[Chorus]/…)\n \"suno-generate:style\": MUSIC_WIZARD_CATEGORIES,\n \"suno-generate:negativeStyle\": MUSIC_WIZARD_CATEGORIES,\n \"suno-generate:lyrics\": MUSIC_WIZARD_CATEGORIES,\n \"text-to-audio\": AUDIO_WIZARD_CATEGORIES,\n \"text-prompt\": TEXT_WIZARD_CATEGORIES,\n}\n\nexport function getCategoriesForNodeType(nodeType: string): readonly WizardCategory[] | undefined {\n return NODE_TYPE_TO_CATEGORIES[nodeType]\n}\n\n/** Node types that support the wizard (excludes edit-image, text-to-speech, lip-sync) */\nexport function isWizardSupported(nodeType: string): boolean {\n return nodeType in NODE_TYPE_TO_CATEGORIES\n}\n\n// ── Provider Capabilities (for model recommendation) ──\n// Must be updated when providers are added (see Provider Enum Sync in CLAUDE.md)\n\nexport const PROVIDER_CAPABILITIES: Record<string, Record<string, string>> = {\n \"generate-image\": {\n \"flux\": \"Photorealistic, highly detailed, best overall quality\",\n \"flux-flex\": \"Fast Flux variant, good quality at lower cost\",\n \"flux-kontext\": \"Character consistency, reference-image-aware generation\",\n \"flux-kontext-max\": \"Premium character consistency with highest detail\",\n \"nano-banana\": \"Fast generation, style flexibility, reference image support\",\n \"nano-banana-pro\": \"Higher quality Nano Banana with better detail\",\n \"nano-banana-2\": \"Latest Nano Banana with resolution options (1K/2K/4K)\",\n \"nano-banana-2-1\": \"Nano Banana 2.1 — sharper quality, prompt adherence, character consistency and text rendering, 1K/2K/4K\",\n \"nano-banana-2-lite\": \"Fast, low-cost 1K generation for drafts and iteration\",\n \"gpt-image\": \"Creative concepts, illustration, variable quality tiers\",\n \"gpt-image-2\": \"Latest GPT Image — sharp text, photorealism, 1K/2K/4K resolution\",\n \"gpt-image-2-5-flare\": \"Fast everyday GPT Image 2.5 — higher quality than GPT Image 2 at ~half the latency; default for iteration, social, high volume\",\n \"gpt-image-2-5-sunburst\": \"Precision GPT Image 2.5 — slower, tighter control and detail fidelity; brand-sensitive, packaging, diagrams, final creative\",\n \"gpt-image-2-6-flare\": \"Fast GPT Image 2.6 — pick for speed; posters, product shots and quick iteration, up to 4K, low/medium/high quality\",\n \"gpt-image-2-6-sunburst\": \"Precision GPT Image 2.6 — pick when every detail counts; strongest consistency across edits, up to 4K, low/medium/high quality\",\n \"gpt-image-2-6-economy\": \"GPT Image 2.6 at a flat low price, 1K only — pick for volume\",\n \"grok\": \"General purpose, good text understanding\",\n \"grok-2\": \"Grok Imagine 2 — expressive, high-contrast, stylized output\",\n \"imagen4\": \"Google's latest, strong photorealism and text rendering\",\n \"imagen4-fast\": \"Faster Imagen 4 variant\",\n \"imagen4-ultra\": \"Highest quality Imagen 4\",\n \"ideogram-v3\": \"Best for typography, text-in-image, logos, reference images\",\n \"qwen\": \"Versatile, good prompt adherence\",\n \"seedream\": \"Artistic, painterly styles, creative interpretation\",\n \"seedream-5-lite\": \"Lighter Seedream, faster artistic generation\",\n \"seedream-5-pro\": \"Flagship Seedream — strongest instruction following, 2K via high quality\",\n \"seedream-5-flash\": \"Fast, low-cost Seedream 5 — quick drafts and iteration at 1K or 2K\",\n \"minimax-h3-image\": \"MiniMax H3 — readable text in the picture, up to about 16 MP at 4K, same price at 1K and 2K\",\n \"seedream-5-5\": \"Seedream 5.5 — natural light, materials and skin, dense small text, transparent backgrounds; 1K / 1.5K / 2K\",\n \"z-image\": \"Experimental, novel generation approaches\",\n \"wan-2.7\": \"Wan 2.7 T2I — 1K/2K/4K, up to 9 ref images\",\n \"wan-2.7-pro\": \"Wan 2.7 Pro T2I — higher quality, 1K/2K/4K\",\n \"flux-2-klein\": \"Open Flux 2 9B via Replicate — fast\",\n \"flux-2-pro\": \"BFL Flux 2 Pro via Replicate — flagship quality\",\n \"flux-2-max\": \"BFL Flux 2 Max via Replicate — even larger than Pro, up to 8 refs (variable pricing)\",\n },\n \"image-to-image\": {\n \"nano-banana\": \"Fast style transfer and transformation\",\n \"nano-banana-pro\": \"Higher quality transformations\",\n \"grok-i2i\": \"General purpose image transformation\",\n \"flux-i2i\": \"High quality image-to-image with strong prompt adherence\",\n \"flux-pro-i2i\": \"Premium Flux transformation\",\n \"gpt-image-i2i\": \"Creative reinterpretation of source images\",\n \"gpt-image-2-i2i\": \"Latest GPT Image — pixel-level edits with original lighting/texture preservation, up to 4K\",\n \"gpt-image-2-5-flare-i2i\": \"Fast GPT Image 2.5 edits — up to 16 sources; use while iterating\",\n \"gpt-image-2-5-sunburst-i2i\": \"Precision GPT Image 2.5 edits — up to 16 sources, tightest control on demanding retouches; slower\",\n \"gpt-image-2-6-flare-i2i\": \"Fast GPT Image 2.6 edits — up to 16 sources, priced per image; use while iterating\",\n \"gpt-image-2-6-sunburst-i2i\": \"Precision GPT Image 2.6 edits — up to 16 sources, priced per image; for finished, detail-critical edits\",\n \"gpt-image-2-6-economy-i2i\": \"Flat-price GPT Image 2.6 edits, 1K only — pick for volume\",\n \"ideogram-edit\": \"Instruction-based editing with text preservation\",\n \"ideogram-remix\": \"Style remixing while preserving structure\",\n \"qwen-i2i\": \"Versatile transformation\",\n \"qwen-edit\": \"Instruction-based editing\",\n \"seedream-edit\": \"Artistic style editing\",\n \"seedream-5-lite-i2i\": \"Light artistic transformation\",\n \"seedream-5-pro-i2i\": \"Pro-grade instruction-based edits, multi-reference\",\n \"seedream-5-flash-i2i\": \"Fast, low-cost Seedream edits — up to 10 input images\",\n \"minimax-h3-image-i2i\": \"MiniMax H3 edits — up to 16 reference images in one edit, readable text, up to 4K\",\n \"seedream-5-5-i2i\": \"Seedream 5.5 edits — round after round, the rest of the picture untouched; up to 10 input images\",\n \"flux-kontext\": \"Character-consistent edits with reference awareness\",\n \"flux-kontext-max\": \"Premium character-consistent editing\",\n \"kontext-multi\": \"Multi-image Kontext via Replicate — up to 4 refs\",\n \"flux-2-pro\": \"BFL Flux 2 Pro via Replicate — flagship quality with reference images\",\n \"flux-2-max\": \"BFL Flux 2 Max via Replicate — even larger sibling, up to 8 refs (variable pricing)\",\n },\n \"modify-image\": {\n \"nano-banana\": \"Fast style transfer and transformation\",\n \"nano-banana-pro\": \"Higher quality transformations\",\n \"nano-banana-edit\": \"AI-powered image editing with instructions\",\n \"grok-i2i\": \"General purpose image transformation\",\n \"flux-i2i\": \"High quality image-to-image with strong prompt adherence\",\n \"flux-pro-i2i\": \"Premium Flux transformation\",\n \"gpt-image-i2i\": \"Creative reinterpretation of source images\",\n \"gpt-image-2-i2i\": \"Latest GPT Image — pixel-level edits with original lighting/texture preservation, up to 4K\",\n \"gpt-image-2-5-flare-i2i\": \"Fast GPT Image 2.5 edits — up to 16 sources; use while iterating\",\n \"gpt-image-2-5-sunburst-i2i\": \"Precision GPT Image 2.5 edits — up to 16 sources, tightest control on demanding retouches; slower\",\n \"gpt-image-2-6-flare-i2i\": \"Fast GPT Image 2.6 edits — up to 16 sources, priced per image; use while iterating\",\n \"gpt-image-2-6-sunburst-i2i\": \"Precision GPT Image 2.6 edits — up to 16 sources, priced per image; for finished, detail-critical edits\",\n \"gpt-image-2-6-economy-i2i\": \"Flat-price GPT Image 2.6 edits, 1K only — pick for volume\",\n \"ideogram-edit\": \"Instruction-based editing with text preservation\",\n \"ideogram-remix\": \"Style remixing while preserving structure\",\n \"qwen-i2i\": \"Versatile transformation\",\n \"qwen-edit\": \"Instruction-based editing\",\n \"seedream-edit\": \"Artistic style editing\",\n \"seedream-5-lite-i2i\": \"Light artistic transformation\",\n \"seedream-5-pro-i2i\": \"Pro-grade instruction-based edits, multi-reference\",\n \"seedream-5-flash-i2i\": \"Fast, low-cost Seedream edits — up to 10 input images\",\n \"minimax-h3-image-i2i\": \"MiniMax H3 edits — up to 16 reference images in one edit, readable text, up to 4K\",\n \"seedream-5-5-i2i\": \"Seedream 5.5 edits — round after round, the rest of the picture untouched; up to 10 input images\",\n \"flux-kontext\": \"Character-consistent edits with reference awareness\",\n \"flux-kontext-max\": \"Premium character-consistent editing\",\n \"kontext-multi\": \"Multi-image Kontext via Replicate — up to 4 refs\",\n \"flux-2-pro\": \"BFL Flux 2 Pro via Replicate — flagship quality with reference images\",\n \"flux-2-max\": \"BFL Flux 2 Max via Replicate — even larger sibling, up to 8 refs (variable pricing)\",\n },\n \"generate-mask\": {\n \"grounded-sam\": \"Text-prompted segmentation — isolates the subject you describe in words (Grounding DINO + Segment Anything)\",\n },\n \"text-to-video\": {\n \"minimax\": \"Versatile, good motion quality, reliable\",\n \"veo3\": \"Google's latest, photorealistic, audio generation support\",\n \"veo3.1\": \"Enhanced VEO with improved motion\",\n \"veo3_lite\": \"Cheapest VEO tier, 4/6/8s output, ideal for high-volume/test runs\",\n \"kling\": \"Cinematic, precise camera control, high motion quality\",\n \"kling-turbo\": \"Faster Kling generation\",\n \"kling-3.0\": \"Latest Kling with motion control and multi-shot\",\n \"grok\": \"General purpose video generation\",\n \"seedance-2\": \"Seedance 2.0 — multimodal refs (9 images / 3 videos / 3 audio), native multi-track audio, multi-shot storytelling, 4-15s\",\n \"seedance-2-fast\": \"Seedance 2.0 Fast — same multimodal + audio capabilities, cheaper and quicker\",\n \"seedance-2-mini\": \"Seedance 2.0 Mini — same multimodal + audio capabilities, budget tier, 480p/720p, 4-15s\",\n \"seedance-2-5\": \"Seedance 2.5 — up to 30s in ONE shot (no stitching), wider multimodal refs (30 images / 10 videos / 10 audio), native audio, 480p/720p/1080p\",\n \"minimax-h3\": \"MiniMax H3 — premium multimodal refs (9 images / 3 videos / 3 audio), always-on audio, 2K or 768P, 4-15s per-second pricing\",\n \"wan\": \"Versatile, good for animations and transformations\",\n \"wan-turbo\": \"Faster Wan generation\",\n \"hailuo-standard\": \"Standard quality, cost-effective\",\n \"bytedance-lite\": \"Fast, lightweight generation\",\n \"bytedance-pro\": \"Higher quality ByteDance\",\n \"runway-kie\": \"Runway via KIE, strong cinematic quality\",\n \"wan-2.7-t2v\": \"Wan 2.7 T2V — 2–15s, 720p/1080p\",\n \"happyhorse\": \"HappyHorse 1.1 T2V — 3–15s, 720p/1080p, 9 aspect ratios incl. 21:9/9:21\",\n \"ltx-2.3-pro\": \"Lightricks LTX 2.3 Pro — text/image/audio→video, 6–10s, up to 4K\",\n \"ltx-2.3-fast\": \"Lightricks LTX 2.3 Fast — text/image→video, 6–20s, up to 4K\",\n \"gemini-omni-video\": \"Google Gemini Omni — multimodal video with native audio, 4–10s, up to 4K.\",\n \"gemini-omni-flash\": \"Google Gemini Omni Flash — faster, cheaper Omni tier; multimodal video with native audio, 4–10s, up to 4K.\",\n \"gemini-omni-flash-1-2\": \"Google Gemini Omni Flash 1.2 — video with native audio, 3–15s, 360p to 4K; text, up to 6 reference images, exact first and last frames, or a video edit.\",\n \"wan-3\": \"Wan 3.0 — multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2–30s, 480p/720p/1080p\",\n \"wan-3-prime\": \"Wan 3.0 Prime — high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate\",\n \"vidu-q4\": \"Vidu Q4 — start frame or up to 15 reference images + 3 MP3 audio refs, native audio, 3–16s, 540p–4K (image required)\",\n \"kling-4\": \"Kling 4.0 — text, or up to 10 reference images / 5 videos / 7 characters / 3 voices; native audio, 3–30s, 720p/1080p\",\n \"kling-4-keyframes\": \"Kling 4.0 Keyframes — start frame, up to 8 in-between frames and an end frame; native audio, 3–30s, 720p/1080p\",\n \"kling-4-flash\": \"Kling 4.0 Flash — text, or up to 10 reference images / 5 videos / 7 characters (a voice clip per character); native audio, 3–20s, 720p\",\n \"grok-imagine-video-1.5\": \"Grok Imagine 1.5 — image-to-video only; exact start and end frame (the same image loops), up to 4 in-between frames; requires an input image\",\n },\n \"image-to-video\": {\n \"minimax\": \"Versatile animation from still images\",\n \"veo3\": \"Photorealistic animation with audio\",\n \"veo3.1\": \"Enhanced image animation\",\n \"veo3_lite\": \"Cheapest VEO tier — half the cost of Fast, 4/6/8s + audio + first/last-frame\",\n \"kling\": \"Precise motion from stills, camera control\",\n \"kling-turbo\": \"Faster Kling animation\",\n \"kling-3.0\": \"Latest Kling with advanced motion\",\n \"kling-master\": \"Highest quality Kling\",\n \"seedance-2\": \"Seedance 2.0 — start/end frame + multimodal refs, native audio, 4-15s\",\n \"seedance-2-fast\": \"Seedance 2.0 Fast — same capabilities, cheaper and quicker\",\n \"seedance-2-mini\": \"Seedance 2.0 Mini — same capabilities, budget tier, 480p/720p\",\n \"seedance-2-5\": \"Seedance 2.5 — start/end frame + wide multimodal refs, native audio, up to 30s, 480p/720p/1080p\",\n \"minimax-h3\": \"MiniMax H3 — first/last frame + multimodal refs, always-on audio, 2K or 768P, 4-15s\",\n \"hailuo-2.3-pro\": \"Premium Hailuo animation\",\n \"hailuo-2.3\": \"Standard Hailuo animation\",\n \"hailuo-standard\": \"Cost-effective animation\",\n \"wan-i2v\": \"Versatile image-to-video\",\n \"wan-turbo\": \"Fast image animation\",\n \"bytedance-lite\": \"Fast, lightweight\",\n \"bytedance-pro\": \"Higher quality ByteDance\",\n \"bytedance-pro-fast\": \"Fast premium ByteDance\",\n \"grok-i2v\": \"General purpose animation\",\n \"runway-kie\": \"Cinematic image animation\",\n \"wan-2.7-i2v\": \"Wan 2.7 I2V — 2–15s, 720p/1080p, start+end frame\",\n \"happyhorse-i2v\": \"HappyHorse 1.1 I2V — 3–15s, 720p/1080p\",\n \"happyhorse-ref2v\": \"HappyHorse 1.1 Ref2V — multi-ref image to video (1–9 refs), 3–15s\",\n \"ltx-2.3-pro\": \"Lightricks LTX 2.3 Pro — start/end frame i2v + audio→video, 6–10s, up to 4K\",\n \"ltx-2.3-fast\": \"Lightricks LTX 2.3 Fast — start/end frame i2v, 6–20s, up to 4K\",\n \"gemini-omni-video\": \"Google Gemini Omni — multimodal video with native audio, 4–10s, up to 4K.\",\n \"gemini-omni-flash\": \"Google Gemini Omni Flash — faster, cheaper Omni tier; multimodal video with native audio, 4–10s, up to 4K.\",\n \"gemini-omni-flash-1-2\": \"Google Gemini Omni Flash 1.2 — video with native audio, 3–15s, 360p to 4K; text, up to 6 reference images, exact first and last frames, or a video edit.\",\n \"wan-3\": \"Wan 3.0 — multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2–30s, 480p/720p/1080p\",\n \"wan-3-prime\": \"Wan 3.0 Prime — high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate\",\n \"vidu-q4\": \"Vidu Q4 — animate a start frame, or direct up to 15 reference images + 3 MP3 audio refs; native audio, 3–16s, 540p–4K\",\n \"kling-4\": \"Kling 4.0 — a start frame joins up to 10 reference images, 5 videos, 7 characters and 3 voices; native audio, 3–30s, 720p/1080p\",\n \"kling-4-keyframes\": \"Kling 4.0 Keyframes — start frame, up to 8 in-between frames and an end frame; native audio, 3–30s, 720p/1080p\",\n \"kling-4-flash\": \"Kling 4.0 Flash — a start frame alone is the exact opening frame; beside up to 10 reference images, 5 videos and 7 characters it joins them; native audio, 3–20s, 720p\",\n \"grok-imagine-video-1.5\": \"Grok Imagine 1.5 — stylized animation, 1–15s, 480p/720p/1080p, start + up to 4 in-between + end frames (image required)\",\n },\n \"video-to-video\": {\n \"wan\": \"Style transfer and video transformation\",\n \"luma-modify\": \"Video modification preserving structure\",\n \"runway-aleph\": \"Advanced video transformation\",\n \"happyhorse-edit\": \"HappyHorse video-to-video editing\",\n },\n \"motion-transfer\": {\n \"kling\": \"Motion transfer with camera control\",\n \"kling-3.0\": \"Advanced motion transfer\",\n \"wan-animate-move\": \"Movement-based motion transfer\",\n \"wan-animate-replace\": \"Subject replacement with motion preservation\",\n },\n \"extend-video\": {\n \"veo-extend\": \"Extend VEO-generated videos\",\n \"runway-extend\": \"Extend Runway-generated videos\",\n \"seedance-2-5-extend\": \"Extend ANY video by URL — seamless trim-stitched continuation with audio, 4–30s added (Seedance 2.5)\",\n \"seedance-2-0-extend\": \"Extend ANY video by URL — seamless trim-stitched continuation with audio, 4–15s added (Seedance 2.0)\",\n },\n \"speech-to-video\": {\n \"wan-speech\": \"Wan 2.2 speech-driven video generation\",\n },\n \"ai-avatar\": {\n \"heygen\": \"HeyGen — industry-standard AI avatars; Avatar IV for established quality, Avatar V for premium fidelity\",\n },\n \"cinematic-avatar\": {\n \"heygen\": \"HeyGen Cinematic Avatar — prompt-driven generative clip (Seedance pipeline) from 1-3 avatar looks\",\n },\n \"generate-music\": {\n \"minimax\": \"General music generation, multiple genres\",\n },\n \"suno-generate\": {\n // Current generation first (V6 = default), then the earlier ones — all\n // offered in the picker; mirrors SUNO_MODELS order in @nodaro/shared.\n \"V6\": \"Flagship — greater musical expression, more natural vocals, richer details\",\n \"V6_WILD\": \"Bolder, more distinctive, less predictable results for exploration\",\n \"V6_MINI\": \"Lightweight and fast — quality/speed balance\",\n \"V5_5\": \"Custom-model tuning with strong vocal quality\",\n \"V5\": \"Superior musical expression, faster generation\",\n \"V4_5PLUS\": \"Enhanced V4.5 with better production\",\n \"V4_5ALL\": \"Full-featured V4.5\",\n \"V4_5\": \"Improved quality and coherence\",\n \"V4\": \"Standard Suno generation\",\n },\n \"text-to-audio\": {\n \"elevenlabs-sfx\": \"High quality sound effects and ambient audio\",\n },\n \"text-prompt\": {},\n}\n\n/** Reference image role options (for multi-select) */\nexport const REFERENCE_IMAGE_ROLES: readonly WizardOption[] = [\n { value: \"character\", label: \"Character reference\", description: \"Preserve identity, face, clothing exactly\" },\n { value: \"style-mood\", label: \"Style / mood reference\", description: \"Apply lighting, color palette, atmosphere only\" },\n { value: \"composition\", label: \"Composition reference\", description: \"Follow layout and framing\" },\n { value: \"scene-background\", label: \"Scene / background reference\", description: \"Use as environment, ignore subjects\" },\n { value: \"texture-material\", label: \"Texture / material reference\", description: \"Apply surface details and textures\" },\n]\n","/**\n * Per-ad creative analysis — the \"expert competitor ad analyst\" pass the\n * social scraper nodes (Meta Ads first; TikTok / Instagram / LinkedIn next)\n * can run on every ad they return. Node-agnostic on purpose: the input is\n * \"one creative + its copy + a little context\", never a Meta-shaped ad.\n *\n * The model answers in a fixed JSON shape (the schema lives with the backend\n * call site); this file owns the WORDS — what each field means and how to\n * judge it — so the prompt can be tuned without touching the wire contract.\n */\n\n/** The fields the analysis returns, in the order a reader wants them. */\nexport const AD_CREATIVE_ANALYSIS_FIELDS = [\n \"assetType\",\n \"format\",\n \"visualHooks\",\n \"audiences\",\n \"graphicIdentity\",\n \"copywritingHooks\",\n \"usps\",\n \"cta\",\n \"summary\",\n] as const\nexport type AdCreativeAnalysisField = (typeof AD_CREATIVE_ANALYSIS_FIELDS)[number]\n\nexport const AD_CREATIVE_ANALYSIS_SYSTEM_PROMPT = `You are an expert competitor ad analyst. You look at a competitor's ad — its creative (image or video poster frame) and its copy — and extract the relevant ad information into a structured summary a marketing team can act on.\n\nJudge from what is actually in the creative and copy; never invent claims that are not visible or written. Be concrete and specific (name the objects, colors, people, layouts, words), not generic (\"eye-catching visuals\"). Write in the language of the ad copy when it is not English, otherwise in English.\n\nFill every field:\n- assetType: \"static\" (a still image), \"motion\" (a video — you see its poster frame), \"carousel\" (several creatives in one ad), or \"unknown\".\n- format: the placement the creative is built for — e.g. \"in-feed\", \"story / reel (9:16)\", \"square feed\", \"banner / web\", judged from its shape and framing.\n- visualHooks: the key visuals and visual angles used to stop the scroll (product close-up, before/after, face + eye contact, big number, screenshot, meme style, UGC selfie, text-on-image…). 2–6 short items.\n- audiences: who the ad represents or addresses (age band, gender, life situation, profession, interest, geography, pain point). 1–5 short items.\n- graphicIdentity: the graphic components — color palette, typography style, logo placement, layout system, illustration vs photo, brand consistency cues. One or two sentences.\n- copywritingHooks: the copywriting angles used in the visual text and in the body (curiosity, urgency, social proof, question, offer, fear of missing out, authority, humor…). 1–6 short items, each naming the angle and quoting or paraphrasing the line that carries it.\n- usps: the unique selling points the ad claims (price, speed, exclusivity, guarantee, results, features). 1–5 short items.\n- cta: the call to action — the button label and/or the closing line that tells the viewer what to do.\n- summary: two to four sentences: what the ad sells, to whom, with what hook, and why it likely works (or does not).`\n\n/**\n * The organic-content twin of the ad prompt — for scraped social POSTS\n * (Instagram / TikTok / LinkedIn), not paid ads. SAME output fields (so one\n * schema and one UI serve both), read for organic content: hooks, audience,\n * the value/benefit the post conveys (`usps`), and its ask (`cta` — \"link in\n * bio\", \"follow\", a comment prompt, or none).\n */\nexport const POST_CONTENT_ANALYSIS_SYSTEM_PROMPT = `You are an expert social-media content analyst. You look at a single organic post — its creative (image or video cover frame) and its caption — and extract what a marketing team can learn from it into a structured summary.\n\nJudge from what is actually in the creative and caption; never invent claims that are not visible or written. Be concrete and specific (name the objects, colors, people, layouts, words), not generic (\"engaging content\"). Write in the language of the caption when it is not English, otherwise in English.\n\nFill every field:\n- assetType: \"static\" (a still image), \"motion\" (a video / reel — you see its cover frame), \"carousel\" (a multi-image post), or \"unknown\".\n- format: the format the post is built for — e.g. \"reel (9:16)\", \"square feed photo\", \"carousel\", \"portrait (4:5)\", judged from its shape and framing.\n- visualHooks: the key visuals and visual angles used to stop the scroll (product close-up, before/after, face + eye contact, big text overlay, meme style, UGC selfie, trend/format…). 2–6 short items.\n- audiences: who the post represents or speaks to (age band, gender, life situation, profession, interest, geography, community). 1–5 short items.\n- graphicIdentity: the graphic components — color palette, typography style, logo / handle placement, layout, illustration vs photo, brand consistency cues. One or two sentences.\n- copywritingHooks: the caption / content angles (curiosity, storytelling, question, trend, humor, social proof, education, behind-the-scenes…). 1–6 short items, each naming the angle and quoting or paraphrasing the line that carries it.\n- usps: the value or benefit the post conveys to the viewer (entertainment, education, inspiration, a product benefit, a deal). 1–5 short items.\n- cta: the ask — the caption's call to action (\"link in bio\", \"shop now\", \"follow\", \"comment below\"), or \"none\" if the post makes none.\n- summary: two to four sentences: what the post is about, who it speaks to, with what hook, and why it likely performs (or does not).`\n\nexport interface AdCreativeAnalysisInput {\n /** Who is advertising (the Page / account name). */\n readonly advertiser?: string\n readonly headline?: string\n readonly body?: string\n readonly ctaLabel?: string\n /** Where the ad points (the landing domain is enough). */\n readonly landing?: string\n /** Placements the ad ran on (Facebook, Instagram, TikTok…). */\n readonly platforms?: readonly string[]\n /** Creative shape already classified by the caller (\"vertical\", \"square\", \"horizontal\"). */\n readonly creativeFormat?: string\n /** \"1 video, 2 images\" — what the ad carries beyond the one frame the model sees. */\n readonly mediaSummary?: string\n /** The user's optional focus (\"we sell running shoes — compare against our positioning\"). */\n readonly focus?: string\n}\n\n/**\n * The user turn's text. The creative itself travels as a separate image\n * block; this is everything else the analyst should know, one labelled\n * line per fact, blanks left out.\n */\nexport function buildAdCreativeAnalysisUserText(input: AdCreativeAnalysisInput): string {\n const lines: string[] = []\n if (input.advertiser) lines.push(`Account / advertiser: ${input.advertiser}`)\n if (input.headline) lines.push(`Headline: ${input.headline}`)\n if (input.body) lines.push(`Body copy:\\n${input.body}`)\n if (input.ctaLabel) lines.push(`CTA button: ${input.ctaLabel}`)\n if (input.landing) lines.push(`Landing: ${input.landing}`)\n if (input.platforms && input.platforms.length > 0) lines.push(`Placements: ${input.platforms.join(\", \")}`)\n if (input.creativeFormat) lines.push(`Creative shape: ${input.creativeFormat}`)\n if (input.mediaSummary) lines.push(`Media: ${input.mediaSummary}`)\n lines.push(\"The attached image is the ad's creative (for a video, its poster frame).\")\n if (input.focus) lines.push(`\\nAnalyst focus from the user: ${input.focus}`)\n return lines.join(\"\\n\")\n}\n"]}
|