@slatesvideo/shared 0.5.6 → 0.5.7
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.d.ts +1 -1
- package/dist/index.js +4 -1
- package/dist/operations/index.d.ts +43 -36
- package/dist/operations/index.js +289 -262
- package/dist/prompts/model-facts.d.ts +42 -0
- package/dist/prompts/model-facts.js +88 -18
- package/dist/prompts/prompting-tips.d.ts +1 -1
- package/dist/prompts/prompting-tips.js +108 -99
- package/dist/prompts/reference-composer.d.ts +21 -3
- package/dist/prompts/reference-composer.js +80 -10
- package/dist/skills/content.js +7 -7
- package/exports/slates-prompt-builder/generated/SKILL.md +2 -2
- package/exports/slates-prompt-builder/generated/reference-seedance.md +12 -1
- package/exports/slates-prompt-builder/generated/slates-prompt-builder-manifest.json +8 -8
- package/exports/slates-prompt-builder/generated/slates-prompt-builder.skill +0 -0
- package/package.json +1 -1
- package/skills/slates-model-selection.md +21 -19
- package/skills/slates-prompting-elevenlabs.md +16 -78
- package/skills/slates-prompting-lip-sync.md +12 -14
- package/skills/slates-prompting-motion-transfer.md +18 -14
- package/skills/slates-prompting-seed-audio.md +2 -2
- package/skills/slates-prompting-seedance-2-5.md +215 -0
- package/skills/slates-prompting-seedance.md +17 -1
- package/skills/slates-prompting-suno.md +0 -110
|
@@ -56,17 +56,28 @@ export function composeReferences(rawPrompt, groups, opts = {}) {
|
|
|
56
56
|
// ── 1. Assign global numbers by walking the list in order ──
|
|
57
57
|
let imageNum = opts.startImageNumber ?? 0;
|
|
58
58
|
let videoNum = opts.startVideoNumber ?? 0;
|
|
59
|
+
let audioNum = opts.startAudioNumber ?? 0;
|
|
59
60
|
const orderedImagePaths = [];
|
|
60
61
|
const orderedVideoPaths = [];
|
|
62
|
+
const orderedAudioPaths = [];
|
|
61
63
|
const numbered = groups.map((g) => {
|
|
62
64
|
const imageNums = [];
|
|
63
65
|
const videoNums = [];
|
|
66
|
+
const audioNums = [];
|
|
64
67
|
for (const m of g.media) {
|
|
65
|
-
|
|
68
|
+
// ONE video counter across the edit source and reference clips. They are
|
|
69
|
+
// mutually exclusive in practice, and a shared counter means a mixed
|
|
70
|
+
// state degrades to wrong-but-unambiguous rather than two "Video 1"s.
|
|
71
|
+
if (m.mediaKind === 'video' && (g.kind === 'video' || g.kind === 'video-ref')) {
|
|
66
72
|
videoNum += 1;
|
|
67
73
|
videoNums.push(videoNum);
|
|
68
74
|
orderedVideoPaths.push(m.path);
|
|
69
75
|
}
|
|
76
|
+
else if (m.mediaKind === 'audio' && g.kind === 'audio-ref') {
|
|
77
|
+
audioNum += 1;
|
|
78
|
+
audioNums.push(audioNum);
|
|
79
|
+
orderedAudioPaths.push(m.path);
|
|
80
|
+
}
|
|
70
81
|
else if (m.mediaKind === 'image' && isFreeRefImageKind(g.kind)) {
|
|
71
82
|
imageNum += 1;
|
|
72
83
|
imageNums.push(imageNum);
|
|
@@ -74,7 +85,7 @@ export function composeReferences(rawPrompt, groups, opts = {}) {
|
|
|
74
85
|
}
|
|
75
86
|
// first-frame / last-frame media: not numbered, not in the free-ref pool.
|
|
76
87
|
}
|
|
77
|
-
return { ...g, imageNums, videoNums };
|
|
88
|
+
return { ...g, imageNums, videoNums, audioNums };
|
|
78
89
|
});
|
|
79
90
|
// ── 2. Inline-name token groups in the prompt body ──
|
|
80
91
|
// For each character/environment group whose token appears in the prompt, the
|
|
@@ -87,21 +98,40 @@ export function composeReferences(rawPrompt, groups, opts = {}) {
|
|
|
87
98
|
byNorm.set(normToken(g.token), g);
|
|
88
99
|
const seenFirst = new Set();
|
|
89
100
|
const matchedInPrompt = new Set();
|
|
101
|
+
// Every token that named nothing, recorded as authored and deduped by the
|
|
102
|
+
// same normalisation used for matching. This is what makes the deletion
|
|
103
|
+
// below reportable instead of silent — see ComposedReferences.unresolvedTokens.
|
|
104
|
+
const unresolvedTokens = [];
|
|
105
|
+
const unresolvedSeen = new Set();
|
|
106
|
+
const noteUnresolved = (sigil, tok) => {
|
|
107
|
+
const key = normToken(`${sigil}${tok}`);
|
|
108
|
+
if (unresolvedSeen.has(key))
|
|
109
|
+
return;
|
|
110
|
+
unresolvedSeen.add(key);
|
|
111
|
+
unresolvedTokens.push(`${sigil}${tok}`);
|
|
112
|
+
};
|
|
90
113
|
// First strip "in/with the style of #tag" phrases so the style reads as a
|
|
91
|
-
// clean trailing clause, not a dangling preposition (legacy cleanPrompt
|
|
92
|
-
|
|
114
|
+
// clean trailing clause, not a dangling preposition (legacy cleanPrompt
|
|
115
|
+
// behaviour). An UNRESOLVED token in that phrase is stripped too: leaving the
|
|
116
|
+
// preposition behind ("…a portrait in the style of") was the worse half of the
|
|
117
|
+
// silent edit — the tag vanished a step later anyway and the sentence was left
|
|
118
|
+
// broken. Stripped or not, the token is reported.
|
|
119
|
+
let body = rawPrompt.replace(/\s+(with|in)\s+the\s+style\s+of\s+([@#])([\w-]+)/gi, (_full, _prep, sigil, tok) => {
|
|
93
120
|
const g = byNorm.get(normToken(`${sigil}${tok}`));
|
|
94
121
|
if (g && g.kind === 'style') {
|
|
95
122
|
matchedInPrompt.add(normToken(`${sigil}${tok}`));
|
|
96
123
|
return '';
|
|
97
124
|
}
|
|
98
|
-
|
|
125
|
+
noteUnresolved(sigil, tok);
|
|
126
|
+
return '';
|
|
99
127
|
});
|
|
100
128
|
body = body.replace(/([@#])([\w-]+)/g, (_full, _sigil, tok) => {
|
|
101
129
|
const key = normToken(`${_sigil}${tok}`);
|
|
102
130
|
const g = byNorm.get(key);
|
|
103
131
|
if (!g) {
|
|
104
132
|
// Unresolved token. A #unknown vanishes; an @unknown humanizes to words.
|
|
133
|
+
// Both are edits the user never asked for, so both are reported.
|
|
134
|
+
noteUnresolved(_sigil, tok);
|
|
105
135
|
return _sigil === '#' ? '' : humanizeToken(tok);
|
|
106
136
|
}
|
|
107
137
|
matchedInPrompt.add(key);
|
|
@@ -128,14 +158,52 @@ export function composeReferences(rawPrompt, groups, opts = {}) {
|
|
|
128
158
|
topKeys.push(`${noun} ${joinNums(g.videoNums)} ${verb} the motion source.`);
|
|
129
159
|
}
|
|
130
160
|
}
|
|
131
|
-
//
|
|
161
|
+
// Reference clips ("Video 2 is a provided reference."). This line SURVIVES
|
|
162
|
+
// the 2026-08-10 cull of null-role key lines because it is not one: the
|
|
163
|
+
// "motion source" wording above belongs to the edit path alone, so a video
|
|
164
|
+
// attachment has two possible roles and the sentence says which. The pinned
|
|
165
|
+
// IMAGE line had no such contrast partner and was deleted (see step 3).
|
|
166
|
+
for (const g of numbered) {
|
|
167
|
+
if (g.kind === 'video-ref' && g.videoNums.length > 0) {
|
|
168
|
+
const noun = g.videoNums.length === 1 ? 'Video' : 'Videos';
|
|
169
|
+
const tail = g.videoNums.length === 1 ? 'is a provided reference.' : 'are provided references.';
|
|
170
|
+
topKeys.push(`${noun} ${joinNums(g.videoNums)} ${tail}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Reference audio ("Audio 1 is a provided reference.").
|
|
132
174
|
for (const g of numbered) {
|
|
133
|
-
if (g.kind === '
|
|
134
|
-
const noun = g.
|
|
135
|
-
const tail = g.
|
|
136
|
-
topKeys.push(`${noun} ${joinNums(g.
|
|
175
|
+
if (g.kind === 'audio-ref' && g.audioNums.length > 0) {
|
|
176
|
+
const noun = g.audioNums.length === 1 ? 'Audio' : 'Audios';
|
|
177
|
+
const tail = g.audioNums.length === 1 ? 'is a provided reference.' : 'are provided references.';
|
|
178
|
+
topKeys.push(`${noun} ${joinNums(g.audioNums)} ${tail}`);
|
|
137
179
|
}
|
|
138
180
|
}
|
|
181
|
+
// 🚨 A PINNED REFERENCE IMAGE GETS NO KEY LINE, DELIBERATELY (2026-08-10).
|
|
182
|
+
// It used to emit "Image 1 is a provided reference." — the only branch here
|
|
183
|
+
// that assigns NO role, and therefore says nothing: every image in the request
|
|
184
|
+
// IS a provided reference, so the sentence restated the transport. Its
|
|
185
|
+
// siblings all carry information — "is the motion source" contrasts with a
|
|
186
|
+
// reference clip, "is the subject" / "is Marcus" name the thing, the style
|
|
187
|
+
// clause assigns a job. This one was the null member of that set, and unlike
|
|
188
|
+
// video there is no competing numbered image role for it to disambiguate
|
|
189
|
+
// against (frames ride dedicated slots and are never numbered).
|
|
190
|
+
//
|
|
191
|
+
// It was also actively wrong for the case pinned-first exists to serve: the
|
|
192
|
+
// desktop's `referenceGroups.ts` orders these images FIRST for the
|
|
193
|
+
// edit/injection case (the movie still you paint over reads as image 1) —
|
|
194
|
+
// where image 1 is the CANVAS, not a reference, and the line asserted the
|
|
195
|
+
// opposite.
|
|
196
|
+
//
|
|
197
|
+
// Every vendor assigns roles inline in natural language instead. Google's own
|
|
198
|
+
// multi-reference example is "the attached napkin sketch as the structure and
|
|
199
|
+
// the attached fabric sample as the texture"; ByteDance's is "use @Image 2 as
|
|
200
|
+
// the dormitory scene style reference". Nobody declares a null role. Our own
|
|
201
|
+
// skills say the same thing: "the model does NOT infer a reference's role from
|
|
202
|
+
// its position; the NAME carries it" — and this line had no name to carry.
|
|
203
|
+
//
|
|
204
|
+
// Do not add it back. Attaching an image already means "here is an image"; if
|
|
205
|
+
// a reference needs a role, it gets one from a role badge or from the user's
|
|
206
|
+
// own words, both of which compose into real sentences above.
|
|
139
207
|
// Token-less or not-in-prompt subjects/environments ("Image 1 is Marcus.").
|
|
140
208
|
for (const g of numbered) {
|
|
141
209
|
if ((g.kind === 'character' || g.kind === 'environment') && g.imageNums.length > 0) {
|
|
@@ -169,6 +237,8 @@ export function composeReferences(rawPrompt, groups, opts = {}) {
|
|
|
169
237
|
prompt: parts.join('\n\n'),
|
|
170
238
|
orderedImagePaths,
|
|
171
239
|
orderedVideoPaths,
|
|
240
|
+
orderedAudioPaths,
|
|
241
|
+
unresolvedTokens,
|
|
172
242
|
};
|
|
173
243
|
}
|
|
174
244
|
/** fal cap: max 4 combined element + style-image references per edit request. */
|