@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 +108 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +241 -31
- package/dist/index.d.ts +241 -31
- package/dist/index.js +105 -24
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/character-fx-timing-catalogs.test.ts +240 -0
- package/src/__tests__/transition-timing-catalogs.test.ts +3 -1
- package/src/__tests__/video-reference-ref-id-tokens.test.ts +301 -0
- package/src/character-fx.ts +102 -19
- package/src/picker-catalogs.ts +18 -1
- package/src/provider-prompt-doctrine.ts +2 -2
- package/src/ref-binding.ts +45 -0
- package/src/ref-id-tokens.ts +112 -0
- package/src/video-reference-resolver.ts +78 -39
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
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
}
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
}
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
|
|
5911
|
-
|
|
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(
|
|
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
|
|
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;
|