@nodaro/prompts 1.5.0 → 1.7.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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ANIMAL_SUBCATEGORY_LABELS, ANIMAL_SUBCATEGORY_ORDER, VEHICLE_SUBCATEGORY_LABELS, VEHICLE_SUBCATEGORY_ORDER, WEAPON_SUBCATEGORY_LABELS, WEAPON_SUBCATEGORY_ORDER, FURNITURE_SUBCATEGORY_LABELS, FURNITURE_SUBCATEGORY_ORDER, SOCIAL_POST_NODE_TYPES, PASSTHROUGH_TYPES, pickIds, getFurniture, getWeapon, getVehicle, getAnimal, DEFAULT_USAGE_MODE, usageModeDirective, DEFAULT_LOCATION_USAGE_MODE, imageReferenceLimit, findCharacterMentionTokens, findLocationMentionTokens, NATIVE_NEGATIVE_PROMPT_MODELS, getMaxNegativePromptChars, getMaxImagePromptChars, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, roleToPhrase, resolveDefaultRole, SEEDANCE_2_REF_LIMITS, ANIMALS, VEHICLES, WEAPONS, FURNITURE, PLACEHOLDER_CHARACTER_NAME, REFERENCE_ROLE_PRESETS, normalizeRoleSlug, defaultRoleForSource, locationReferencePhotoKindLabel, resolveNodeRefs } from '@nodaro/shared';
1
+ import { ANIMAL_SUBCATEGORY_LABELS, ANIMAL_SUBCATEGORY_ORDER, VEHICLE_SUBCATEGORY_LABELS, VEHICLE_SUBCATEGORY_ORDER, WEAPON_SUBCATEGORY_LABELS, WEAPON_SUBCATEGORY_ORDER, FURNITURE_SUBCATEGORY_LABELS, FURNITURE_SUBCATEGORY_ORDER, SOCIAL_POST_NODE_TYPES, FURNITURE, WEAPONS, VEHICLES, ANIMALS, PASSTHROUGH_TYPES, pickIds, getFurniture, getWeapon, getVehicle, getAnimal, DEFAULT_USAGE_MODE, usageModeDirective, DEFAULT_LOCATION_USAGE_MODE, imageReferenceLimit, findCharacterMentionTokens, findLocationMentionTokens, NATIVE_NEGATIVE_PROMPT_MODELS, getMaxNegativePromptChars, getMaxImagePromptChars, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, roleToPhrase, resolveDefaultRole, SEEDANCE_2_REF_LIMITS, PLACEHOLDER_CHARACTER_NAME, REFERENCE_ROLE_PRESETS, normalizeRoleSlug, defaultRoleForSource, locationReferencePhotoKindLabel, resolveNodeRefs } from '@nodaro/shared';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
4
  var __export = (target, all) => {
@@ -67,6 +67,25 @@ function buildIdentityLockLine(ref, binding) {
67
67
  return text ? interpolate(text) : null;
68
68
  }
69
69
 
70
+ // src/reference-rules.ts
71
+ var REFERENCE_RULES = "Do not use anything from reference images unless specified explicitly. All elements taken from reference images must preserve likeness. Compose them naturally into a single image.";
72
+ var REFERENCE_RULES_MULTI_PERSON = "Do not take anything from the reference images unless specified explicitly. Do not alter face structure. Do not blend faces. Preserve the likeness of every element taken. Compose them naturally into a single image.";
73
+ var FILM_STILL_PREFIX = "Film still of";
74
+ function filmStillPrefix(shotSize) {
75
+ const shot = shotSize?.trim();
76
+ return shot ? `${shot} film still of` : FILM_STILL_PREFIX;
77
+ }
78
+ var SCENE_FRAME_RULE = "Nobody looks at the camera.";
79
+ var CINEMATIC_LOOK_TAIL = "Shot on Super 16mm Kodak 7298 with Canon K35 lenses, soft naturalistic window light mixed with dim tungsten practicals and muted fluorescent spill, earthy muted palette with faded greens, warm skin tones and gentle shadow fall-off";
80
+ function referenceRulesBlock(opts) {
81
+ const parts = [];
82
+ if (opts?.referenceRules !== false) {
83
+ parts.push(opts?.multiPerson === true ? REFERENCE_RULES_MULTI_PERSON : REFERENCE_RULES);
84
+ }
85
+ if (opts?.sceneFrame === true) parts.push(SCENE_FRAME_RULE);
86
+ return parts.join(" ");
87
+ }
88
+
70
89
  // src/framing.ts
71
90
  var FRAMINGS = [
72
91
  // Shot size (how much of the subject is in frame)
@@ -10511,6 +10530,7 @@ function assembleSunoInput(input) {
10511
10530
  styleWeight: data.styleWeight,
10512
10531
  weirdnessConstraint: data.weirdnessConstraint,
10513
10532
  audioWeight: data.audioWeight,
10533
+ duration: data.duration,
10514
10534
  customMode,
10515
10535
  instrumental: data.instrumental ?? false,
10516
10536
  ...input.persona ?? {}
@@ -25672,9 +25692,10 @@ function date4(params) {
25672
25692
 
25673
25693
  // ../../node_modules/zod/v4/classic/external.js
25674
25694
  config(en_default());
25675
-
25676
- // src/picker-analyzer-registry.ts
25677
25695
  var PERSON_EXCLUDED = /* @__PURE__ */ new Set(["age-custom"]);
25696
+ function tagDim(arr, dimension) {
25697
+ return arr.map((e) => ({ id: e.id, label: e.label, description: e.description, dimension }));
25698
+ }
25678
25699
  var personCleanup = (patch, mode) => {
25679
25700
  if (mode === "override") {
25680
25701
  patch.customAge = void 0;
@@ -25729,9 +25750,148 @@ var PICKER_ANALYZER_REGISTRY = {
25729
25750
  field: "cameraFormat",
25730
25751
  label: "Camera / Film Stock",
25731
25752
  entries: CAMERA_FORMATS
25753
+ },
25754
+ // ─── Text-to-picker expansion (Cine AI Fill): every remaining catalog ─────
25755
+ // Flat single-value pickers — field names match the picker wiring's
25756
+ // valueField (and the node-data shape the published-app input card writes).
25757
+ setting: { kind: "flat", toolName: "emit_setting", field: "setting", label: "Setting", entries: SETTINGS },
25758
+ atmosphere: { kind: "flat", toolName: "emit_atmosphere", field: "atmosphere", label: "Atmosphere", entries: ATMOSPHERES },
25759
+ style: { kind: "flat", toolName: "emit_style", field: "style", label: "Style", entries: STYLES },
25760
+ mood: { kind: "flat", toolName: "emit_mood", field: "mood", label: "Mood", entries: MOODS },
25761
+ "color-look": { kind: "flat", toolName: "emit_color_look", field: "colorLook", label: "Color / Look", entries: COLOR_LOOKS },
25762
+ photographer: { kind: "flat", toolName: "emit_photographer", field: "photographer", label: "Photographer / Artist", entries: PHOTOGRAPHERS },
25763
+ aesthetic: { kind: "flat", toolName: "emit_aesthetic", field: "aesthetic", label: "Aesthetic / Microtrend", entries: AESTHETICS },
25764
+ era: { kind: "flat", toolName: "emit_era", field: "era", label: "Era / Period", entries: ERAS },
25765
+ "photo-genre": { kind: "flat", toolName: "emit_photo_genre", field: "photoGenre", label: "Photo Genre", entries: PHOTO_GENRES },
25766
+ backdrop: { kind: "flat", toolName: "emit_backdrop", field: "backdrop", label: "Backdrop", entries: BACKDROPS },
25767
+ "render-quality": { kind: "flat", toolName: "emit_render_quality", field: "renderQuality", label: "Render Quality", entries: RENDER_QUALITIES },
25768
+ "composition-effects": { kind: "flat", toolName: "emit_composition_effects", field: "compositionEffect", label: "Composition Effect", entries: COMPOSITION_EFFECTS },
25769
+ "post-process-effects": { kind: "flat", toolName: "emit_post_process_effects", field: "postProcess", label: "Post-Process Effect", entries: POST_PROCESS_EFFECTS },
25770
+ "action-fx": { kind: "flat", toolName: "emit_action_fx", field: "actionFx", label: "Action FX", entries: ACTION_FX },
25771
+ "loop-subject": { kind: "flat", toolName: "emit_loop_subject", field: "loopSubject", label: "Loop Subject", entries: LOOP_SUBJECTS },
25772
+ transition: { kind: "flat", toolName: "emit_transition", field: "transition", label: "Transition", entries: TRANSITIONS },
25773
+ "character-fx": { kind: "flat", toolName: "emit_character_fx", field: "characterFx", label: "Character FX", entries: CHARACTER_FX },
25774
+ pose: { kind: "flat", toolName: "emit_pose", field: "pose", label: "Pose", entries: POSES },
25775
+ material: { kind: "flat", toolName: "emit_material", field: "material", label: "Material", entries: MATERIALS },
25776
+ "held-prop": { kind: "flat", toolName: "emit_held_prop", field: "heldProp", label: "Held Prop", entries: HELD_PROPS },
25777
+ "camera-motion": { kind: "flat", toolName: "emit_camera_motion", field: "cameraMotion", label: "Camera Motion", entries: CAMERA_MOTIONS },
25778
+ animal: { kind: "flat", toolName: "emit_animal", field: "animal", label: "Animal", entries: ANIMALS },
25779
+ vehicle: { kind: "flat", toolName: "emit_vehicle", field: "vehicle", label: "Vehicle", entries: VEHICLES },
25780
+ weapon: { kind: "flat", toolName: "emit_weapon", field: "weapon", label: "Weapon", entries: WEAPONS },
25781
+ furniture: { kind: "flat", toolName: "emit_furniture", field: "furniture", label: "Furniture", entries: FURNITURE },
25782
+ // Discriminated multi-dim pickers. lighting/temporal/exposure discriminate
25783
+ // on the single catalog's `category`; the sound/voice pickers span several
25784
+ // per-field catalogs, so their entries are synthesized with an explicit
25785
+ // `dimension` tag (tagDim below) — same wire shape either way.
25786
+ lighting: {
25787
+ kind: "discriminated",
25788
+ toolName: "emit_lighting",
25789
+ discriminator: "category",
25790
+ order: LIGHTING_CATEGORY_ORDER,
25791
+ fieldByKey: LIGHTING_FIELD_BY_CATEGORY,
25792
+ labels: LIGHTING_CATEGORY_LABELS,
25793
+ entries: LIGHTINGS,
25794
+ limitFn: () => 1
25795
+ },
25796
+ temporal: {
25797
+ kind: "discriminated",
25798
+ toolName: "emit_temporal",
25799
+ discriminator: "category",
25800
+ order: ["speed", "freeze", "direction", "shutter"],
25801
+ fieldByKey: { speed: "temporalSpeed", freeze: "temporalFreeze", direction: "temporalDirection", shutter: "temporalShutter" },
25802
+ labels: { speed: "Playback Speed", freeze: "Freeze", direction: "Direction", shutter: "Shutter" },
25803
+ entries: TEMPORALS,
25804
+ limitFn: () => 1
25805
+ },
25806
+ "exposure-settings": {
25807
+ kind: "discriminated",
25808
+ toolName: "emit_exposure_settings",
25809
+ discriminator: "category",
25810
+ order: ["aperture", "shutter-speed", "iso"],
25811
+ fieldByKey: { aperture: "aperture", "shutter-speed": "shutterSpeed", iso: "isoValue" },
25812
+ labels: { aperture: "Aperture", "shutter-speed": "Shutter Speed", iso: "ISO" },
25813
+ entries: EXPOSURE_SETTINGS,
25814
+ limitFn: () => 1
25815
+ },
25816
+ "music-genre": {
25817
+ kind: "discriminated",
25818
+ toolName: "emit_music_genre",
25819
+ discriminator: "dimension",
25820
+ order: ["genre", "subgenre", "era"],
25821
+ fieldByKey: { genre: "genre", subgenre: "subgenre", era: "era" },
25822
+ labels: { genre: "Genre", subgenre: "Subgenre", era: "Era" },
25823
+ entries: [
25824
+ ...tagDim(MUSIC_GENRES, "genre"),
25825
+ // Subgenres carry promptHint but no description — the hint doubles as
25826
+ // the legend text (it describes the sound well enough for matching).
25827
+ ...MUSIC_GENRES.flatMap(
25828
+ (g) => g.subgenres.map((s) => ({ id: s.id, label: s.label, description: s.promptHint, dimension: "subgenre" }))
25829
+ ),
25830
+ ...tagDim(MUSIC_ERAS, "era")
25831
+ ],
25832
+ limitFn: (k) => k === "genre" ? 2 : 1
25833
+ },
25834
+ "music-mood": {
25835
+ kind: "discriminated",
25836
+ toolName: "emit_music_mood",
25837
+ discriminator: "dimension",
25838
+ order: ["energy", "emotion", "vibe"],
25839
+ fieldByKey: { energy: "energy", emotion: "emotion", vibe: "vibe" },
25840
+ labels: { energy: "Energy", emotion: "Emotion", vibe: "Vibe" },
25841
+ entries: [...tagDim(MUSIC_ENERGIES, "energy"), ...tagDim(MUSIC_EMOTIONS, "emotion"), ...tagDim(MUSIC_VIBES, "vibe")],
25842
+ limitFn: (k) => k === "energy" ? 1 : 2
25843
+ },
25844
+ instrumentation: {
25845
+ kind: "discriminated",
25846
+ toolName: "emit_instrumentation",
25847
+ discriminator: "dimension",
25848
+ order: ["instruments", "production", "vocalPresence", "singingStyle"],
25849
+ fieldByKey: { instruments: "instruments", production: "production", vocalPresence: "vocalPresence", singingStyle: "singingStyle" },
25850
+ labels: { instruments: "Instruments", production: "Production Style", vocalPresence: "Vocal Presence", singingStyle: "Singing Style" },
25851
+ entries: [
25852
+ ...tagDim(INSTRUMENTS, "instruments"),
25853
+ ...tagDim(PRODUCTION_STYLES, "production"),
25854
+ ...tagDim(VOCAL_PRESENCE, "vocalPresence"),
25855
+ ...tagDim(SINGING_STYLES, "singingStyle")
25856
+ ],
25857
+ limitFn: (k) => k === "instruments" ? 3 : k === "production" ? 1 : 2
25858
+ },
25859
+ "voice-character": {
25860
+ kind: "discriminated",
25861
+ toolName: "emit_voice_character",
25862
+ discriminator: "dimension",
25863
+ order: ["age", "gender", "language", "accent", "timbre"],
25864
+ fieldByKey: { age: "age", gender: "gender", language: "language", accent: "accent", timbre: "timbre" },
25865
+ labels: { age: "Age", gender: "Gender", language: "Language", accent: "Accent", timbre: "Timbre" },
25866
+ entries: [
25867
+ ...tagDim(VOICE_AGES, "age"),
25868
+ ...tagDim(VOICE_GENDERS, "gender"),
25869
+ ...tagDim(VOICE_LANGUAGES, "language"),
25870
+ ...tagDim(VOICE_ACCENTS, "accent"),
25871
+ ...tagDim(VOICE_TIMBRES, "timbre")
25872
+ ],
25873
+ limitFn: (k) => k === "language" ? 2 : 1
25874
+ },
25875
+ "voice-delivery": {
25876
+ kind: "discriminated",
25877
+ toolName: "emit_voice_delivery",
25878
+ discriminator: "dimension",
25879
+ order: ["pace", "emotion", "archetype"],
25880
+ fieldByKey: { pace: "pace", emotion: "emotion", archetype: "archetype" },
25881
+ labels: { pace: "Pace", emotion: "Emotion", archetype: "Archetype" },
25882
+ entries: [...tagDim(VOICE_PACES, "pace"), ...tagDim(VOICE_EMOTIONS, "emotion"), ...tagDim(VOICE_ARCHETYPES, "archetype")],
25883
+ limitFn: () => 1
25732
25884
  }
25733
25885
  };
25734
25886
  var PICKER_TYPES = Object.keys(PICKER_ANALYZER_REGISTRY);
25887
+ var PICKER_ANALYZER_FAMILIES = {
25888
+ scene: ["setting", "atmosphere", "backdrop", "era", "temporal"],
25889
+ look: ["style", "color-look", "mood", "aesthetic", "photographer", "photo-genre", "render-quality", "composition-effects", "post-process-effects"],
25890
+ camera: ["framing", "camera-motion", "lens", "camera-format", "lighting", "exposure-settings"],
25891
+ character: ["person", "styling", "pose", "character-fx"],
25892
+ elements: ["animal", "vehicle", "weapon", "furniture", "held-prop", "material", "action-fx", "loop-subject", "transition"],
25893
+ audio: ["music-genre", "music-mood", "instrumentation", "voice-character", "voice-delivery"]
25894
+ };
25735
25895
  var ANALYZABLE_PICKER_TYPES = new Set(PICKER_TYPES);
25736
25896
  function isAnalyzablePicker(t) {
25737
25897
  return ANALYZABLE_PICKER_TYPES.has(t);
@@ -26038,14 +26198,16 @@ function buildWardrobeHints(value) {
26038
26198
 
26039
26199
  // src/provider-prompt-doctrine.ts
26040
26200
  var SEEDANCE_2_DOCTRINE = {
26041
- providers: ["seedance-2", "seedance-2-fast", "seedance-2-mini"],
26042
- heading: "Seedance 2.0 (seedance-2, seedance-2-fast, seedance-2-mini)",
26201
+ providers: ["seedance-2", "seedance-2-fast", "seedance-2-mini", "seedance-2-5"],
26202
+ heading: "Seedance 2 (seedance-2, seedance-2-fast, seedance-2-mini, seedance-2-5)",
26043
26203
  tips: [
26044
26204
  "Storyboard complex videos as 'Shot 1: \u2026 Shot 2: \u2026' WITHOUT timestamps \u2014 timed shots like '(0-3s)' are officially unstable and can break generation.",
26045
26205
  "One camera movement per shot; describe actions per body part with degree ('slowly raises a hand'); express emotion as physical detail, never abstract words.",
26046
26206
  "Native multi-track audio \u2014 cue it inline: \uFF08background music\uFF09, <sound effects>, and quoted dialogue.",
26047
26207
  "References go by ordinal (@Image 1, Video 2) in attachment order; earlier = higher priority. Identity = ONE headshot + ONE full-body (multi-view sheets cause ID drift). 4-5 assets total beats maxing the 9/3/3 caps.",
26048
- "No negative-prompt parameter \u2014 put constraints in the prompt: 'keep it subtitle-free, do not generate a watermark, do not generate a logo'."
26208
+ "No negative-prompt parameter \u2014 put constraints in the prompt: 'keep it subtitle-free, do not generate a watermark, do not generate a logo'.",
26209
+ "seedance-2-5 only: one shot runs to 30s (the 2.0 SKUs stop at 15s), so storyboard a whole beat instead of planning a stitch. Ref caps are wider (30/10/10), but 4-5 assets still gives the best identity fidelity.",
26210
+ "Auto-path formula: Subject \u2192 Action \u2192 Environment \u2192 Camera \u2192 Style \u2192 Constraints in 60-100 words; ONE camera instruction (chain with 'then'); separate camera motion from subject motion; always add one lighting phrase."
26049
26211
  ],
26050
26212
  doctrine: `Prompt structure (front-load what matters most):
26051
26213
  precise subject \u2192 action details \u2192 scene/environment \u2192 lighting & color tone \u2192 camera movement \u2192 visual style \u2192 image quality \u2192 constraints.
@@ -26057,6 +26219,12 @@ precise subject \u2192 action details \u2192 scene/environment \u2192 lighting &
26057
26219
  - 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".
26058
26220
  - 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".
26059
26221
 
26222
+ **Generation differences (seedance-2-5 vs the 2.0 SKUs)**
26223
+ - 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 \u2014 no seam to hide, and continuity holds because it never leaves the model.
26224
+ - 2.5 also takes far more reference material (30 images / 10 videos / 10 audio vs 9/3/3). Treat that as room for COVERAGE \u2014 more distinct characters, locations and props in one shot \u2014 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.
26225
+ - 2.5 renders at 480p/720p only: there is no 1080p or 4K tier, so route a job that needs one to seedance-2 (which has both) or upscale afterwards.
26226
+ - With a start frame, 2.5 always derives the output aspect from that frame \u2014 an explicit aspect ratio is rejected outright, so compose the frame at the ratio you want.
26227
+
26060
26228
  **References (when reference media is attached)**
26061
26229
  - Refer to assets by ordinal in attachment order: "@Image 1", "Video 2", "Audio 1". Asset ORDER is priority \u2014 put the most identity-critical asset first. (In the editor, the \`{image:N:label}\` / \`{video:N}\` / \`{audio:N}\` prompt tokens auto-emit this binding \u2014 \`{image:1:person}\` resolves to "the person from @image_1" \u2014 so a wired reference and its mention stay in sync.)
26062
26230
  - Define each subject once, then reuse the label consistently: 'Define the woman in the red dress in Image 1 as the courier' \u2026 '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".
@@ -26077,11 +26245,34 @@ precise subject \u2192 action details \u2192 scene/environment \u2192 lighting &
26077
26245
  **Known weaknesses \u2192 workarounds**
26078
26246
  - 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".
26079
26247
  - More than 4 referenced people gets unstable: group people into composite images of \u22644 first (image generation), then reference those composites.
26080
- - Repeated extension degrades quality: prefer high-definition reference assets and avoid stacking many continuations.`
26248
+ - Repeated extension degrades quality: prefer high-definition reference assets and avoid stacking many continuations.
26249
+
26250
+ **Auto-path formula (community-sourced enrichment \u2014 apiyi.com Seedance 2.0 prompt guide,
26251
+ higgsfield.ai 4K breakdown; captured 2026-08-09)**
26252
+ - Six steps IN ORDER, 60-100 words total (longer measurably degrades): Subject \u2192 Action \u2192 Environment \u2192 Camera \u2192 Style \u2192 Constraints.
26253
+ - ONE primary camera instruction per shot. Compound moves chain with "then": "camera slow tracking then subtle rise" \u2014 never two competing verbs. The 8 reliable camera types: push-in, pull-out, pan, tracking, orbit/arc, aerial, handheld, locked-off.
26254
+ - SEPARATE camera movement from subject movement \u2014 the single biggest quality lever: "The dancer spins slowly. Camera holds fixed framing." \u2014 never "spinning camera around a dancing person".
26255
+ - Pace with human words (slow / gentle / gradual / smooth / controlled) \u2014 never fps numbers or f-stops in the basic path.
26256
+ - ALWAYS add one lighting phrase (highest-impact single addition): golden hour / rim light / neon glow / backlit / overcast.
26257
+ - Bake stability constraints in: "avoid jitter and bent limbs", "avoid temporal flicker", "avoid identity drift".
26258
+ - Ban vague adjectives standing alone ("epic", "amazing", "beautiful", bare "cinematic") \u2014 every adjective needs a concrete noun.
26259
+ - Mode notes: i2v \u2014 skip subject description (the frame has it), focus on motion, append "preserve composition and colors". v2v \u2014 describe the style TRANSFORM, keep motion + identity.
26260
+ - Advanced (pro path): focal angles in degrees ("47\xB0 normal", "29\xB0 telephoto", "107\xB0 wide"); "180\xB0 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.
26261
+
26262
+ **Camera-path control \u2014 the magenta-line method (STORYBOARD community technique; the
26263
+ manual pro path for precise trajectories, NOT the auto path)**
26264
+ 1. Duplicate the start frame; on the COPY draw a thick magenta line + arrowhead \u2014 the line is the camera's flight path, the arrow its end point. Keep the clean original.
26265
+ 2. Attach BOTH frames and declare the guide: "Image N contains a magenta line and arrow \u2014 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.
26266
+ 3. Command the path: "one continuous FPV drone glide following the S-shaped curve as closely as possible \u2014 do not shortcut. Camera motion is the priority." Lock the clean frame as first frame + scene reference; lock the destination frame if wired.
26267
+ 4. Pace with timing blocks ("[00:00-00:02] rise over the rooftop \u2026 [00:07-00:09] settle on the doorway") and keep any dialogue SHORT \u2014 long lines fight the move.
26268
+ 5. Assign image-input roles explicitly: first-frame/scene-ref \xB7 destination frame \xB7 path-guide \xB7 3-6 character-identity refs \u2014 and bind identities with @-mentions exactly like the platform's reference pills.`
26081
26269
  };
26082
26270
  var KLING_AUDIO_DOCTRINE = {
26083
- providers: ["kling", "kling-3.0", "kling-3-omni"],
26084
- heading: "Kling 2.6 / 3.0 / 3 Omni (kling, kling-3.0, kling-3-omni)",
26271
+ // kling-turbo (2.5 Turbo Pro) + kling-master (2.1 Master) are SILENT tiers of
26272
+ // the same engine: the structure/motion guidance applies, the Audio block
26273
+ // does not (variant note in the doctrine body).
26274
+ providers: ["kling", "kling-3.0", "kling-3-omni", "kling-turbo", "kling-master"],
26275
+ heading: "Kling 2.1 / 2.5 / 2.6 / 3.0 / 3 Omni (kling, kling-3.0, kling-3-omni, kling-turbo, kling-master)",
26085
26276
  tips: [
26086
26277
  'Kling speaks scripted dialogue natively with lip sync \u2014 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.',
26087
26278
  "Structure prompts as Scene \u2192 character/element \u2192 Motion \u2192 Audio \u2192 style. Put ALL sound in one 'Audio:' block: dialogue in quotes, then SFX and ambience described plainly ('rain tapping on glass, no music').",
@@ -26113,11 +26304,240 @@ var KLING_AUDIO_DOCTRINE = {
26113
26304
 
26114
26305
  **Limits**
26115
26306
  - Kling 2.6 prompts cap at 1000 characters \u2014 front-load scene + dialogue and trim style tails first. kling-3.0 accepts long prompts.
26116
- - Durations: 2.6 = 5/10s; 3.0/omni = 3-15s. A spoken line needs roughly 1s per 2-3 words \u2014 don't script more dialogue than the clip can hold.`
26307
+ - Durations: 2.6 = 5/10s; 3.0/omni = 3-15s. A spoken line needs roughly 1s per 2-3 words \u2014 don't script more dialogue than the clip can hold.
26308
+
26309
+ **Variant note \u2014 kling-turbo (2.5 Turbo Pro) & kling-master (2.1 Master)**
26310
+ - SILENT tiers: no audio parameter, so the entire Audio block above does not apply \u2014 skip dialogue/SFX cues; the Scene \u2192 Character \u2192 Motion \u2192 Style structure and motion guidance carry over unchanged.
26311
+ - Durations 5/10s; kling-turbo takes an end frame (tail_image_url); kling-master is single-image i2v.`
26312
+ };
26313
+ var MINIMAX_H3_DOCTRINE = {
26314
+ providers: ["minimax-h3"],
26315
+ heading: "MiniMax Hailuo 3 (minimax-h3)",
26316
+ tips: [
26317
+ "Natural-language prompts up to 7000 chars. Front-load what matters: subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera move \u2192 style. One camera movement per shot.",
26318
+ "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).",
26319
+ "References go by ordinal in attachment order (@Image 1, Video 1) \u2014 earlier = higher priority. Caps: 9 images, 3 videos (2-15s each, \u226415s total), 3 audio clips (\u226415s total).",
26320
+ "Reference audio drives speech/lip-sync but never rides alone \u2014 pair it with an image or video reference. Audio input is free; the first 5 input images are free, extras bill per image.",
26321
+ "No negative-prompt parameter \u2014 put constraints in the prompt text: 'keep it subtitle-free, do not generate a watermark, do not generate a logo'."
26322
+ ],
26323
+ doctrine: `Prompt structure (front-load what matters most):
26324
+ precise subject \u2192 action details \u2192 scene/environment \u2192 lighting & color tone \u2192 camera movement \u2192 visual style \u2192 image quality \u2192 constraints. Prompts are natural language, 1-7000 characters, across all three modes.
26325
+
26326
+ **Modes (picked automatically from the wired inputs)**
26327
+ - First frame and/or last frame connected, nothing else \u2192 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 \u2014 there is no aspect parameter in this mode.
26328
+ - ANY reference connected (image, video, or audio) \u2192 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.
26329
+ - Nothing visual connected \u2192 text-to-video. A concrete aspect ratio is required (21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16 \u2014 no adaptive); Nodaro renders 16:9 unless one is picked.
26330
+
26331
+ **References (when reference media is attached)**
26332
+ - 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.)
26333
+ - Caps: 9 reference images; 3 reference videos, each 2-15s and \u226415s combined; 3 reference audio clips, \u226415s combined. Reference audio cannot be used alone \u2014 it must accompany an image or video reference.
26334
+ - Define each subject once, then reuse the label consistently ("the woman from @Image 1 \u2026 the woman opens the door"). A focused set of 4-5 assets beats maxing every cap.
26335
+ - 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.
26336
+
26337
+ **Audio**
26338
+ - Audio is always generated \u2014 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).
26339
+ - Quoted dialogue in the prompt gives the model the line to perform; describe the voice in words when no reference audio is supplied.
26340
+
26341
+ **Duration & pacing**
26342
+ - 4-15 seconds, integer, default 6. Per-second pricing \u2014 a 15s clip costs ~3.7\xD7 a 4s clip, so pick the shortest duration that serves the shot.
26343
+ - 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.
26344
+
26345
+ **Constraints**
26346
+ - There is NO negative-prompt parameter \u2014 all constraints belong in the prompt text itself: "keep it subtitle-free, do not generate a watermark, do not generate a logo, stable picture".`
26347
+ };
26348
+ var VEO_31_DOCTRINE = {
26349
+ providers: ["veo3", "veo3.1", "veo3_lite", "veo-1080p", "veo-4k", "veo-extend"],
26350
+ heading: "VEO 3.1 \u2014 Quality / Fast / Lite (veo3, veo3.1, veo3_lite)",
26351
+ tips: [
26352
+ "Structure prompts as [Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance] \u2014 lead with the camera, not the subject (Google's official formula).",
26353
+ 'Dialogue: quote the exact line with attribution \u2014 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.',
26354
+ "Multi-shot pacing via timestamp blocks: [00:00-00:02] medium shot\u2026 [00:02-00:04] reverse shot\u2026 \u2014 VEO honors per-window actions inside one 8s generation.",
26355
+ "Negative prompting is positive phrasing: not 'no buildings' but 'a desolate landscape with no buildings or roads'. Keep prompts under ~175 words \u2014 longer overloads the generation.",
26356
+ "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."
26357
+ ],
26358
+ doctrine: `Prompt structure (Google's official Veo 3.1 formula \u2014 lead with the camera):
26359
+ [Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance].
26360
+ Example: "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."
26361
+
26362
+ **Camera vocabulary (use the exact terms)**
26363
+ - Movement: dolly shot, tracking shot, crane shot, aerial view, slow pan, POV shot, 180-degree arc shot.
26364
+ - Composition: wide shot, medium shot, close-up, extreme close-up, two-shot, low angle, high angle.
26365
+ - Lens/focus: shallow depth of field, deep focus, wide-angle lens, macro lens, soft focus.
26366
+
26367
+ **Audio (native, multi-track \u2014 dialogue / SFX / ambience)**
26368
+ - 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)" \u2014 VEO otherwise tends to burn captions in.
26369
+ - 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".
26370
+ - Sound can drive the visual ("the sound reverberating through the empty ballroom") \u2014 VEO syncs audio-visual timing.
26371
+
26372
+ **Multi-shot timestamp prompting (inside one generation)**
26373
+ - Split the clip into [mm:ss-mm:ss] windows, one action per window:
26374
+ [00:00-00:02] Medium shot from behind a young explorer walking toward a clearing.
26375
+ [00:02-00:04] Reverse shot of her freckled face, eyes widening.
26376
+ [00:04-00:08] Wide, high-angle crane shot revealing the ruins below.
26377
+ - 4 / 6 / 8 second clips; budget ~2s per window.
26378
+
26379
+ **Frames & references**
26380
+ - Start + end frame: wire both (imageUrls [start, end]) and describe the camera path between them \u2014 "a smooth 180-degree arc shot, starting front-facing and circling to end on the POV from behind her".
26381
+ - Reference images (ingredients): attach character/object/scene refs and name them in the prompt ("using the provided images for the detective and the office, \u2026"). Reference runs DO generate audio.
26382
+
26383
+ **Constraints**
26384
+ - Negative prompting works by positive description: write "a desolate landscape with no buildings or roads", not "no buildings".
26385
+ - Keep prompts \u2264 ~175 words \u2014 beyond that instructions conflict and adherence drops. Resolution 720p/1080p; aspect 16:9 / 9:16.
26386
+
26387
+ Sources: Google Cloud "Ultimate prompting guide for Veo 3.1"
26388
+ (cloud.google.com/blog/products/ai-machine-learning/ultimate-prompting-guide-for-veo-3-1),
26389
+ KIE VEO API docs (docs.kie.ai/veo3-api/generate-veo-3-video). Captured 2026-08-09.`
26390
+ };
26391
+ var GEMINI_OMNI_DOCTRINE = {
26392
+ providers: ["gemini-omni-video"],
26393
+ heading: "Gemini Omni Video (gemini-omni-video)",
26394
+ tips: [
26395
+ "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.",
26396
+ "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.",
26397
+ "Text-to-video REQUIRES a concrete aspect ratio (the API hard-rejects a missing one); image runs infer aspect from the input.",
26398
+ "Reference images ride along as additional imageUrls \u2014 bind them in the prompt ('the woman from the first image'). Video-edit: wire a source clip and describe the change, not the whole scene."
26399
+ ],
26400
+ doctrine: `Prompt structure (no public Google prompt guide exists for the Omni video endpoint \u2014
26401
+ the API contract is the doctrine source, like MiniMax H3; structure guidance mirrors the
26402
+ platform's ordinal-reference conventions):
26403
+ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera movement \u2192 style \u2192 constraints.
26404
+
26405
+ **Modes (picked from the wired inputs)**
26406
+ - Nothing visual \u2192 text-to-video. A concrete aspect ratio is REQUIRED \u2014 the API hard-rejects a missing one (Nodaro sends the node's ratio; there is no adaptive).
26407
+ - Image(s) wired \u2192 image-to-video: the first image anchors the scene; extra images are references \u2014 bind each in the prompt ("the woman from the first image", "the interior from the second image").
26408
+ - Source video wired \u2192 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.
26409
+
26410
+ **Audio (native)**
26411
+ - 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.
26412
+
26413
+ **Duration & tiers**
26414
+ - 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).
26415
+
26416
+ Source: KIE gemini-omni-video market contract (parameters + live behavior probed for the
26417
+ aspect-ratio hard-reject, see providers/kie/video.ts). Captured 2026-08-09.`
26418
+ };
26419
+ var GROK_IMAGINE_DOCTRINE = {
26420
+ providers: ["grok-i2v", "grok-imagine-video-1.5"],
26421
+ heading: "Grok Imagine (grok-i2v, grok-imagine-video-1.5)",
26422
+ tips: [
26423
+ "Keep prompts simple and direct \u2014 Subject + Action + Setting + Camera + Mood. Grok expands the prompt itself; over-specification fights the expander.",
26424
+ "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.",
26425
+ "Video 1.5: 1-15s (default 8), 480p/720p/1080p, up to 7 input images (1080p allows only one). Native audio incl. music, SFX, and lip-synced dialogue \u2014 quote the line to have it spoken.",
26426
+ "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."
26427
+ ],
26428
+ doctrine: `Prompt structure (xAI's guidance is minimal by design \u2014 the model auto-expands prompts):
26429
+ Subject + Action + Setting + Camera + Lighting/Mood, written simply and directly. Reduce
26430
+ descriptions of static/unchanged parts \u2014 spend the words on what MOVES.
26431
+
26432
+ **Image-to-video (the primary mode)**
26433
+ - 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.
26434
+ - grok-imagine-video-1.5 accepts up to 7 images (identity/scene references beyond the first frame); at 1080p only ONE image is allowed.
26435
+
26436
+ **Audio (video-1.5)**
26437
+ - Native audio generates with the clip \u2014 background music, SFX, and lip-synced dialogue. Quote the spoken line; describe the music/SFX plainly. There is no audio toggle on the KIE contract \u2014 cue (or exclude) sound in the prompt text.
26438
+
26439
+ **Durations / tiers**
26440
+ - 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.
26441
+
26442
+ Sources: KIE Grok Imagine contracts (docs.kie.ai/market/grok-imagine/image-to-video,
26443
+ docs.kie.ai/market/grok-imagine/1-5-preview), xAI Grok Imagine 1.5 release notes
26444
+ (x.ai/news/grok-imagine-1-5). Captured 2026-08-09.`
26445
+ };
26446
+ var WAN_DOCTRINE = {
26447
+ 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"],
26448
+ heading: "Wan 2.x (wan, wan-i2v, wan-turbo, wan-2.7 family)",
26449
+ tips: [
26450
+ "Alibaba's official formula: Entity + Scene + Motion (basic) \u2192 add Aesthetic control + Stylization (advanced). Image-to-video: Motion + Camera only \u2014 the image already defines entity and scene.",
26451
+ "Sound (2.5+): append a sound description block \u2014 voice / sound effects / background music. Avoid scripting EXACT lip-synced lines (official anti-pattern); describe the voice and intent instead.",
26452
+ "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).",
26453
+ "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.",
26454
+ "Style words are strong levers: cyberpunk, claymation, pixel style, felt style, tilt-shift, time-lapse. wan-videoedit: describe the transform, keep motion + identity."
26455
+ ],
26456
+ doctrine: `Prompt structure (Alibaba Model Studio's official formulas):
26457
+ - Basic: Entity + Scene + Motion.
26458
+ - Advanced: Entity (description) + Scene (description) + Motion (description) + Aesthetic control + Stylization.
26459
+ - Image-to-video: Motion + Camera movement ONLY \u2014 the wired image already defines entity and scene; re-describing it fights the frame.
26460
+ - Sound (2.5/2.6/2.7): \u2026 + Sound description (voice / sound effects / background music).
26461
+ - Multi-shot (2.6/2.7): Overall description + Shot number + Timestamp + Shot content.
26462
+ - Reference-to-video (2.6/2.7): Reference identifier + Action + Scene + optional Lines + optional BGM.
26463
+
26464
+ **Camera vocabulary**
26465
+ push-in (intimacy/tension), pull-out (scale/isolation), tracking shot, orbit, fixed camera, and compound movements chained sequentially for epic scale.
26466
+
26467
+ **Single-shot control (2.7)**
26468
+ - The shot_type parameter no longer exists \u2014 write "Generate single shot" in the prompt to force one continuous take; otherwise 2.7's planner may cut.
26469
+
26470
+ **References**
26471
+ - English format is "Image 1" / "Video 1" (capitalized, space-separated) \u2014 bind every wired asset by that name or it may be ignored.
26472
+
26473
+ **Official anti-patterns (from Alibaba's guide)**
26474
+ - Do NOT name specific real people.
26475
+ - Do NOT script exact lip-synced dialogue \u2014 describe the voice and intent ("she murmurs a reassurance, warm and low") instead of demanding word-perfect lips.
26476
+ - Avoid rapid scene changes inside a single clip, very long choreographed sequences, and demands for exactly legible on-screen text.
26477
+
26478
+ **Stylization**
26479
+ - 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.
26480
+
26481
+ Source: Alibaba Cloud Model Studio \u2014 "Text-to-video / image-to-video prompt guide"
26482
+ (alibabacloud.com/help/en/model-studio/text-to-video-prompt). Captured 2026-08-09.`
26483
+ };
26484
+ var HAPPYHORSE_DOCTRINE = {
26485
+ providers: ["happyhorse", "happyhorse-i2v", "happyhorse-ref2v", "happyhorse-edit"],
26486
+ heading: "HappyHorse 1.1 (happyhorse, happyhorse-i2v, happyhorse-ref2v)",
26487
+ tips: [
26488
+ "Any-language prompts up to 5000 chars (2500 Chinese) \u2014 excess is silently truncated, so front-load subject \u2192 action \u2192 scene \u2192 camera \u2192 style.",
26489
+ "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.",
26490
+ "ref2v is one of the few true REFERENCE modes on the roster: wired refs keep identity across the clip \u2014 bind each reference explicitly in the prompt.",
26491
+ "No published vendor style guide \u2014 the platform's standard structure applies; keep one camera move per shot and quantify motion physically."
26492
+ ],
26493
+ doctrine: `Prompt structure (no public HappyHorse prompt guide exists \u2014 the KIE API contract is the
26494
+ doctrine source; platform-standard structure applies):
26495
+ subject \u2192 action \u2192 scene/environment \u2192 lighting \u2192 camera movement \u2192 style \u2192 constraints.
26496
+
26497
+ **Contract facts (KIE, per-mode pages)**
26498
+ - Prompts: any language, up to 5000 non-Chinese / 2500 Chinese characters \u2014 excess is TRUNCATED silently, so put the load-bearing content first.
26499
+ - Duration 3-15s (default 5), billed per second. Resolution 720p / 1080p (default). Aspect 16:9 (default) / 9:16 / 1:1 / 4:3 / 3:4.
26500
+ - Modes: text-to-video (happyhorse), image-to-video (happyhorse-i2v), reference-to-video (happyhorse-ref2v) \u2014 ref2v preserves wired identities; name each reference in the prompt so the binding is explicit.
26501
+
26502
+ **Style guidance (platform-standard, honestly generic)**
26503
+ - 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.
26504
+
26505
+ Source: KIE HappyHorse 1.1 contracts (docs.kie.ai/market/happyhorse/text-to-video,
26506
+ \u2026/happyhorse-1-1/image-to-video, \u2026/happyhorse-1-1/reference-to-video). Captured 2026-08-09.`
26507
+ };
26508
+ var RUNWAY_KIE_DOCTRINE = {
26509
+ providers: ["runway-kie", "runway-extend", "runway-aleph"],
26510
+ heading: "Runway via KIE (runway-kie)",
26511
+ tips: [
26512
+ "Prompt cap is 1800 chars; KIE's own guidance: be specific about subject, action, style, and setting. No native audio \u2014 plan sound as a separate pass.",
26513
+ "Durations 5 or 10s with a hard trade-off: 10s cannot be 1080p, 1080p cannot exceed 5s \u2014 pick per deliverable.",
26514
+ "Text runs REQUIRE an aspect ratio (16:9/4:3/1:1/3:4/9:16); image runs IGNORE it \u2014 the input image dictates output dimensions.",
26515
+ "Image-to-video treats the image as the anchor frame: describe motion and camera, not the still."
26516
+ ],
26517
+ doctrine: `Prompt structure (KIE contract guidance): "be specific about subject, action, style, and
26518
+ setting" \u2014 subject \u2192 action \u2192 scene \u2192 camera \u2192 style, within the 1800-character cap.
26519
+
26520
+ **Contract facts (KIE Runway endpoint)**
26521
+ - Duration 5 or 10 seconds; quality 720p or 1080p \u2014 10s@1080p does NOT exist (10s forces 720p; 1080p forces 5s). Choose by deliverable: crisp hero shot \u2192 5s/1080p; longer beat \u2192 10s/720p.
26522
+ - Text-to-video REQUIRES aspectRatio (16:9 / 4:3 / 1:1 / 3:4 / 9:16). Image-to-video IGNORES aspectRatio \u2014 the input image dictates output dimensions.
26523
+ - No audio is generated \u2014 score/SFX are a separate pass (merge-video-audio / video-sfx downstream).
26524
+
26525
+ **Style guidance**
26526
+ - The image input anchors composition and identity \u2014 describe the motion ("she pushes the door open as the camera tracks left"), not the still.
26527
+ - Keep one continuous camera idea per clip; front-load the subject and action.
26528
+
26529
+ Source: KIE Runway contract (docs.kie.ai/runway-api/generate-ai-video). Captured 2026-08-09.`
26117
26530
  };
26118
26531
  var PROVIDER_PROMPT_DOCTRINES = [
26119
26532
  SEEDANCE_2_DOCTRINE,
26120
- KLING_AUDIO_DOCTRINE
26533
+ KLING_AUDIO_DOCTRINE,
26534
+ MINIMAX_H3_DOCTRINE,
26535
+ VEO_31_DOCTRINE,
26536
+ GEMINI_OMNI_DOCTRINE,
26537
+ GROK_IMAGINE_DOCTRINE,
26538
+ WAN_DOCTRINE,
26539
+ HAPPYHORSE_DOCTRINE,
26540
+ RUNWAY_KIE_DOCTRINE
26121
26541
  ];
26122
26542
  var DOCTRINE_BY_PROVIDER = new Map(
26123
26543
  PROVIDER_PROMPT_DOCTRINES.flatMap((d) => d.providers.map((p) => [p, d]))
@@ -26297,6 +26717,8 @@ var PROVIDER_CAPABILITIES = {
26297
26717
  "seedance-2": "Seedance 2.0 \u2014 multimodal refs (9 images / 3 videos / 3 audio), native multi-track audio, multi-shot storytelling, 4-15s",
26298
26718
  "seedance-2-fast": "Seedance 2.0 Fast \u2014 same multimodal + audio capabilities, cheaper and quicker",
26299
26719
  "seedance-2-mini": "Seedance 2.0 Mini \u2014 same multimodal + audio capabilities, budget tier, 480p/720p, 4-15s",
26720
+ "seedance-2-5": "Seedance 2.5 \u2014 up to 30s in ONE shot (no stitching), wider multimodal refs (30 images / 10 videos / 10 audio), native audio, 480p/720p",
26721
+ "minimax-h3": "MiniMax Hailuo 3 \u2014 premium multimodal refs (9 images / 3 videos / 3 audio), always-on audio, 2K or 768P, 4-15s per-second pricing",
26300
26722
  "wan": "Versatile, good for animations and transformations",
26301
26723
  "wan-turbo": "Faster Wan generation",
26302
26724
  "hailuo-standard": "Standard quality, cost-effective",
@@ -26323,6 +26745,8 @@ var PROVIDER_CAPABILITIES = {
26323
26745
  "seedance-2": "Seedance 2.0 \u2014 start/end frame + multimodal refs, native audio, 4-15s",
26324
26746
  "seedance-2-fast": "Seedance 2.0 Fast \u2014 same capabilities, cheaper and quicker",
26325
26747
  "seedance-2-mini": "Seedance 2.0 Mini \u2014 same capabilities, budget tier, 480p/720p",
26748
+ "seedance-2-5": "Seedance 2.5 \u2014 start/end frame + wide multimodal refs, native audio, up to 30s, 480p/720p",
26749
+ "minimax-h3": "MiniMax Hailuo 3 \u2014 first/last frame + multimodal refs, always-on audio, 2K or 768P, 4-15s",
26326
26750
  "hailuo-2.3-pro": "Premium Hailuo animation",
26327
26751
  "hailuo-2.3": "Standard Hailuo animation",
26328
26752
  "hailuo-standard": "Cost-effective animation",
@@ -31333,7 +31757,24 @@ var FACTORY_SNIPPETS = [
31333
31757
  { id: "wardrobe-lock", name: "Wardrobe Lock", description: "Outfit continuity across shots and edits", text: "wearing exactly the same outfit as the reference \u2014 same garments, colors, fabrics, and accessories, unchanged", target: "prompt", media: B, category: "Identity & Consistency" },
31334
31758
  { id: "no-beautify", name: "No Beautify", description: "Stop the model 'improving' a face", text: "preserve natural skin texture, age lines, and asymmetries; do not beautify, smooth, slim, or rejuvenate the face", target: "prompt", media: I, category: "Identity & Consistency" },
31335
31759
  // ── Reference locks (prompt) — insert at the START of a reference prompt ──
31336
- { id: "reference-lock", name: "Reference Lock", description: "Default-deny + preserve likeness + compose into one image (full scenes)", text: "Do not use anything from reference images unless specified explicitly. All elements taken from reference images must preserve likeness. Compose them naturally into a single image.", target: "prompt", media: I, category: "Reference locks" },
31760
+ // Text comes from the shared constant, not a hand-written twin. This entry used
31761
+ // to carry its own wording — no face rules, likeness phrased as a passive —
31762
+ // which scored 0/4 on moving a garment between references where the merged
31763
+ // block scored 4/4 (see reference-rules.ts). A snippet is copied into the
31764
+ // prompt at INSERT time, so changing it here only affects future insertions.
31765
+ { id: "reference-lock", name: "Reference Lock", description: "Default-deny + preserve likeness + compose into one image (full scenes)", text: REFERENCE_RULES, target: "prompt", media: I, category: "Reference locks" },
31766
+ // The eyeline suppressor, kept OUT of Reference Lock on purpose: a portrait
31767
+ // or a piece to camera wants the eyeline. 4/4 on a brief where the lock alone
31768
+ // was 0/4, at no measured cost to identity or wardrobe.
31769
+ { id: "scene-frame", name: "Scene Frame", description: "Reads as a frame from a film, not a posed photo \u2014 nobody faces the lens", text: SCENE_FRAME_RULE, target: "prompt", media: I, category: "Reference locks" },
31770
+ // A PREFIX, not a sentence — it swallows the scene that follows it, which is
31771
+ // exactly why it costs nothing. The same idea written as a standalone claim
31772
+ // ("This image is a scene start frame of a video.") lost the lead's identity
31773
+ // in 3 of 3 draws. Goes at the very TOP, above the scene.
31774
+ { id: "film-still-of", name: "Film Still Of", description: 'Put at the very top, before the scene \u2014 lead with the shot size, e.g. "Medium wide\u2026"', text: `Medium wide ${FILM_STILL_PREFIX.charAt(0).toLowerCase()}${FILM_STILL_PREFIX.slice(1)}`, target: "prompt", media: I, category: "Reference locks" },
31775
+ // Goes at the very END. An example to edit — a different film wants a
31776
+ // different stock; what generalises is that the look comes LAST.
31777
+ { id: "cinematic-look", name: "Cinematic Look (16mm)", description: "Append at the END \u2014 film stock, lens, light and palette", text: CINEMATIC_LOOK_TAIL, target: "prompt", media: I, category: "Reference locks" },
31337
31778
  { id: "reference-extract", name: "Reference Extract", description: "Isolate only the specified elements \u2014 no scene, no figure", text: "Take only what is specified from the reference images. Do not take anything else.", target: "prompt", media: I, category: "Reference locks" },
31338
31779
  { id: "ghost-mannequin", name: "Ghost Mannequin", description: "Show worn garments without a wearer (product shot)", text: "Ghost-mannequin product shot: the garment in its natural worn shape, with no person, body, face, or mannequin visible.", target: "prompt", media: I, category: "Reference locks" },
31339
31780
  // ── Quality (prompt) ──
@@ -31425,7 +31866,213 @@ function getFactorySnippets(target, media) {
31425
31866
  (s) => s.target === target && s.media.includes(media)
31426
31867
  );
31427
31868
  }
31869
+ function mapCat(arr, groupKey) {
31870
+ return arr.map((e) => ({
31871
+ id: e.id,
31872
+ label: e.label,
31873
+ description: e.description,
31874
+ group: groupKey ? e[groupKey] : void 0
31875
+ }));
31876
+ }
31877
+ function flatCat(arr) {
31878
+ return arr.map((e) => ({ id: e.id, label: e.label }));
31879
+ }
31880
+ function optionsByDiscriminator(arr, keyOf, fieldByKey) {
31881
+ const out = {};
31882
+ for (const e of arr) {
31883
+ const field = fieldByKey[keyOf(e)];
31884
+ if (!field) continue;
31885
+ (out[field] ??= []).push({ id: e.id, label: e.label });
31886
+ }
31887
+ return out;
31888
+ }
31889
+ var SINGLE_PICKER_WIRING = [
31890
+ // -------- "Look" family --------
31891
+ { kind: "single", nodeType: "setting", label: "Setting", valueField: "setting", defaultValue: "forest", catalogId: "setting", entries: mapCat(SETTINGS, "category"), groupOrder: ["indoor", "urban", "nature", "fantastical"], groupLabels: SETTING_CATEGORY_LABELS },
31892
+ { kind: "single", nodeType: "atmosphere", label: "Atmosphere", valueField: "atmosphere", defaultValue: "clear", catalogId: "atmosphere", entries: mapCat(ATMOSPHERES) },
31893
+ { kind: "single", nodeType: "style", label: "Style", valueField: "style", defaultValue: "cinematic", catalogId: "style", entries: mapCat(STYLES) },
31894
+ { kind: "single", nodeType: "color-look", label: "Color / Look", valueField: "colorLook", defaultValue: "warm", catalogId: "color-look", entries: mapCat(COLOR_LOOKS, "category"), groupOrder: COLOR_LOOK_CATEGORY_ORDER, groupLabels: COLOR_LOOK_CATEGORY_LABELS },
31895
+ { kind: "single", nodeType: "mood", label: "Mood", valueField: "mood", defaultValue: "calm", catalogId: "mood", entries: mapCat(MOODS, "category"), groupOrder: MOOD_CATEGORY_ORDER, groupLabels: MOOD_CATEGORY_LABELS },
31896
+ { kind: "single", nodeType: "photographer", label: "Photographer / Artist", valueField: "photographer", defaultValue: "tim-walker", catalogId: "photographer", entries: mapCat(PHOTOGRAPHERS, "category"), groupOrder: PHOTOGRAPHER_CATEGORY_ORDER, groupLabels: PHOTOGRAPHER_CATEGORY_LABELS },
31897
+ { kind: "single", nodeType: "aesthetic", label: "Aesthetic / Microtrend", valueField: "aesthetic", defaultValue: "y2k", catalogId: "aesthetic", entries: mapCat(AESTHETICS, "category"), groupOrder: AESTHETIC_CATEGORY_ORDER, groupLabels: AESTHETIC_CATEGORY_LABELS },
31898
+ { kind: "single", nodeType: "era", label: "Era / Period", valueField: "era", defaultValue: "1990s-mall", catalogId: "era", entries: mapCat(ERAS, "category"), groupOrder: ERA_CATEGORY_ORDER, groupLabels: ERA_CATEGORY_LABELS },
31899
+ { kind: "single", nodeType: "photo-genre", label: "Photo Genre", valueField: "photoGenre", defaultValue: "fashion-editorial", catalogId: "photo-genre", entries: mapCat(PHOTO_GENRES, "category"), groupOrder: PHOTO_GENRE_CATEGORY_ORDER, groupLabels: PHOTO_GENRE_CATEGORY_LABELS },
31900
+ { kind: "single", nodeType: "backdrop", label: "Backdrop", valueField: "backdrop", defaultValue: "white-seamless", catalogId: "backdrop", entries: mapCat(BACKDROPS, "category"), groupOrder: BACKDROP_CATEGORY_ORDER, groupLabels: BACKDROP_CATEGORY_LABELS },
31901
+ { kind: "single", nodeType: "render-quality", label: "Render Quality", valueField: "renderQuality", defaultValue: "raytracing", catalogId: "render-quality", entries: mapCat(RENDER_QUALITIES) },
31902
+ { kind: "single", nodeType: "composition-effects", label: "Composition Effect", valueField: "compositionEffect", defaultValue: "bursting-through-frame", catalogId: "composition-effects", entries: mapCat(COMPOSITION_EFFECTS) },
31903
+ { kind: "single", nodeType: "action-fx", label: "Action FX", valueField: "actionFx", defaultValue: "earthquake-tremor", catalogId: "action-fx", entries: mapCat(ACTION_FX, "category"), groupOrder: ACTION_FX_CATEGORY_ORDER, groupLabels: ACTION_FX_CATEGORY_LABELS },
31904
+ { kind: "single", nodeType: "loop-subject", label: "Loop Subject", valueField: "loopSubject", defaultValue: "tunnel", catalogId: "loop-subject", entries: mapCat(LOOP_SUBJECTS, "category"), groupOrder: LOOP_SUBJECT_CATEGORY_ORDER, groupLabels: LOOP_SUBJECT_CATEGORY_LABELS },
31905
+ { kind: "single", nodeType: "post-process-effects", label: "Post-Process Effect", valueField: "postProcess", defaultValue: "vignette-soft", catalogId: "post-process-effects", entries: mapCat(POST_PROCESS_EFFECTS) },
31906
+ // -------- "Camera" family --------
31907
+ { kind: "single", nodeType: "camera-motion", label: "Camera Motion", valueField: "cameraMotion", defaultValue: "static", catalogId: "camera-motions", entries: mapCat(CAMERA_MOTIONS, "category"), groupOrder: CAMERA_MOTION_CATEGORY_ORDER, groupLabels: CAMERA_MOTION_CATEGORY_LABELS },
31908
+ { kind: "single", nodeType: "lens", label: "Lens", valueField: "lens", defaultValue: "normal-50mm", catalogId: "lens", entries: mapCat(LENSES) },
31909
+ { kind: "single", nodeType: "camera-format", label: "Camera / Film", valueField: "cameraFormat", defaultValue: "35mm-film", catalogId: "camera-format", entries: mapCat(CAMERA_FORMATS) },
31910
+ { kind: "single", nodeType: "transition", label: "Transition", valueField: "transition", defaultValue: "auto", catalogId: "transitions", entries: mapCat(TRANSITIONS, "category"), groupOrder: TRANSITION_CATEGORY_ORDER, groupLabels: TRANSITION_CATEGORY_LABELS },
31911
+ { kind: "single", nodeType: "character-fx", label: "Character FX", valueField: "characterFx", defaultValue: "auto", catalogId: "character-fx", entries: mapCat(CHARACTER_FX, "category"), groupOrder: CHARACTER_FX_CATEGORY_ORDER, groupLabels: CHARACTER_FX_CATEGORY_LABELS },
31912
+ // -------- "Subject / Object" family --------
31913
+ { kind: "single", nodeType: "pose", label: "Pose", valueField: "pose", defaultValue: "standing-upright", catalogId: "pose", entries: mapCat(POSES, "category"), groupOrder: POSE_CATEGORY_ORDER, groupLabels: POSE_CATEGORY_LABELS },
31914
+ { kind: "single", nodeType: "material", label: "Material", valueField: "material", defaultValue: "silk", catalogId: "materials", entries: mapCat(MATERIALS, "category"), groupOrder: MATERIAL_CATEGORY_ORDER, groupLabels: MATERIAL_CATEGORY_LABELS },
31915
+ { kind: "single", nodeType: "animal", label: "Animal", valueField: "animal", defaultValue: "dog-golden-retriever", catalogId: "animals", entries: mapCat(ANIMALS, "subcategory"), groupOrder: ANIMAL_SUBCATEGORY_ORDER, groupLabels: ANIMAL_SUBCATEGORY_LABELS },
31916
+ { kind: "single", nodeType: "vehicle", label: "Vehicle", valueField: "vehicle", defaultValue: "sedan", catalogId: "vehicles", entries: mapCat(VEHICLES, "subcategory"), groupOrder: VEHICLE_SUBCATEGORY_ORDER, groupLabels: VEHICLE_SUBCATEGORY_LABELS },
31917
+ { kind: "single", nodeType: "weapon", label: "Weapon", valueField: "weapon", defaultValue: "katana", catalogId: "weapons", entries: mapCat(WEAPONS, "subcategory"), groupOrder: WEAPON_SUBCATEGORY_ORDER, groupLabels: WEAPON_SUBCATEGORY_LABELS },
31918
+ { kind: "single", nodeType: "furniture", label: "Furniture", valueField: "furniture", defaultValue: "sofa", catalogId: "furniture", entries: mapCat(FURNITURE, "subcategory"), groupOrder: FURNITURE_SUBCATEGORY_ORDER, groupLabels: FURNITURE_SUBCATEGORY_LABELS },
31919
+ { kind: "single", nodeType: "held-prop", label: "Held Prop", valueField: "heldProp", defaultValue: "smartphone", catalogId: "held-prop", entries: mapCat(HELD_PROPS, "category"), groupOrder: HELD_PROP_CATEGORY_ORDER, groupLabels: HELD_PROP_CATEGORY_LABELS }
31920
+ ];
31921
+ var STYLING_FIELDS2 = STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]);
31922
+ var PERSON_FIELDS2 = PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]);
31923
+ var LIGHTING_FIELDS2 = LIGHTING_CATEGORY_ORDER.map((c) => LIGHTING_FIELD_BY_CATEGORY[c]);
31924
+ var TEMPORAL_FIELD_BY_CATEGORY2 = {
31925
+ speed: "temporalSpeed",
31926
+ freeze: "temporalFreeze",
31927
+ direction: "temporalDirection",
31928
+ shutter: "temporalShutter"
31929
+ };
31930
+ var EXPOSURE_FIELD_BY_CATEGORY2 = {
31931
+ aperture: "aperture",
31932
+ "shutter-speed": "shutterSpeed",
31933
+ iso: "isoValue"
31934
+ };
31935
+ var MULTI_PICKER_WIRING = [
31936
+ {
31937
+ kind: "multi",
31938
+ nodeType: "framing",
31939
+ label: "Framing",
31940
+ fields: ["shotSize", "angle", "coverage", "composition", "vantage"],
31941
+ catalogId: "framing",
31942
+ catalogEntries: flatCat(FRAMINGS),
31943
+ fieldOptions: optionsByDiscriminator(FRAMINGS, (e) => e.category, FRAMING_FIELD_BY_CATEGORY)
31944
+ },
31945
+ {
31946
+ kind: "multi",
31947
+ nodeType: "lighting",
31948
+ label: "Lighting",
31949
+ fields: LIGHTING_FIELDS2,
31950
+ catalogId: "lighting",
31951
+ catalogEntries: flatCat(LIGHTINGS),
31952
+ fieldOptions: optionsByDiscriminator(LIGHTINGS, (e) => e.category, LIGHTING_FIELD_BY_CATEGORY)
31953
+ },
31954
+ {
31955
+ kind: "multi",
31956
+ nodeType: "person",
31957
+ label: "Person",
31958
+ fields: PERSON_FIELDS2,
31959
+ catalogId: "person",
31960
+ catalogEntries: flatCat(PEOPLE),
31961
+ fieldOptions: optionsByDiscriminator(PEOPLE, (e) => e.dimension, PERSON_FIELD_BY_DIMENSION)
31962
+ },
31963
+ {
31964
+ kind: "multi",
31965
+ nodeType: "styling",
31966
+ label: "Styling",
31967
+ fields: STYLING_FIELDS2,
31968
+ catalogId: "styling",
31969
+ catalogEntries: flatCat(STYLINGS),
31970
+ fieldOptions: optionsByDiscriminator(STYLINGS, (e) => e.dimension, STYLING_FIELD_BY_DIMENSION)
31971
+ },
31972
+ {
31973
+ kind: "multi",
31974
+ nodeType: "temporal",
31975
+ label: "Temporal",
31976
+ fields: ["temporalSpeed", "temporalFreeze", "temporalDirection", "temporalShutter"],
31977
+ catalogId: "temporal",
31978
+ catalogEntries: flatCat(TEMPORALS),
31979
+ fieldOptions: optionsByDiscriminator(TEMPORALS, (e) => e.category, TEMPORAL_FIELD_BY_CATEGORY2)
31980
+ },
31981
+ {
31982
+ kind: "multi",
31983
+ nodeType: "exposure-settings",
31984
+ label: "Exposure Settings",
31985
+ fields: ["aperture", "shutterSpeed", "isoValue"],
31986
+ catalogId: "exposure-settings",
31987
+ catalogEntries: flatCat(EXPOSURE_SETTINGS),
31988
+ fieldOptions: optionsByDiscriminator(EXPOSURE_SETTINGS, (e) => e.category, EXPOSURE_FIELD_BY_CATEGORY2)
31989
+ },
31990
+ // -------- "Sound" family --------
31991
+ // Music Genre catalog is hierarchical: flatten genres + every subgenre +
31992
+ // eras so summary chips can resolve any selected id back to a human label.
31993
+ {
31994
+ kind: "multi",
31995
+ nodeType: "music-genre",
31996
+ label: "Music Genre",
31997
+ fields: ["genre", "subgenre", "era"],
31998
+ catalogId: "music-genre",
31999
+ catalogEntries: [
32000
+ ...flatCat(MUSIC_GENRES),
32001
+ ...MUSIC_GENRES.flatMap((g) => g.subgenres.map((s) => ({ id: s.id, label: s.label }))),
32002
+ ...flatCat(MUSIC_ERAS)
32003
+ ],
32004
+ fieldOptions: {
32005
+ genre: flatCat(MUSIC_GENRES),
32006
+ subgenre: MUSIC_GENRES.flatMap((g) => g.subgenres.map((s) => ({ id: s.id, label: s.label }))),
32007
+ era: flatCat(MUSIC_ERAS)
32008
+ }
32009
+ },
32010
+ {
32011
+ kind: "multi",
32012
+ nodeType: "music-mood",
32013
+ label: "Music Mood",
32014
+ fields: ["energy", "emotion", "vibe"],
32015
+ catalogId: "music-mood",
32016
+ catalogEntries: [...flatCat(MUSIC_ENERGIES), ...flatCat(MUSIC_EMOTIONS), ...flatCat(MUSIC_VIBES)],
32017
+ fieldOptions: {
32018
+ energy: flatCat(MUSIC_ENERGIES),
32019
+ emotion: flatCat(MUSIC_EMOTIONS),
32020
+ vibe: flatCat(MUSIC_VIBES)
32021
+ }
32022
+ },
32023
+ {
32024
+ kind: "multi",
32025
+ nodeType: "instrumentation",
32026
+ label: "Instrumentation",
32027
+ fields: ["instruments", "production", "vocalPresence", "singingStyle"],
32028
+ catalogId: "instrumentation",
32029
+ catalogEntries: [...flatCat(INSTRUMENTS), ...flatCat(PRODUCTION_STYLES), ...flatCat(VOCAL_PRESENCE), ...flatCat(SINGING_STYLES)],
32030
+ fieldOptions: {
32031
+ instruments: flatCat(INSTRUMENTS),
32032
+ production: flatCat(PRODUCTION_STYLES),
32033
+ vocalPresence: flatCat(VOCAL_PRESENCE),
32034
+ singingStyle: flatCat(SINGING_STYLES)
32035
+ }
32036
+ },
32037
+ {
32038
+ kind: "multi",
32039
+ nodeType: "voice-character",
32040
+ label: "Voice Character",
32041
+ fields: ["age", "gender", "language", "accent", "timbre"],
32042
+ catalogId: "voice-character",
32043
+ catalogEntries: [...flatCat(VOICE_AGES), ...flatCat(VOICE_GENDERS), ...flatCat(VOICE_LANGUAGES), ...flatCat(VOICE_ACCENTS), ...flatCat(VOICE_TIMBRES)],
32044
+ fieldOptions: {
32045
+ age: flatCat(VOICE_AGES),
32046
+ gender: flatCat(VOICE_GENDERS),
32047
+ language: flatCat(VOICE_LANGUAGES),
32048
+ accent: flatCat(VOICE_ACCENTS),
32049
+ timbre: flatCat(VOICE_TIMBRES)
32050
+ }
32051
+ },
32052
+ {
32053
+ kind: "multi",
32054
+ nodeType: "voice-delivery",
32055
+ label: "Voice Delivery",
32056
+ fields: ["pace", "emotion", "archetype"],
32057
+ catalogId: "voice-delivery",
32058
+ catalogEntries: [...flatCat(VOICE_PACES), ...flatCat(VOICE_EMOTIONS), ...flatCat(VOICE_ARCHETYPES)],
32059
+ fieldOptions: {
32060
+ pace: flatCat(VOICE_PACES),
32061
+ emotion: flatCat(VOICE_EMOTIONS),
32062
+ archetype: flatCat(VOICE_ARCHETYPES)
32063
+ }
32064
+ }
32065
+ ];
32066
+ var ALL_PICKER_WIRING = [
32067
+ ...SINGLE_PICKER_WIRING,
32068
+ ...MULTI_PICKER_WIRING
32069
+ ];
32070
+ var WIRING_MAP = new Map(ALL_PICKER_WIRING.map((w) => [w.nodeType, w]));
32071
+ function getPickerWiring(nodeType) {
32072
+ if (!nodeType) return void 0;
32073
+ return WIRING_MAP.get(nodeType);
32074
+ }
31428
32075
 
31429
- export { ACTION_FX, ACTION_FX_CATEGORY_LABELS, ACTION_FX_CATEGORY_ORDER, ACTION_FX_IDS, AESTHETICS, AESTHETIC_CATEGORY_LABELS, AESTHETIC_CATEGORY_ORDER, AESTHETIC_IDS, ANALYZABLE_PICKER_TYPES, ANGLE_LABELS, ASPECT_RATIO_LABELS, ATMOSPHERES, ATMOSPHERE_IDS, AUDIO_WIZARD_CATEGORIES, BACKDROPS, BACKDROP_CATEGORY_LABELS, BACKDROP_CATEGORY_ORDER, BACKDROP_IDS, BRAND_PRESETS, BRAND_PRESET_IDS, BRAND_PRESET_META, CAMERA_FORMATS, CAMERA_FORMAT_IDS, CAMERA_MOTIONS, CAMERA_MOTION_CATEGORY_LABELS, CAMERA_MOTION_CATEGORY_ORDER, CAMERA_MOTION_IDS, CHARACTER_FX, CHARACTER_FX_CATEGORY_LABELS, CHARACTER_FX_CATEGORY_ORDER, CHARACTER_FX_IDS, COLOR_LOOKS, COLOR_LOOK_CATEGORY_LABELS, COLOR_LOOK_CATEGORY_ORDER, COLOR_LOOK_IDS, COMPOSITION_EFFECTS, COMPOSITION_EFFECT_IDS, DEFAULT_IDENTITY_LOCK, DEFAULT_TEMPLATES, ERAS, ERA_CATEGORY_LABELS, ERA_CATEGORY_ORDER, ERA_IDS, EXPOSURE_CATEGORY_LABELS, EXPOSURE_CATEGORY_ORDER, EXPOSURE_FIELD_BY_CATEGORY, EXPOSURE_IDS, EXPOSURE_SETTINGS, FACTORY_PRESETS, FACTORY_SNIPPETS, FRAMINGS, FRAMING_CATEGORY_LABELS, FRAMING_CATEGORY_ORDER, FRAMING_FIELD_BY_CATEGORY, FRAMING_IDS, GAPS_SCHEMA, HELD_PROPS, HELD_PROP_CATEGORY_LABELS, HELD_PROP_CATEGORY_ORDER, HELD_PROP_IDS, IMAGE_WIZARD_CATEGORIES, INSTRUMENTATION_DEFAULT_DATA, INSTRUMENTS, INSTRUMENT_CATEGORY_LABELS, INSTRUMENT_CATEGORY_ORDER, LENSES, LENS_IDS, LIGHTINGS, LIGHTING_CATEGORY_LABELS, LIGHTING_CATEGORY_ORDER, LIGHTING_FIELD_BY_CATEGORY, LIGHTING_IDS, LLM_CHAT_WIZARD_CATEGORIES, LOOP_SUBJECTS, LOOP_SUBJECT_CATEGORY_LABELS, LOOP_SUBJECT_CATEGORY_ORDER, MATERIALS, MATERIAL_CATEGORY_LABELS, MATERIAL_CATEGORY_ORDER, MATERIAL_IDS, MAX_SELECTED_BY_DIMENSION, MAX_SELECTED_BY_FRAMING_CATEGORY, MAX_SELECTED_BY_STYLING_DIMENSION, MOODS, MOOD_CATEGORY_LABELS, MOOD_CATEGORY_ORDER, MOOD_IDS, MOVEMENT_LABELS, MUSIC_EMOTIONS, MUSIC_ENERGIES, MUSIC_ERAS, MUSIC_GENRES, MUSIC_GENRE_CATEGORY_LABELS, MUSIC_GENRE_CATEGORY_ORDER, MUSIC_GENRE_DEFAULT_DATA, MUSIC_MOOD_DEFAULT_DATA, MUSIC_VIBES, MUSIC_WIZARD_CATEGORIES, NODE_PROMPT_CANDIDATE_FIELDS, OBJECT_ANGLE_PRESETS, OBJECT_ANGLE_PROMPTS, OBJECT_ASSET_PRESETS, OBJECT_ASSET_PROMPTS, OBJECT_MATERIAL_PRESETS, OBJECT_MATERIAL_PROMPTS, OBJECT_VARIATION_PRESETS, OBJECT_VARIATION_PROMPTS, PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, PERSON_DIMENSION_SECTIONS, PERSON_FIELD_BY_DIMENSION, PERSON_IDS, PHOTOGRAPHERS, PHOTOGRAPHER_CATEGORY_LABELS, PHOTOGRAPHER_CATEGORY_ORDER, PHOTOGRAPHER_IDS, PHOTO_GENRES, PHOTO_GENRE_CATEGORY_LABELS, PHOTO_GENRE_CATEGORY_ORDER, PHOTO_GENRE_IDS, PICKER_ANALYZER_REGISTRY, PICKER_CATALOGS, PICKER_TYPES, POSES, POSE_CATEGORY_LABELS, POSE_CATEGORY_ORDER, POSE_IDS, POST_PROCESS_EFFECTS, POST_PROCESS_EFFECT_IDS, PRODUCTION_STYLES, PROVIDER_CAPABILITIES, PROVIDER_PROMPT_DOCTRINES, REFERENCE_IMAGE_ROLES, REF_BINDING, RENDER_QUALITIES, RENDER_QUALITY_IDS, SCENE_PROMPT_MAX_LENGTH, SETTINGS, SETTING_CATEGORY_LABELS, SETTING_IDS, SHOT_LABELS, SINGING_STYLES, SNIPPET_MEDIA_VALUES, STYLES, STYLE_IDS, STYLE_PRESETS, STYLINGS, STYLING_DIMENSION_LABELS, STYLING_DIMENSION_ORDER, STYLING_FIELD_BY_DIMENSION, STYLING_IDS, TEMPORALS, TEMPORAL_CATEGORY_LABELS, TEMPORAL_CATEGORY_ORDER, TEMPORAL_FIELD_BY_CATEGORY, TEMPORAL_IDS, TEXT_WIZARD_CATEGORIES, TRANSITIONS, TRANSITION_CATEGORY_LABELS, TRANSITION_CATEGORY_ORDER, TRANSITION_IDS, VIDEO_WIZARD_CATEGORIES, VOCAL_PRESENCE, VOCAL_PRESENCE_INSTRUMENTAL_ID, VOICE_ACCENTS, VOICE_AGES, VOICE_ARCHETYPES, VOICE_CHARACTER_DEFAULT_DATA, VOICE_DELIVERY_DEFAULT_DATA, VOICE_EMOTIONS, VOICE_GENDERS, VOICE_LANGUAGES, VOICE_PACES, VOICE_TIMBRES, WARDROBE, WARDROBE_CATEGORY_LABELS, WARDROBE_DIMENSION_ORDER, WARDROBE_FIELD_BY_DIMENSION, appendField, appendMusicMeta, applyPickerJson, applyReferenceOrderToVideo, applyTemplate, assembleImageInput, assembleSunoInput, buildActionFxHints, buildAestheticHints, buildAgeHint, buildAtmosphereHints, buildCharacterPrompt, buildCreaturePrompt, buildExposureHints, buildFaceTemplateInputs, buildFramingHints, buildHeldPropHints, buildIdentityDirectives, buildIdentityLockLine, buildImagePrompt, buildImagePromptSegments, buildInstrumentationHints, buildLightingHints, buildLocationMotionPrompt, buildLocationPrompt, buildLocationRefinePrompt, buildMaterialHints, buildMoodHints, buildMotionPrompt, buildMultiPickerAnalyzerSpec, buildMusicGenreHints, buildMusicMoodHints, buildObjectMotionPrompt, buildObjectPrompt, buildPersonHints, buildPhotographerHints, buildPickerAnalyzerSpec, buildPickerLegend, buildPickerZodSchema, buildPoseHints, buildPostProcessHints, buildReferenceBlocks, buildScenePrompt, buildStylingHints, buildTemporalHints, buildVoiceCharacterHints, buildVoiceDeliveryHints, buildWardrobeHints, characterLockToRefLock, collectIdentityLockClause, composeCameraMotionHintFromConnections, composeCharacterFxHintFromConnections, composeNegative, composeSoundHintFromConnections, composeTransitionHintFromConnections, computeLlmChatFields, computeNodePrompt, expandImagePositionRefs, expandImageRefTokens, getActionFx, getActionFxLabel, getActionFxPromptHint, getAesthetic, getAestheticLabel, getAestheticPromptHint, getAtmosphere, getAtmosphereLabel, getAtmospherePromptHint, getBackdrop, getBackdropLabel, getBackdropPromptHint, getCameraFormat, getCameraFormatLabel, getCameraFormatPromptHint, getCameraMotion, getCameraMotionLabel, getCameraMotionPromptHint, getCategoriesForNodeType, getCharacterFx, getCharacterFxLabel, getCharacterFxPromptHint, getColorLook, getColorLookLabel, getColorLookPromptHint, getCompositionEffect, getCompositionEffectLabel, getCompositionEffectPromptHint, getEffectiveSunoCustomMode, getEra, getEraLabel, getEraPromptHint, getExposure, getExposureLabel, getExposurePromptHint, getFactoryPresets, getFactorySnippets, getFraming, getFramingCategoryLimit, getFramingLabel, getFramingPromptHint, getHeldProp, getHeldPropLabel, getHeldPropPromptHint, getIdentityLockClause, getInstrument, getLens, getLensLabel, getLensPromptHint, getLighting, getLightingLabel, getLightingPromptHint, getLoopSubject, getLoopSubjectLabel, getLoopSubjectPromptHint, getMaterial, getMaterialLabel, getMaterialPromptHint, getMood, getMoodLabel, getMoodPromptHint, getMusicEmotion, getMusicEnergy, getMusicEra, getMusicGenre, getMusicGenreLabel, getMusicSubgenre, getMusicVibe, getParameterPromptHint, getPerson, getPersonDimensionLimit, getPersonLabel, getPersonPromptHint, getPhotoGenre, getPhotoGenreLabel, getPhotoGenrePromptHint, getPhotographer, getPhotographerLabel, getPhotographerPromptHint, getPickerAnalyzer, getPickerCatalog, getPose, getPoseLabel, getPosePromptHint, getPostProcessEffect, getPostProcessEffectLabel, getPostProcessEffectPromptHint, getProductionStyle, getPromptDoctrine, getPromptTips, getRenderQuality, getRenderQualityLabel, getRenderQualityPromptHint, getSetting, getSettingLabel, getSettingPromptHint, getSingingStyle, getStyle, getStyleLabel, getStylePreset, getStylePromptHint, getStyling, getStylingDimensionLimit, getStylingLabel, getStylingPromptHint, getTemporal, getTemporalLabel, getTemporalPromptHint, getTransition, getTransitionLabel, getTransitionPromptHint, getVocalPresence, getVoiceAccent, getVoiceAge, getVoiceArchetype, getVoiceEmotion, getVoiceGender, getVoiceLanguage, getVoicePace, getVoiceTimbre, getWardrobeEntriesByDimension, getWardrobeEntry, getWardrobePromptHint, groupFactoryPresets, hasUpstreamCharacter, isAnalyzablePicker, isInstrumentalVocal, isVantageFraming, isWizardSupported, listPickerCatalogs, migratePersonValue, pickerFanoutTargets, projectPickerCatalog, promptBindsFirstFrame, renderStructuredFields, resolveBrandInput, resolveCharacterMentions, resolveLocationMentions, resolvePrompt, resolveReferenceTokens, resolveSeedance2Inputs, resolveTemplate, resolveVideoReferenceCore, summarizePickerCatalogs, toIdentityLockMode, truncateForField, truncateText, withForcedIdentityLock };
32076
+ export { ACTION_FX, ACTION_FX_CATEGORY_LABELS, ACTION_FX_CATEGORY_ORDER, ACTION_FX_IDS, AESTHETICS, AESTHETIC_CATEGORY_LABELS, AESTHETIC_CATEGORY_ORDER, AESTHETIC_IDS, ALL_PICKER_WIRING, ANALYZABLE_PICKER_TYPES, ANGLE_LABELS, ASPECT_RATIO_LABELS, ATMOSPHERES, ATMOSPHERE_IDS, AUDIO_WIZARD_CATEGORIES, BACKDROPS, BACKDROP_CATEGORY_LABELS, BACKDROP_CATEGORY_ORDER, BACKDROP_IDS, BRAND_PRESETS, BRAND_PRESET_IDS, BRAND_PRESET_META, CAMERA_FORMATS, CAMERA_FORMAT_IDS, CAMERA_MOTIONS, CAMERA_MOTION_CATEGORY_LABELS, CAMERA_MOTION_CATEGORY_ORDER, CAMERA_MOTION_IDS, CHARACTER_FX, CHARACTER_FX_CATEGORY_LABELS, CHARACTER_FX_CATEGORY_ORDER, CHARACTER_FX_IDS, CINEMATIC_LOOK_TAIL, COLOR_LOOKS, COLOR_LOOK_CATEGORY_LABELS, COLOR_LOOK_CATEGORY_ORDER, COLOR_LOOK_IDS, COMPOSITION_EFFECTS, COMPOSITION_EFFECT_IDS, DEFAULT_IDENTITY_LOCK, DEFAULT_TEMPLATES, ERAS, ERA_CATEGORY_LABELS, ERA_CATEGORY_ORDER, ERA_IDS, EXPOSURE_CATEGORY_LABELS, EXPOSURE_CATEGORY_ORDER, EXPOSURE_FIELD_BY_CATEGORY, EXPOSURE_IDS, EXPOSURE_SETTINGS, FACTORY_PRESETS, FACTORY_SNIPPETS, FILM_STILL_PREFIX, FRAMINGS, FRAMING_CATEGORY_LABELS, FRAMING_CATEGORY_ORDER, FRAMING_FIELD_BY_CATEGORY, FRAMING_IDS, GAPS_SCHEMA, HELD_PROPS, HELD_PROP_CATEGORY_LABELS, HELD_PROP_CATEGORY_ORDER, HELD_PROP_IDS, IMAGE_WIZARD_CATEGORIES, INSTRUMENTATION_DEFAULT_DATA, INSTRUMENTS, INSTRUMENT_CATEGORY_LABELS, INSTRUMENT_CATEGORY_ORDER, LENSES, LENS_IDS, LIGHTINGS, LIGHTING_CATEGORY_LABELS, LIGHTING_CATEGORY_ORDER, LIGHTING_FIELD_BY_CATEGORY, LIGHTING_IDS, LLM_CHAT_WIZARD_CATEGORIES, LOOP_SUBJECTS, LOOP_SUBJECT_CATEGORY_LABELS, LOOP_SUBJECT_CATEGORY_ORDER, MATERIALS, MATERIAL_CATEGORY_LABELS, MATERIAL_CATEGORY_ORDER, MATERIAL_IDS, MAX_SELECTED_BY_DIMENSION, MAX_SELECTED_BY_FRAMING_CATEGORY, MAX_SELECTED_BY_STYLING_DIMENSION, MOODS, MOOD_CATEGORY_LABELS, MOOD_CATEGORY_ORDER, MOOD_IDS, MOVEMENT_LABELS, MULTI_PICKER_WIRING, MUSIC_EMOTIONS, MUSIC_ENERGIES, MUSIC_ERAS, MUSIC_GENRES, MUSIC_GENRE_CATEGORY_LABELS, MUSIC_GENRE_CATEGORY_ORDER, MUSIC_GENRE_DEFAULT_DATA, MUSIC_MOOD_DEFAULT_DATA, MUSIC_VIBES, MUSIC_WIZARD_CATEGORIES, NODE_PROMPT_CANDIDATE_FIELDS, OBJECT_ANGLE_PRESETS, OBJECT_ANGLE_PROMPTS, OBJECT_ASSET_PRESETS, OBJECT_ASSET_PROMPTS, OBJECT_MATERIAL_PRESETS, OBJECT_MATERIAL_PROMPTS, OBJECT_VARIATION_PRESETS, OBJECT_VARIATION_PROMPTS, PEOPLE, PERSON_DIMENSION_LABELS, PERSON_DIMENSION_ORDER, PERSON_DIMENSION_SECTIONS, PERSON_FIELD_BY_DIMENSION, PERSON_IDS, PHOTOGRAPHERS, PHOTOGRAPHER_CATEGORY_LABELS, PHOTOGRAPHER_CATEGORY_ORDER, PHOTOGRAPHER_IDS, PHOTO_GENRES, PHOTO_GENRE_CATEGORY_LABELS, PHOTO_GENRE_CATEGORY_ORDER, PHOTO_GENRE_IDS, PICKER_ANALYZER_FAMILIES, PICKER_ANALYZER_REGISTRY, PICKER_CATALOGS, PICKER_TYPES, POSES, POSE_CATEGORY_LABELS, POSE_CATEGORY_ORDER, POSE_IDS, POST_PROCESS_EFFECTS, POST_PROCESS_EFFECT_IDS, PRODUCTION_STYLES, PROVIDER_CAPABILITIES, PROVIDER_PROMPT_DOCTRINES, REFERENCE_IMAGE_ROLES, REFERENCE_RULES, REFERENCE_RULES_MULTI_PERSON, REF_BINDING, RENDER_QUALITIES, RENDER_QUALITY_IDS, SCENE_FRAME_RULE, SCENE_PROMPT_MAX_LENGTH, SETTINGS, SETTING_CATEGORY_LABELS, SETTING_IDS, SHOT_LABELS, SINGING_STYLES, SINGLE_PICKER_WIRING, SNIPPET_MEDIA_VALUES, STYLES, STYLE_IDS, STYLE_PRESETS, STYLINGS, STYLING_DIMENSION_LABELS, STYLING_DIMENSION_ORDER, STYLING_FIELD_BY_DIMENSION, STYLING_IDS, TEMPORALS, TEMPORAL_CATEGORY_LABELS, TEMPORAL_CATEGORY_ORDER, TEMPORAL_FIELD_BY_CATEGORY, TEMPORAL_IDS, TEXT_WIZARD_CATEGORIES, TRANSITIONS, TRANSITION_CATEGORY_LABELS, TRANSITION_CATEGORY_ORDER, TRANSITION_IDS, VIDEO_WIZARD_CATEGORIES, VOCAL_PRESENCE, VOCAL_PRESENCE_INSTRUMENTAL_ID, VOICE_ACCENTS, VOICE_AGES, VOICE_ARCHETYPES, VOICE_CHARACTER_DEFAULT_DATA, VOICE_DELIVERY_DEFAULT_DATA, VOICE_EMOTIONS, VOICE_GENDERS, VOICE_LANGUAGES, VOICE_PACES, VOICE_TIMBRES, WARDROBE, WARDROBE_CATEGORY_LABELS, WARDROBE_DIMENSION_ORDER, WARDROBE_FIELD_BY_DIMENSION, appendField, appendMusicMeta, applyPickerJson, applyReferenceOrderToVideo, applyTemplate, assembleImageInput, assembleSunoInput, buildActionFxHints, buildAestheticHints, buildAgeHint, buildAtmosphereHints, buildCharacterPrompt, buildCreaturePrompt, buildExposureHints, buildFaceTemplateInputs, buildFramingHints, buildHeldPropHints, buildIdentityDirectives, buildIdentityLockLine, buildImagePrompt, buildImagePromptSegments, buildInstrumentationHints, buildLightingHints, buildLocationMotionPrompt, buildLocationPrompt, buildLocationRefinePrompt, buildMaterialHints, buildMoodHints, buildMotionPrompt, buildMultiPickerAnalyzerSpec, buildMusicGenreHints, buildMusicMoodHints, buildObjectMotionPrompt, buildObjectPrompt, buildPersonHints, buildPhotographerHints, buildPickerAnalyzerSpec, buildPickerLegend, buildPickerZodSchema, buildPoseHints, buildPostProcessHints, buildReferenceBlocks, buildScenePrompt, buildStylingHints, buildTemporalHints, buildVoiceCharacterHints, buildVoiceDeliveryHints, buildWardrobeHints, characterLockToRefLock, collectIdentityLockClause, composeCameraMotionHintFromConnections, composeCharacterFxHintFromConnections, composeNegative, composeSoundHintFromConnections, composeTransitionHintFromConnections, computeLlmChatFields, computeNodePrompt, expandImagePositionRefs, expandImageRefTokens, filmStillPrefix, getActionFx, getActionFxLabel, getActionFxPromptHint, getAesthetic, getAestheticLabel, getAestheticPromptHint, getAtmosphere, getAtmosphereLabel, getAtmospherePromptHint, getBackdrop, getBackdropLabel, getBackdropPromptHint, getCameraFormat, getCameraFormatLabel, getCameraFormatPromptHint, getCameraMotion, getCameraMotionLabel, getCameraMotionPromptHint, getCategoriesForNodeType, getCharacterFx, getCharacterFxLabel, getCharacterFxPromptHint, getColorLook, getColorLookLabel, getColorLookPromptHint, getCompositionEffect, getCompositionEffectLabel, getCompositionEffectPromptHint, getEffectiveSunoCustomMode, getEra, getEraLabel, getEraPromptHint, getExposure, getExposureLabel, getExposurePromptHint, getFactoryPresets, getFactorySnippets, getFraming, getFramingCategoryLimit, getFramingLabel, getFramingPromptHint, getHeldProp, getHeldPropLabel, getHeldPropPromptHint, getIdentityLockClause, getInstrument, getLens, getLensLabel, getLensPromptHint, getLighting, getLightingLabel, getLightingPromptHint, getLoopSubject, getLoopSubjectLabel, getLoopSubjectPromptHint, getMaterial, getMaterialLabel, getMaterialPromptHint, getMood, getMoodLabel, getMoodPromptHint, getMusicEmotion, getMusicEnergy, getMusicEra, getMusicGenre, getMusicGenreLabel, getMusicSubgenre, getMusicVibe, getParameterPromptHint, getPerson, getPersonDimensionLimit, getPersonLabel, getPersonPromptHint, getPhotoGenre, getPhotoGenreLabel, getPhotoGenrePromptHint, getPhotographer, getPhotographerLabel, getPhotographerPromptHint, getPickerAnalyzer, getPickerCatalog, getPickerWiring, getPose, getPoseLabel, getPosePromptHint, getPostProcessEffect, getPostProcessEffectLabel, getPostProcessEffectPromptHint, getProductionStyle, getPromptDoctrine, getPromptTips, getRenderQuality, getRenderQualityLabel, getRenderQualityPromptHint, getSetting, getSettingLabel, getSettingPromptHint, getSingingStyle, getStyle, getStyleLabel, getStylePreset, getStylePromptHint, getStyling, getStylingDimensionLimit, getStylingLabel, getStylingPromptHint, getTemporal, getTemporalLabel, getTemporalPromptHint, getTransition, getTransitionLabel, getTransitionPromptHint, getVocalPresence, getVoiceAccent, getVoiceAge, getVoiceArchetype, getVoiceEmotion, getVoiceGender, getVoiceLanguage, getVoicePace, getVoiceTimbre, getWardrobeEntriesByDimension, getWardrobeEntry, getWardrobePromptHint, groupFactoryPresets, hasUpstreamCharacter, isAnalyzablePicker, isInstrumentalVocal, isVantageFraming, isWizardSupported, listPickerCatalogs, migratePersonValue, pickerFanoutTargets, projectPickerCatalog, promptBindsFirstFrame, referenceRulesBlock, renderStructuredFields, resolveBrandInput, resolveCharacterMentions, resolveLocationMentions, resolvePrompt, resolveReferenceTokens, resolveSeedance2Inputs, resolveTemplate, resolveVideoReferenceCore, summarizePickerCatalogs, toIdentityLockMode, truncateForField, truncateText, withForcedIdentityLock };
31430
32077
  //# sourceMappingURL=index.js.map
31431
32078
  //# sourceMappingURL=index.js.map