@nodaro/prompts 1.10.0 → 1.12.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.
Files changed (35) hide show
  1. package/dist/index.cjs +693 -53
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +1084 -27
  4. package/dist/index.d.ts +1084 -27
  5. package/dist/index.js +664 -55
  6. package/dist/index.js.map +1 -1
  7. package/package.json +2 -2
  8. package/src/__tests__/__snapshots__/entity-convergence-image.test.ts.snap +19 -0
  9. package/src/__tests__/animal-getters-parity.test.ts +82 -0
  10. package/src/__tests__/assemble-image-input-cap.test.ts +212 -0
  11. package/src/__tests__/assemble-image-input.test.ts +93 -3
  12. package/src/__tests__/assemble-video-input-cap.test.ts +356 -0
  13. package/src/__tests__/assemble-video-input.test.ts +301 -0
  14. package/src/__tests__/direction-hint-token-safety.test.ts +113 -0
  15. package/src/__tests__/direction-registry.test.ts +393 -0
  16. package/src/__tests__/entity-convergence-image.test.ts +374 -0
  17. package/src/__tests__/image-convergence-image.test.ts +370 -0
  18. package/src/__tests__/location-convergence-image.test.ts +29 -1
  19. package/src/__tests__/location-default-role-image.test.ts +166 -0
  20. package/src/__tests__/mention-splice-spacing.test.ts +257 -0
  21. package/src/__tests__/read-node-direction.test.ts +154 -0
  22. package/src/__tests__/read-node-subject.test.ts +140 -0
  23. package/src/__tests__/subject-fold.test.ts +232 -0
  24. package/src/__tests__/subject-registry.test.ts +312 -0
  25. package/src/assemble-image-input.ts +160 -58
  26. package/src/assemble-video-input.ts +244 -0
  27. package/src/direction-registry.ts +371 -0
  28. package/src/hint-shedding.ts +68 -0
  29. package/src/index.ts +10 -2
  30. package/src/parameter-prompt-hint.ts +8 -7
  31. package/src/picker-catalogs.ts +14 -7
  32. package/src/prompt-builder.ts +728 -58
  33. package/src/prompt-hint-join.ts +30 -0
  34. package/src/read-node-direction.ts +233 -0
  35. package/src/subject-registry.ts +464 -0
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, VIDEO_REF_LIMITS_BY_PROVIDER, SOCIAL_POST_NODE_TYPES, FURNITURE, WEAPONS, VEHICLES, ANIMALS, PASSTHROUGH_TYPES, registerCatalogSidecars, resetCatalogSidecars, 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, NON_EN_LOCALE_IDS, readPromptAffixes, setRegisteredPersonPackFields, 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, VIDEO_REF_LIMITS_BY_PROVIDER, SOCIAL_POST_NODE_TYPES, FURNITURE, WEAPONS, VEHICLES, ANIMALS, PASSTHROUGH_TYPES, registerCatalogSidecars, resetCatalogSidecars, pickIds, getAnimalPromptHint, getFurniture, getWeapon, getVehicle, DEFAULT_USAGE_MODE, usageModeDirective, DEFAULT_LOCATION_USAGE_MODE, imageReferenceLimit, knownImageSlugsFromRefs, findImageMentionTokens, knownEntitySlugsFromRefs, findEntityMentionTokens, findCharacterMentionTokens, findLocationMentionTokens, NATIVE_NEGATIVE_PROMPT_MODELS, getMaxNegativePromptChars, getMaxImagePromptChars, MODELS_WITH_REFERENCE_IMAGE_SUPPORT, getAnimalTerm, roleToPhrase, resolveDefaultRole, SEEDANCE_2_REF_LIMITS, NON_EN_LOCALE_IDS, readPromptAffixes, setRegisteredPersonPackFields, PLACEHOLDER_CHARACTER_NAME, REFERENCE_ROLE_PRESETS, imageMentionSlugForRef, entityMentionSlugForRef, defaultRoleForSource, locationReferencePhotoKindLabel, resolveNodeRefs, normalizeRoleSlug } from '@nodaro/shared';
2
2
 
3
3
  var __defProp = Object.defineProperty;
