@nodaro/prompts 1.12.0 → 1.14.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/index.cjs +389 -194
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +244 -29
- package/dist/index.d.ts +244 -29
- package/dist/index.js +377 -196
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/assemble-image-input-cap.test.ts +37 -13
- package/src/__tests__/assemble-image-input.test.ts +100 -19
- package/src/__tests__/assemble-video-input-cap.test.ts +101 -15
- package/src/__tests__/assemble-video-input.test.ts +167 -33
- package/src/__tests__/direction-hint-token-safety.test.ts +21 -0
- package/src/__tests__/multi-picker-spec.test.ts +21 -1
- package/src/__tests__/person-regional-aesthetic.test.ts +2 -1
- package/src/__tests__/prompt-style-section.test.ts +345 -0
- package/src/__tests__/provider-prompt-doctrine.test.ts +39 -0
- package/src/__tests__/style-section-boundary.test.ts +179 -0
- package/src/__tests__/subject-fold.test.ts +32 -13
- package/src/assemble-image-input.ts +51 -26
- package/src/assemble-video-input.ts +54 -34
- package/src/direction-registry.ts +108 -37
- package/src/gemini-omni-inputs.ts +11 -3
- package/src/held-prop.ts +1 -0
- package/src/hint-shedding.ts +23 -4
- package/src/index.ts +1 -0
- package/src/person.ts +4 -0
- package/src/picker-analyzer-registry.ts +37 -0
- package/src/prompt-builder.ts +84 -27
- package/src/prompt-hint-join.ts +9 -0
- package/src/prompt-style-section.ts +256 -0
- package/src/prompt-wizard-categories.ts +6 -0
- package/src/provider-prompt-doctrine.ts +51 -2
- package/src/setting.ts +1 -0
- package/src/style.ts +1 -0
- package/src/styling.ts +5 -1
- package/src/video-reference-resolver.ts +5 -2
package/dist/index.cjs
CHANGED
|
@@ -1766,7 +1766,8 @@ var STYLES = [
|
|
|
1766
1766
|
{ id: "pastel", label: "Pastel", description: "Degas-era soft chalk pastel", promptHint: "rendered as a soft chalk pastel drawing, dry powdery pigment laid in feathered strokes on tinted paper with luminous dusty colors, gently blended edges and the dreamy Degas-era atmosphere of dancers in stage light", term: "soft pastel drawing" },
|
|
1767
1767
|
{ id: "acrylic-paint", label: "Acrylic Paint", description: "Fast-drying opaque acrylic on canvas", promptHint: "rendered as an acrylic painting on canvas, fast-drying opaque pigment with crisp sharp edges, confident quick brush strokes, high-key saturated color and a flatter more graphic finish than traditional oil paint", term: "acrylic painting" },
|
|
1768
1768
|
{ id: "mixed-media", label: "Mixed Media", description: "Collage + paint + ink hybrid", promptHint: "rendered as a mixed-media artwork combining torn paper collage, acrylic paint, ink and graphite on a layered substrate, heterogeneous textures, visible tape and stitching, and an exuberant hand-assembled studio-art quality" },
|
|
1769
|
-
{ id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic \u2014 separate from full-color anime" }
|
|
1769
|
+
{ id: "manga", label: "Manga", description: "Inked B&W Japanese comic panel", promptHint: "rendered as inked manga panel art, crisp black ink on white with confident line weight variation, screen-tone dot patterns for shading, dramatic speed lines and the distinctly Japanese black-and-white comic aesthetic \u2014 separate from full-color anime" },
|
|
1770
|
+
{ id: "early-color-photo", label: "Early Color Photo", description: "Prokudin-Gorsky / autochrome early-1900s color", promptHint: "rendered as an early-1900s color photograph in the Prokudin-Gorsky / autochrome tradition \u2014 soft three-colour-separation registration, muted dye-toned palette, fine grain and a gentle antique warmth", term: "early autochrome color photograph" }
|
|
1770
1771
|
];
|
|
1771
1772
|
var styleById = new Map(STYLES.map((s) => [s.id, s]));
|
|
1772
1773
|
function getStyle(id) {
|
|
@@ -1832,6 +1833,7 @@ var SETTINGS = [
|
|
|
1832
1833
|
{ id: "parking-lot", label: "Parking Lot", category: "urban", description: "Suburban parking lot at dusk", promptHint: "set in an empty suburban parking lot at dusk with sodium-vapor lamps casting orange pools, scattered shopping carts and painted lane lines" },
|
|
1833
1834
|
{ id: "penthouse", label: "Penthouse", category: "urban", description: "Luxury penthouse with skyline view", promptHint: "set in a luxury penthouse interior with panoramic skyline views, marble floors, modernist furniture and low warm ambient light" },
|
|
1834
1835
|
{ id: "gas-station", label: "Gas Station", category: "urban", description: "Lonely highway gas station at night", promptHint: "set at a lonely highway gas station at night with a fluorescent canopy, bug-swarmed sodium lamps and cracked asphalt" },
|
|
1836
|
+
{ id: "open-air-market", label: "Open-Air Market", category: "urban", description: "Bustling market of vendor stalls under canopies", term: "open-air market", promptHint: "set in a bustling open-air market \u2014 rows of vendor stalls under thatched and canvas canopies, produce piled high, warm dusty light and crowds moving between the stalls" },
|
|
1835
1837
|
// -------------------- Nature --------------------
|
|
1836
1838
|
{ id: "forest", label: "Forest Clearing", category: "nature", description: "Sunlit mossy clearing", promptHint: "set in a sunlit forest clearing with moss-covered stones, dappled light through tall trees and a soft carpet of fallen leaves" },
|
|
1837
1839
|
{ id: "beach", label: "Beach", category: "nature", description: "Wide sandy beach with surf", promptHint: "set on a wide sandy beach with gentle breaking surf, footprints in wet sand and a pastel horizon" },
|
|
@@ -2958,6 +2960,9 @@ var PEOPLE = [
|
|
|
2958
2960
|
{ id: "mumbai-bollywood", label: "Mumbai Bollywood", group: "Asia", dimension: "regional-aesthetic", description: "Mumbai Indian film-industry aesthetic", promptHint: "a Mumbai Bollywood aesthetic \u2014 Indian film-industry vibe, vibrant statement-glamour", term: "mumbai bollywood aesthetic" },
|
|
2959
2961
|
{ id: "south-india-traditional", label: "South India Traditional", group: "Asia", dimension: "regional-aesthetic", description: "Tamil / Kerala temple-town classical aesthetic", promptHint: "a South Indian traditional aesthetic \u2014 Tamil / Kerala temple-town vibe, classical refinement", term: "south indian traditional aesthetic" },
|
|
2960
2962
|
{ id: "bangkok-street", label: "Bangkok Street", group: "Asia", dimension: "regional-aesthetic", description: "Bangkok Thai night-market neon-urban aesthetic", promptHint: "a Bangkok street aesthetic \u2014 Thai night-market energy, neon-and-warmth urban vibe", term: "bangkok street aesthetic" },
|
|
2963
|
+
// ----- Central Asia -----
|
|
2964
|
+
{ id: "samarkand-silk-road", label: "Samarkand Silk Road", group: "Central Asia", dimension: "regional-aesthetic", description: "Uzbek Silk Road bazaar aesthetic (Samarkand / Bukhara)", promptHint: "a Central Asian Silk Road aesthetic \u2014 Samarkand / Bukhara bazaar vibe, ikat-and-suzani textiles, sun-baked adobe and blue-tiled madrasa mood", term: "samarkand silk road aesthetic" },
|
|
2965
|
+
{ id: "tashkent-modern", label: "Tashkent Modern", group: "Central Asia", dimension: "regional-aesthetic", description: "Contemporary Uzbek metropolitan Central Asian aesthetic", promptHint: "a modern Tashkent aesthetic \u2014 contemporary Uzbek metropolitan vibe, Soviet-modern-meets-Silk-Road blend, warm steppe-city confidence", term: "tashkent modern aesthetic" },
|
|
2961
2966
|
// ----- Latin America -----
|
|
2962
2967
|
{ id: "carioca-rio", label: "Carioca (Rio)", group: "Latin America", dimension: "regional-aesthetic", description: "Rio de Janeiro beach-and-favela-music Brazilian aesthetic", promptHint: "a Carioca aesthetic \u2014 Rio de Janeiro beach-and-favela-music vibe, sun-warmed Brazilian energy", term: "carioca aesthetic" },
|
|
2963
2968
|
{ id: "paulista", label: "Paulista (S\xE3o Paulo)", group: "Latin America", dimension: "regional-aesthetic", description: "S\xE3o Paulo metropolitan Brazilian creative-class aesthetic", promptHint: "a Paulista aesthetic \u2014 S\xE3o Paulo metropolitan vibe, urban-Brazilian creative-class polish", term: "paulista aesthetic" },
|
|
@@ -3798,6 +3803,9 @@ var STYLINGS = [
|
|
|
3798
3803
|
{ id: "outfit-fairy", label: "Fairy", dimension: "outfit", description: "Fantasy fairy: gauzy wings, flower crown, ethereal dress", promptHint: "wearing a fantasy fairy costume \u2014 gauzy translucent wings, a flower crown, and an ethereal flowing dress", term: "fairy costume with wings" },
|
|
3799
3804
|
{ id: "outfit-mermaid", label: "Mermaid", dimension: "outfit", description: "Fantasy mermaid: scaled tail/skirt, shell top, flowing hair", promptHint: "wearing a fantasy mermaid costume \u2014 a scaled tail or fitted scaled skirt, a shell top, and long flowing hair", term: "mermaid costume" },
|
|
3800
3805
|
{ id: "outfit-pharaoh", label: "Pharaoh Regalia", dimension: "outfit", description: "Ancient Egyptian royalty: usekh collar, pectoral, pleated kilt", promptHint: "wearing ancient Egyptian pharaoh regalia \u2014 a broad beaded usekh collar, a jeweled falcon pectoral, and a pleated linen shendyt kilt with golden arm cuffs" },
|
|
3806
|
+
{ id: "outfit-workwear-overalls", label: "Workwear Overalls", dimension: "outfit", description: "Denim bib overalls over a plaid flannel shirt", promptHint: "dressed in a farmer's workwear outfit \u2014 denim bib overalls over a checked plaid flannel shirt, sturdy and worn-in", term: "denim overalls and plaid shirt" },
|
|
3807
|
+
{ id: "outfit-chapan", label: "Chapan Robe", dimension: "outfit", description: "Central Asian long quilted ikat robe", promptHint: "dressed in a traditional Central Asian chapan \u2014 a long quilted robe with an ikat-striped weave, tied at the waist with a sash" },
|
|
3808
|
+
{ id: "outfit-caftan", label: "Caftan", dimension: "outfit", description: "Long flowing Middle-Eastern / North-African robe", promptHint: "dressed in a long flowing caftan robe, a full-length garment worn across the Middle East and North Africa" },
|
|
3801
3809
|
// -------------------- Top (upper-body garment) --------------------
|
|
3802
3810
|
{ id: "top-tshirt", label: "T-Shirt", dimension: "top", description: "Plain crewneck t-shirt", promptHint: "wearing a fitted plain crewneck t-shirt with short sleeves" },
|
|
3803
3811
|
{ id: "top-tank", label: "Tank Top", dimension: "top", description: "Scoop-neck tank top", promptHint: "wearing a fitted scoop-neck tank top with thin shoulder straps" },
|
|
@@ -3972,6 +3980,8 @@ var STYLING_FIELD_BY_DIMENSION = {
|
|
|
3972
3980
|
"wardrobe-state": "wardrobeState"
|
|
3973
3981
|
};
|
|
3974
3982
|
var MAX_SELECTED_BY_STYLING_DIMENSION = {
|
|
3983
|
+
headwear: 2,
|
|
3984
|
+
// a hat layered over a wrap/turban
|
|
3975
3985
|
jewelry: 3,
|
|
3976
3986
|
"wardrobe-state": 3,
|
|
3977
3987
|
"hair-state": 2
|
|
@@ -6326,7 +6336,8 @@ var HELD_PROPS = [
|
|
|
6326
6336
|
{ id: "flashlight", label: "Flashlight", category: "occupational", description: "Modern flashlight cutting a beam", promptHint: "holding a modern flashlight raised forward in one hand, a sharp white beam cutting through the darkness ahead and side-lighting the face", term: "holding a flashlight raised forward" },
|
|
6327
6337
|
{ id: "compass", label: "Compass", category: "occupational", description: "Vintage handheld nautical compass", promptHint: "holding a vintage brass nautical compass open in one cupped palm at chest height, the needle clearly visible as the eyes drift down to read the bearing", term: "holding an open brass nautical compass" },
|
|
6328
6338
|
{ id: "bow-and-arrow", label: "Bow and Arrow", category: "occupational", description: "Drawn archery bow with arrow nocked", promptHint: "holding an archery bow drawn at full tension with one hand on the grip and the other pulling the string back to the cheek, an arrow nocked and aimed forward", term: "drawing an archery bow with a nocked arrow" },
|
|
6329
|
-
{ id: "shield", label: "Shield", category: "occupational", description: "Handheld medieval shield", promptHint: "holding a medieval shield raised across the body with one arm strapped through the back, the front face angled forward in a defensive stance", term: "holding a raised medieval shield" }
|
|
6339
|
+
{ id: "shield", label: "Shield", category: "occupational", description: "Handheld medieval shield", promptHint: "holding a medieval shield raised across the body with one arm strapped through the back, the front face angled forward in a defensive stance", term: "holding a raised medieval shield" },
|
|
6340
|
+
{ id: "work-gloves", label: "Work Gloves", category: "occupational", description: "Worn leather work gloves held in hand", promptHint: "holding a worn pair of tan leather work gloves in both hands at waist height, the thick weathered leather clearly visible", term: "holding a pair of leather work gloves" }
|
|
6330
6341
|
];
|
|
6331
6342
|
var heldPropById = new Map(HELD_PROPS.map((p) => [p.id, p]));
|
|
6332
6343
|
function getHeldProp(id) {
|
|
@@ -10217,6 +10228,218 @@ function applyTemplate(template, vars) {
|
|
|
10217
10228
|
template
|
|
10218
10229
|
);
|
|
10219
10230
|
}
|
|
10231
|
+
|
|
10232
|
+
// src/prompt-hint-join.ts
|
|
10233
|
+
var PROMPT_HINT_SEPARATOR = ". ";
|
|
10234
|
+
function joinPromptHints(userPrompt, hints) {
|
|
10235
|
+
if (hints.length === 0) return userPrompt;
|
|
10236
|
+
return [userPrompt.trim(), ...hints].filter((p) => p.length > 0).join(PROMPT_HINT_SEPARATOR);
|
|
10237
|
+
}
|
|
10238
|
+
|
|
10239
|
+
// src/direction-registry.ts
|
|
10240
|
+
var perId = (full, compact) => (ids, mode) => {
|
|
10241
|
+
const out = [];
|
|
10242
|
+
for (const id of ids) {
|
|
10243
|
+
const frag = mode === "compact" ? compact(id) : full(id);
|
|
10244
|
+
if (frag.length > 0) out.push(frag);
|
|
10245
|
+
}
|
|
10246
|
+
return out;
|
|
10247
|
+
};
|
|
10248
|
+
var viaListBuilder = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
|
|
10249
|
+
var viaStringBuilder = (build) => (ids, mode) => {
|
|
10250
|
+
const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
|
|
10251
|
+
return s.length > 0 ? [s] : [];
|
|
10252
|
+
};
|
|
10253
|
+
var viaMood = (ids, mode) => buildMoodHints({ mood: ids.length === 1 ? ids[0] : [...ids] }, mode).filter(
|
|
10254
|
+
(s) => s.length > 0
|
|
10255
|
+
);
|
|
10256
|
+
var framing = perId(getFramingPromptHint, getFramingTerm);
|
|
10257
|
+
var lighting = perId(getLightingPromptHint, getLightingTerm);
|
|
10258
|
+
var exposure = perId(getExposurePromptHint, getExposureTerm);
|
|
10259
|
+
var temporal = perId(getTemporalPromptHint, getTemporalTerm);
|
|
10260
|
+
var DIRECTION_FIELDS = [
|
|
10261
|
+
{ key: "cameraMotion", surface: "video", family: "motion", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },
|
|
10262
|
+
// Composition (the Framing catalog, one row per category).
|
|
10263
|
+
{ key: "shotSize", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10264
|
+
{ key: "angle", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10265
|
+
{ key: "coverage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10266
|
+
{ key: "composition", surface: "both", family: "look", maxPicks: 2, render: framing },
|
|
10267
|
+
{ key: "vantage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10268
|
+
{ key: "pose", surface: "both", family: "look", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },
|
|
10269
|
+
{ key: "compositionEffect", surface: "both", family: "look", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },
|
|
10270
|
+
// Camera.
|
|
10271
|
+
{ key: "cameraFormat", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },
|
|
10272
|
+
{ key: "lens", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
10273
|
+
// Exposure (stills only — a video's exposure rides its own temporal levers).
|
|
10274
|
+
{ key: "aperture", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10275
|
+
{ key: "shutterSpeed", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10276
|
+
{ key: "isoValue", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
10277
|
+
// Light (the Lighting catalog, one row per category).
|
|
10278
|
+
{ key: "timeOfDay", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10279
|
+
{ key: "lightingStyle", surface: "both", family: "look", maxPicks: 2, render: lighting },
|
|
10280
|
+
{ key: "lightingDirection", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10281
|
+
{ key: "lightingRatio", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10282
|
+
{ key: "colorTemperature", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10283
|
+
{ key: "colorLook", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getColorLookPromptHint, getColorLookTerm) },
|
|
10284
|
+
{ key: "atmosphere", surface: "both", family: "look", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },
|
|
10285
|
+
{ key: "postProcess", surface: "image", family: "look", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },
|
|
10286
|
+
// Style.
|
|
10287
|
+
{ key: "style", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getStylePromptHint, getStyleTerm) },
|
|
10288
|
+
{ key: "mood", surface: "both", family: "look", maxPicks: 2, render: viaMood },
|
|
10289
|
+
{ key: "aesthetic", surface: "both", family: "look", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },
|
|
10290
|
+
{ key: "photoGenre", surface: "image", family: "look", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },
|
|
10291
|
+
{ key: "photographer", surface: "image", family: "look", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },
|
|
10292
|
+
{ key: "renderQuality", surface: "image", family: "look", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },
|
|
10293
|
+
// Scene.
|
|
10294
|
+
{ key: "setting", surface: "both", family: "look", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },
|
|
10295
|
+
{ key: "era", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },
|
|
10296
|
+
{ key: "backdrop", surface: "both", family: "look", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },
|
|
10297
|
+
// Motion & time.
|
|
10298
|
+
{ key: "actionFx", surface: "video", family: "motion", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },
|
|
10299
|
+
{ key: "temporalSpeed", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10300
|
+
{ key: "temporalFreeze", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10301
|
+
{ key: "temporalDirection", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10302
|
+
{ key: "temporalShutter", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
10303
|
+
{ key: "transition", surface: "video", family: "motion", maxPicks: 2, render: perId(getTransitionPromptHint, getTransitionTerm) },
|
|
10304
|
+
{ key: "loopSubject", surface: "video", family: "motion", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },
|
|
10305
|
+
// ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact
|
|
10306
|
+
// `composePromptText` order, so every pre-registry caller is byte-identical.
|
|
10307
|
+
{ key: "framingId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10308
|
+
{ key: "framingAngleId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
10309
|
+
{ key: "lightingId", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
10310
|
+
{ key: "lensId", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
10311
|
+
{ key: "cameraFormatId", surface: "both", family: "look", styleGroup: "film", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) }
|
|
10312
|
+
];
|
|
10313
|
+
var DIRECTION_SPECS = DIRECTION_FIELDS;
|
|
10314
|
+
var DIRECTION_KEYS = DIRECTION_FIELDS.map((f) => f.key);
|
|
10315
|
+
var FILM_STYLE_KEYS = DIRECTION_SPECS.filter(
|
|
10316
|
+
(f) => f.styleGroup === "film"
|
|
10317
|
+
).map((f) => f.key);
|
|
10318
|
+
var IMAGE_HINT_MODE_DEFAULT = "full";
|
|
10319
|
+
var VIDEO_HINT_MODE_DEFAULT = { look: "full", motion: "compact" };
|
|
10320
|
+
function modeForFamily(mode, family) {
|
|
10321
|
+
return typeof mode === "string" ? mode : family === "motion" ? mode.motion : mode.look;
|
|
10322
|
+
}
|
|
10323
|
+
var DIRECTION_ARRAY_CEILING = 8;
|
|
10324
|
+
var DIRECTION_ID_MAX_CHARS = 100;
|
|
10325
|
+
function normalizeDirectionIds(value, maxPicks) {
|
|
10326
|
+
const ids = [];
|
|
10327
|
+
if (typeof value === "string") {
|
|
10328
|
+
if (value) ids.push(value);
|
|
10329
|
+
} else if (Array.isArray(value)) {
|
|
10330
|
+
for (const v of value) {
|
|
10331
|
+
if (ids.length >= maxPicks) break;
|
|
10332
|
+
if (typeof v === "string" && v && !ids.includes(v)) ids.push(v);
|
|
10333
|
+
}
|
|
10334
|
+
}
|
|
10335
|
+
return ids.slice(0, maxPicks);
|
|
10336
|
+
}
|
|
10337
|
+
function directionFieldsForSurface(surface) {
|
|
10338
|
+
return DIRECTION_SPECS.filter((f) => f.surface === "both" || f.surface === surface);
|
|
10339
|
+
}
|
|
10340
|
+
function renderDirectionHintClauses(direction, opts) {
|
|
10341
|
+
if (!direction) return [];
|
|
10342
|
+
const mode = opts.mode ?? "full";
|
|
10343
|
+
const out = [];
|
|
10344
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10345
|
+
for (const spec of DIRECTION_SPECS) {
|
|
10346
|
+
if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
|
|
10347
|
+
const ids = normalizeDirectionIds(
|
|
10348
|
+
direction[spec.key],
|
|
10349
|
+
spec.maxPicks
|
|
10350
|
+
);
|
|
10351
|
+
if (ids.length === 0) continue;
|
|
10352
|
+
for (const hint of spec.render(ids, modeForFamily(mode, spec.family))) {
|
|
10353
|
+
if (hint.length > 0 && !seen.has(hint)) {
|
|
10354
|
+
seen.add(hint);
|
|
10355
|
+
out.push({
|
|
10356
|
+
key: spec.key,
|
|
10357
|
+
family: spec.family,
|
|
10358
|
+
...spec.styleGroup !== void 0 ? { styleGroup: spec.styleGroup } : {},
|
|
10359
|
+
text: hint
|
|
10360
|
+
});
|
|
10361
|
+
}
|
|
10362
|
+
}
|
|
10363
|
+
}
|
|
10364
|
+
return out;
|
|
10365
|
+
}
|
|
10366
|
+
function renderDirectionHints(direction, opts) {
|
|
10367
|
+
return renderDirectionHintClauses(direction, opts).map((c) => c.text);
|
|
10368
|
+
}
|
|
10369
|
+
|
|
10370
|
+
// src/prompt-style-section.ts
|
|
10371
|
+
var STYLE_SECTION_HEADER = "[style]:";
|
|
10372
|
+
var STYLE_SECTION_GAP = "\n\n";
|
|
10373
|
+
var STYLE_SECTION_OPENING = `${STYLE_SECTION_GAP}${STYLE_SECTION_HEADER}
|
|
10374
|
+
`;
|
|
10375
|
+
function splitStyleSection(prompt) {
|
|
10376
|
+
const at = prompt.lastIndexOf(STYLE_SECTION_OPENING);
|
|
10377
|
+
if (at >= 0) {
|
|
10378
|
+
return { body: prompt.slice(0, at), section: prompt.slice(at + STYLE_SECTION_GAP.length) };
|
|
10379
|
+
}
|
|
10380
|
+
return prompt.startsWith(`${STYLE_SECTION_HEADER}
|
|
10381
|
+
`) ? { body: "", section: prompt } : { body: prompt, section: "" };
|
|
10382
|
+
}
|
|
10383
|
+
function insertBeforeStyleSection(prompt, lines) {
|
|
10384
|
+
if (lines.length === 0) return prompt;
|
|
10385
|
+
const block = lines.join("\n");
|
|
10386
|
+
const { body, section } = splitStyleSection(prompt);
|
|
10387
|
+
if (section.length === 0) return `${prompt}
|
|
10388
|
+
${block}`;
|
|
10389
|
+
return `${body.length > 0 ? `${body}
|
|
10390
|
+
${block}` : block}${STYLE_SECTION_GAP}${section}`;
|
|
10391
|
+
}
|
|
10392
|
+
function endsInsideStyleSection(prompt) {
|
|
10393
|
+
const at = prompt.lastIndexOf(STYLE_SECTION_GAP);
|
|
10394
|
+
const lastBlock = at >= 0 ? prompt.slice(at + STYLE_SECTION_GAP.length) : prompt;
|
|
10395
|
+
return lastBlock.startsWith(`${STYLE_SECTION_HEADER}
|
|
10396
|
+
`);
|
|
10397
|
+
}
|
|
10398
|
+
function styleSlotFor(row) {
|
|
10399
|
+
if (row.family === "motion") return "body";
|
|
10400
|
+
return row.styleGroup === "film" ? "film" : "scene";
|
|
10401
|
+
}
|
|
10402
|
+
function asBodyClauses(texts) {
|
|
10403
|
+
return texts.map((text) => ({ text, slot: "body" }));
|
|
10404
|
+
}
|
|
10405
|
+
function partitionStyleClauses(direction, opts) {
|
|
10406
|
+
return renderDirectionHintClauses(direction, opts).map((clause) => ({
|
|
10407
|
+
text: clause.text,
|
|
10408
|
+
slot: styleSlotFor(clause)
|
|
10409
|
+
}));
|
|
10410
|
+
}
|
|
10411
|
+
function styleSectionFromClauses(clauses) {
|
|
10412
|
+
const line = (slot) => clauses.filter((c) => c.slot === slot).map((c) => c.text).join(PROMPT_HINT_SEPARATOR);
|
|
10413
|
+
const lines = [line("film"), line("scene")].filter((l) => l.length > 0);
|
|
10414
|
+
return lines.length === 0 ? "" : `${STYLE_SECTION_HEADER}
|
|
10415
|
+
${lines.join("\n")}`;
|
|
10416
|
+
}
|
|
10417
|
+
function renderStyleSection(direction, opts) {
|
|
10418
|
+
return styleSectionFromClauses(partitionStyleClauses(direction, opts));
|
|
10419
|
+
}
|
|
10420
|
+
function composeSectionedPrompt(userPrompt, clauses, structuredFragment) {
|
|
10421
|
+
const bodyHints = [
|
|
10422
|
+
...clauses.filter((c) => c.slot === "body").map((c) => c.text),
|
|
10423
|
+
structuredFragment
|
|
10424
|
+
].filter((p) => p.length > 0);
|
|
10425
|
+
const section = styleSectionFromClauses(clauses);
|
|
10426
|
+
if (section.length === 0) {
|
|
10427
|
+
return bodyHints.length === 0 ? userPrompt : joinPromptHints(userPrompt ?? "", bodyHints);
|
|
10428
|
+
}
|
|
10429
|
+
const body = bodyHints.length > 0 ? joinPromptHints(userPrompt ?? "", bodyHints) : (userPrompt ?? "").trim();
|
|
10430
|
+
return body.length > 0 ? `${body}${STYLE_SECTION_GAP}${section}` : section;
|
|
10431
|
+
}
|
|
10432
|
+
function sectionedClauseCosts(userPrompt, clauses, structuredFragment) {
|
|
10433
|
+
const lengthAt = (kept) => composeSectionedPrompt(userPrompt, clauses.slice(0, kept), structuredFragment)?.length ?? 0;
|
|
10434
|
+
const costs = [];
|
|
10435
|
+
let below = lengthAt(0);
|
|
10436
|
+
for (let i = 0; i < clauses.length; i++) {
|
|
10437
|
+
const at = lengthAt(i + 1);
|
|
10438
|
+
costs.push(at - below);
|
|
10439
|
+
below = at;
|
|
10440
|
+
}
|
|
10441
|
+
return costs;
|
|
10442
|
+
}
|
|
10220
10443
|
function composeIdentityDescPart(subject, canonicalDesc, elementInjection) {
|
|
10221
10444
|
const parts = [];
|
|
10222
10445
|
const c = canonicalDesc?.trim();
|
|
@@ -10906,6 +11129,12 @@ function reconcileBodySegments(body, bodySegments) {
|
|
|
10906
11129
|
}
|
|
10907
11130
|
return [{ text: body, origin: "user" }];
|
|
10908
11131
|
}
|
|
11132
|
+
function controlSuffixes(body, styleLine, avoidLine) {
|
|
11133
|
+
const separator = (text) => endsInsideStyleSection(text) ? STYLE_SECTION_GAP : "\n";
|
|
11134
|
+
const styleSuffix = styleLine ? `${separator(body)}${styleLine}` : "";
|
|
11135
|
+
const avoidSuffix = avoidLine ? `${separator(body + styleSuffix)}${avoidLine}` : "";
|
|
11136
|
+
return { styleSuffix, avoidSuffix };
|
|
11137
|
+
}
|
|
10909
11138
|
function buildImagePrompt(config2) {
|
|
10910
11139
|
return buildImagePromptInternal(config2);
|
|
10911
11140
|
}
|
|
@@ -11182,9 +11411,7 @@ ${promptForNext}`;
|
|
|
11182
11411
|
const lockBlock = allLockLines.length > 0 ? `${allLockLines.join("\n")}
|
|
11183
11412
|
|
|
11184
11413
|
` : "";
|
|
11185
|
-
|
|
11186
|
-
${trailingLines.join("\n")}` : "";
|
|
11187
|
-
promptForNext = `${lockBlock}${promptForNext}${trailingBlock}`;
|
|
11414
|
+
promptForNext = `${lockBlock}${insertBeforeStyleSection(promptForNext, trailingLines)}`;
|
|
11188
11415
|
}
|
|
11189
11416
|
config2 = {
|
|
11190
11417
|
...config2,
|
|
@@ -11232,9 +11459,7 @@ ${trailingLines.join("\n")}` : "";
|
|
|
11232
11459
|
...locCanon.elementDirectives,
|
|
11233
11460
|
...objCanon.elementDirectives
|
|
11234
11461
|
];
|
|
11235
|
-
const
|
|
11236
|
-
${canonTrailingLines.join("\n")}` : "";
|
|
11237
|
-
const composedScene = `${canonLockBlock}${scene}${canonTrailingBlock}`;
|
|
11462
|
+
const composedScene = `${canonLockBlock}${insertBeforeStyleSection(scene, canonTrailingLines)}`;
|
|
11238
11463
|
prompt2 = config2.referenceLockSnippet ? `${config2.referenceLockSnippet}
|
|
11239
11464
|
${composedScene}` : composedScene;
|
|
11240
11465
|
if (marks) marks.directivesPrefix = "";
|
|
@@ -11260,29 +11485,29 @@ ${directives}`;
|
|
|
11260
11485
|
}
|
|
11261
11486
|
}
|
|
11262
11487
|
const styleText2 = style?.trim();
|
|
11263
|
-
const
|
|
11264
|
-
Style: ${getStylePromptHint(styleText2) || styleText2}` : "";
|
|
11488
|
+
const styleLine2 = styleText2 ? `Style: ${getStylePromptHint(styleText2) || styleText2}` : "";
|
|
11265
11489
|
const negPrompt2 = negativePrompt?.trim();
|
|
11266
11490
|
let nativeNegativePrompt2;
|
|
11267
|
-
let
|
|
11491
|
+
let avoidLine2 = "";
|
|
11268
11492
|
if (negPrompt2) {
|
|
11269
11493
|
if (shared.NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {
|
|
11270
11494
|
nativeNegativePrompt2 = negPrompt2.slice(0, shared.getMaxNegativePromptChars(provider));
|
|
11271
11495
|
} else {
|
|
11272
|
-
|
|
11273
|
-
Avoid: ${negPrompt2}`;
|
|
11496
|
+
avoidLine2 = `Avoid: ${negPrompt2}`;
|
|
11274
11497
|
}
|
|
11275
11498
|
}
|
|
11276
|
-
if (marks) {
|
|
11277
|
-
marks.styleSuffix = styleSuffix2;
|
|
11278
|
-
marks.avoidSuffix = avoidSuffix2;
|
|
11279
|
-
}
|
|
11280
11499
|
const maxLen2 = shared.getMaxImagePromptChars(provider);
|
|
11281
|
-
const
|
|
11500
|
+
const preCut2 = controlSuffixes(prompt2, styleLine2, avoidLine2);
|
|
11501
|
+
const reserved2 = preCut2.styleSuffix.length + preCut2.avoidSuffix.length;
|
|
11282
11502
|
if (prompt2.length + reserved2 > maxLen2) {
|
|
11283
11503
|
if (marks) marks.overflowChars += prompt2.length + reserved2 - maxLen2;
|
|
11284
11504
|
prompt2 = prompt2.slice(0, Math.max(0, maxLen2 - reserved2 - 3)) + "...";
|
|
11285
11505
|
}
|
|
11506
|
+
const { styleSuffix: styleSuffix2, avoidSuffix: avoidSuffix2 } = controlSuffixes(prompt2, styleLine2, avoidLine2);
|
|
11507
|
+
if (marks) {
|
|
11508
|
+
marks.styleSuffix = styleSuffix2;
|
|
11509
|
+
marks.avoidSuffix = avoidSuffix2;
|
|
11510
|
+
}
|
|
11286
11511
|
if (marks) marks.bodyBeforeSuffixes = prompt2.slice(marks.directivesPrefix.length);
|
|
11287
11512
|
prompt2 = prompt2 + styleSuffix2 + avoidSuffix2;
|
|
11288
11513
|
if (prompt2.length > maxLen2) {
|
|
@@ -11334,35 +11559,37 @@ Avoid: ${negPrompt2}`;
|
|
|
11334
11559
|
let prompt = config2.prompt;
|
|
11335
11560
|
if (charDescs.length > 0) {
|
|
11336
11561
|
const wrapperTemplate = resolveTemplate("generate-image-wrapper", userTemplates, flowTemplates);
|
|
11337
|
-
|
|
11338
|
-
|
|
11562
|
+
const { body, section } = splitStyleSection(prompt);
|
|
11563
|
+
const wrapped = applyTemplate(wrapperTemplate, {
|
|
11564
|
+
userPrompt: body,
|
|
11339
11565
|
assetDescriptions: charDescs.join(" ")
|
|
11340
11566
|
});
|
|
11567
|
+
prompt = section.length > 0 ? `${wrapped}${STYLE_SECTION_GAP}${section}` : wrapped;
|
|
11341
11568
|
}
|
|
11342
11569
|
const styleText = style?.trim();
|
|
11343
|
-
const
|
|
11344
|
-
Style: ${getStylePromptHint(styleText) || styleText}` : "";
|
|
11570
|
+
const styleLine = styleText ? `Style: ${getStylePromptHint(styleText) || styleText}` : "";
|
|
11345
11571
|
const negPrompt = negativePrompt?.trim();
|
|
11346
11572
|
let nativeNegativePrompt;
|
|
11347
|
-
let
|
|
11573
|
+
let avoidLine = "";
|
|
11348
11574
|
if (negPrompt) {
|
|
11349
11575
|
if (shared.NATIVE_NEGATIVE_PROMPT_MODELS.has(provider)) {
|
|
11350
11576
|
nativeNegativePrompt = negPrompt.slice(0, shared.getMaxNegativePromptChars(provider));
|
|
11351
11577
|
} else {
|
|
11352
|
-
|
|
11353
|
-
Avoid: ${negPrompt}`;
|
|
11578
|
+
avoidLine = `Avoid: ${negPrompt}`;
|
|
11354
11579
|
}
|
|
11355
11580
|
}
|
|
11356
|
-
if (marks) {
|
|
11357
|
-
marks.styleSuffix = styleSuffix;
|
|
11358
|
-
marks.avoidSuffix = avoidSuffix;
|
|
11359
|
-
}
|
|
11360
11581
|
const maxLen = shared.getMaxImagePromptChars(provider);
|
|
11361
|
-
const
|
|
11582
|
+
const preCut = controlSuffixes(prompt, styleLine, avoidLine);
|
|
11583
|
+
const reserved = preCut.styleSuffix.length + preCut.avoidSuffix.length;
|
|
11362
11584
|
if (prompt.length + reserved > maxLen) {
|
|
11363
11585
|
if (marks) marks.overflowChars += prompt.length + reserved - maxLen;
|
|
11364
11586
|
prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + "...";
|
|
11365
11587
|
}
|
|
11588
|
+
const { styleSuffix, avoidSuffix } = controlSuffixes(prompt, styleLine, avoidLine);
|
|
11589
|
+
if (marks) {
|
|
11590
|
+
marks.styleSuffix = styleSuffix;
|
|
11591
|
+
marks.avoidSuffix = avoidSuffix;
|
|
11592
|
+
}
|
|
11366
11593
|
if (marks) marks.bodyBeforeSuffixes = prompt;
|
|
11367
11594
|
prompt = prompt + styleSuffix + avoidSuffix;
|
|
11368
11595
|
if (prompt.length > maxLen) {
|
|
@@ -11589,7 +11816,12 @@ function capitalizeLineInitial(line) {
|
|
|
11589
11816
|
return line.replace(/[a-zA-Z]/, (c) => c.toUpperCase());
|
|
11590
11817
|
}
|
|
11591
11818
|
function buildHybridScene(prompt, refs, finalIndexByUrl) {
|
|
11592
|
-
|
|
11819
|
+
const lines = prompt.split("\n");
|
|
11820
|
+
const sectionAt = lines.indexOf(STYLE_SECTION_HEADER);
|
|
11821
|
+
return lines.map((line, i) => {
|
|
11822
|
+
const expanded = expandImageRefTokensHybrid(line, refs, finalIndexByUrl);
|
|
11823
|
+
return sectionAt >= 0 && i >= sectionAt ? expanded : capitalizeLineInitial(expanded);
|
|
11824
|
+
}).join("\n");
|
|
11593
11825
|
}
|
|
11594
11826
|
function buildIdentityDirectives(prompt, refs, meta3 = [], suppressedCanonicalLocationIds) {
|
|
11595
11827
|
return collectIdentities(prompt, refs, meta3).map((id) => buildIdentityDirective(id, suppressedCanonicalLocationIds)).filter((s) => s.length > 0).join("\n");
|
|
@@ -11807,125 +12039,6 @@ function renderLens(l) {
|
|
|
11807
12039
|
if (l.aperture) bits.push(`f/${l.aperture}`);
|
|
11808
12040
|
return bits.length > 0 ? `Lens: ${bits.join(", ")}.` : "";
|
|
11809
12041
|
}
|
|
11810
|
-
|
|
11811
|
-
// src/direction-registry.ts
|
|
11812
|
-
var perId = (full, compact) => (ids, mode) => {
|
|
11813
|
-
const out = [];
|
|
11814
|
-
for (const id of ids) {
|
|
11815
|
-
const frag = mode === "compact" ? compact(id) : full(id);
|
|
11816
|
-
if (frag.length > 0) out.push(frag);
|
|
11817
|
-
}
|
|
11818
|
-
return out;
|
|
11819
|
-
};
|
|
11820
|
-
var viaListBuilder = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
|
|
11821
|
-
var viaStringBuilder = (build) => (ids, mode) => {
|
|
11822
|
-
const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
|
|
11823
|
-
return s.length > 0 ? [s] : [];
|
|
11824
|
-
};
|
|
11825
|
-
var viaMood = (ids, mode) => buildMoodHints({ mood: ids.length === 1 ? ids[0] : [...ids] }, mode).filter(
|
|
11826
|
-
(s) => s.length > 0
|
|
11827
|
-
);
|
|
11828
|
-
var framing = perId(getFramingPromptHint, getFramingTerm);
|
|
11829
|
-
var lighting = perId(getLightingPromptHint, getLightingTerm);
|
|
11830
|
-
var exposure = perId(getExposurePromptHint, getExposureTerm);
|
|
11831
|
-
var temporal = perId(getTemporalPromptHint, getTemporalTerm);
|
|
11832
|
-
var DIRECTION_FIELDS = [
|
|
11833
|
-
{ key: "cameraMotion", surface: "video", family: "motion", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },
|
|
11834
|
-
// Composition (the Framing catalog, one row per category).
|
|
11835
|
-
{ key: "shotSize", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11836
|
-
{ key: "angle", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11837
|
-
{ key: "coverage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11838
|
-
{ key: "composition", surface: "both", family: "look", maxPicks: 2, render: framing },
|
|
11839
|
-
{ key: "vantage", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11840
|
-
{ key: "pose", surface: "both", family: "look", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },
|
|
11841
|
-
{ key: "compositionEffect", surface: "both", family: "look", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },
|
|
11842
|
-
// Camera.
|
|
11843
|
-
{ key: "cameraFormat", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },
|
|
11844
|
-
{ key: "lens", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
11845
|
-
// Exposure (stills only — a video's exposure rides its own temporal levers).
|
|
11846
|
-
{ key: "aperture", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11847
|
-
{ key: "shutterSpeed", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11848
|
-
{ key: "isoValue", surface: "image", family: "look", maxPicks: 1, render: exposure },
|
|
11849
|
-
// Light (the Lighting catalog, one row per category).
|
|
11850
|
-
{ key: "timeOfDay", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11851
|
-
{ key: "lightingStyle", surface: "both", family: "look", maxPicks: 2, render: lighting },
|
|
11852
|
-
{ key: "lightingDirection", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11853
|
-
{ key: "lightingRatio", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11854
|
-
{ key: "colorTemperature", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11855
|
-
{ key: "colorLook", surface: "both", family: "look", maxPicks: 1, render: perId(getColorLookPromptHint, getColorLookTerm) },
|
|
11856
|
-
{ key: "atmosphere", surface: "both", family: "look", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },
|
|
11857
|
-
{ key: "postProcess", surface: "image", family: "look", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },
|
|
11858
|
-
// Style.
|
|
11859
|
-
{ key: "style", surface: "both", family: "look", maxPicks: 1, render: perId(getStylePromptHint, getStyleTerm) },
|
|
11860
|
-
{ key: "mood", surface: "both", family: "look", maxPicks: 2, render: viaMood },
|
|
11861
|
-
{ key: "aesthetic", surface: "both", family: "look", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },
|
|
11862
|
-
{ key: "photoGenre", surface: "image", family: "look", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },
|
|
11863
|
-
{ key: "photographer", surface: "image", family: "look", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },
|
|
11864
|
-
{ key: "renderQuality", surface: "image", family: "look", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },
|
|
11865
|
-
// Scene.
|
|
11866
|
-
{ key: "setting", surface: "both", family: "look", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },
|
|
11867
|
-
{ key: "era", surface: "both", family: "look", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },
|
|
11868
|
-
{ key: "backdrop", surface: "both", family: "look", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },
|
|
11869
|
-
// Motion & time.
|
|
11870
|
-
{ key: "actionFx", surface: "video", family: "motion", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },
|
|
11871
|
-
{ key: "temporalSpeed", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11872
|
-
{ key: "temporalFreeze", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11873
|
-
{ key: "temporalDirection", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11874
|
-
{ key: "temporalShutter", surface: "video", family: "motion", maxPicks: 1, render: temporal },
|
|
11875
|
-
{ key: "transition", surface: "video", family: "motion", maxPicks: 2, render: perId(getTransitionPromptHint, getTransitionTerm) },
|
|
11876
|
-
{ key: "loopSubject", surface: "video", family: "motion", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },
|
|
11877
|
-
// ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact
|
|
11878
|
-
// `composePromptText` order, so every pre-registry caller is byte-identical.
|
|
11879
|
-
{ key: "framingId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11880
|
-
{ key: "framingAngleId", surface: "both", family: "look", maxPicks: 1, render: framing },
|
|
11881
|
-
{ key: "lightingId", surface: "both", family: "look", maxPicks: 1, render: lighting },
|
|
11882
|
-
{ key: "lensId", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
|
|
11883
|
-
{ key: "cameraFormatId", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) }
|
|
11884
|
-
];
|
|
11885
|
-
var DIRECTION_KEYS = DIRECTION_FIELDS.map((f) => f.key);
|
|
11886
|
-
var IMAGE_HINT_MODE_DEFAULT = "full";
|
|
11887
|
-
var VIDEO_HINT_MODE_DEFAULT = { look: "full", motion: "compact" };
|
|
11888
|
-
function modeForFamily(mode, family) {
|
|
11889
|
-
return typeof mode === "string" ? mode : family === "motion" ? mode.motion : mode.look;
|
|
11890
|
-
}
|
|
11891
|
-
var DIRECTION_ARRAY_CEILING = 8;
|
|
11892
|
-
var DIRECTION_ID_MAX_CHARS = 100;
|
|
11893
|
-
function normalizeDirectionIds(value, maxPicks) {
|
|
11894
|
-
const ids = [];
|
|
11895
|
-
if (typeof value === "string") {
|
|
11896
|
-
if (value) ids.push(value);
|
|
11897
|
-
} else if (Array.isArray(value)) {
|
|
11898
|
-
for (const v of value) {
|
|
11899
|
-
if (ids.length >= maxPicks) break;
|
|
11900
|
-
if (typeof v === "string" && v && !ids.includes(v)) ids.push(v);
|
|
11901
|
-
}
|
|
11902
|
-
}
|
|
11903
|
-
return ids.slice(0, maxPicks);
|
|
11904
|
-
}
|
|
11905
|
-
function directionFieldsForSurface(surface) {
|
|
11906
|
-
return DIRECTION_FIELDS.filter((f) => f.surface === "both" || f.surface === surface);
|
|
11907
|
-
}
|
|
11908
|
-
function renderDirectionHints(direction, opts) {
|
|
11909
|
-
if (!direction) return [];
|
|
11910
|
-
const mode = opts.mode ?? "full";
|
|
11911
|
-
const out = [];
|
|
11912
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11913
|
-
for (const spec of DIRECTION_FIELDS) {
|
|
11914
|
-
if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
|
|
11915
|
-
const ids = normalizeDirectionIds(
|
|
11916
|
-
direction[spec.key],
|
|
11917
|
-
spec.maxPicks
|
|
11918
|
-
);
|
|
11919
|
-
if (ids.length === 0) continue;
|
|
11920
|
-
for (const hint of spec.render(ids, modeForFamily(mode, spec.family))) {
|
|
11921
|
-
if (hint.length > 0 && !seen.has(hint)) {
|
|
11922
|
-
seen.add(hint);
|
|
11923
|
-
out.push(hint);
|
|
11924
|
-
}
|
|
11925
|
-
}
|
|
11926
|
-
}
|
|
11927
|
-
return out;
|
|
11928
|
-
}
|
|
11929
12042
|
var viaFragmentBuilder = (build) => (subject, mode) => {
|
|
11930
12043
|
const clause = build(subject, mode).filter((s) => s.length > 0).join(", ");
|
|
11931
12044
|
return clause.length > 0 ? [clause] : [];
|
|
@@ -12050,20 +12163,13 @@ function renderSubjectHints(subject, opts) {
|
|
|
12050
12163
|
return out;
|
|
12051
12164
|
}
|
|
12052
12165
|
|
|
12053
|
-
// src/prompt-hint-join.ts
|
|
12054
|
-
var PROMPT_HINT_SEPARATOR = ". ";
|
|
12055
|
-
function joinPromptHints(userPrompt, hints) {
|
|
12056
|
-
if (hints.length === 0) return userPrompt;
|
|
12057
|
-
return [userPrompt.trim(), ...hints].filter((p) => p.length > 0).join(PROMPT_HINT_SEPARATOR);
|
|
12058
|
-
}
|
|
12059
|
-
|
|
12060
12166
|
// src/hint-shedding.ts
|
|
12061
|
-
function keepableDirectionHints(hintClauses, kept, deficit) {
|
|
12167
|
+
function keepableDirectionHints(hintClauses, kept, deficit, clauseCosts) {
|
|
12062
12168
|
let remaining = deficit;
|
|
12063
12169
|
let next = kept;
|
|
12064
12170
|
while (next > 0 && remaining > 0) {
|
|
12065
12171
|
next -= 1;
|
|
12066
|
-
remaining -= hintClauses[next].length + PROMPT_HINT_SEPARATOR.length;
|
|
12172
|
+
remaining -= clauseCosts?.[next] ?? hintClauses[next].length + PROMPT_HINT_SEPARATOR.length;
|
|
12067
12173
|
}
|
|
12068
12174
|
return next;
|
|
12069
12175
|
}
|
|
@@ -12417,9 +12523,7 @@ function resolveVideoReferenceCore(args) {
|
|
|
12417
12523
|
const lockBlock = lockLines.length > 0 ? `${lockLines.join("\n")}
|
|
12418
12524
|
|
|
12419
12525
|
` : "";
|
|
12420
|
-
|
|
12421
|
-
${trailingLines.join("\n")}` : "";
|
|
12422
|
-
finalPrompt = `${lockBlock}${finalPrompt}${trailingBlock}`;
|
|
12526
|
+
finalPrompt = `${lockBlock}${insertBeforeStyleSection(finalPrompt, trailingLines)}`;
|
|
12423
12527
|
} else {
|
|
12424
12528
|
const allFallbackLines = [...fallbackDirectiveLines, ...extraDirectiveLines];
|
|
12425
12529
|
if (allFallbackLines.length > 0) {
|
|
@@ -12656,24 +12760,26 @@ function assembleSunoInput(input) {
|
|
|
12656
12760
|
function renderImageHintPieces(subject, direction, structured) {
|
|
12657
12761
|
return {
|
|
12658
12762
|
hintClauses: [
|
|
12659
|
-
...
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12763
|
+
...asBodyClauses(
|
|
12764
|
+
renderSubjectHints(subject, {
|
|
12765
|
+
surface: "image",
|
|
12766
|
+
mode: SUBJECT_IMAGE_HINT_MODE_DEFAULT
|
|
12767
|
+
})
|
|
12768
|
+
),
|
|
12769
|
+
...partitionStyleClauses(direction, {
|
|
12664
12770
|
surface: "image",
|
|
12665
12771
|
mode: IMAGE_HINT_MODE_DEFAULT
|
|
12666
12772
|
})
|
|
12667
|
-
].filter((
|
|
12773
|
+
].filter((c) => c.text.length > 0),
|
|
12668
12774
|
structuredFragment: structured ? renderStructuredFields(structured) : ""
|
|
12669
12775
|
};
|
|
12670
12776
|
}
|
|
12671
12777
|
function composePromptText(userPrompt, pieces, keptHintClauses) {
|
|
12672
|
-
|
|
12673
|
-
|
|
12778
|
+
return composeSectionedPrompt(
|
|
12779
|
+
userPrompt,
|
|
12780
|
+
pieces.hintClauses.slice(0, keptHintClauses),
|
|
12674
12781
|
pieces.structuredFragment
|
|
12675
|
-
|
|
12676
|
-
return joinPromptHints(userPrompt, hints);
|
|
12782
|
+
);
|
|
12677
12783
|
}
|
|
12678
12784
|
function assembleImageInput(input) {
|
|
12679
12785
|
const pieces = renderImageHintPieces(input.subject, input.direction, input.structured);
|
|
@@ -12703,9 +12809,17 @@ function assembleImageInput(input) {
|
|
|
12703
12809
|
});
|
|
12704
12810
|
let kept = pieces.hintClauses.length;
|
|
12705
12811
|
let fitted = assembleWith(kept);
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12812
|
+
if (fitted.overflowChars > 0) {
|
|
12813
|
+
const costs = sectionedClauseCosts(
|
|
12814
|
+
input.userPrompt,
|
|
12815
|
+
pieces.hintClauses,
|
|
12816
|
+
pieces.structuredFragment
|
|
12817
|
+
);
|
|
12818
|
+
const texts = pieces.hintClauses.map((c) => c.text);
|
|
12819
|
+
while (fitted.overflowChars > 0 && kept > 0) {
|
|
12820
|
+
kept = keepableDirectionHints(texts, kept, fitted.overflowChars, costs);
|
|
12821
|
+
fitted = assembleWith(kept);
|
|
12822
|
+
}
|
|
12709
12823
|
}
|
|
12710
12824
|
const { overflowChars, ...result } = fitted;
|
|
12711
12825
|
if (input.throwOnEmpty && !result.prompt.trim()) {
|
|
@@ -12719,31 +12833,30 @@ function assembleImageInput(input) {
|
|
|
12719
12833
|
// src/assemble-video-input.ts
|
|
12720
12834
|
function composeVideoPromptText(userPrompt, direction, structured, opts) {
|
|
12721
12835
|
const hintClauses = [
|
|
12722
|
-
...
|
|
12723
|
-
|
|
12724
|
-
|
|
12725
|
-
|
|
12726
|
-
|
|
12836
|
+
...asBodyClauses(
|
|
12837
|
+
renderSubjectHints(opts?.subject, {
|
|
12838
|
+
surface: "video",
|
|
12839
|
+
mode: opts?.subjectHintMode ?? SUBJECT_VIDEO_HINT_MODE_DEFAULT
|
|
12840
|
+
})
|
|
12841
|
+
),
|
|
12842
|
+
...partitionStyleClauses(direction, {
|
|
12727
12843
|
surface: "video",
|
|
12728
12844
|
mode: opts?.hintMode ?? VIDEO_HINT_MODE_DEFAULT
|
|
12729
12845
|
})
|
|
12730
|
-
].filter((
|
|
12846
|
+
].filter((c) => c.text.length > 0);
|
|
12731
12847
|
const structuredFragment = structured ? renderStructuredFields(structured) : "";
|
|
12732
|
-
const composeWith = (kept2) =>
|
|
12733
|
-
const hints = [...hintClauses.slice(0, kept2), structuredFragment].filter(
|
|
12734
|
-
(p) => p.length > 0
|
|
12735
|
-
);
|
|
12736
|
-
if (hints.length === 0) return userPrompt;
|
|
12737
|
-
return joinPromptHints(userPrompt ?? "", hints);
|
|
12738
|
-
};
|
|
12848
|
+
const composeWith = (kept2) => composeSectionedPrompt(userPrompt, hintClauses.slice(0, kept2), structuredFragment);
|
|
12739
12849
|
const cap = opts?.cap;
|
|
12740
12850
|
if (cap === void 0) return composeWith(hintClauses.length);
|
|
12741
12851
|
const frame = opts?.frame ?? ((body2) => body2);
|
|
12742
12852
|
let kept = hintClauses.length;
|
|
12743
12853
|
let body = composeWith(kept);
|
|
12744
12854
|
let framedLength = frame(body)?.length ?? 0;
|
|
12855
|
+
if (framedLength <= cap) return body;
|
|
12856
|
+
const costs = sectionedClauseCosts(userPrompt, hintClauses, structuredFragment);
|
|
12857
|
+
const texts = hintClauses.map((c) => c.text);
|
|
12745
12858
|
while (framedLength > cap && kept > 0) {
|
|
12746
|
-
kept = keepableDirectionHints(
|
|
12859
|
+
kept = keepableDirectionHints(texts, kept, framedLength - cap, costs);
|
|
12747
12860
|
body = composeWith(kept);
|
|
12748
12861
|
framedLength = frame(body)?.length ?? 0;
|
|
12749
12862
|
}
|
|
@@ -12920,10 +13033,13 @@ function resolveSeedance2Inputs(args) {
|
|
|
12920
13033
|
droppedRefImages
|
|
12921
13034
|
};
|
|
12922
13035
|
}
|
|
12923
|
-
var
|
|
13036
|
+
var DEFAULT_GEMINI_OMNI_PROVIDER = "gemini-omni-video";
|
|
13037
|
+
function geminiOmniInputSlots(provider) {
|
|
13038
|
+
return shared.VIDEO_REF_LIMITS_BY_PROVIDER[provider ?? DEFAULT_GEMINI_OMNI_PROVIDER]?.images ?? 7;
|
|
13039
|
+
}
|
|
12924
13040
|
function resolveGeminiOmniI2vInputs(args) {
|
|
12925
13041
|
const refs = (args.refImageUrls ?? []).filter((u) => typeof u === "string" && u.length > 0);
|
|
12926
|
-
const slots =
|
|
13042
|
+
const slots = geminiOmniInputSlots(args.provider) - (args.videoConnected ? 2 : 0);
|
|
12927
13043
|
const refSlots = Math.max(0, slots - 1);
|
|
12928
13044
|
const kept = refs.slice(0, refSlots);
|
|
12929
13045
|
const droppedRefImages = refs.length - kept.length;
|
|
@@ -27762,6 +27878,23 @@ var GAPS_SCHEMA = external_exports.object({
|
|
|
27762
27878
|
).max(8).default([])
|
|
27763
27879
|
}).default({ missingItems: [], missingCategories: [] });
|
|
27764
27880
|
var MULTI_CACHE = /* @__PURE__ */ new Map();
|
|
27881
|
+
function pickerDisplayName(type) {
|
|
27882
|
+
return type.split("-").map((w) => w.length > 0 ? w[0].toUpperCase() + w.slice(1) : w).join(" ");
|
|
27883
|
+
}
|
|
27884
|
+
function buildOtherPickersLegend(sorted) {
|
|
27885
|
+
const otherTypes = PICKER_TYPES.filter((t) => !sorted.includes(t));
|
|
27886
|
+
if (otherTypes.length === 0) return "";
|
|
27887
|
+
const lines = otherTypes.map((type) => {
|
|
27888
|
+
const descriptor = PICKER_ANALYZER_REGISTRY[type];
|
|
27889
|
+
if (descriptor.kind === "flat") {
|
|
27890
|
+
return `- ${type}: ${descriptor.label}`;
|
|
27891
|
+
}
|
|
27892
|
+
const dims = descriptor.order.map((k) => descriptor.labels[k]).filter(Boolean).join(", ");
|
|
27893
|
+
return `- ${type}: ${pickerDisplayName(type)}${dims ? ` \u2014 ${dims}` : ""}`;
|
|
27894
|
+
});
|
|
27895
|
+
return `Non-wired pickers \u2014 use one of these keys in a gap's \`picker\` when an attribute belongs to it:
|
|
27896
|
+
${lines.join("\n")}`;
|
|
27897
|
+
}
|
|
27765
27898
|
function buildMultiPickerAnalyzerSpec(types) {
|
|
27766
27899
|
const sorted = [...new Set(types)].sort();
|
|
27767
27900
|
const key = sorted.join(",");
|
|
@@ -27779,7 +27912,8 @@ ${buildPickerLegend(spec)}`);
|
|
|
27779
27912
|
const result = {
|
|
27780
27913
|
schema: external_exports.object(shape).strict(),
|
|
27781
27914
|
toolName: "emit_pickers",
|
|
27782
|
-
legend: legendParts.join("\n\n")
|
|
27915
|
+
legend: legendParts.join("\n\n"),
|
|
27916
|
+
otherPickersLegend: buildOtherPickersLegend(sorted)
|
|
27783
27917
|
};
|
|
27784
27918
|
MULTI_CACHE.set(key, result);
|
|
27785
27919
|
return result;
|
|
@@ -28185,8 +28319,8 @@ Sources: Google Cloud "Ultimate prompting guide for Veo 3.1"
|
|
|
28185
28319
|
KIE VEO API docs (docs.kie.ai/veo3-api/generate-veo-3-video). Captured 2026-08-09.`
|
|
28186
28320
|
};
|
|
28187
28321
|
var GEMINI_OMNI_DOCTRINE = {
|
|
28188
|
-
providers: ["gemini-omni-video"],
|
|
28189
|
-
heading: "Gemini Omni
|
|
28322
|
+
providers: ["gemini-omni-video", "gemini-omni-flash"],
|
|
28323
|
+
heading: "Gemini Omni (gemini-omni-video, gemini-omni-flash)",
|
|
28190
28324
|
tips: [
|
|
28191
28325
|
"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.",
|
|
28192
28326
|
"Structure like the platform default: subject \u2192 action \u2192 scene \u2192 lighting \u2192 camera \u2192 style. Quote dialogue lines to have them spoken; describe SFX/ambience plainly in the prompt.",
|
|
@@ -28208,6 +28342,7 @@ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera mov
|
|
|
28208
28342
|
|
|
28209
28343
|
**Duration & tiers**
|
|
28210
28344
|
- 4 / 6 / 8 / 10 seconds. 720p/1080p tier or the pricier 4K tier \u2014 pick 4K only when the deliverable needs it (nearly 2\xD7 the credits).
|
|
28345
|
+
- gemini-omni-flash is the faster/cheaper tier with the identical request surface \u2014 same 4/6/8/10s, same 720p/1080p and 4K tiers, same video-edit path. Everything above applies verbatim.
|
|
28211
28346
|
|
|
28212
28347
|
Source: KIE gemini-omni-video market contract (parameters + live behavior probed for the
|
|
28213
28348
|
aspect-ratio hard-reject, see providers/kie/video.ts). Captured 2026-08-09.`
|
|
@@ -28277,6 +28412,45 @@ push-in (intimacy/tension), pull-out (scale/isolation), tracking shot, orbit, fi
|
|
|
28277
28412
|
Source: Alibaba Cloud Model Studio \u2014 "Text-to-video / image-to-video prompt guide"
|
|
28278
28413
|
(alibabacloud.com/help/en/model-studio/text-to-video-prompt). Captured 2026-08-09.`
|
|
28279
28414
|
};
|
|
28415
|
+
var WAN_3_DOCTRINE = {
|
|
28416
|
+
providers: ["wan-3", "wan-3-prime"],
|
|
28417
|
+
heading: "Wan 3.0 (wan-3, wan-3-prime)",
|
|
28418
|
+
tips: [
|
|
28419
|
+
"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.",
|
|
28420
|
+
`References bind by ordinal token in array order: Image1, Image2, Video1, Audio1 \u2014 no space, unlike Wan 2.x's "Image 1". Name every wired asset or it may be ignored.`,
|
|
28421
|
+
"Reference caps: 10 images / 5 videos / 5 audio clips; each video and each audio clip 1-15s, with \u226415s combined per array. With reference videos, input seconds + output duration \u2264 30.",
|
|
28422
|
+
"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 \u2014 excess is truncated silently.",
|
|
28423
|
+
'`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") \u2014 it is not a dialogue guarantee.',
|
|
28424
|
+
"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 \u2014 choose it for latency, not for looks."
|
|
28425
|
+
],
|
|
28426
|
+
doctrine: `Prompt structure (no public Wan 3.0 prompt guide exists \u2014 the KIE API contract is the
|
|
28427
|
+
doctrine source, like MiniMax H3 and HappyHorse; platform-standard structure applies):
|
|
28428
|
+
subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera movement \u2192 style \u2192 constraints.
|
|
28429
|
+
|
|
28430
|
+
**Modes (mutually exclusive at the provider)**
|
|
28431
|
+
- Frame mode: first_frame_url, optionally with last_frame_url, and NO references \u2014 the frames anchor the shot exactly, so describe MOTION and camera, not the still.
|
|
28432
|
+
- 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 \u2014 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.
|
|
28433
|
+
- Text-only runs are supported and are the model's default mode.
|
|
28434
|
+
|
|
28435
|
+
**Reference binding**
|
|
28436
|
+
- Assets bind by ORDINAL TOKEN in array order: Image1, Image2, \u2026, Video1, \u2026, Audio1, \u2026. Note the format has NO space \u2014 Wan 2.x's "Image 1" is a different generation and does not apply here.
|
|
28437
|
+
- Write the binding into the prompt explicitly ("Image1 walks into the room described in Image2"); an unnamed reference may simply be ignored.
|
|
28438
|
+
- Caps: up to 10 images, 5 videos, 5 audio clips. Each video and each audio clip must be 1-15s with \u226415s combined per array. Audio should not be the only media input \u2014 pair it with an image or a video.
|
|
28439
|
+
|
|
28440
|
+
**Duration, resolution, aspect**
|
|
28441
|
+
- 2-30 seconds (provider default 5). With reference videos there is an extra ceiling: input video duration + output duration \u2264 30 seconds.
|
|
28442
|
+
- 480p / 720p / 1080p. Aspect "adaptive" (the default \u2014 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.
|
|
28443
|
+
- Prompts accept Chinese and English, up to 20,000 characters; anything beyond is truncated silently, so front-load the load-bearing content.
|
|
28444
|
+
|
|
28445
|
+
**Audio**
|
|
28446
|
+
- 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 \u2014 plan spoken lines as a separate TTS + lip-sync pass.
|
|
28447
|
+
|
|
28448
|
+
**Tiers**
|
|
28449
|
+
- 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.
|
|
28450
|
+
|
|
28451
|
+
Source: KIE Wan 3.0 market contract (docs.kie.ai/market/wan/3-0-video,
|
|
28452
|
+
docs.kie.ai/market/wan/3-0-video-prime). Captured 2026-09-01.`
|
|
28453
|
+
};
|
|
28280
28454
|
var HAPPYHORSE_DOCTRINE = {
|
|
28281
28455
|
providers: ["happyhorse", "happyhorse-i2v", "happyhorse-ref2v", "happyhorse-edit"],
|
|
28282
28456
|
heading: "HappyHorse 1.1 (happyhorse, happyhorse-i2v, happyhorse-ref2v)",
|
|
@@ -28332,6 +28506,7 @@ var PROVIDER_PROMPT_DOCTRINES = [
|
|
|
28332
28506
|
GEMINI_OMNI_DOCTRINE,
|
|
28333
28507
|
GROK_IMAGINE_DOCTRINE,
|
|
28334
28508
|
WAN_DOCTRINE,
|
|
28509
|
+
WAN_3_DOCTRINE,
|
|
28335
28510
|
HAPPYHORSE_DOCTRINE,
|
|
28336
28511
|
RUNWAY_KIE_DOCTRINE
|
|
28337
28512
|
];
|
|
@@ -28556,6 +28731,9 @@ var PROVIDER_CAPABILITIES = {
|
|
|
28556
28731
|
"ltx-2.3-pro": "Lightricks LTX 2.3 Pro \u2014 text/image/audio\u2192video, 6\u201310s, up to 4K",
|
|
28557
28732
|
"ltx-2.3-fast": "Lightricks LTX 2.3 Fast \u2014 text/image\u2192video, 6\u201320s, up to 4K",
|
|
28558
28733
|
"gemini-omni-video": "Google Gemini Omni \u2014 multimodal video with native audio, 4\u201310s, up to 4K.",
|
|
28734
|
+
"gemini-omni-flash": "Google Gemini Omni Flash \u2014 faster, cheaper Omni tier; multimodal video with native audio, 4\u201310s, up to 4K.",
|
|
28735
|
+
"wan-3": "Wan 3.0 \u2014 multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2\u201330s, 480p/720p/1080p",
|
|
28736
|
+
"wan-3-prime": "Wan 3.0 Prime \u2014 high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate",
|
|
28559
28737
|
"grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 image-to-video only; requires an input image"
|
|
28560
28738
|
},
|
|
28561
28739
|
"image-to-video": {
|
|
@@ -28589,6 +28767,9 @@ var PROVIDER_CAPABILITIES = {
|
|
|
28589
28767
|
"ltx-2.3-pro": "Lightricks LTX 2.3 Pro \u2014 start/end frame i2v + audio\u2192video, 6\u201310s, up to 4K",
|
|
28590
28768
|
"ltx-2.3-fast": "Lightricks LTX 2.3 Fast \u2014 start/end frame i2v, 6\u201320s, up to 4K",
|
|
28591
28769
|
"gemini-omni-video": "Google Gemini Omni \u2014 multimodal video with native audio, 4\u201310s, up to 4K.",
|
|
28770
|
+
"gemini-omni-flash": "Google Gemini Omni Flash \u2014 faster, cheaper Omni tier; multimodal video with native audio, 4\u201310s, up to 4K.",
|
|
28771
|
+
"wan-3": "Wan 3.0 \u2014 multimodal refs (10 images / 5 videos / 5 audio) or first+last frame, native audio, 2\u201330s, 480p/720p/1080p",
|
|
28772
|
+
"wan-3-prime": "Wan 3.0 Prime \u2014 high-speed Wan 3.0 tier; same surface, faster turnaround at a higher rate",
|
|
28592
28773
|
"grok-imagine-video-1.5": "Grok Imagine 1.5 \u2014 stylized animation, 1\u201315s, 480p/720p (image required)"
|
|
28593
28774
|
},
|
|
28594
28775
|
"video-to-video": {
|
|
@@ -34121,6 +34302,7 @@ exports.EXPOSURE_SETTINGS = EXPOSURE_SETTINGS;
|
|
|
34121
34302
|
exports.FACTORY_PRESETS = FACTORY_PRESETS;
|
|
34122
34303
|
exports.FACTORY_SNIPPETS = FACTORY_SNIPPETS;
|
|
34123
34304
|
exports.FILM_STILL_PREFIX = FILM_STILL_PREFIX;
|
|
34305
|
+
exports.FILM_STYLE_KEYS = FILM_STYLE_KEYS;
|
|
34124
34306
|
exports.FRAMINGS = FRAMINGS;
|
|
34125
34307
|
exports.FRAMING_CATEGORY_LABELS = FRAMING_CATEGORY_LABELS;
|
|
34126
34308
|
exports.FRAMING_CATEGORY_ORDER = FRAMING_CATEGORY_ORDER;
|
|
@@ -34231,6 +34413,8 @@ exports.SNIPPET_MEDIA_VALUES = SNIPPET_MEDIA_VALUES;
|
|
|
34231
34413
|
exports.STYLES = STYLES;
|
|
34232
34414
|
exports.STYLE_IDS = STYLE_IDS;
|
|
34233
34415
|
exports.STYLE_PRESETS = STYLE_PRESETS;
|
|
34416
|
+
exports.STYLE_SECTION_GAP = STYLE_SECTION_GAP;
|
|
34417
|
+
exports.STYLE_SECTION_HEADER = STYLE_SECTION_HEADER;
|
|
34234
34418
|
exports.STYLINGS = STYLINGS;
|
|
34235
34419
|
exports.STYLING_DIMENSION_LABELS = STYLING_DIMENSION_LABELS;
|
|
34236
34420
|
exports.STYLING_DIMENSION_ORDER = STYLING_DIMENSION_ORDER;
|
|
@@ -34283,6 +34467,7 @@ exports.applyPickerJson = applyPickerJson;
|
|
|
34283
34467
|
exports.applyPromptAffixes = applyPromptAffixes;
|
|
34284
34468
|
exports.applyReferenceOrderToVideo = applyReferenceOrderToVideo;
|
|
34285
34469
|
exports.applyTemplate = applyTemplate;
|
|
34470
|
+
exports.asBodyClauses = asBodyClauses;
|
|
34286
34471
|
exports.assembleImageInput = assembleImageInput;
|
|
34287
34472
|
exports.assembleSunoInput = assembleSunoInput;
|
|
34288
34473
|
exports.buildActionFxHints = buildActionFxHints;
|
|
@@ -34356,6 +34541,7 @@ exports.composeCameraMotionTermFromConnections = composeCameraMotionTermFromConn
|
|
|
34356
34541
|
exports.composeCharacterFxHintFromConnections = composeCharacterFxHintFromConnections;
|
|
34357
34542
|
exports.composeNegative = composeNegative;
|
|
34358
34543
|
exports.composePickerCatalogs = composePickerCatalogs;
|
|
34544
|
+
exports.composeSectionedPrompt = composeSectionedPrompt;
|
|
34359
34545
|
exports.composeSoundHintFromConnections = composeSoundHintFromConnections;
|
|
34360
34546
|
exports.composeTransitionHintFromConnections = composeTransitionHintFromConnections;
|
|
34361
34547
|
exports.composeVideoPromptText = composeVideoPromptText;
|
|
@@ -34364,6 +34550,7 @@ exports.computeNodePrompt = computeNodePrompt;
|
|
|
34364
34550
|
exports.computePackSidecarCoverage = computePackSidecarCoverage;
|
|
34365
34551
|
exports.deriveTerm = deriveTerm;
|
|
34366
34552
|
exports.directionFieldsForSurface = directionFieldsForSurface;
|
|
34553
|
+
exports.endsInsideStyleSection = endsInsideStyleSection;
|
|
34367
34554
|
exports.expandImagePositionRefs = expandImagePositionRefs;
|
|
34368
34555
|
exports.expandImageRefTokens = expandImageRefTokens;
|
|
34369
34556
|
exports.filmStillPrefix = filmStillPrefix;
|
|
@@ -34550,6 +34737,7 @@ exports.getWardrobePromptHint = getWardrobePromptHint;
|
|
|
34550
34737
|
exports.groupFactoryPresets = groupFactoryPresets;
|
|
34551
34738
|
exports.hasUpstreamCharacter = hasUpstreamCharacter;
|
|
34552
34739
|
exports.identityRefsSentence = identityRefsSentence;
|
|
34740
|
+
exports.insertBeforeStyleSection = insertBeforeStyleSection;
|
|
34553
34741
|
exports.isAnalyzablePicker = isAnalyzablePicker;
|
|
34554
34742
|
exports.isInstrumentalVocal = isInstrumentalVocal;
|
|
34555
34743
|
exports.isSuspiciousDerivedTerm = isSuspiciousDerivedTerm;
|
|
@@ -34565,6 +34753,7 @@ exports.nodeHasInlinePrompt = nodeHasInlinePrompt;
|
|
|
34565
34753
|
exports.nodeHasPromptField = nodeHasPromptField;
|
|
34566
34754
|
exports.nodeSupportsPromptAffixes = nodeSupportsPromptAffixes;
|
|
34567
34755
|
exports.normalizeSubjectFields = normalizeSubjectFields;
|
|
34756
|
+
exports.partitionStyleClauses = partitionStyleClauses;
|
|
34568
34757
|
exports.personPacksVersion = personPacksVersion;
|
|
34569
34758
|
exports.pickerFanoutTargets = pickerFanoutTargets;
|
|
34570
34759
|
exports.projectAllCatalogs = projectAllCatalogs;
|
|
@@ -34579,8 +34768,10 @@ exports.readSubjectFields = readSubjectFields;
|
|
|
34579
34768
|
exports.referenceRulesBlock = referenceRulesBlock;
|
|
34580
34769
|
exports.registerCatalogPack = registerCatalogPack;
|
|
34581
34770
|
exports.registerPersonPack = registerPersonPack;
|
|
34771
|
+
exports.renderDirectionHintClauses = renderDirectionHintClauses;
|
|
34582
34772
|
exports.renderDirectionHints = renderDirectionHints;
|
|
34583
34773
|
exports.renderStructuredFields = renderStructuredFields;
|
|
34774
|
+
exports.renderStyleSection = renderStyleSection;
|
|
34584
34775
|
exports.renderSubjectHints = renderSubjectHints;
|
|
34585
34776
|
exports.resetCatalogPacks = resetCatalogPacks;
|
|
34586
34777
|
exports.resetPersonPacks = resetPersonPacks;
|
|
@@ -34596,6 +34787,10 @@ exports.resolveTemplate = resolveTemplate;
|
|
|
34596
34787
|
exports.resolveTerm = resolveTerm;
|
|
34597
34788
|
exports.resolveVeoI2vInputs = resolveVeoI2vInputs;
|
|
34598
34789
|
exports.resolveVideoReferenceCore = resolveVideoReferenceCore;
|
|
34790
|
+
exports.sectionedClauseCosts = sectionedClauseCosts;
|
|
34791
|
+
exports.splitStyleSection = splitStyleSection;
|
|
34792
|
+
exports.styleSectionFromClauses = styleSectionFromClauses;
|
|
34793
|
+
exports.styleSlotFor = styleSlotFor;
|
|
34599
34794
|
exports.subjectFieldsForSurface = subjectFieldsForSurface;
|
|
34600
34795
|
exports.summarizePickerCatalogs = summarizePickerCatalogs;
|
|
34601
34796
|
exports.toIdentityLockMode = toIdentityLockMode;
|