@nodaro/prompts 1.9.0 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5892,24 +5892,35 @@ function getCharacterFxTerm(id) {
5892
5892
  return resolveTerm(getCharacterFx(id));
5893
5893
  }
5894
5894
  var CHARACTER_FX_IDS = CHARACTER_FX.map((c) => c.id);
5895
- var POSITION_CLAUSES2 = {
5896
- start: "the effect occurs at the opening of the clip",
5897
- middle: "the effect occurs in the middle of the clip",
5898
- end: "the effect occurs at the end of the clip",
5899
- full: "the effect persists for the entire clip"
5900
- };
5901
- var DURATION_CLAUSES2 = {
5902
- instant: "manifesting instantaneously",
5903
- short: "manifesting over approximately 1 second",
5904
- medium: "manifesting over approximately 2 seconds",
5905
- long: "manifesting over approximately 3 seconds"
5906
- };
5907
- var INTENSITY_CLAUSES2 = {
5908
- subtle: "with subtle restrained energy and minimal flourish",
5909
- natural: "with natural unhurried timing",
5910
- dynamic: "with dynamic energy and assertive flourish",
5911
- crazy: "with extreme exaggerated energy, wild flourishes, and dramatic distortion"
5912
- };
5895
+ var CHARACTER_FX_POSITIONS = [
5896
+ { id: "auto", label: "Auto", description: "Let the model place the effect", promptHint: "", term: "" },
5897
+ { id: "start", label: "Start", description: "Occurs at the opening of the clip", promptHint: "the effect occurs at the opening of the clip", term: "at the opening of the clip" },
5898
+ { id: "middle", label: "Middle", description: "Occurs in the middle of the clip", promptHint: "the effect occurs in the middle of the clip", term: "mid-clip" },
5899
+ { id: "end", label: "End", description: "Occurs at the end of the clip", promptHint: "the effect occurs at the end of the clip", term: "at the end of the clip" },
5900
+ { id: "full", label: "Full", description: "Persists for the entire clip", promptHint: "the effect persists for the entire clip", term: "persisting for the whole clip" }
5901
+ ];
5902
+ var CHARACTER_FX_DURATIONS = [
5903
+ { id: "auto", label: "Auto", description: "Let the model time the effect", promptHint: "", term: "" },
5904
+ { id: "instant", label: "Instant", description: "Manifests instantaneously", promptHint: "manifesting instantaneously", term: "manifesting instantly" },
5905
+ { id: "short", label: "Short (~1s)", description: "Manifests over approximately 1 second", promptHint: "manifesting over approximately 1 second", term: "manifesting over about 1 second" },
5906
+ { id: "medium", label: "Medium (~2s)", description: "Manifests over approximately 2 seconds", promptHint: "manifesting over approximately 2 seconds", term: "manifesting over about 2 seconds" },
5907
+ { id: "long", label: "Long (~3s)", description: "Manifests over approximately 3 seconds", promptHint: "manifesting over approximately 3 seconds", term: "manifesting over about 3 seconds" }
5908
+ ];
5909
+ var CHARACTER_FX_INTENSITIES = [
5910
+ { id: "auto", label: "Auto", description: "Let the model judge the effect's energy", promptHint: "", term: "" },
5911
+ { id: "subtle", label: "Subtle", description: "Restrained, minimal flourish", promptHint: "with subtle restrained energy and minimal flourish", term: "subtly" },
5912
+ { id: "natural", label: "Natural", description: "Unhurried, unforced timing", promptHint: "with natural unhurried timing", term: "at a natural pace" },
5913
+ { id: "dynamic", label: "Dynamic", description: "Assertive, energetic", promptHint: "with dynamic energy and assertive flourish", term: "energetically" },
5914
+ { id: "crazy", label: "Crazy", description: "Extreme, wild, distorted", promptHint: "with extreme exaggerated energy, wild flourishes, and dramatic distortion", term: "wildly exaggerated" }
5915
+ ];
5916
+ function clausesOf2(options) {
5917
+ return Object.fromEntries(
5918
+ options.filter((o) => o.id !== "auto").map((o) => [o.id, o.promptHint])
5919
+ );
5920
+ }
5921
+ var POSITION_CLAUSES2 = clausesOf2(CHARACTER_FX_POSITIONS);
5922
+ var DURATION_CLAUSES2 = clausesOf2(CHARACTER_FX_DURATIONS);
5923
+ var INTENSITY_CLAUSES2 = clausesOf2(CHARACTER_FX_INTENSITIES);
5913
5924
  function composeCharacterFxHintFromConnections(effectId, targetHints, timing, mode = "full") {
5914
5925
  const ids = Array.isArray(effectId) ? Array.from(new Set(effectId)).slice(0, 2) : effectId ? [effectId] : [];
5915
5926
  const resolveBase = mode === "compact" ? getCharacterFxTerm : getCharacterFxPromptHint;
@@ -9518,7 +9529,17 @@ var SINGLE_CATALOGS = [
9518
9529
  defaultValue: "auto",
9519
9530
  categoryOrder: CHARACTER_FX_CATEGORY_ORDER,
9520
9531
  categoryLabels: CHARACTER_FX_CATEGORY_LABELS,
9521
- options: toOptions(CHARACTER_FX, "category")
9532
+ options: toOptions(CHARACTER_FX, "category"),
9533
+ // The node's three timing parameters, alongside the effect itself — the
9534
+ // same shape `transition` carries above, but the character-fx scales, not
9535
+ // the transition ones: the wording is deliberately different (an effect
9536
+ // manifests and persists; a transition occurs and spans), so an id-only
9537
+ // consumer must read these rows, never reuse the transition rows.
9538
+ dimensions: perFieldDims([
9539
+ ["position", CHARACTER_FX_POSITIONS],
9540
+ ["duration", CHARACTER_FX_DURATIONS],
9541
+ ["intensity", CHARACTER_FX_INTENSITIES]
9542
+ ])
9522
9543
  },
9523
9544
  // -------- "Subject / Object" family --------
9524
9545
  {
@@ -11600,6 +11621,8 @@ function renderLens(l) {
11600
11621
  if (l.aperture) bits.push(`f/${l.aperture}`);
11601
11622
  return bits.length > 0 ? `Lens: ${bits.join(", ")}.` : "";
11602
11623
  }
11624
+
11625
+ // src/ref-binding.ts
11603
11626
  function identityRefsSentence(firstOrdinal, lastOrdinal) {
11604
11627
  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.`;
11605
11628
  }
@@ -11611,6 +11634,38 @@ var REF_BINDING = {
11611
11634
  ordinal: (n) => `@image_${n}`,
11612
11635
  frame: (n, role) => `Use @image_${n} as the ${role} (${role === "opening" ? "first" : "last"}) frame of the video.`
11613
11636
  };
11637
+
11638
+ // src/ref-id-tokens.ts
11639
+ var REF_TOKEN_LABEL_RE = /^[a-zA-Z0-9_ -]+$/;
11640
+ var HAS_REF_ID_TOKEN_RE = /\{ref:/i;
11641
+ var REF_ID_TOKEN_RE = /\{[rR][eE][fF]:([^{}]*)\}/g;
11642
+ var MALFORMED_REF_ID_TOKEN_RE = /\{[rR][eE][fF]:[^\s{}]*\}?/g;
11643
+ function splitLabel(content) {
11644
+ const at = content.lastIndexOf(":");
11645
+ if (at === -1) return { id: content };
11646
+ const tail = content.slice(at + 1);
11647
+ if (!REF_TOKEN_LABEL_RE.test(tail)) return { id: content };
11648
+ return { id: content.slice(0, at), label: tail };
11649
+ }
11650
+ function resolveRefIdTokens(prompt, ctx) {
11651
+ if (!prompt || !HAS_REF_ID_TOKEN_RE.test(prompt)) return prompt;
11652
+ const known = (id) => id.length > 0 && (ctx.slotById.has(id) || ctx.nameById.has(id));
11653
+ const bind = (id, label) => {
11654
+ const slot = ctx.slotById.get(id);
11655
+ if (slot !== void 0 && slot >= 1 && slot <= ctx.imageCount) {
11656
+ return label ? REF_BINDING.image(label, slot) : REF_BINDING.ordinal(slot);
11657
+ }
11658
+ return label ?? ctx.nameById.get(id) ?? "";
11659
+ };
11660
+ return prompt.replace(REF_ID_TOKEN_RE, (_match, content) => {
11661
+ if (known(content)) return bind(content, void 0);
11662
+ const { id, label } = splitLabel(content);
11663
+ if (known(id)) return bind(id, label);
11664
+ return label ?? "";
11665
+ }).replace(MALFORMED_REF_ID_TOKEN_RE, "");
11666
+ }
11667
+
11668
+ // src/video-reference-resolver.ts
11614
11669
  var REFERENCE_TOKEN_RE = /\{(image|video|audio):(\d+)(?::([a-zA-Z0-9_ -]+))?\}/gi;
11615
11670
  function resolveReferenceTokens(prompt, counts) {
11616
11671
  if (!prompt) return prompt;
@@ -11711,12 +11766,27 @@ function resolveVideoReferenceCore(args) {
11711
11766
  });
11712
11767
  }
11713
11768
  const hasExtras = (args.extraRefs?.length ?? 0) > 0;
11769
+ const nameByRefId = /* @__PURE__ */ new Map();
11770
+ for (const r of args.wiredCharRefs) {
11771
+ if (r.id && !nameByRefId.has(r.id)) nameByRefId.set(r.id, r.defaultName || r.characterSlug || "");
11772
+ }
11773
+ for (const ex of args.extraRefs ?? []) {
11774
+ if (ex.id && !nameByRefId.has(ex.id)) nameByRefId.set(ex.id, "");
11775
+ }
11776
+ for (const [id, name] of args.refNamesById ?? []) {
11777
+ if (id) nameByRefId.set(id, name);
11778
+ }
11779
+ const slotByRefId = /* @__PURE__ */ new Map();
11714
11780
  if (wiredCharRefs.length === 0 && !hasExtras) {
11781
+ const counts = tokenCounts(leadingRefUrls.length);
11715
11782
  return {
11716
11783
  // tokenCounts(leadingRefUrls.length) → image count == offset (no assets here):
11717
11784
  // leadingRefUrls mode counts the leading refs; ordinalOffset mode counts the
11718
11785
  // caller-owned leading refs the offset stands in for.
11719
- prompt: resolveReferenceTokens(args.prompt, tokenCounts(leadingRefUrls.length)),
11786
+ prompt: resolveReferenceTokens(
11787
+ resolveRefIdTokens(args.prompt, { slotById: slotByRefId, nameById: nameByRefId, imageCount: counts.image }),
11788
+ counts
11789
+ ),
11720
11790
  additionalUrls: [...leadingRefUrls]
11721
11791
  };
11722
11792
  }
@@ -11749,9 +11819,13 @@ function resolveVideoReferenceCore(args) {
11749
11819
  let position = offset;
11750
11820
  for (let i = 0; i < resolved.additionalUrls.length; i++) {
11751
11821
  position += 1;
11752
- const ref = wiredCharRefs.find((r) => r.url === resolved.additionalUrls[i]);
11822
+ const url2 = resolved.additionalUrls[i];
11823
+ const ref = wiredCharRefs.find((r) => r.url === url2);
11753
11824
  const slug = ref?.characterSlug;
11754
11825
  if (slug && !positionsByChar.has(slug)) positionsByChar.set(slug, position);
11826
+ for (const r of wiredCharRefs) {
11827
+ if (r.url === url2 && r.id && !slotByRefId.has(r.id)) slotByRefId.set(r.id, position);
11828
+ }
11755
11829
  }
11756
11830
  for (const r of wiredCharRefs) {
11757
11831
  if (r.source !== "wired-character") continue;
@@ -11764,6 +11838,7 @@ function resolveVideoReferenceCore(args) {
11764
11838
  fallbackUrls.push(r.url);
11765
11839
  position += 1;
11766
11840
  if (!positionsByChar.has(r.characterSlug)) positionsByChar.set(r.characterSlug, position);
11841
+ if (r.id && !slotByRefId.has(r.id)) slotByRefId.set(r.id, position);
11767
11842
  if (hybrid) {
11768
11843
  const binding = REF_BINDING.ordinal(position);
11769
11844
  canonicalPhrases.push(shared.roleToPhrase(shared.resolveDefaultRole(r.defaultRole, r.defaultUsageMode, r.source), binding));
@@ -11801,6 +11876,7 @@ function resolveVideoReferenceCore(args) {
11801
11876
  for (const ex of args.extraRefs) {
11802
11877
  if (!ex.url) continue;
11803
11878
  position += 1;
11879
+ if (ex.id && !slotByRefId.has(ex.id)) slotByRefId.set(ex.id, position);
11804
11880
  const desc = (ex.description ?? "").trim();
11805
11881
  if (ex.characterSlug) {
11806
11882
  const meta3 = args.lookupCharacterBySlug?.(ex.characterSlug);
@@ -11947,6 +12023,11 @@ ${finalPrompt}` : block;
11947
12023
  merged.push(u);
11948
12024
  }
11949
12025
  }
12026
+ finalPrompt = resolveRefIdTokens(finalPrompt, {
12027
+ slotById: slotByRefId,
12028
+ nameById: nameByRefId,
12029
+ imageCount: tokenCounts(merged.length).image
12030
+ }) ?? finalPrompt;
11950
12031
  const referenceOrder = args.referenceOrder;
11951
12032
  const assetUrls = merged.slice(leadingRefUrls.length);
11952
12033
  if (referenceOrder && referenceOrder.length > 0 && assetUrls.length > 1) {
@@ -27333,7 +27414,7 @@ precise subject \u2192 action details \u2192 scene/environment \u2192 lighting &
27333
27414
  - Transitions and camera terms on 2.5: state a transition's trigger point AND method in one sentence \u2014 "At the 5-second mark, the camera quickly transitions leftward using a left wipe combined with a natural dissolve." Basic shot and camera terms are written directly (push in / pull out / pan / track / orbit / dolly zoom / whip pan / hard cut / dissolve / one-shot / speed ramp); only niche terms need [term + descriptive explanation] \u2014 which is exactly what the pickers' compact hint mode emits versus their long hints.
27334
27415
 
27335
27416
  **References (when reference media is attached)**
27336
- - 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.)
27417
+ - 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. An API caller that passes \`connectedReferences\` can instead name a reference by its own id \u2014 \`{ref:<id>}\` / \`{ref:<id>:label}\` \u2014 and the platform substitutes the \`@image_N\` seat after it has numbered the references, so the client never computes N; a token whose reference was not attached drops to its label or name.)
27337
27418
  - 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".
27338
27419
  - Character identity: ONE close-up headshot + ONE full-body image is ideal. On the 2.0 SKUs do NOT attach multi-view/three-view character sheets \u2014 the model reads the views as separate people, causing identity drift and twin duplicates; 2.5 accepts multi-view images (see "Generation differences").
27339
27420
  - 4-5 assets total works best (1-2 character images + 1 scene image + 1 camera-movement video + 1 audio clip). Maxing out the 9-image/3-video/3-audio limits degrades feature priority and adherence.
@@ -27435,7 +27516,7 @@ precise subject \u2192 action details \u2192 scene/environment \u2192 lighting &
27435
27516
  - 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.
27436
27517
 
27437
27518
  **References (when reference media is attached)**
27438
- - 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.)
27519
+ - Refer to assets by ordinal in attachment order: "@Image 1", "Video 1", "Audio 1". Put the identity-critical asset first. (In the editor, the \`{image:N:label}\` / \`{video:N}\` / \`{audio:N}\` prompt tokens auto-emit this binding, so a wired reference and its mention stay in sync. An API caller that passes \`connectedReferences\` can instead write \`{ref:<id>}\` / \`{ref:<id>:label}\` with the reference's own id \u2014 the platform substitutes the \`@image_N\` seat after numbering.)
27439
27520
  - 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.
27440
27521
  - 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.
27441
27522
  - 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.
@@ -33402,7 +33483,10 @@ exports.CAMERA_MOTION_IDS = CAMERA_MOTION_IDS;
33402
33483
  exports.CHARACTER_FX = CHARACTER_FX;
33403
33484
  exports.CHARACTER_FX_CATEGORY_LABELS = CHARACTER_FX_CATEGORY_LABELS;
33404
33485
  exports.CHARACTER_FX_CATEGORY_ORDER = CHARACTER_FX_CATEGORY_ORDER;
33486
+ exports.CHARACTER_FX_DURATIONS = CHARACTER_FX_DURATIONS;
33405
33487
  exports.CHARACTER_FX_IDS = CHARACTER_FX_IDS;
33488
+ exports.CHARACTER_FX_INTENSITIES = CHARACTER_FX_INTENSITIES;
33489
+ exports.CHARACTER_FX_POSITIONS = CHARACTER_FX_POSITIONS;
33406
33490
  exports.CINEMATIC_LOOK_TAIL = CINEMATIC_LOOK_TAIL;
33407
33491
  exports.COLOR_LOOKS = COLOR_LOOKS;
33408
33492
  exports.COLOR_LOOK_CATEGORY_LABELS = COLOR_LOOK_CATEGORY_LABELS;
@@ -33866,6 +33950,7 @@ exports.resolveCharacterMentions = resolveCharacterMentions;
33866
33950
  exports.resolveGeminiOmniI2vInputs = resolveGeminiOmniI2vInputs;
33867
33951
  exports.resolveLocationMentions = resolveLocationMentions;
33868
33952
  exports.resolvePrompt = resolvePrompt;
33953
+ exports.resolveRefIdTokens = resolveRefIdTokens;
33869
33954
  exports.resolveReferenceTokens = resolveReferenceTokens;
33870
33955
  exports.resolveSeedance2Inputs = resolveSeedance2Inputs;
33871
33956
  exports.resolveTemplate = resolveTemplate;