4
4
  var __export = (target, all) => {
@@ -9239,7 +9239,7 @@ function objectOptions(arr, phrase) {
9239
9239
  label: e.label,
9240
9240
  description: e.description,
9241
9241
  category: e.subcategory,
9242
- promptHint: phrase(e.label.toLowerCase(), e.description),
9242
+ promptHint: phrase(e),
9243
9243
  // Object entities have no `promptHint` field of their own (it is
9244
9244
  // synthesized above), so the term cannot come from `resolveTerm`'s
9245
9245
  // empty-hint rule: an authored `term` wins, and otherwise the label IS the
@@ -9571,7 +9571,7 @@ var SINGLE_CATALOGS = [
9571
9571
  defaultValue: "dog-golden-retriever",
9572
9572
  categoryOrder: ANIMAL_SUBCATEGORY_ORDER,
9573
9573
  categoryLabels: ANIMAL_SUBCATEGORY_LABELS,
9574
- options: objectOptions(ANIMALS, (label, description) => `featuring a ${label}, ${description}`)
9574
+ options: objectOptions(ANIMALS, (e) => getAnimalPromptHint(e.id))
9575
9575
  },
9576
9576
  {
9577
9577
  nodeType: "vehicle",
@@ -9582,7 +9582,7 @@ var SINGLE_CATALOGS = [
9582
9582
  defaultValue: "sedan",
9583
9583
  categoryOrder: VEHICLE_SUBCATEGORY_ORDER,
9584
9584
  categoryLabels: VEHICLE_SUBCATEGORY_LABELS,
9585
- options: objectOptions(VEHICLES, (label, description) => `featuring a ${label}, ${description}`)
9585
+ options: objectOptions(VEHICLES, (e) => `featuring a ${e.label.toLowerCase()}, ${e.description}`)
9586
9586
  },
9587
9587
  {
9588
9588
  nodeType: "weapon",
@@ -9593,7 +9593,7 @@ var SINGLE_CATALOGS = [
9593
9593
  defaultValue: "katana",
9594
9594
  categoryOrder: WEAPON_SUBCATEGORY_ORDER,
9595
9595
  categoryLabels: WEAPON_SUBCATEGORY_LABELS,
9596
- options: objectOptions(WEAPONS, (label, description) => `with a ${label}, ${description}`)
9596
+ options: objectOptions(WEAPONS, (e) => `with a ${e.label.toLowerCase()}, ${e.description}`)
9597
9597
  },
9598
9598
  {
9599
9599
  nodeType: "furniture",
@@ -9604,7 +9604,7 @@ var SINGLE_CATALOGS = [
9604
9604
  defaultValue: "sofa",
9605
9605
  categoryOrder: FURNITURE_SUBCATEGORY_ORDER,
9606
9606
  categoryLabels: FURNITURE_SUBCATEGORY_LABELS,
9607
- options: objectOptions(FURNITURE, (label, description) => `including a ${label}, ${description}`)
9607
+ options: objectOptions(FURNITURE, (e) => `including a ${e.label.toLowerCase()}, ${e.description}`)
9608
9608
  },
9609
9609
  {
9610
9610
  nodeType: "held-prop",
@@ -9972,13 +9972,16 @@ function resolveBaseHint(type, data, mode = "full") {
9972
9972
  return withCustomText(data, byMode(mode, getLoopSubjectPromptHint, getLoopSubjectTerm)(asStr(data.loopSubject)));
9973
9973
  case "material":
9974
9974
  return withCustomText(data, buildMaterialHints(data.material, mode));
9975
- case "animal": {
9976
- const animal = getAnimal(asStr(data.animal));
9975
+ // Animal is the one Object-entity catalog whose phrasing has a single
9976
+ // owner: `@nodaro/shared`'s `getAnimalPromptHint` / `getAnimalTerm`, which
9977
+ // the picker-catalog funnel calls too. Both getters already return "" on a
9978
+ // miss, so the entry lookup and the `animal ? … : ""` guard are the
9979
+ // getters' job now, not this switch's.
9980
+ case "animal":
9977
9981
  return withCustomText(
9978
9982
  data,
9979
- animal ? byMode(mode, `featuring a ${animal.label.toLowerCase()}, ${animal.description}`, objectEntityTerm(animal)) : ""
9983
+ byMode(mode, getAnimalPromptHint, getAnimalTerm)(asStr(data.animal))
9980
9984
  );
9981
- }
9982
9985
  case "vehicle": {
9983
9986
  const vehicle = getVehicle(asStr(data.vehicle));
9984
9987
  return withCustomText(
@@ -10282,6 +10285,11 @@ ${resolvedPrompt}`;
10282
10285
  }
10283
10286
  return { prompt: resolvedPrompt, additionalUrls, mentionedCharacterSlugs };
10284
10287
  }
10288
+ function spliceMentionPhrase(prompt, offset, tokenLength, phrase) {
10289
+ const before = prompt.slice(0, offset).replace(/(?<=\S)[^\S\r\n]{2,}$/, " ");
10290
+ const after = prompt.slice(offset + tokenLength).replace(/^[^\S\r\n]{2,}/, " ");
10291
+ return before + phrase + after;
10292
+ }
10285
10293
  function resolveCharacterMentionsHybrid(prompt, tokens, refs, existingUrls) {
10286
10294
  const bySlug = /* @__PURE__ */ new Map();
10287
10295
  const byVariant = /* @__PURE__ */ new Map();
@@ -10320,7 +10328,7 @@ function resolveCharacterMentionsHybrid(prompt, tokens, refs, existingUrls) {
10320
10328
  let resolvedPrompt = prompt;
10321
10329
  for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
10322
10330
  const phrase = roleToPhrase(m.role, bindingFor(m.url));
10323
- resolvedPrompt = resolvedPrompt.slice(0, m.offset) + phrase + resolvedPrompt.slice(m.offset + m.token.length);
10331
+ resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
10324
10332
  }
10325
10333
  const lockLines = [];
10326
10334
  const elementDirectives = [];
@@ -10351,16 +10359,21 @@ function locationModeDirective(mode) {
10351
10359
  }
10352
10360
  }
10353
10361
  function locationModeToRole(mode) {
10354
- switch (mode) {
10355
- case "identical":
10356
- return "background";
10357
- case "style":
10358
- return "style";
10359
- case "layout":
10360
- return "layout";
10361
- default:
10362
- return defaultRoleForSource("wired-location");
10363
- }
10362
+ return roleBearingLocationMode(mode) ?? defaultRoleForSource("wired-location");
10363
+ }
10364
+ function roleBearingLocationMode(mode) {
10365
+ const m = mode?.trim();
10366
+ if (!m) return null;
10367
+ return REFERENCE_ROLE_PRESETS["wired-location"].includes(m) ? m : null;
10368
+ }
10369
+ function resolveLocationRole(tokenRole, tokenUsageMode, ref) {
10370
+ const explicitRole = tokenRole?.trim();
10371
+ if (explicitRole) return normalizeRoleSlug(explicitRole);
10372
+ const modeRole = roleBearingLocationMode(tokenUsageMode);
10373
+ if (modeRole) return modeRole;
10374
+ const nodeRole = ref.defaultRole?.trim();
10375
+ if (nodeRole) return normalizeRoleSlug(nodeRole);
10376
+ return locationModeToRole(ref.defaultUsageMode ?? DEFAULT_LOCATION_USAGE_MODE);
10364
10377
  }
10365
10378
  function resolveLocationMentions(prompt, tokens, refs) {
10366
10379
  const bySlug = /* @__PURE__ */ new Map();
@@ -10442,8 +10455,7 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
10442
10455
  mentionedLocationSlugs.add(t.locationSlug);
10443
10456
  refByUrl.set(match.url, match);
10444
10457
  if (t.lock !== void 0) lockOverrideByUrl.set(match.url, t.lock);
10445
- const mode = t.usageMode ?? match.defaultUsageMode ?? DEFAULT_LOCATION_USAGE_MODE;
10446
- const role = t.role ? normalizeRoleSlug(t.role) : locationModeToRole(mode);
10458
+ const role = resolveLocationRole(t.role, t.usageMode, match);
10447
10459
  matched.push({ token: t.token, offset: t.offset, url: match.url, role });
10448
10460
  }
10449
10461
  const slotByUrl = /* @__PURE__ */ new Map();
@@ -10457,7 +10469,7 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
10457
10469
  let resolvedPrompt = prompt;
10458
10470
  for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
10459
10471
  const phrase = roleToPhrase(m.role, bindingFor(m.url));
10460
- resolvedPrompt = resolvedPrompt.slice(0, m.offset) + phrase + resolvedPrompt.slice(m.offset + m.token.length);
10472
+ resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
10461
10473
  }
10462
10474
  const lockLines = [];
10463
10475
  const elementDirectives = [];
@@ -10475,6 +10487,109 @@ function resolveLocationMentionsHybrid(prompt, tokens, refs, existingUrls) {
10475
10487
  }
10476
10488
  return { prompt: resolvedPrompt, additionalUrls, mentionedLocationSlugs, lockLines, elementDirectives };
10477
10489
  }
10490
+ function resolveImageMentionsHybrid(prompt, tokens, refs, existingUrls) {
10491
+ const bySlug = /* @__PURE__ */ new Map();
10492
+ for (const r of refs) {
10493
+ const slug = imageMentionSlugForRef(r);
10494
+ if (!slug) continue;
10495
+ if (!bySlug.has(slug)) bySlug.set(slug, r);
10496
+ }
10497
+ const additionalUrls = [];
10498
+ const refByUrl = /* @__PURE__ */ new Map();
10499
+ const lockOverrideByUrl = /* @__PURE__ */ new Map();
10500
+ const matched = [];
10501
+ for (const t of tokens) {
10502
+ const match = bySlug.get(t.imageSlug);
10503
+ if (!match || !match.url) continue;
10504
+ additionalUrls.push(match.url);
10505
+ refByUrl.set(match.url, match);
10506
+ if (t.lock !== void 0) lockOverrideByUrl.set(match.url, t.lock);
10507
+ const role = (t.role ?? "").trim() || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source);
10508
+ matched.push({ token: t.token, offset: t.offset, url: match.url, role });
10509
+ }
10510
+ const slotByUrl = /* @__PURE__ */ new Map();
10511
+ for (const u of [...existingUrls, ...additionalUrls]) {
10512
+ if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1);
10513
+ }
10514
+ const bindingFor = (url2) => {
10515
+ const slot = slotByUrl.get(url2);
10516
+ return slot ? `reference image ${slotToLetter(slot)}` : "the reference image";
10517
+ };
10518
+ let resolvedPrompt = prompt;
10519
+ for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
10520
+ const phrase = roleToPhrase(m.role, bindingFor(m.url));
10521
+ resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
10522
+ }
10523
+ const lockLines = [];
10524
+ const elementDirectives = [];
10525
+ const seenUrls = /* @__PURE__ */ new Set();
10526
+ for (const m of matched) {
10527
+ if (seenUrls.has(m.url)) continue;
10528
+ seenUrls.add(m.url);
10529
+ const ref = refByUrl.get(m.url);
10530
+ if (!ref) continue;
10531
+ const binding = bindingFor(m.url);
10532
+ const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
10533
+ if (lock) lockLines.push(lock);
10534
+ const inject = ref.elementInjection?.trim();
10535
+ if (inject) elementDirectives.push(inject);
10536
+ }
10537
+ return { prompt: resolvedPrompt, additionalUrls, lockLines, elementDirectives };
10538
+ }
10539
+ function resolveEntityMentionsHybrid(prompt, tokens, refs, existingUrls) {
10540
+ const bySlug = /* @__PURE__ */ new Map();
10541
+ for (const source of ["wired-creature", "wired-object"]) {
10542
+ for (const r of refs) {
10543
+ if (r.source !== source) continue;
10544
+ const slug = entityMentionSlugForRef(r);
10545
+ if (!slug) continue;
10546
+ if (!bySlug.has(slug)) bySlug.set(slug, r);
10547
+ }
10548
+ }
10549
+ const additionalUrls = [];
10550
+ const mentionedUrls = /* @__PURE__ */ new Set();
10551
+ const refByUrl = /* @__PURE__ */ new Map();
10552
+ const lockOverrideByUrl = /* @__PURE__ */ new Map();
10553
+ const matched = [];
10554
+ for (const t of tokens) {
10555
+ const match = bySlug.get(t.entitySlug);
10556
+ if (!match || !match.url) continue;
10557
+ additionalUrls.push(match.url);
10558
+ mentionedUrls.add(match.url);
10559
+ refByUrl.set(match.url, match);
10560
+ if (t.lock !== void 0) lockOverrideByUrl.set(match.url, t.lock);
10561
+ const role = (t.role ?? "").trim() || resolveDefaultRole(match.defaultRole, match.defaultUsageMode, match.source);
10562
+ matched.push({ token: t.token, offset: t.offset, url: match.url, role });
10563
+ }
10564
+ const slotByUrl = /* @__PURE__ */ new Map();
10565
+ for (const u of [...existingUrls, ...additionalUrls]) {
10566
+ if (!slotByUrl.has(u)) slotByUrl.set(u, slotByUrl.size + 1);
10567
+ }
10568
+ const bindingFor = (url2) => {
10569
+ const slot = slotByUrl.get(url2);
10570
+ return slot ? `reference image ${slotToLetter(slot)}` : "the reference image";
10571
+ };
10572
+ let resolvedPrompt = prompt;
10573
+ for (const m of [...matched].sort((a, b) => b.offset - a.offset)) {
10574
+ const phrase = roleToPhrase(m.role, bindingFor(m.url));
10575
+ resolvedPrompt = spliceMentionPhrase(resolvedPrompt, m.offset, m.token.length, phrase);
10576
+ }
10577
+ const lockLines = [];
10578
+ const elementDirectives = [];
10579
+ const seenUrls = /* @__PURE__ */ new Set();
10580
+ for (const m of matched) {
10581
+ if (seenUrls.has(m.url)) continue;
10582
+ seenUrls.add(m.url);
10583
+ const ref = refByUrl.get(m.url);
10584
+ if (!ref) continue;
10585
+ const binding = bindingFor(m.url);
10586
+ const lock = buildIdentityLockLine(withForcedIdentityLock(ref, lockOverrideByUrl.get(m.url)), binding);
10587
+ if (lock) lockLines.push(lock);
10588
+ const inject = ref.elementInjection?.trim();
10589
+ if (inject) elementDirectives.push(inject);
10590
+ }
10591
+ return { prompt: resolvedPrompt, additionalUrls, mentionedUrls, lockLines, elementDirectives };
10592
+ }
10478
10593
  function buildCanonicalFallback(refs, mentionedSlugs, startIndex) {
10479
10594
  const directiveLines = [];
10480
10595
  const urls = [];
@@ -10633,7 +10748,7 @@ function renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, covere
10633
10748
  if (!slot) continue;
10634
10749
  seenUrls.add(r.url);
10635
10750
  const binding = `reference image ${slotToLetter(slot)}`;
10636
- phrases.push(roleToPhrase(locationModeToRole(r.defaultUsageMode), binding));
10751
+ phrases.push(roleToPhrase(resolveLocationRole(null, null, r), binding));
10637
10752
  const lock = buildIdentityLockLine(r, binding);
10638
10753
  if (lock) lockLines.push(lock);
10639
10754
  const inject = r.elementInjection?.trim();
@@ -10792,6 +10907,20 @@ function reconcileBodySegments(body, bodySegments) {
10792
10907
  function buildImagePrompt(config2) {
10793
10908
  return buildImagePromptInternal(config2);
10794
10909
  }
10910
+ function buildImagePromptWithOverflow(config2) {
10911
+ const marks = newAssemblyMarks();
10912
+ const result = buildImagePromptInternal(config2, marks);
10913
+ return { ...result, overflowChars: marks.overflowChars };
10914
+ }
10915
+ function newAssemblyMarks() {
10916
+ return {
10917
+ directivesPrefix: "",
10918
+ bodyBeforeSuffixes: "",
10919
+ styleSuffix: "",
10920
+ avoidSuffix: "",
10921
+ overflowChars: 0
10922
+ };
10923
+ }
10795
10924
  function buildImagePromptInternal(config2, marks) {
10796
10925
  let {
10797
10926
  provider,
@@ -10813,6 +10942,7 @@ function buildImagePromptInternal(config2, marks) {
10813
10942
  const suppressedCanonicalLocationIds = config2.suppressedCanonicalLocationIds ?? [];
10814
10943
  const isHybrid = config2.referenceFormat === "hybrid";
10815
10944
  let hybridBodyConverged = false;
10945
+ const mentionedEntityUrls = /* @__PURE__ */ new Set();
10816
10946
  if (config2.skipCharacterMentions) {
10817
10947
  config2 = {
10818
10948
  ...config2,
@@ -10857,7 +10987,11 @@ function buildImagePromptInternal(config2, marks) {
10857
10987
  connectedReferences.map((r) => r.locationSlug).filter((s) => typeof s === "string" && s.length > 0)
10858
10988
  )
10859
10989
  );
10860
- if (knownCharacterSlugs.length > 0 || hasExtraRefs || knownLocationSlugs.length > 0) {
10990
+ const knownImageSlugs = knownImageSlugsFromRefs(connectedReferences);
10991
+ const hasImageMentionTokens = isHybrid && knownImageSlugs.length > 0 && findImageMentionTokens(config2.prompt, knownImageSlugs).length > 0;
10992
+ const knownEntitySlugs = knownEntitySlugsFromRefs(connectedReferences);
10993
+ const hasEntityMentionTokens = isHybrid && knownEntitySlugs.length > 0 && findEntityMentionTokens(config2.prompt, knownEntitySlugs).length > 0;
10994
+ if (knownCharacterSlugs.length > 0 || hasExtraRefs || knownLocationSlugs.length > 0 || hasImageMentionTokens || hasEntityMentionTokens) {
10861
10995
  const mentionTokens = knownCharacterSlugs.length > 0 ? findCharacterMentionTokens(config2.prompt, knownCharacterSlugs) : [];
10862
10996
  let hybridLockLines = [];
10863
10997
  let hybridElementDirectives = [];
@@ -10911,6 +11045,43 @@ function buildImagePromptInternal(config2, marks) {
10911
11045
  if (r.locationVariantBucket) return false;
10912
11046
  return !mentionedLocationSlugs.has(r.locationSlug);
10913
11047
  });
11048
+ let hybridImageLockLines = [];
11049
+ let hybridImageElementDirectives = [];
11050
+ if (hasImageMentionTokens) {
11051
+ const imageTokens = findImageMentionTokens(resolved.prompt, knownImageSlugs);
11052
+ if (imageTokens.length > 0) {
11053
+ const hi = resolveImageMentionsHybrid(
11054
+ resolved.prompt,
11055
+ imageTokens,
11056
+ connectedReferences,
11057
+ [...referenceImageUrls || [], ...resolved.additionalUrls]
11058
+ );
11059
+ resolved.prompt = hi.prompt;
11060
+ resolved.additionalUrls = [...resolved.additionalUrls, ...hi.additionalUrls];
11061
+ hybridImageLockLines = hi.lockLines;
11062
+ hybridImageElementDirectives = hi.elementDirectives;
11063
+ if (hi.additionalUrls.length > 0) hybridBodyConverged = true;
11064
+ }
11065
+ }
11066
+ let hybridEntityLockLines = [];
11067
+ let hybridEntityElementDirectives = [];
11068
+ if (hasEntityMentionTokens) {
11069
+ const entityTokens = findEntityMentionTokens(resolved.prompt, knownEntitySlugs);
11070
+ if (entityTokens.length > 0) {
11071
+ const he = resolveEntityMentionsHybrid(
11072
+ resolved.prompt,
11073
+ entityTokens,
11074
+ connectedReferences,
11075
+ [...referenceImageUrls || [], ...resolved.additionalUrls]
11076
+ );
11077
+ resolved.prompt = he.prompt;
11078
+ resolved.additionalUrls = [...resolved.additionalUrls, ...he.additionalUrls];
11079
+ hybridEntityLockLines = he.lockLines;
11080
+ hybridEntityElementDirectives = he.elementDirectives;
11081
+ for (const u of he.mentionedUrls) mentionedEntityUrls.add(u);
11082
+ if (he.additionalUrls.length > 0) hybridBodyConverged = true;
11083
+ }
11084
+ }
10914
11085
  const prefixDedupedLength = [
10915
11086
  ...referenceImageUrls || [],
10916
11087
  ...resolved.additionalUrls
@@ -10991,12 +11162,16 @@ ${promptForNext}`;
10991
11162
  const allLockLines = [.../* @__PURE__ */ new Set([
10992
11163
  ...hybridLockLines,
10993
11164
  ...hybridLocationLockLines,
11165
+ ...hybridImageLockLines,
11166
+ ...hybridEntityLockLines,
10994
11167
  ...canonical.lockLines,
10995
11168
  ...extrasRendered.lockLines
10996
11169
  ])];
10997
11170
  const trailingLines = [
10998
11171
  ...hybridElementDirectives,
10999
11172
  ...hybridLocationElementDirectives,
11173
+ ...hybridImageElementDirectives,
11174
+ ...hybridEntityElementDirectives,
11000
11175
  ...canonical.phrases,
11001
11176
  ...canonical.elementDirectives,
11002
11177
  ...extrasRendered.bodyLines,
@@ -11043,7 +11218,8 @@ ${trailingLines.join("\n")}` : "";
11043
11218
  if (coveredUrl) tokenCoveredUrls.add(coveredUrl);
11044
11219
  }
11045
11220
  const locCanon = renderLocationCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, tokenCoveredUrls);
11046
- const objCanon = renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, tokenCoveredUrls);
11221
+ const objCoveredUrls = mentionedEntityUrls.size > 0 ? /* @__PURE__ */ new Set([...tokenCoveredUrls, ...mentionedEntityUrls]) : tokenCoveredUrls;
11222
+ const objCanon = renderObjectCreatureCanonicalHybrid(nonCharacterRefs, finalIndexByUrl, objCoveredUrls);
11047
11223
  const canonLockLines = [...locCanon.lockLines, ...objCanon.lockLines];
11048
11224
  const canonLockBlock = canonLockLines.length > 0 ? `${canonLockLines.join("\n")}
11049
11225
 
@@ -11102,11 +11278,13 @@ Avoid: ${negPrompt2}`;
11102
11278
  const maxLen2 = getMaxImagePromptChars(provider);
11103
11279
  const reserved2 = styleSuffix2.length + avoidSuffix2.length;
11104
11280
  if (prompt2.length + reserved2 > maxLen2) {
11281
+ if (marks) marks.overflowChars += prompt2.length + reserved2 - maxLen2;
11105
11282
  prompt2 = prompt2.slice(0, Math.max(0, maxLen2 - reserved2 - 3)) + "...";
11106
11283
  }
11107
11284
  if (marks) marks.bodyBeforeSuffixes = prompt2.slice(marks.directivesPrefix.length);
11108
11285
  prompt2 = prompt2 + styleSuffix2 + avoidSuffix2;
11109
11286
  if (prompt2.length > maxLen2) {
11287
+ if (marks) marks.overflowChars += prompt2.length - maxLen2;
11110
11288
  prompt2 = prompt2.slice(0, maxLen2 - 3) + "...";
11111
11289
  }
11112
11290
  if (!isHybrid) {
@@ -11180,11 +11358,13 @@ Avoid: ${negPrompt}`;
11180
11358
  const maxLen = getMaxImagePromptChars(provider);
11181
11359
  const reserved = styleSuffix.length + avoidSuffix.length;
11182
11360
  if (prompt.length + reserved > maxLen) {
11361
+ if (marks) marks.overflowChars += prompt.length + reserved - maxLen;
11183
11362
  prompt = prompt.slice(0, Math.max(0, maxLen - reserved - 3)) + "...";
11184
11363
  }
11185
11364
  if (marks) marks.bodyBeforeSuffixes = prompt;
11186
11365
  prompt = prompt + styleSuffix + avoidSuffix;
11187
11366
  if (prompt.length > maxLen) {
11367
+ if (marks) marks.overflowChars += prompt.length - maxLen;
11188
11368
  prompt = prompt.slice(0, maxLen - 3) + "...";
11189
11369
  }
11190
11370
  const allRefs = referenceImageUrls.length > 0 ? referenceImageUrls : ancestorRefs;
@@ -11194,12 +11374,7 @@ Avoid: ${negPrompt}`;
11194
11374
  return { prompt, nativeNegativePrompt, referenceImageUrls: refsToSend };
11195
11375
  }
11196
11376
  function buildImagePromptSegments(config2, bodySegments) {
11197
- const marks = {
11198
- directivesPrefix: "",
11199
- bodyBeforeSuffixes: "",
11200
- styleSuffix: "",
11201
- avoidSuffix: ""
11202
- };
11377
+ const marks = newAssemblyMarks();
11203
11378
  const result = buildImagePromptInternal(config2, marks);
11204
11379
  let segments = [
11205
11380
  ...marks.directivesPrefix ? [{ text: marks.directivesPrefix, origin: "mention" }] : [],
@@ -11389,13 +11564,24 @@ function hybridRolePhrase(label, letter) {
11389
11564
  return `the ${label} from reference image ${letter}`;
11390
11565
  }
11391
11566
  function expandImageRefTokensHybrid(prompt, refs, finalIndexByUrl) {
11392
- return prompt.replace(IMAGE_TOKEN_PATTERN, (match, num, label) => {
11393
- const n = parseInt(num, 10);
11567
+ const splices = [];
11568
+ for (const m of prompt.matchAll(IMAGE_TOKEN_PATTERN)) {
11569
+ const n = parseInt(m[1], 10);
11394
11570
  const ref = refs[n - 1];
11395
11571
  const finalIdx = ref?.url ? finalIndexByUrl.get(ref.url) : void 0;
11396
- if (!finalIdx) return match;
11397
- return hybridRolePhrase((label ?? "").trim(), slotToLetter(finalIdx));
11398
- });
11572
+ if (!finalIdx) continue;
11573
+ splices.push({
11574
+ offset: m.index ?? 0,
11575
+ length: m[0].length,
11576
+ phrase: hybridRolePhrase((m[2] ?? "").trim(), slotToLetter(finalIdx))
11577
+ });
11578
+ }
11579
+ let resolved = prompt;
11580
+ for (let i = splices.length - 1; i >= 0; i--) {
11581
+ const s = splices[i];
11582
+ resolved = spliceMentionPhrase(resolved, s.offset, s.length, s.phrase);
11583
+ }
11584
+ return resolved;
11399
11585
  }
11400
11586
  function capitalizeLineInitial(line) {
11401
11587
  return line.replace(/[a-zA-Z]/, (c) => c.toUpperCase());
@@ -11620,6 +11806,266 @@ function renderLens(l) {
11620
11806
  return bits.length > 0 ? `Lens: ${bits.join(", ")}.` : "";
11621
11807
  }
11622
11808
 
11809
+ // src/direction-registry.ts
11810
+ var perId = (full, compact) => (ids, mode) => {
11811
+ const out = [];
11812
+ for (const id of ids) {
11813
+ const frag = mode === "compact" ? compact(id) : full(id);
11814
+ if (frag.length > 0) out.push(frag);
11815
+ }
11816
+ return out;
11817
+ };
11818
+ var viaListBuilder = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
11819
+ var viaStringBuilder = (build) => (ids, mode) => {
11820
+ const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
11821
+ return s.length > 0 ? [s] : [];
11822
+ };
11823
+ var viaMood = (ids, mode) => buildMoodHints({ mood: ids.length === 1 ? ids[0] : [...ids] }, mode).filter(
11824
+ (s) => s.length > 0
11825
+ );
11826
+ var framing = perId(getFramingPromptHint, getFramingTerm);
11827
+ var lighting = perId(getLightingPromptHint, getLightingTerm);
11828
+ var exposure = perId(getExposurePromptHint, getExposureTerm);
11829
+ var temporal = perId(getTemporalPromptHint, getTemporalTerm);
11830
+ var DIRECTION_FIELDS = [
11831
+ { key: "cameraMotion", surface: "video", family: "motion", maxPicks: 1, render: perId(getCameraMotionPromptHint, getCameraMotionTerm) },
11832
+ // Composition (the Framing catalog, one row per category).
11833
+ { key: "shotSize", surface: "both", family: "look", maxPicks: 1, render: framing },
11834
+ { key: "angle", surface: "both", family: "look", maxPicks: 1, render: framing },
11835
+ { key: "coverage", surface: "both", family: "look", maxPicks: 1, render: framing },
11836
+ { key: "composition", surface: "both", family: "look", maxPicks: 2, render: framing },
11837
+ { key: "vantage", surface: "both", family: "look", maxPicks: 1, render: framing },
11838
+ { key: "pose", surface: "both", family: "look", maxPicks: 1, render: perId(getPosePromptHint, getPoseTerm) },
11839
+ { key: "compositionEffect", surface: "both", family: "look", maxPicks: 1, render: perId(getCompositionEffectPromptHint, getCompositionEffectTerm) },
11840
+ // Camera.
11841
+ { key: "cameraFormat", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) },
11842
+ { key: "lens", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
11843
+ // Exposure (stills only — a video's exposure rides its own temporal levers).
11844
+ { key: "aperture", surface: "image", family: "look", maxPicks: 1, render: exposure },
11845
+ { key: "shutterSpeed", surface: "image", family: "look", maxPicks: 1, render: exposure },
11846
+ { key: "isoValue", surface: "image", family: "look", maxPicks: 1, render: exposure },
11847
+ // Light (the Lighting catalog, one row per category).
11848
+ { key: "timeOfDay", surface: "both", family: "look", maxPicks: 1, render: lighting },
11849
+ { key: "lightingStyle", surface: "both", family: "look", maxPicks: 2, render: lighting },
11850
+ { key: "lightingDirection", surface: "both", family: "look", maxPicks: 1, render: lighting },
11851
+ { key: "lightingRatio", surface: "both", family: "look", maxPicks: 1, render: lighting },
11852
+ { key: "colorTemperature", surface: "both", family: "look", maxPicks: 1, render: lighting },
11853
+ { key: "colorLook", surface: "both", family: "look", maxPicks: 1, render: perId(getColorLookPromptHint, getColorLookTerm) },
11854
+ { key: "atmosphere", surface: "both", family: "look", maxPicks: 2, render: viaListBuilder(buildAtmosphereHints) },
11855
+ { key: "postProcess", surface: "image", family: "look", maxPicks: 2, render: viaListBuilder(buildPostProcessHints) },
11856
+ // Style.
11857
+ { key: "style", surface: "both", family: "look", maxPicks: 1, render: perId(getStylePromptHint, getStyleTerm) },
11858
+ { key: "mood", surface: "both", family: "look", maxPicks: 2, render: viaMood },
11859
+ { key: "aesthetic", surface: "both", family: "look", maxPicks: 2, render: viaStringBuilder(buildAestheticHints) },
11860
+ { key: "photoGenre", surface: "image", family: "look", maxPicks: 1, render: perId(getPhotoGenrePromptHint, getPhotoGenreTerm) },
11861
+ { key: "photographer", surface: "image", family: "look", maxPicks: 2, render: viaStringBuilder(buildPhotographerHints) },
11862
+ { key: "renderQuality", surface: "image", family: "look", maxPicks: 1, render: perId(getRenderQualityPromptHint, getRenderQualityTerm) },
11863
+ // Scene.
11864
+ { key: "setting", surface: "both", family: "look", maxPicks: 1, render: perId(getSettingPromptHint, getSettingTerm) },
11865
+ { key: "era", surface: "both", family: "look", maxPicks: 1, render: perId(getEraPromptHint, getEraTerm) },
11866
+ { key: "backdrop", surface: "both", family: "look", maxPicks: 1, render: perId(getBackdropPromptHint, getBackdropTerm) },
11867
+ // Motion & time.
11868
+ { key: "actionFx", surface: "video", family: "motion", maxPicks: 2, render: viaListBuilder(buildActionFxHints) },
11869
+ { key: "temporalSpeed", surface: "video", family: "motion", maxPicks: 1, render: temporal },
11870
+ { key: "temporalFreeze", surface: "video", family: "motion", maxPicks: 1, render: temporal },
11871
+ { key: "temporalDirection", surface: "video", family: "motion", maxPicks: 1, render: temporal },
11872
+ { key: "temporalShutter", surface: "video", family: "motion", maxPicks: 1, render: temporal },
11873
+ { key: "transition", surface: "video", family: "motion", maxPicks: 2, render: perId(getTransitionPromptHint, getTransitionTerm) },
11874
+ { key: "loopSubject", surface: "video", family: "motion", maxPicks: 1, render: perId(getLoopSubjectPromptHint, getLoopSubjectTerm) },
11875
+ // ── LEGACY BLOCK — see the table doc above. Placed LAST, in today's exact
11876
+ // `composePromptText` order, so every pre-registry caller is byte-identical.
11877
+ { key: "framingId", surface: "both", family: "look", maxPicks: 1, render: framing },
11878
+ { key: "framingAngleId", surface: "both", family: "look", maxPicks: 1, render: framing },
11879
+ { key: "lightingId", surface: "both", family: "look", maxPicks: 1, render: lighting },
11880
+ { key: "lensId", surface: "both", family: "look", maxPicks: 1, render: perId(getLensPromptHint, getLensTerm) },
11881
+ { key: "cameraFormatId", surface: "both", family: "look", maxPicks: 1, render: perId(getCameraFormatPromptHint, getCameraFormatTerm) }
11882
+ ];
11883
+ var DIRECTION_KEYS = DIRECTION_FIELDS.map((f) => f.key);
11884
+ var IMAGE_HINT_MODE_DEFAULT = "full";
11885
+ var VIDEO_HINT_MODE_DEFAULT = { look: "full", motion: "compact" };
11886
+ function modeForFamily(mode, family) {
11887
+ return typeof mode === "string" ? mode : family === "motion" ? mode.motion : mode.look;
11888
+ }
11889
+ var DIRECTION_ARRAY_CEILING = 8;
11890
+ var DIRECTION_ID_MAX_CHARS = 100;
11891
+ function normalizeDirectionIds(value, maxPicks) {
11892
+ const ids = [];
11893
+ if (typeof value === "string") {
11894
+ if (value) ids.push(value);
11895
+ } else if (Array.isArray(value)) {
11896
+ for (const v of value) {
11897
+ if (ids.length >= maxPicks) break;
11898
+ if (typeof v === "string" && v && !ids.includes(v)) ids.push(v);
11899
+ }
11900
+ }
11901
+ return ids.slice(0, maxPicks);
11902
+ }
11903
+ function directionFieldsForSurface(surface) {
11904
+ return DIRECTION_FIELDS.filter((f) => f.surface === "both" || f.surface === surface);
11905
+ }
11906
+ function renderDirectionHints(direction, opts) {
11907
+ if (!direction) return [];
11908
+ const mode = opts.mode ?? "full";
11909
+ const out = [];
11910
+ const seen = /* @__PURE__ */ new Set();
11911
+ for (const spec of DIRECTION_FIELDS) {
11912
+ if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
11913
+ const ids = normalizeDirectionIds(
11914
+ direction[spec.key],
11915
+ spec.maxPicks
11916
+ );
11917
+ if (ids.length === 0) continue;
11918
+ for (const hint of spec.render(ids, modeForFamily(mode, spec.family))) {
11919
+ if (hint.length > 0 && !seen.has(hint)) {
11920
+ seen.add(hint);
11921
+ out.push(hint);
11922
+ }
11923
+ }
11924
+ }
11925
+ return out;
11926
+ }
11927
+ var viaFragmentBuilder = (build) => (subject, mode) => {
11928
+ const clause = build(subject, mode).filter((s) => s.length > 0).join(", ");
11929
+ return clause.length > 0 ? [clause] : [];
11930
+ };
11931
+ var viaListBuilder2 = (build) => (ids, mode) => build(ids.length === 1 ? ids[0] : [...ids], mode).filter((s) => s.length > 0);
11932
+ var viaStringBuilder2 = (build) => (ids, mode) => {
11933
+ const s = build(ids.length === 1 ? ids[0] : [...ids], mode);
11934
+ return s.length > 0 ? [s] : [];
11935
+ };
11936
+ var perId2 = (full, compact) => (ids, mode) => {
11937
+ const out = [];
11938
+ for (const id of ids) {
11939
+ const frag = mode === "compact" ? compact(id) : full(id);
11940
+ if (frag.length > 0) out.push(frag);
11941
+ }
11942
+ return out;
11943
+ };
11944
+ var SUBJECT_FIELDS = [
11945
+ { key: "person", kind: "group", surface: "both", render: viaFragmentBuilder(buildPersonHints) },
11946
+ { key: "styling", kind: "group", surface: "both", render: viaFragmentBuilder(buildStylingHints) },
11947
+ { key: "heldProp", kind: "ids", surface: "both", maxPicks: 2, render: viaListBuilder2(buildHeldPropHints) },
11948
+ { key: "material", kind: "ids", surface: "both", maxPicks: 2, render: viaStringBuilder2(buildMaterialHints) },
11949
+ { key: "animal", kind: "ids", surface: "both", maxPicks: 1, render: perId2(getAnimalPromptHint, getAnimalTerm) }
11950
+ ];
11951
+ var SUBJECT_FOLD_KEYS = SUBJECT_FIELDS.map((f) => f.key);
11952
+ var IDS_ROWS = SUBJECT_FIELDS.filter((f) => f.kind === "ids");
11953
+ var SUBJECT_CUSTOM_AGE_KEY = "customAge";
11954
+ var CUSTOM_AGE_MIN = 0;
11955
+ var CUSTOM_AGE_MAX = 120;
11956
+ var SUBJECT_KEYS = [
11957
+ ...PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]),
11958
+ SUBJECT_CUSTOM_AGE_KEY,
11959
+ ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),
11960
+ ...IDS_ROWS.map((f) => f.key)
11961
+ ];
11962
+ function getRegisteredSubjectKeys() {
11963
+ const fieldByDimension = getRegisteredPersonFieldByDimension();
11964
+ const personFields = [];
11965
+ for (const dimension of getRegisteredPersonDimensionOrder()) {
11966
+ const field = fieldByDimension[dimension];
11967
+ if (field) personFields.push(field);
11968
+ }
11969
+ return [
11970
+ ...personFields,
11971
+ SUBJECT_CUSTOM_AGE_KEY,
11972
+ ...STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]),
11973
+ ...IDS_ROWS.map((f) => f.key)
11974
+ ];
11975
+ }
11976
+ var SUBJECT_IMAGE_HINT_MODE_DEFAULT = "full";
11977
+ var SUBJECT_VIDEO_HINT_MODE_DEFAULT = "compact";
11978
+ var SUBJECT_ARRAY_CEILING = DIRECTION_ARRAY_CEILING;
11979
+ var SUBJECT_ID_MAX_CHARS = DIRECTION_ID_MAX_CHARS;
11980
+ var MAX_SUBJECT_KEYS = 128;
11981
+ var SUBJECT_KEY_MAX_CHARS = 64;
11982
+ function normalizeIds(value, maxPicks) {
11983
+ const ids = [];
11984
+ if (typeof value === "string") {
11985
+ if (value) ids.push(value);
11986
+ } else if (Array.isArray(value)) {
11987
+ for (const v of value) {
11988
+ if (ids.length >= maxPicks) break;
11989
+ if (typeof v === "string" && v && !ids.includes(v)) ids.push(v);
11990
+ }
11991
+ }
11992
+ return ids.slice(0, maxPicks);
11993
+ }
11994
+ function limitByField() {
11995
+ const out = /* @__PURE__ */ new Map();
11996
+ const personFieldByDimension = getRegisteredPersonFieldByDimension();
11997
+ for (const dimension of getRegisteredPersonDimensionOrder()) {
11998
+ const field = personFieldByDimension[dimension];
11999
+ if (field) out.set(field, getPersonDimensionLimit(dimension));
12000
+ }
12001
+ for (const dimension of STYLING_DIMENSION_ORDER) {
12002
+ out.set(
12003
+ STYLING_FIELD_BY_DIMENSION[dimension],
12004
+ getStylingDimensionLimit(dimension)
12005
+ );
12006
+ }
12007
+ for (const row of IDS_ROWS) out.set(row.key, row.maxPicks);
12008
+ return out;
12009
+ }
12010
+ function normalizeSubjectFields(subject) {
12011
+ if (!subject || typeof subject !== "object" || Array.isArray(subject)) return void 0;
12012
+ const src = subject;
12013
+ const limits = limitByField();
12014
+ const out = {};
12015
+ const rawAge = src[SUBJECT_CUSTOM_AGE_KEY];
12016
+ if (typeof rawAge === "number" && Number.isFinite(rawAge)) {
12017
+ out[SUBJECT_CUSTOM_AGE_KEY] = Math.max(
12018
+ CUSTOM_AGE_MIN,
12019
+ Math.min(CUSTOM_AGE_MAX, Math.round(rawAge))
12020
+ );
12021
+ }
12022
+ for (const [field, limit] of limits) {
12023
+ const ids = normalizeIds(src[field], limit);
12024
+ if (ids.length === 0) continue;
12025
+ out[field] = ids.length === 1 ? ids[0] : ids;
12026
+ }
12027
+ return Object.keys(out).length > 0 ? out : void 0;
12028
+ }
12029
+ function subjectFieldsForSurface(surface) {
12030
+ return SUBJECT_FIELDS.filter((f) => f.surface === "both" || f.surface === surface);
12031
+ }
12032
+ function renderSubjectHints(subject, opts) {
12033
+ const bag = normalizeSubjectFields(subject);
12034
+ if (!bag) return [];
12035
+ const mode = opts.mode ?? "full";
12036
+ const out = [];
12037
+ const seen = /* @__PURE__ */ new Set();
12038
+ for (const spec of SUBJECT_FIELDS) {
12039
+ if (spec.surface !== "both" && spec.surface !== opts.surface) continue;
12040
+ const hints = spec.kind === "group" ? spec.render(bag, mode) : spec.render(normalizeIds(bag[spec.key], spec.maxPicks), mode);
12041
+ for (const hint of hints) {
12042
+ if (hint.length > 0 && !seen.has(hint)) {
12043
+ seen.add(hint);
12044
+ out.push(hint);
12045
+ }
12046
+ }
12047
+ }
12048
+ return out;
12049
+ }
12050
+
12051
+ // src/prompt-hint-join.ts
12052
+ var PROMPT_HINT_SEPARATOR = ". ";
12053
+ function joinPromptHints(userPrompt, hints) {
12054
+ if (hints.length === 0) return userPrompt;
12055
+ return [userPrompt.trim(), ...hints].filter((p) => p.length > 0).join(PROMPT_HINT_SEPARATOR);
12056
+ }
12057
+
12058
+ // src/hint-shedding.ts
12059
+ function keepableDirectionHints(hintClauses, kept, deficit) {
12060
+ let remaining = deficit;
12061
+ let next = kept;
12062
+ while (next > 0 && remaining > 0) {
12063
+ next -= 1;
12064
+ remaining -= hintClauses[next].length + PROMPT_HINT_SEPARATOR.length;
12065
+ }
12066
+ return next;
12067
+ }
12068
+
11623
12069
  // src/ref-binding.ts
11624
12070
  function identityRefsSentence(firstOrdinal, lastOrdinal) {
11625
12071
  return firstOrdinal === lastOrdinal ? `${REF_BINDING.ordinal(firstOrdinal)} is an identity reference for this shot's subjects \u2014 match its subject's exact appearance; it is not a frame.` : `${REF_BINDING.ordinal(firstOrdinal)} through ${REF_BINDING.ordinal(lastOrdinal)} are identity references for this shot's subjects \u2014 match each subject's exact appearance; they are not frames.`;
@@ -12205,22 +12651,32 @@ function assembleSunoInput(input) {
12205
12651
  }
12206
12652
 
12207
12653
  // src/assemble-image-input.ts
12208
- function composePromptText(userPrompt, direction, structured) {
12654
+ function renderImageHintPieces(subject, direction, structured) {
12655
+ return {
12656
+ hintClauses: [
12657
+ ...renderSubjectHints(subject, {
12658
+ surface: "image",
12659
+ mode: SUBJECT_IMAGE_HINT_MODE_DEFAULT
12660
+ }),
12661
+ ...renderDirectionHints(direction, {
12662
+ surface: "image",
12663
+ mode: IMAGE_HINT_MODE_DEFAULT
12664
+ })
12665
+ ].filter((p) => p.length > 0),
12666
+ structuredFragment: structured ? renderStructuredFields(structured) : ""
12667
+ };
12668
+ }
12669
+ function composePromptText(userPrompt, pieces, keptHintClauses) {
12209
12670
  const hints = [
12210
- getFramingPromptHint(direction?.framingId),
12211
- getFramingPromptHint(direction?.framingAngleId),
12212
- getLightingPromptHint(direction?.lightingId),
12213
- getLensPromptHint(direction?.lensId),
12214
- getCameraFormatPromptHint(direction?.cameraFormatId),
12215
- structured ? renderStructuredFields(structured) : ""
12671
+ ...pieces.hintClauses.slice(0, keptHintClauses),
12672
+ pieces.structuredFragment
12216
12673
  ].filter((p) => p.length > 0);
12217
- if (hints.length === 0) return userPrompt;
12218
- return [userPrompt.trim(), ...hints].filter((p) => p.length > 0).join(". ");
12674
+ return joinPromptHints(userPrompt, hints);
12219
12675
  }
12220
12676
  function assembleImageInput(input) {
12221
- const prompt = composePromptText(input.userPrompt, input.direction, input.structured);
12222
- const result = buildImagePrompt({
12223
- prompt,
12677
+ const pieces = renderImageHintPieces(input.subject, input.direction, input.structured);
12678
+ const assembleWith = (keptHintClauses) => buildImagePromptWithOverflow({
12679
+ prompt: composePromptText(input.userPrompt, pieces, keptHintClauses),
12224
12680
  provider: input.provider,
12225
12681
  ...input.connectedReferences !== void 0 ? { connectedReferences: input.connectedReferences } : {},
12226
12682
  // Manual uploads / direct refs ride the builder's reference-URL channel so
@@ -12243,6 +12699,13 @@ function assembleImageInput(input) {
12243
12699
  ...input.sourceNodeIdById !== void 0 ? { sourceNodeIdById: input.sourceNodeIdById } : {},
12244
12700
  ...input.skipCharacterMentions !== void 0 ? { skipCharacterMentions: input.skipCharacterMentions } : {}
12245
12701
  });
12702
+ let kept = pieces.hintClauses.length;
12703
+ let fitted = assembleWith(kept);
12704
+ while (fitted.overflowChars > 0 && kept > 0) {
12705
+ kept = keepableDirectionHints(pieces.hintClauses, kept, fitted.overflowChars);
12706
+ fitted = assembleWith(kept);
12707
+ }
12708
+ const { overflowChars, ...result } = fitted;
12246
12709
  if (input.throwOnEmpty && !result.prompt.trim()) {
12247
12710
  throw new Error(
12248
12711
  "No prompt \u2014 type one, bind a character, or pick a cinematography direction"
@@ -12250,6 +12713,152 @@ function assembleImageInput(input) {
12250
12713
  }
12251
12714
  return result;
12252
12715
  }
12716
+
12717
+ // src/assemble-video-input.ts
12718
+ function composeVideoPromptText(userPrompt, direction, structured, opts) {
12719
+ const hintClauses = [
12720
+ ...renderSubjectHints(opts?.subject, {
12721
+ surface: "video",
12722
+ mode: opts?.subjectHintMode ?? SUBJECT_VIDEO_HINT_MODE_DEFAULT
12723
+ }),
12724
+ ...renderDirectionHints(direction, {
12725
+ surface: "video",
12726
+ mode: opts?.hintMode ?? VIDEO_HINT_MODE_DEFAULT
12727
+ })
12728
+ ].filter((p) => p.length > 0);
12729
+ const structuredFragment = structured ? renderStructuredFields(structured) : "";
12730
+ const composeWith = (kept2) => {
12731
+ const hints = [...hintClauses.slice(0, kept2), structuredFragment].filter(
12732
+ (p) => p.length > 0
12733
+ );
12734
+ if (hints.length === 0) return userPrompt;
12735
+ return joinPromptHints(userPrompt ?? "", hints);
12736
+ };
12737
+ const cap = opts?.cap;
12738
+ if (cap === void 0) return composeWith(hintClauses.length);
12739
+ const frame = opts?.frame ?? ((body2) => body2);
12740
+ let kept = hintClauses.length;
12741
+ let body = composeWith(kept);
12742
+ let framedLength = frame(body)?.length ?? 0;
12743
+ while (framedLength > cap && kept > 0) {
12744
+ kept = keepableDirectionHints(hintClauses, kept, framedLength - cap);
12745
+ body = composeWith(kept);
12746
+ framedLength = frame(body)?.length ?? 0;
12747
+ }
12748
+ return body;
12749
+ }
12750
+
12751
+ // src/read-node-direction.ts
12752
+ function readDirectionFields(value) {
12753
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
12754
+ const src = value;
12755
+ const out = {};
12756
+ for (const spec of DIRECTION_FIELDS) {
12757
+ const v = src[spec.key];
12758
+ if (typeof v === "string") {
12759
+ if (v.length > 0 && v.length <= DIRECTION_ID_MAX_CHARS) out[spec.key] = v;
12760
+ } else if (Array.isArray(v)) {
12761
+ const kept = [];
12762
+ for (const x of v) {
12763
+ if (kept.length >= DIRECTION_ARRAY_CEILING) break;
12764
+ if (typeof x === "string" && x.length > 0 && x.length <= DIRECTION_ID_MAX_CHARS) {
12765
+ kept.push(x);
12766
+ }
12767
+ }
12768
+ if (kept.length > 0) out[spec.key] = kept;
12769
+ }
12770
+ }
12771
+ return Object.keys(out).length > 0 ? out : void 0;
12772
+ }
12773
+ function readSubjectFields(value) {
12774
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
12775
+ const src = value;
12776
+ const out = {};
12777
+ for (const key of getRegisteredSubjectKeys()) {
12778
+ const v = src[key];
12779
+ if (key === SUBJECT_CUSTOM_AGE_KEY) {
12780
+ if (typeof v === "number" && Number.isFinite(v)) out[key] = v;
12781
+ continue;
12782
+ }
12783
+ if (typeof v === "string") {
12784
+ if (v.length > 0 && v.length <= SUBJECT_ID_MAX_CHARS) out[key] = v;
12785
+ } else if (Array.isArray(v)) {
12786
+ const kept = [];
12787
+ for (const x of v) {
12788
+ if (kept.length >= SUBJECT_ARRAY_CEILING) break;
12789
+ if (typeof x === "string" && x.length > 0 && x.length <= SUBJECT_ID_MAX_CHARS) {
12790
+ kept.push(x);
12791
+ }
12792
+ }
12793
+ if (kept.length > 0) out[key] = kept;
12794
+ }
12795
+ }
12796
+ return Object.keys(out).length > 0 ? out : void 0;
12797
+ }
12798
+ var GENDERS = ["man", "woman", "child", "non-binary"];
12799
+ var MAX_STRUCTURED_VALUE_CHARS = 200;
12800
+ var PERSON_FIELDS2 = {
12801
+ age: "number",
12802
+ gender: "gender",
12803
+ hair: "string",
12804
+ eyes: "string",
12805
+ expression: "string",
12806
+ profession: "string",
12807
+ warriorType: "string"
12808
+ };
12809
+ var STYLING_FIELDS2 = {
12810
+ mood: "string",
12811
+ lighting: "string",
12812
+ aesthetic: "string",
12813
+ colorLook: "string"
12814
+ };
12815
+ var SETTING_FIELDS = {
12816
+ era: "string",
12817
+ atmosphere: "string",
12818
+ backdrop: "string"
12819
+ };
12820
+ var CAMERA_FIELDS = {
12821
+ framing: "string",
12822
+ motion: "string",
12823
+ format: "string"
12824
+ };
12825
+ var LENS_FIELDS = { focalLength: "string", aperture: "string" };
12826
+ var STRUCTURED_GROUPS = {
12827
+ person: PERSON_FIELDS2,
12828
+ styling: STYLING_FIELDS2,
12829
+ setting: SETTING_FIELDS,
12830
+ camera: CAMERA_FIELDS,
12831
+ lens: LENS_FIELDS
12832
+ };
12833
+ function readField(v, kind) {
12834
+ if (kind === "number") return typeof v === "number" && Number.isFinite(v) ? v : void 0;
12835
+ if (typeof v !== "string" || v.length === 0 || v.length > MAX_STRUCTURED_VALUE_CHARS) {
12836
+ return void 0;
12837
+ }
12838
+ if (kind === "gender") return GENDERS.includes(v) ? v : void 0;
12839
+ return v;
12840
+ }
12841
+ function readStructuredFields(value) {
12842
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
12843
+ const src = value;
12844
+ const out = {};
12845
+ for (const group of Object.keys(STRUCTURED_GROUPS)) {
12846
+ const raw = src[group];
12847
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) continue;
12848
+ const rawRec = raw;
12849
+ const kept = {};
12850
+ for (const [field, kind] of Object.entries(
12851
+ STRUCTURED_GROUPS[group]
12852
+ )) {
12853
+ const v = readField(rawRec[field], kind);
12854
+ if (v !== void 0) kept[field] = v;
12855
+ }
12856
+ if (Object.keys(kept).length > 0) out[group] = kept;
12857
+ }
12858
+ const mood = readField(src.mood, "string");
12859
+ if (mood !== void 0) out.mood = mood;
12860
+ return Object.keys(out).length > 0 ? out : void 0;
12861
+ }
12253
12862
  var clean = (u) => {
12254
12863
  const t = u?.trim();
12255
12864
  return t && t.length > 0 ? t : void 0;
@@ -33266,8 +33875,8 @@ var SINGLE_PICKER_WIRING = [
33266
33875
  { kind: "single", nodeType: "furniture", label: "Furniture", valueField: "furniture", defaultValue: "sofa", catalogId: "furniture", entries: mapCat(FURNITURE, "subcategory"), groupOrder: FURNITURE_SUBCATEGORY_ORDER, groupLabels: FURNITURE_SUBCATEGORY_LABELS },
33267
33876
  { 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 }
33268
33877
  ];
33269
- var STYLING_FIELDS2 = STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]);
33270
- var PERSON_FIELDS2 = PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]);
33878
+ var STYLING_FIELDS3 = STYLING_DIMENSION_ORDER.map((d) => STYLING_FIELD_BY_DIMENSION[d]);
33879
+ var PERSON_FIELDS3 = PERSON_DIMENSION_ORDER.map((d) => PERSON_FIELD_BY_DIMENSION[d]);
33271
33880
  var LIGHTING_FIELDS2 = LIGHTING_CATEGORY_ORDER.map((c) => LIGHTING_FIELD_BY_CATEGORY[c]);
33272
33881
  var TEMPORAL_FIELD_BY_CATEGORY2 = {
33273
33882
  speed: "temporalSpeed",
@@ -33303,7 +33912,7 @@ var MULTI_PICKER_WIRING = [
33303
33912
  kind: "multi",
33304
33913
  nodeType: "person",
33305
33914
  label: "Person",
33306
- fields: PERSON_FIELDS2,
33915
+ fields: PERSON_FIELDS3,
33307
33916
  catalogId: "person",
33308
33917
  catalogEntries: flatCat(PEOPLE),
33309
33918
  fieldOptions: optionsByDiscriminator(PEOPLE, (e) => e.dimension, PERSON_FIELD_BY_DIMENSION)
@@ -33312,7 +33921,7 @@ var MULTI_PICKER_WIRING = [
33312
33921
  kind: "multi",
33313
33922
  nodeType: "styling",
33314
33923
  label: "Styling",
33315
- fields: STYLING_FIELDS2,
33924
+ fields: STYLING_FIELDS3,
33316
33925
  catalogId: "styling",
33317
33926
  catalogEntries: flatCat(STYLINGS),
33318
33927
  fieldOptions: optionsByDiscriminator(STYLINGS, (e) => e.dimension, STYLING_FIELD_BY_DIMENSION)
@@ -33450,6 +34059,6 @@ function buildSurroundFillPrompt(direction, userPrompt) {
33450
34059
  return `${scene}This is a partial frame: the ${carried} portion contains real, finished pixels and the ${painted} portion is flat gray that MUST be painted in. Paint ONLY the ${painted} gray region as a natural, seamless continuation of the ${carried} portion \u2014 same scene, same perspective, continuing the horizon, geometry, and content across the boundary with no break. Keep the ${carried} portion completely unchanged. CRITICAL: do NOT change the lighting, exposure, white balance, or time of day. Match the ${carried} portion's EXACT light, color temperature, and contrast across the whole frame \u2014 if it is flat overcast daylight, keep flat overcast daylight. No golden hour, no sunset, no warm relight, no cinematic regrade. The seam between the ${carried} and ${painted} portions must be invisible. No people, no text, no labels, no watermarks.`;
33451
34060
  }
33452
34061
 
33453
- 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_DURATIONS, CHARACTER_FX_IDS, CHARACTER_FX_INTENSITIES, CHARACTER_FX_POSITIONS, 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_REFERENCE_PROMPT_DOCTRINE, 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, NODE_PROMPT_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, PROMPT_AFFIX_CORE_FIELD_OVERRIDES, PROMPT_AFFIX_NODE_TYPES, 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, TERM_MAX_CHARS, TEXT_WIZARD_CATEGORIES, TRANSITIONS, TRANSITION_CATEGORY_LABELS, TRANSITION_CATEGORY_ORDER, TRANSITION_DURATIONS, TRANSITION_IDS, TRANSITION_INTENSITIES, TRANSITION_POSITIONS, 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, applyPromptAffixes, applyReferenceOrderToVideo, applyTemplate, assembleImageInput, assembleSunoInput, buildActionFxHints, buildActionFxTerms, buildAestheticHints, buildAestheticTerms, buildAgeHint, buildAtmosphereHints, buildAtmosphereTerms, buildCharacterPrompt, buildCreaturePrompt, buildExposureHints, buildExposureTerms, buildFaceTemplateInputs, buildFramingHints, buildFramingTerms, buildHeldPropHints, buildHeldPropTerms, buildIdentityDirectives, buildIdentityLockLine, buildImagePrompt, buildImagePromptSegments, buildInstrumentationHints, buildInstrumentationTerms, buildLightingHints, buildLightingTerms, buildLocationMotionPrompt, buildLocationPrompt, buildLocationRefinePrompt, buildMaterialHints, buildMaterialTerms, buildMoodHints, buildMoodTerms, buildMotionPrompt, buildMultiPickerAnalyzerSpec, buildMusicGenreHints, buildMusicGenreTerms, buildMusicMoodHints, buildMusicMoodTerms, buildObjectMotionPrompt, buildObjectPrompt, buildPersonHints, buildPersonTerms, buildPhotographerHints, buildPhotographerTerms, buildPickerAnalyzerSpec, buildPickerLegend, buildPickerZodSchema, buildPoseHints, buildPoseTerms, buildPostProcessHints, buildPostProcessTerms, buildReferenceBlocks, buildScenePrompt, buildStylingHints, buildStylingTerms, buildSurroundFillPrompt, buildTemporalHints, buildTemporalTerms, buildVoiceCharacterHints, buildVoiceCharacterTerms, buildVoiceDeliveryHints, buildVoiceDeliveryTerms, buildWardrobeHints, catalogPacksVersion, characterLockToRefLock, collectIdentityLockClause, composeCameraMotionHintFromConnections, composeCameraMotionTermFromConnections, composeCharacterFxHintFromConnections, composeNegative, composePickerCatalogs, composeSoundHintFromConnections, composeTransitionHintFromConnections, computeLlmChatFields, computeNodePrompt, computePackSidecarCoverage, deriveTerm, expandImagePositionRefs, expandImageRefTokens, filmStillPrefix, getActionFx, getActionFxLabel, getActionFxPromptHint, getActionFxTerm, getAesthetic, getAestheticLabel, getAestheticPromptHint, getAestheticTerm, getAtmosphere, getAtmosphereLabel, getAtmospherePromptHint, getAtmosphereTerm, getBackdrop, getBackdropLabel, getBackdropPromptHint, getBackdropTerm, getCameraFormat, getCameraFormatLabel, getCameraFormatPromptHint, getCameraFormatTerm, getCameraMotion, getCameraMotionLabel, getCameraMotionPromptHint, getCameraMotionTerm, getCategoriesForNodeType, getCharacterFx, getCharacterFxLabel, getCharacterFxPromptHint, getCharacterFxTerm, getColorLook, getColorLookLabel, getColorLookPromptHint, getColorLookTerm, getCompositionEffect, getCompositionEffectLabel, getCompositionEffectPromptHint, getCompositionEffectTerm, getEffectiveSunoCustomMode, getEra, getEraLabel, getEraPromptHint, getEraTerm, getExposure, getExposureLabel, getExposurePromptHint, getExposureTerm, getFactoryPresets, getFactorySnippets, getFraming, getFramingCategoryLimit, getFramingLabel, getFramingPromptHint, getFramingTerm, getHeldProp, getHeldPropLabel, getHeldPropPromptHint, getHeldPropTerm, getIdentityLockClause, getInstrument, getInstrumentTerm, getLens, getLensLabel, getLensPromptHint, getLensTerm, getLighting, getLightingLabel, getLightingPromptHint, getLightingTerm, getLoopSubject, getLoopSubjectLabel, getLoopSubjectPromptHint, getLoopSubjectTerm, getMaterial, getMaterialLabel, getMaterialPromptHint, getMaterialTerm, getMood, getMoodLabel, getMoodPromptHint, getMoodTerm, getMusicEmotion, getMusicEmotionTerm, getMusicEnergy, getMusicEnergyTerm, getMusicEra, getMusicEraTerm, getMusicGenre, getMusicGenreLabel, getMusicGenreTerm, getMusicSubgenre, getMusicSubgenreTerm, getMusicVibe, getMusicVibeTerm, getParameterPromptHint, getPerson, getPersonDimensionLimit, getPersonLabel, getPersonPromptHint, getPersonTerm, getPhotoGenre, getPhotoGenreLabel, getPhotoGenrePromptHint, getPhotoGenreTerm, getPhotographer, getPhotographerLabel, getPhotographerPromptHint, getPhotographerTerm, getPickerAnalyzer, getPickerCatalog, getPickerWiring, getPose, getPoseLabel, getPosePromptHint, getPoseTerm, getPostProcessEffect, getPostProcessEffectLabel, getPostProcessEffectPromptHint, getPostProcessEffectTerm, getProductionStyle, getProductionStyleTerm, getPromptDoctrine, getPromptFields, getPromptTips, getRegisteredCatalogPacks, getRegisteredPeople, getRegisteredPersonDimensionLabels, getRegisteredPersonDimensionOrder, getRegisteredPersonFieldByDimension, getRegisteredPickerCatalogs, getRenderQuality, getRenderQualityLabel, getRenderQualityPromptHint, getRenderQualityTerm, getSetting, getSettingLabel, getSettingPromptHint, getSettingTerm, getSingingStyle, getSingingStyleTerm, getSnippetMedia, getStyle, getStyleLabel, getStylePreset, getStylePromptHint, getStyleTerm, getStyling, getStylingDimensionLimit, getStylingLabel, getStylingPromptHint, getStylingTerm, getTemporal, getTemporalLabel, getTemporalPromptHint, getTemporalTerm, getTransition, getTransitionLabel, getTransitionPromptHint, getTransitionTerm, getVocalPresence, getVocalPresenceTerm, getVoiceAccent, getVoiceAccentTerm, getVoiceAge, getVoiceAgeTerm, getVoiceArchetype, getVoiceArchetypeTerm, getVoiceEmotion, getVoiceEmotionTerm, getVoiceGender, getVoiceGenderTerm, getVoiceLanguage, getVoiceLanguageTerm, getVoicePace, getVoicePaceTerm, getVoiceTimbre, getVoiceTimbreTerm, getWardrobeEntriesByDimension, getWardrobeEntry, getWardrobePromptHint, groupFactoryPresets, hasUpstreamCharacter, identityRefsSentence, isAnalyzablePicker, isInstrumentalVocal, isSuspiciousDerivedTerm, isVantageFraming, isWizardSupported, joinPromptParts, listPickerCatalogs, migratePersonValue, nodeHasInlinePrompt, nodeHasPromptField, nodeSupportsPromptAffixes, personPacksVersion, pickerFanoutTargets, projectAllCatalogs, projectPickerCatalog, promptAffixCoreField, promptBindsFirstFrame, promptFieldCarriesAffixes, promptPartSeparator, referenceRulesBlock, registerCatalogPack, registerPersonPack, renderStructuredFields, resetCatalogPacks, resetPersonPacks, resolveBrandInput, resolveCharacterMentions, resolveGeminiOmniI2vInputs, resolveLocationMentions, resolvePrompt, resolveRefIdTokens, resolveReferenceTokens, resolveSeedance2Inputs, resolveTemplate, resolveTerm, resolveVeoI2vInputs, resolveVideoReferenceCore, summarizePickerCatalogs, toIdentityLockMode, truncateForField, truncateText, withForcedIdentityLock };
34062
+ 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_DURATIONS, CHARACTER_FX_IDS, CHARACTER_FX_INTENSITIES, CHARACTER_FX_POSITIONS, 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, DIRECTION_ARRAY_CEILING, DIRECTION_FIELDS, DIRECTION_ID_MAX_CHARS, DIRECTION_KEYS, 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_HINT_MODE_DEFAULT, IMAGE_REFERENCE_PROMPT_DOCTRINE, 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, MAX_SUBJECT_KEYS, 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, NODE_PROMPT_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, PROMPT_AFFIX_CORE_FIELD_OVERRIDES, PROMPT_AFFIX_NODE_TYPES, PROMPT_HINT_SEPARATOR, 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, SUBJECT_ARRAY_CEILING, SUBJECT_CUSTOM_AGE_KEY, SUBJECT_FIELDS, SUBJECT_FOLD_KEYS, SUBJECT_ID_MAX_CHARS, SUBJECT_IMAGE_HINT_MODE_DEFAULT, SUBJECT_KEYS, SUBJECT_KEY_MAX_CHARS, SUBJECT_VIDEO_HINT_MODE_DEFAULT, TEMPORALS, TEMPORAL_CATEGORY_LABELS, TEMPORAL_CATEGORY_ORDER, TEMPORAL_FIELD_BY_CATEGORY, TEMPORAL_IDS, TERM_MAX_CHARS, TEXT_WIZARD_CATEGORIES, TRANSITIONS, TRANSITION_CATEGORY_LABELS, TRANSITION_CATEGORY_ORDER, TRANSITION_DURATIONS, TRANSITION_IDS, TRANSITION_INTENSITIES, TRANSITION_POSITIONS, VIDEO_HINT_MODE_DEFAULT, 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, applyPromptAffixes, applyReferenceOrderToVideo, applyTemplate, assembleImageInput, assembleSunoInput, buildActionFxHints, buildActionFxTerms, buildAestheticHints, buildAestheticTerms, buildAgeHint, buildAtmosphereHints, buildAtmosphereTerms, buildCharacterPrompt, buildCreaturePrompt, buildExposureHints, buildExposureTerms, buildFaceTemplateInputs, buildFramingHints, buildFramingTerms, buildHeldPropHints, buildHeldPropTerms, buildIdentityDirectives, buildIdentityLockLine, buildImagePrompt, buildImagePromptSegments, buildImagePromptWithOverflow, buildInstrumentationHints, buildInstrumentationTerms, buildLightingHints, buildLightingTerms, buildLocationMotionPrompt, buildLocationPrompt, buildLocationRefinePrompt, buildMaterialHints, buildMaterialTerms, buildMoodHints, buildMoodTerms, buildMotionPrompt, buildMultiPickerAnalyzerSpec, buildMusicGenreHints, buildMusicGenreTerms, buildMusicMoodHints, buildMusicMoodTerms, buildObjectMotionPrompt, buildObjectPrompt, buildPersonHints, buildPersonTerms, buildPhotographerHints, buildPhotographerTerms, buildPickerAnalyzerSpec, buildPickerLegend, buildPickerZodSchema, buildPoseHints, buildPoseTerms, buildPostProcessHints, buildPostProcessTerms, buildReferenceBlocks, buildScenePrompt, buildStylingHints, buildStylingTerms, buildSurroundFillPrompt, buildTemporalHints, buildTemporalTerms, buildVoiceCharacterHints, buildVoiceCharacterTerms, buildVoiceDeliveryHints, buildVoiceDeliveryTerms, buildWardrobeHints, catalogPacksVersion, characterLockToRefLock, collectIdentityLockClause, composeCameraMotionHintFromConnections, composeCameraMotionTermFromConnections, composeCharacterFxHintFromConnections, composeNegative, composePickerCatalogs, composeSoundHintFromConnections, composeTransitionHintFromConnections, composeVideoPromptText, computeLlmChatFields, computeNodePrompt, computePackSidecarCoverage, deriveTerm, directionFieldsForSurface, expandImagePositionRefs, expandImageRefTokens, filmStillPrefix, getActionFx, getActionFxLabel, getActionFxPromptHint, getActionFxTerm, getAesthetic, getAestheticLabel, getAestheticPromptHint, getAestheticTerm, getAtmosphere, getAtmosphereLabel, getAtmospherePromptHint, getAtmosphereTerm, getBackdrop, getBackdropLabel, getBackdropPromptHint, getBackdropTerm, getCameraFormat, getCameraFormatLabel, getCameraFormatPromptHint, getCameraFormatTerm, getCameraMotion, getCameraMotionLabel, getCameraMotionPromptHint, getCameraMotionTerm, getCategoriesForNodeType, getCharacterFx, getCharacterFxLabel, getCharacterFxPromptHint, getCharacterFxTerm, getColorLook, getColorLookLabel, getColorLookPromptHint, getColorLookTerm, getCompositionEffect, getCompositionEffectLabel, getCompositionEffectPromptHint, getCompositionEffectTerm, getEffectiveSunoCustomMode, getEra, getEraLabel, getEraPromptHint, getEraTerm, getExposure, getExposureLabel, getExposurePromptHint, getExposureTerm, getFactoryPresets, getFactorySnippets, getFraming, getFramingCategoryLimit, getFramingLabel, getFramingPromptHint, getFramingTerm, getHeldProp, getHeldPropLabel, getHeldPropPromptHint, getHeldPropTerm, getIdentityLockClause, getInstrument, getInstrumentTerm, getLens, getLensLabel, getLensPromptHint, getLensTerm, getLighting, getLightingLabel, getLightingPromptHint, getLightingTerm, getLoopSubject, getLoopSubjectLabel, getLoopSubjectPromptHint, getLoopSubjectTerm, getMaterial, getMaterialLabel, getMaterialPromptHint, getMaterialTerm, getMood, getMoodLabel, getMoodPromptHint, getMoodTerm, getMusicEmotion, getMusicEmotionTerm, getMusicEnergy, getMusicEnergyTerm, getMusicEra, getMusicEraTerm, getMusicGenre, getMusicGenreLabel, getMusicGenreTerm, getMusicSubgenre, getMusicSubgenreTerm, getMusicVibe, getMusicVibeTerm, getParameterPromptHint, getPerson, getPersonDimensionLimit, getPersonLabel, getPersonPromptHint, getPersonTerm, getPhotoGenre, getPhotoGenreLabel, getPhotoGenrePromptHint, getPhotoGenreTerm, getPhotographer, getPhotographerLabel, getPhotographerPromptHint, getPhotographerTerm, getPickerAnalyzer, getPickerCatalog, getPickerWiring, getPose, getPoseLabel, getPosePromptHint, getPoseTerm, getPostProcessEffect, getPostProcessEffectLabel, getPostProcessEffectPromptHint, getPostProcessEffectTerm, getProductionStyle, getProductionStyleTerm, getPromptDoctrine, getPromptFields, getPromptTips, getRegisteredCatalogPacks, getRegisteredPeople, getRegisteredPersonDimensionLabels, getRegisteredPersonDimensionOrder, getRegisteredPersonFieldByDimension, getRegisteredPickerCatalogs, getRegisteredSubjectKeys, getRenderQuality, getRenderQualityLabel, getRenderQualityPromptHint, getRenderQualityTerm, getSetting, getSettingLabel, getSettingPromptHint, getSettingTerm, getSingingStyle, getSingingStyleTerm, getSnippetMedia, getStyle, getStyleLabel, getStylePreset, getStylePromptHint, getStyleTerm, getStyling, getStylingDimensionLimit, getStylingLabel, getStylingPromptHint, getStylingTerm, getTemporal, getTemporalLabel, getTemporalPromptHint, getTemporalTerm, getTransition, getTransitionLabel, getTransitionPromptHint, getTransitionTerm, getVocalPresence, getVocalPresenceTerm, getVoiceAccent, getVoiceAccentTerm, getVoiceAge, getVoiceAgeTerm, getVoiceArchetype, getVoiceArchetypeTerm, getVoiceEmotion, getVoiceEmotionTerm, getVoiceGender, getVoiceGenderTerm, getVoiceLanguage, getVoiceLanguageTerm, getVoicePace, getVoicePaceTerm, getVoiceTimbre, getVoiceTimbreTerm, getWardrobeEntriesByDimension, getWardrobeEntry, getWardrobePromptHint, groupFactoryPresets, hasUpstreamCharacter, identityRefsSentence, isAnalyzablePicker, isInstrumentalVocal, isSuspiciousDerivedTerm, isVantageFraming, isWizardSupported, joinPromptHints, joinPromptParts, keepableDirectionHints, listPickerCatalogs, migratePersonValue, modeForFamily, nodeHasInlinePrompt, nodeHasPromptField, nodeSupportsPromptAffixes, normalizeSubjectFields, personPacksVersion, pickerFanoutTargets, projectAllCatalogs, projectPickerCatalog, promptAffixCoreField, promptBindsFirstFrame, promptFieldCarriesAffixes, promptPartSeparator, readDirectionFields, readStructuredFields, readSubjectFields, referenceRulesBlock, registerCatalogPack, registerPersonPack, renderDirectionHints, renderStructuredFields, renderSubjectHints, resetCatalogPacks, resetPersonPacks, resolveBrandInput, resolveCharacterMentions, resolveGeminiOmniI2vInputs, resolveLocationMentions, resolvePrompt, resolveRefIdTokens, resolveReferenceTokens, resolveSeedance2Inputs, resolveTemplate, resolveTerm, resolveVeoI2vInputs, resolveVideoReferenceCore, subjectFieldsForSurface, summarizePickerCatalogs, toIdentityLockMode, truncateForField, truncateText, withForcedIdentityLock };
33454
34063
  //# sourceMappingURL=index.js.map
33455
34064
  //# sourceMappingURL=index.js.map