@slatesvideo/shared 0.4.1 → 0.4.3
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/operations/index.d.ts +22 -3
- package/dist/operations/index.js +86 -19
- package/dist/prompts/content-policy.d.ts +31 -0
- package/dist/prompts/content-policy.js +108 -0
- package/dist/prompts/index.d.ts +2 -0
- package/dist/prompts/index.js +2 -0
- package/dist/prompts/reference-composer.d.ts +46 -0
- package/dist/prompts/reference-composer.js +175 -0
- package/dist/prompts/reference-rules.d.ts +1 -1
- package/dist/prompts/reference-rules.js +5 -5
- package/dist/skills/content.js +10 -8
- package/package.json +64 -59
- package/skills/slates-character-turnaround.md +2 -2
- package/skills/slates-content-policy.md +55 -0
- package/skills/slates-cost-discipline.md +8 -0
- package/skills/slates-one-prompt-film.md +1 -1
- package/skills/slates-project-organization.md +22 -0
- package/skills/slates-prompting-flux-2-max.md +4 -4
- package/skills/slates-prompting-kling-v3.md +2 -2
- package/skills/slates-prompting-nano-banana-2.md +4 -12
- package/skills/slates-prompting-seedance.md +17 -4
- package/skills/slates-prompting-veo-3.md +2 -2
|
@@ -93,6 +93,19 @@ export declare const createEnvironment: Operation<{
|
|
|
93
93
|
description?: string;
|
|
94
94
|
style?: string;
|
|
95
95
|
}>;
|
|
96
|
+
export declare const generateCharacterSheets: Operation<{
|
|
97
|
+
characterId: string;
|
|
98
|
+
projectId: string;
|
|
99
|
+
baseAssetId: string;
|
|
100
|
+
sheetTypes?: ('turnaround' | 'expression')[];
|
|
101
|
+
userNotes?: string;
|
|
102
|
+
}>;
|
|
103
|
+
export declare const generateEnvironmentPlate: Operation<{
|
|
104
|
+
environmentId: string;
|
|
105
|
+
projectId: string;
|
|
106
|
+
baseAssetId?: string;
|
|
107
|
+
userNotes?: string;
|
|
108
|
+
}>;
|
|
96
109
|
export declare const listStoryboards: Operation<{
|
|
97
110
|
projectId: string;
|
|
98
111
|
}>;
|
|
@@ -141,7 +154,7 @@ export declare const editImage: Operation<{
|
|
|
141
154
|
confirm?: boolean;
|
|
142
155
|
background?: boolean;
|
|
143
156
|
}>;
|
|
144
|
-
declare const VIDEO_MODELS: readonly ["kling-v3.0-std", "kling-v3.0-pro", "kling-v3.0-omni", "veo-3.1-fast", "veo-3.1-standard", "seedance-2
|
|
157
|
+
declare const VIDEO_MODELS: readonly ["kling-v3.0-std", "kling-v3.0-pro", "kling-v3.0-omni", "veo-3.1-fast", "veo-3.1-standard", "seedance-2"];
|
|
145
158
|
type VideoModel = (typeof VIDEO_MODELS)[number];
|
|
146
159
|
export declare const generateVideo: Operation<{
|
|
147
160
|
prompt: string;
|
|
@@ -149,14 +162,18 @@ export declare const generateVideo: Operation<{
|
|
|
149
162
|
projectId?: string;
|
|
150
163
|
aspectRatio?: '1:1' | '16:9' | '9:16' | '4:3' | '3:4' | '21:9' | '9:21' | '4:5' | '5:4' | '2:3' | '3:2';
|
|
151
164
|
duration?: number;
|
|
152
|
-
videoResolution?: '720p' | '1080p' | '4k';
|
|
153
|
-
seedanceSpeed?: 'economy' | 'priority';
|
|
165
|
+
videoResolution?: '480p' | '720p' | '1080p' | '4k';
|
|
154
166
|
firstFrameAssetId?: string;
|
|
155
167
|
lastFrameAssetId?: string;
|
|
156
168
|
ingredientAssetIds?: string[];
|
|
169
|
+
characterAssetIds?: string[];
|
|
170
|
+
environmentAssetIds?: string[];
|
|
171
|
+
styleAssetIds?: string[];
|
|
172
|
+
videoReferenceAssetId?: string;
|
|
157
173
|
sound?: boolean;
|
|
158
174
|
audioLanguage?: 'EN' | 'ZH' | 'JA' | 'KO' | 'ES';
|
|
159
175
|
generateMusic?: boolean;
|
|
176
|
+
seedanceFace?: boolean;
|
|
160
177
|
negativePrompt?: string;
|
|
161
178
|
background?: boolean;
|
|
162
179
|
confirm?: boolean;
|
|
@@ -172,6 +189,7 @@ export declare const generateLipSync: Operation<{
|
|
|
172
189
|
ttsSpeed?: number;
|
|
173
190
|
audioFilePath?: string;
|
|
174
191
|
avatarModel?: 'avatar-standard' | 'avatar-pro';
|
|
192
|
+
klingProvider?: 'fal' | 'kling';
|
|
175
193
|
background?: boolean;
|
|
176
194
|
confirm?: boolean;
|
|
177
195
|
}>;
|
|
@@ -182,6 +200,7 @@ export declare const generateMotionTransfer: Operation<{
|
|
|
182
200
|
motionModel?: 'kling-mc-std' | 'kling-mc-pro';
|
|
183
201
|
characterOrientation?: 'video' | 'image';
|
|
184
202
|
prompt?: string;
|
|
203
|
+
klingProvider?: 'fal' | 'kling';
|
|
185
204
|
background?: boolean;
|
|
186
205
|
confirm?: boolean;
|
|
187
206
|
}>;
|
package/dist/operations/index.js
CHANGED
|
@@ -372,6 +372,51 @@ export const createEnvironment = {
|
|
|
372
372
|
return ok(await ctx.desktop().post('/agent/environments', input));
|
|
373
373
|
},
|
|
374
374
|
};
|
|
375
|
+
export const generateCharacterSheets = {
|
|
376
|
+
id: 'slates_generate_character_sheets',
|
|
377
|
+
description: "Generate a character's turnaround sheet (4 neutral full-body angles — identity: body, proportions, outfit) AND expression sheet (close-up facial detail) from a base portrait asset, on Nano Banana 2 at 2K, and bind both to the character. THE real character-building workflow — call right after slates_create_character. baseAssetId is the source portrait (a project asset). Both sheets generate by default. Afterward, carry the character into a scene by passing its turnaround + expression asset ids as characterAssetIds to slates_generate_video (or referenceAssetIds to slates_generate_image) so identity stays consistent across shots. Cost ~$0.36 for both sheets.",
|
|
378
|
+
input: z.object({
|
|
379
|
+
characterId: z.string().uuid(),
|
|
380
|
+
projectId: z.string().uuid(),
|
|
381
|
+
baseAssetId: z.string().uuid().describe('The base portrait asset the sheets are generated from.'),
|
|
382
|
+
sheetTypes: z
|
|
383
|
+
.array(z.enum(['turnaround', 'expression']))
|
|
384
|
+
.optional()
|
|
385
|
+
.describe('Which sheets to generate. Default both.'),
|
|
386
|
+
userNotes: z.string().optional().describe('Extra instruction, e.g. "use the woman on the left".'),
|
|
387
|
+
}),
|
|
388
|
+
async run(input, ctx) {
|
|
389
|
+
return ok(await ctx.desktop().post('/agent/characters/generate-sheets', {
|
|
390
|
+
characterId: input.characterId,
|
|
391
|
+
projectId: input.projectId,
|
|
392
|
+
baseAssetIds: [input.baseAssetId],
|
|
393
|
+
sheetTypes: input.sheetTypes,
|
|
394
|
+
userNotes: input.userNotes,
|
|
395
|
+
}));
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
export const generateEnvironmentPlate = {
|
|
399
|
+
id: 'slates_generate_environment_plate',
|
|
400
|
+
description: "Generate an environment's single clean establishing plate (Nano Banana 2, 2K) from an optional base image, and bind it as the environment's reference. THE real environment-building workflow — call right after slates_create_environment. Afterward, pass the plate asset id as environmentAssetIds to slates_generate_video (or referenceAssetIds to slates_generate_image) so the location stays consistent across shots. Cost ~$0.18.",
|
|
401
|
+
input: z.object({
|
|
402
|
+
environmentId: z.string().uuid(),
|
|
403
|
+
projectId: z.string().uuid(),
|
|
404
|
+
baseAssetId: z
|
|
405
|
+
.string()
|
|
406
|
+
.uuid()
|
|
407
|
+
.optional()
|
|
408
|
+
.describe('Optional base image to establish from (e.g. a rough location shot).'),
|
|
409
|
+
userNotes: z.string().optional(),
|
|
410
|
+
}),
|
|
411
|
+
async run(input, ctx) {
|
|
412
|
+
return ok(await ctx.desktop().post('/agent/environments/generate-plate', {
|
|
413
|
+
environmentId: input.environmentId,
|
|
414
|
+
projectId: input.projectId,
|
|
415
|
+
baseAssetIds: input.baseAssetId ? [input.baseAssetId] : [],
|
|
416
|
+
userNotes: input.userNotes,
|
|
417
|
+
}));
|
|
418
|
+
},
|
|
419
|
+
};
|
|
375
420
|
// ── Storyboards ─────────────────────────────────────────────────
|
|
376
421
|
export const listStoryboards = {
|
|
377
422
|
id: 'slates_list_storyboards',
|
|
@@ -915,19 +960,16 @@ const VIDEO_MODELS = [
|
|
|
915
960
|
'kling-v3.0-omni',
|
|
916
961
|
'veo-3.1-fast',
|
|
917
962
|
'veo-3.1-standard',
|
|
918
|
-
'seedance-2
|
|
919
|
-
'seedance-2-std',
|
|
963
|
+
'seedance-2',
|
|
920
964
|
];
|
|
921
965
|
// Model → registry cost-key. Each provider's keys ship with their own
|
|
922
966
|
// shape (verified against /api/agent/models):
|
|
923
967
|
// Kling: kling-v3-{standard|pro|omni}-{N}s — note the user-facing
|
|
924
968
|
// model id `kling-v3.0-std` maps to registry key `kling-v3-standard`.
|
|
925
969
|
// Veo: veo-3.1-{fast|standard}[-4k]-{N}s[-audio]
|
|
926
|
-
// Seedance: seedance-2-{
|
|
927
|
-
//
|
|
928
|
-
//
|
|
929
|
-
// pre-flight quote understates a priority gen (the desktop charges the
|
|
930
|
-
// priority key regardless of what we quoted).
|
|
970
|
+
// Seedance: seedance-2-{res}-{N}s (BytePlus ModelArk, sole provider). The
|
|
971
|
+
// cost key encodes resolution (480p/720p/1080p/4k) — price scales with
|
|
972
|
+
// resolution, so the key MUST carry it or the pre-flight quote is wrong.
|
|
931
973
|
const KLING_TIER_MAP = {
|
|
932
974
|
'kling-v3.0-std': 'kling-v3-standard',
|
|
933
975
|
'kling-v3.0-pro': 'kling-v3-pro',
|
|
@@ -935,10 +977,12 @@ const KLING_TIER_MAP = {
|
|
|
935
977
|
};
|
|
936
978
|
function videoCostKey(input) {
|
|
937
979
|
if (input.model.startsWith('seedance')) {
|
|
938
|
-
// Mirrors seedanceCreditKey() in slate/src/shared/pricing.ts.
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
980
|
+
// Mirrors seedanceCreditKey() in slate/src/shared/pricing.ts (face × res × duration).
|
|
981
|
+
// Face route (AI-character face ref) bills the EvoLink relaxed rate (+10%) via
|
|
982
|
+
// the `-face-` key; faceless uses the cheaper BytePlus key.
|
|
983
|
+
const res = input.videoResolution ?? '1080p';
|
|
984
|
+
const face = input.seedanceFace ? '-face' : '';
|
|
985
|
+
return `${input.model}${face}-${res}-${input.duration}s`;
|
|
942
986
|
}
|
|
943
987
|
if (input.model.startsWith('veo')) {
|
|
944
988
|
const is4k = input.videoResolution === '4k';
|
|
@@ -972,21 +1016,25 @@ function promptingSkillFor(model) {
|
|
|
972
1016
|
}
|
|
973
1017
|
export const generateVideo = {
|
|
974
1018
|
id: 'slates_generate_video',
|
|
975
|
-
description: 'Generate video via Slates credits. REQUIRED before calling: read the slates-cost-discipline skill plus the per-model prompting skill (slates-prompting-seedance / slates-prompting-kling-v3 / slates-prompting-veo-3) — video models prompt very differently. projectId is REQUIRED for UI integration (the user sees a progress card and the asset lands in the project — without it the call fails). aspectRatio + duration are required (server returns requires_clarification when missing). Cost > $0.50 returns requires_confirm — pass confirm=true after explicit user OK. Veo locks to 16:9 and to 4/6/8s durations (4K only at 8s). Image-to-video via firstFrameAssetId. Frames-to-video via firstFrameAssetId + lastFrameAssetId (Veo / Seedance only). Ingredients via ingredientAssetIds (Kling Omni / Seedance). No skill files installed? Call slates_get_prompting_guide with the per-model guide (\'slates-prompting-veo-3\' / \'slates-prompting-kling-v3\' / \'slates-prompting-seedance\') and \'slates-cost-discipline\' before first use.',
|
|
1019
|
+
description: 'Generate video via Slates credits. REQUIRED before calling: read the slates-cost-discipline skill plus the per-model prompting skill (slates-prompting-seedance / slates-prompting-kling-v3 / slates-prompting-veo-3) — video models prompt very differently. Also read slates-content-policy when the scene involves conflict, creatures, crowds, destruction, weapons, or young characters (build it safe-by-construction so the filter doesn\'t reject or degrade it). projectId is REQUIRED for UI integration (the user sees a progress card and the asset lands in the project — without it the call fails). aspectRatio + duration are required (server returns requires_clarification when missing). Cost > $0.50 returns requires_confirm — pass confirm=true after explicit user OK. Veo locks to 16:9 and to 4/6/8s durations (4K only at 8s). Image-to-video via firstFrameAssetId. Frames-to-video via firstFrameAssetId + lastFrameAssetId (Veo / Seedance only). Ingredients via ingredientAssetIds (Kling Omni / Seedance). No skill files installed? Call slates_get_prompting_guide with the per-model guide (\'slates-prompting-veo-3\' / \'slates-prompting-kling-v3\' / \'slates-prompting-seedance\') and \'slates-cost-discipline\' before first use.',
|
|
976
1020
|
input: z.object({
|
|
977
1021
|
prompt: z.string().min(1).max(4000),
|
|
978
|
-
model: z.enum(VIDEO_MODELS).describe('Pick deliberately by capability AND cost. Kling V3.0 std = cheapest (no audio); pro = mid; omni = multi-char dialogue + audio. Veo 3.1 = top quality, locks 16:9, audio; fast vs standard. Seedance 2 = ByteDance, audio included,
|
|
1022
|
+
model: z.enum(VIDEO_MODELS).describe('Pick deliberately by capability AND cost. Kling V3.0 std = cheapest (no audio); pro = mid; omni = multi-char dialogue + audio. Veo 3.1 = top quality, locks 16:9, audio; fast vs standard. Seedance 2 = ByteDance (BytePlus), audio included, first+last frame + up to 9 reference images, full 480p–4K ladder (native 4K) via videoResolution. For exact per-call credit cost, call slates_estimate_generation_cost or slates_list_available_models — never quote prices from memory (they change).'),
|
|
979
1023
|
projectId: z.string().uuid().optional().describe('Save into this Slates project. Strongly recommended — the desktop UI shows a progress card live and the asset appears when complete.'),
|
|
980
1024
|
aspectRatio: z.enum(['1:1', '16:9', '9:16', '4:3', '3:4', '21:9', '9:21', '4:5', '5:4', '2:3', '3:2']).optional().describe('Veo locks to 16:9 — passing anything else will be ignored or fail. Kling/Seedance support all.'),
|
|
981
1025
|
duration: z.number().int().min(4).max(15).optional().describe('Seconds. Kling: 5-15. Veo: 4, 6, or 8 only (4K only at 8s). Seedance: 4-15. Default 5 if omitted but always be explicit (cost scales linearly).'),
|
|
982
|
-
videoResolution: z.enum(['720p', '1080p', '4k']).optional().describe('Veo
|
|
983
|
-
seedanceSpeed: z.enum(['economy', 'priority']).optional().describe('Seedance only. Economy via PiAPI (cheaper, slower). Priority via fal.ai (faster).'),
|
|
1026
|
+
videoResolution: z.enum(['480p', '720p', '1080p', '4k']).optional().describe('Veo + Seedance. Seedance: 480p/720p/1080p/4K (default 1080p; 4K is native, the most expensive). Veo: 720p/1080p same price, 4K more (8s only).'),
|
|
984
1027
|
firstFrameAssetId: z.string().uuid().optional().describe('Asset id from the project — used as the starting frame for image-to-video. Must already exist in the project.'),
|
|
985
1028
|
lastFrameAssetId: z.string().uuid().optional().describe('Asset id from the project — used as the ending frame. Veo and Seedance only. Pairs with firstFrameAssetId for guided transitions.'),
|
|
986
1029
|
ingredientAssetIds: z.array(z.string().uuid()).max(9).optional().describe('Asset ids used as visual reference / ingredients for Kling Omni or Seedance. Up to 9 (Seedance) or 4 (Kling).'),
|
|
1030
|
+
characterAssetIds: z.array(z.string().uuid()).optional().describe('Asset ids of character sheets — keeps a character consistent across the shot. From a Slates project.'),
|
|
1031
|
+
environmentAssetIds: z.array(z.string().uuid()).optional().describe('Asset ids of environment grids — keeps a location/setting consistent across the shot. From a Slates project.'),
|
|
1032
|
+
styleAssetIds: z.array(z.string().uuid()).optional().describe('Asset ids of style references — locks the visual style of the shot. From a Slates project.'),
|
|
1033
|
+
videoReferenceAssetId: z.string().uuid().optional().describe('Seedance ONLY: an existing VIDEO asset to use as a reference (edit / relocate an existing clip — Seedance ref-to-video). 2-15s. If the clip contains a human/AI character, pair with seedanceFace=true so it routes to the face-capable provider (the default Seedance route blocks people). Ignored by Kling/Veo.'),
|
|
987
1034
|
sound: z.boolean().optional().describe('Kling Omni / Veo / Seedance: enable audio generation. Default true.'),
|
|
988
1035
|
audioLanguage: z.enum(['EN', 'ZH', 'JA', 'KO', 'ES']).optional().describe('Kling Omni only — language for dialogue.'),
|
|
989
1036
|
generateMusic: z.boolean().optional().describe('Kling Omni only — auto-generate background music.'),
|
|
1037
|
+
seedanceFace: z.boolean().optional().describe('Seedance ONLY: set true when a reference/ingredient shows an AI-character\'s FACE. Faces are blocked on the default (cheaper) Seedance route, so this reroutes the gen to a face-capable provider and costs ~10% more (the cost key becomes seedance-2-face-*). Leave false/unset for faceless or object-only references. No effect on Kling/Veo. Real-person faces are not supported on any route.'),
|
|
990
1038
|
negativePrompt: z.string().optional(),
|
|
991
1039
|
background: z.boolean().optional().describe(BACKGROUND_DESCRIBE),
|
|
992
1040
|
confirm: z.boolean().optional().describe('Set true after explicit user OK to bypass the >$0.50 cost confirm gate (which fires for almost every video gen since they\'re expensive).'),
|
|
@@ -1044,7 +1092,7 @@ export const generateVideo = {
|
|
|
1044
1092
|
duration: input.duration,
|
|
1045
1093
|
videoResolution: input.videoResolution,
|
|
1046
1094
|
sound: input.sound,
|
|
1047
|
-
|
|
1095
|
+
seedanceFace: input.seedanceFace,
|
|
1048
1096
|
});
|
|
1049
1097
|
const entry = registry.models.find((m) => m.model === costKey);
|
|
1050
1098
|
if (!entry) {
|
|
@@ -1070,6 +1118,15 @@ export const generateVideo = {
|
|
|
1070
1118
|
for (const id of input.ingredientAssetIds ?? []) {
|
|
1071
1119
|
referenceRefs.push({ id, type: 'image', role: 'ingredient' });
|
|
1072
1120
|
}
|
|
1121
|
+
for (const id of input.characterAssetIds ?? []) {
|
|
1122
|
+
referenceRefs.push({ id, type: 'image', role: 'character' });
|
|
1123
|
+
}
|
|
1124
|
+
for (const id of input.environmentAssetIds ?? []) {
|
|
1125
|
+
referenceRefs.push({ id, type: 'image', role: 'environment' });
|
|
1126
|
+
}
|
|
1127
|
+
for (const id of input.styleAssetIds ?? []) {
|
|
1128
|
+
referenceRefs.push({ id, type: 'image', role: 'style' });
|
|
1129
|
+
}
|
|
1073
1130
|
const hasReferences = referenceRefs.length > 0;
|
|
1074
1131
|
if ((totalCents > 50 || hasReferences) && !input.confirm) {
|
|
1075
1132
|
const previews = hasReferences ? await previewAssets(ctx, referenceRefs) : [];
|
|
@@ -1114,13 +1171,17 @@ export const generateVideo = {
|
|
|
1114
1171
|
aspectRatio: input.aspectRatio,
|
|
1115
1172
|
duration: input.duration,
|
|
1116
1173
|
videoResolution: input.videoResolution,
|
|
1117
|
-
seedanceSpeed: input.seedanceSpeed,
|
|
1118
1174
|
firstFrameAssetId: input.firstFrameAssetId,
|
|
1119
1175
|
lastFrameAssetId: input.lastFrameAssetId,
|
|
1120
1176
|
ingredientAssetIds: input.ingredientAssetIds ?? [],
|
|
1177
|
+
characterAssetIds: input.characterAssetIds ?? [],
|
|
1178
|
+
environmentAssetIds: input.environmentAssetIds ?? [],
|
|
1179
|
+
styleAssetIds: input.styleAssetIds ?? [],
|
|
1180
|
+
videoReferenceAssetId: input.videoReferenceAssetId,
|
|
1121
1181
|
sound: input.sound,
|
|
1122
1182
|
audioLanguage: input.audioLanguage,
|
|
1123
1183
|
generateMusic: input.generateMusic,
|
|
1184
|
+
seedanceFace: input.seedanceFace,
|
|
1124
1185
|
negativePrompt: input.negativePrompt,
|
|
1125
1186
|
background: input.background,
|
|
1126
1187
|
});
|
|
@@ -1170,6 +1231,7 @@ export const generateLipSync = {
|
|
|
1170
1231
|
ttsSpeed: z.number().min(0.5).max(2).optional().describe('TTS speech rate. Default 1.0. Range 0.5-2.0.'),
|
|
1171
1232
|
audioFilePath: z.string().optional().describe('Required when audioMethod=upload. Absolute path to the audio file on the user\'s machine (mp3, wav, m4a).'),
|
|
1172
1233
|
avatarModel: z.enum(['avatar-standard', 'avatar-pro']).optional().describe('Image-source only. avatar-standard ($0.42/5s) for general use. avatar-pro ($0.86/5s) for sharper face fidelity. Ignored when sourceType=video.'),
|
|
1234
|
+
klingProvider: z.enum(['fal', 'kling']).optional().describe('Provider routing for the Kling call. "fal" (default) uses Slates credits. "kling" uses the user\'s own BYOK Kling key if configured — omit unless the user explicitly wants BYOK.'),
|
|
1173
1235
|
background: z.boolean().optional().describe(BACKGROUND_DESCRIBE),
|
|
1174
1236
|
confirm: z.boolean().optional().describe('Set true to bypass the >$0.50 cost confirm gate. Required for avatar-pro.'),
|
|
1175
1237
|
}),
|
|
@@ -1238,6 +1300,7 @@ export const generateLipSync = {
|
|
|
1238
1300
|
ttsSpeed: input.ttsSpeed,
|
|
1239
1301
|
audioFilePath: input.audioFilePath,
|
|
1240
1302
|
avatarModel: input.avatarModel,
|
|
1303
|
+
klingProvider: input.klingProvider,
|
|
1241
1304
|
estimatedCost: totalCents,
|
|
1242
1305
|
background: input.background,
|
|
1243
1306
|
});
|
|
@@ -1283,6 +1346,7 @@ export const generateMotionTransfer = {
|
|
|
1283
1346
|
motionModel: z.enum(['kling-mc-std', 'kling-mc-pro']).optional().describe('std ($0.95) for general motion. pro ($1.26) for cleaner anatomy + identity preservation. Default pro — pick std deliberately for cost savings.'),
|
|
1284
1347
|
characterOrientation: z.enum(['video', 'image']).optional().describe('"video" = use the source video\'s framing. "image" = use the target image\'s framing. Default video.'),
|
|
1285
1348
|
prompt: z.string().optional().describe('Optional refinement prompt. Read slates-prompting-motion-transfer for guidance.'),
|
|
1349
|
+
klingProvider: z.enum(['fal', 'kling']).optional().describe('Provider routing for the Kling call. "fal" (default) uses Slates credits. "kling" uses the user\'s own BYOK Kling key if configured — omit unless the user explicitly wants BYOK.'),
|
|
1286
1350
|
background: z.boolean().optional().describe(BACKGROUND_DESCRIBE),
|
|
1287
1351
|
confirm: z.boolean().optional().describe('Set true to bypass the >$0.50 confirm gate. Required — both tiers exceed.'),
|
|
1288
1352
|
}),
|
|
@@ -1329,6 +1393,7 @@ export const generateMotionTransfer = {
|
|
|
1329
1393
|
motionModel,
|
|
1330
1394
|
characterOrientation: input.characterOrientation ?? 'video',
|
|
1331
1395
|
prompt: input.prompt,
|
|
1396
|
+
klingProvider: input.klingProvider,
|
|
1332
1397
|
estimatedCost: totalCents,
|
|
1333
1398
|
background: input.background,
|
|
1334
1399
|
});
|
|
@@ -1838,12 +1903,12 @@ function resolveGuideTopic(topic) {
|
|
|
1838
1903
|
}
|
|
1839
1904
|
export const getPromptingGuide = {
|
|
1840
1905
|
id: 'slates_get_prompting_guide',
|
|
1841
|
-
description: "Return the full markdown of a bundled Slates prompting/workflow guide. MCP-only clients (Claude Desktop, Smithery) don't get the CLI-installed skill files — call this instead. Accepts a guide name or a model id (e.g. 'veo-3.1-fast', 'kling-v3.0-pro', 'seedance-2
|
|
1906
|
+
description: "Return the full markdown of a bundled Slates prompting/workflow guide. MCP-only clients (Claude Desktop, Smithery) don't get the CLI-installed skill files — call this instead. Accepts a guide name or a model id (e.g. 'veo-3.1-fast', 'kling-v3.0-pro', 'seedance-2', 'nano-banana-2') which maps to the right guide. ALWAYS read 'slates-cost-discipline' plus the relevant model guide before your first generation in a session.",
|
|
1842
1907
|
input: z.object({
|
|
1843
1908
|
topic: z
|
|
1844
1909
|
.string()
|
|
1845
1910
|
.min(1)
|
|
1846
|
-
.describe('Guide name or model id. Guides: slates-cost-discipline, slates-prompting-nano-banana-2, slates-prompting-veo-3, slates-prompting-kling-v3, slates-prompting-seedance, slates-prompting-lip-sync, slates-prompting-motion-transfer, slates-prompting-flux-2-max, slates-prompting-seedream-5-lite, slates-edit-and-iterate, slates-vision-feedback-loop, slates-character-turnaround, slates-storyboard-from-script, slates-direct-response-ad, slates-one-prompt-film'),
|
|
1911
|
+
.describe('Guide name or model id. Guides: slates-cost-discipline, slates-content-policy, slates-prompting-nano-banana-2, slates-prompting-veo-3, slates-prompting-kling-v3, slates-prompting-seedance, slates-prompting-lip-sync, slates-prompting-motion-transfer, slates-prompting-flux-2-max, slates-prompting-seedream-5-lite, slates-edit-and-iterate, slates-vision-feedback-loop, slates-character-turnaround, slates-storyboard-from-script, slates-direct-response-ad, slates-one-prompt-film'),
|
|
1847
1912
|
}),
|
|
1848
1913
|
async run(input) {
|
|
1849
1914
|
const resolved = resolveGuideTopic(input.topic);
|
|
@@ -1881,6 +1946,8 @@ export const ALL_OPERATIONS = [
|
|
|
1881
1946
|
setCharacterExpression,
|
|
1882
1947
|
listEnvironments,
|
|
1883
1948
|
createEnvironment,
|
|
1949
|
+
generateCharacterSheets,
|
|
1950
|
+
generateEnvironmentPlate,
|
|
1884
1951
|
listStoryboards,
|
|
1885
1952
|
createStoryboard,
|
|
1886
1953
|
getStoryboardWithFrames,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface SubstitutionRule {
|
|
2
|
+
/** The risky construction to avoid. */
|
|
3
|
+
avoid: string;
|
|
4
|
+
/** The safe-by-construction substitution that usually reads more cinematic. */
|
|
5
|
+
use: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The substitution table — the core craft move. When a scene drifts toward any
|
|
9
|
+
* `avoid`, re-stage it as the matching `use` before writing the prompt.
|
|
10
|
+
*/
|
|
11
|
+
export declare const CONTENT_POLICY_SUBSTITUTIONS: SubstitutionRule[];
|
|
12
|
+
/** The pre-flight checklist — run before delivering any risk-surface prompt. */
|
|
13
|
+
export declare const CONTENT_POLICY_PREFLIGHT: string[];
|
|
14
|
+
/** One-line summary used as a header in skills + the lead magnet. */
|
|
15
|
+
export declare const CONTENT_POLICY_HEADLINE = "Don't depict the harm \u2014 depict the energy, the aftermath, the threat, or the scale. Build the scene safe from the first word.";
|
|
16
|
+
/** The confirmed-safe envelope — pull a drifting scene back toward this shape. */
|
|
17
|
+
export declare const CONTENT_POLICY_SAFE_BENCHMARK = "One original creature, in a generalized monument or amphitheatre, in daylight, no weapons present, performing expressive action (rising, roaring, spreading wings). Original design, generalized location, daylight, expressive rather than violent \u2014 most epic ideas re-stage into this without losing the punch.";
|
|
18
|
+
/** The containment clause — keeps a scene in policy AND grounds its physics. */
|
|
19
|
+
export declare const CONTENT_POLICY_CONTAINMENT = "Give any creature or combat scene a containment rule (\"the fight STAYS at the sea surface\", \"boss scale locked ~2.5 human-heights, NOT kaiju-giant\", \"destruction stays in the evacuated valley\"). It improves coherence (no absurd escalation) AND keeps the scene inside policy \u2014 same clause buys both.";
|
|
20
|
+
/** The hard, non-negotiable rule on minors. Overrides every stylistic goal. */
|
|
21
|
+
export declare const CONTENT_POLICY_MINORS = "Never write romantic, sexual, or suggestive content involving or directed at minors, and never anything that sexualizes a young-presenting character. Any scene with children stays wholesome and age-appropriate. Non-negotiable.";
|
|
22
|
+
/**
|
|
23
|
+
* Canonical markdown block — the SOURCE OF TRUTH the skill markdown, the desktop
|
|
24
|
+
* inline mirror, and the lead-magnet are reconciled AGAINST. NOTE: nothing
|
|
25
|
+
* imports this yet — the desktop carries its own inline copy and the skills
|
|
26
|
+
* hand-author their prose, so a change here must be propagated to those copies
|
|
27
|
+
* in the same pass until the desktop-import + skill-embed wiring lands (see
|
|
28
|
+
* plans/2026-06-25-slates-prompting-system-overhaul.md).
|
|
29
|
+
*/
|
|
30
|
+
export declare const CONTENT_POLICY_TEXT: string;
|
|
31
|
+
//# sourceMappingURL=content-policy.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Content-policy-safe construction — the canonical "build the scene safe from
|
|
2
|
+
// the first word" knowledge for every Slates surface (desktop templates, MCP
|
|
3
|
+
// skills, the lead-magnet .skill). Authored ONCE here; consumers derive from it.
|
|
4
|
+
//
|
|
5
|
+
// The principle: don't depict the harm — depict the energy, the aftermath, the
|
|
6
|
+
// threat, or the scale. A standoff is more tense than a massacre; an evacuated
|
|
7
|
+
// city is eerier than a crowd in panic; a roar lands harder than a kill. The
|
|
8
|
+
// substitutions below usually read as MORE cinematic, not less, and they keep a
|
|
9
|
+
// generation from getting silently rejected or degraded by the model's filter.
|
|
10
|
+
//
|
|
11
|
+
// Source: second-brain business/projects/slates/content-strategy/lead-magnets/
|
|
12
|
+
// reference-content-policy.md. SSOT map: business/projects/slates/product/
|
|
13
|
+
// prompting-ssot.md.
|
|
14
|
+
/**
|
|
15
|
+
* The substitution table — the core craft move. When a scene drifts toward any
|
|
16
|
+
* `avoid`, re-stage it as the matching `use` before writing the prompt.
|
|
17
|
+
*/
|
|
18
|
+
export const CONTENT_POLICY_SUBSTITUTIONS = [
|
|
19
|
+
{
|
|
20
|
+
avoid: 'Civilians in panic, crowds fleeing under debris',
|
|
21
|
+
use: 'An evacuated / empty city; abandoned streets; a lone figure for scale',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
avoid: 'Weapons firing into buildings or at people',
|
|
25
|
+
use: 'Energy-discharge standoffs, searchlights sweeping, charged auras, shockwaves with no muzzle fire',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
avoid: 'Creatures tearing into each other, gore',
|
|
29
|
+
use: 'A grapple / standoff — roars, near-misses, circling, an energy clash; combat that stays contained (in/on the water, never lifting into the air)',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
avoid: 'Destruction with people in harm’s way',
|
|
33
|
+
use: 'Destruction in uninhabited terrain — glaciers, deserts, ruins, open sea, evacuated zones',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
avoid: 'Realistic guns as the focus',
|
|
37
|
+
use: 'Stylized / fantasy implements, weapons slung-not-fired, the weapon as silhouette or prop only',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
avoid: 'Blood, wounds, death',
|
|
41
|
+
use: 'Impact light, dust, debris, buckling and collapse, a silhouette dropping out of frame',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
avoid: 'Real, named public figures',
|
|
45
|
+
use: 'Original / anonymous characters',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
avoid: 'Real brand logos',
|
|
49
|
+
use: 'Original or generalized branding — except the user’s own product, which is the whole point of a brand film',
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
/** The pre-flight checklist — run before delivering any risk-surface prompt. */
|
|
53
|
+
export const CONTENT_POLICY_PREFLIGHT = [
|
|
54
|
+
'No civilians depicted in panic/harm; crowds are evacuated or absent.',
|
|
55
|
+
'No weapons firing at people/buildings; threat is energy / searchlight / silhouette.',
|
|
56
|
+
'No creature-on-creature or creature-on-person gore; combat is grapple / standoff / roar, contained.',
|
|
57
|
+
'Destruction is in uninhabited / evacuated terrain.',
|
|
58
|
+
'Creatures are original ("not based on any franchise"); no real public figures; no real brand logos except the user’s own product.',
|
|
59
|
+
'Anything with children is wholesome and age-appropriate.',
|
|
60
|
+
];
|
|
61
|
+
// ── Reusable text fragments (the template-assembly building blocks) ──
|
|
62
|
+
// The exact strings the desktop prompt templates, MCP skills, and lead-magnet
|
|
63
|
+
// compose. Change a rule HERE and every consumer follows.
|
|
64
|
+
/** One-line summary used as a header in skills + the lead magnet. */
|
|
65
|
+
export const CONTENT_POLICY_HEADLINE = "Don't depict the harm — depict the energy, the aftermath, the threat, or the scale. Build the scene safe from the first word.";
|
|
66
|
+
/** The confirmed-safe envelope — pull a drifting scene back toward this shape. */
|
|
67
|
+
export const CONTENT_POLICY_SAFE_BENCHMARK = 'One original creature, in a generalized monument or amphitheatre, in daylight, no weapons present, performing expressive action (rising, roaring, spreading wings). Original design, generalized location, daylight, expressive rather than violent — most epic ideas re-stage into this without losing the punch.';
|
|
68
|
+
/** The containment clause — keeps a scene in policy AND grounds its physics. */
|
|
69
|
+
export const CONTENT_POLICY_CONTAINMENT = 'Give any creature or combat scene a containment rule ("the fight STAYS at the sea surface", "boss scale locked ~2.5 human-heights, NOT kaiju-giant", "destruction stays in the evacuated valley"). It improves coherence (no absurd escalation) AND keeps the scene inside policy — same clause buys both.';
|
|
70
|
+
/** The hard, non-negotiable rule on minors. Overrides every stylistic goal. */
|
|
71
|
+
export const CONTENT_POLICY_MINORS = 'Never write romantic, sexual, or suggestive content involving or directed at minors, and never anything that sexualizes a young-presenting character. Any scene with children stays wholesome and age-appropriate. Non-negotiable.';
|
|
72
|
+
/**
|
|
73
|
+
* Canonical markdown block — the SOURCE OF TRUTH the skill markdown, the desktop
|
|
74
|
+
* inline mirror, and the lead-magnet are reconciled AGAINST. NOTE: nothing
|
|
75
|
+
* imports this yet — the desktop carries its own inline copy and the skills
|
|
76
|
+
* hand-author their prose, so a change here must be propagated to those copies
|
|
77
|
+
* in the same pass until the desktop-import + skill-embed wiring lands (see
|
|
78
|
+
* plans/2026-06-25-slates-prompting-system-overhaul.md).
|
|
79
|
+
*/
|
|
80
|
+
export const CONTENT_POLICY_TEXT = `## Content-policy-safe construction
|
|
81
|
+
|
|
82
|
+
${CONTENT_POLICY_HEADLINE}
|
|
83
|
+
|
|
84
|
+
Write scenes that hit full cinematic impact without ever *needing* to depict prohibited content. This is a craft move, not a compromise — the substitutions below usually read as more cinematic, not less, and they keep your generation from getting silently rejected or degraded by the model's filter. Load this whenever a prompt involves conflict, creatures, crowds, destruction, weapons, or young characters.
|
|
85
|
+
|
|
86
|
+
### Substitution table
|
|
87
|
+
|
|
88
|
+
| Avoid | Use instead |
|
|
89
|
+
|---|---|
|
|
90
|
+
${CONTENT_POLICY_SUBSTITUTIONS.map((s) => `| ${s.avoid} | ${s.use} |`).join('\n')}
|
|
91
|
+
|
|
92
|
+
### The safe benchmark
|
|
93
|
+
${CONTENT_POLICY_SAFE_BENCHMARK}
|
|
94
|
+
|
|
95
|
+
### Containment rule — it doubles as a physics win
|
|
96
|
+
${CONTENT_POLICY_CONTAINMENT}
|
|
97
|
+
|
|
98
|
+
### Scale and stakes without harm
|
|
99
|
+
Epic stakes come from environmental danger and reaction, not depicted victims: tiny figures diving clear of *collapsing* terrain (not being crushed), a war-horn over an *empty* field, an army *scrambling* across a frozen valley as a titan tears free of a glacier. The danger is the environment; the figures are reacting, not dying. Snow plumes, glowing runes, splintering ice, shockwaves, and dust carry the chaos.
|
|
100
|
+
|
|
101
|
+
### Minors — hard rule
|
|
102
|
+
${CONTENT_POLICY_MINORS}
|
|
103
|
+
|
|
104
|
+
### Pre-flight (run before delivering any risk-surface prompt)
|
|
105
|
+
${CONTENT_POLICY_PREFLIGHT.map((c) => `- [ ] ${c}`).join('\n')}
|
|
106
|
+
|
|
107
|
+
If a box fails, apply the substitution table before writing the prompt.`;
|
|
108
|
+
//# sourceMappingURL=content-policy.js.map
|
package/dist/prompts/index.d.ts
CHANGED
package/dist/prompts/index.js
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
// plan). So a change here must be applied to those copies in the same pass for
|
|
11
11
|
// now. SSOT map: second-brain business/projects/slates/product/prompting-ssot.md
|
|
12
12
|
export * from './reference-rules.js';
|
|
13
|
+
export * from './reference-composer.js';
|
|
14
|
+
export * from './content-policy.js';
|
|
13
15
|
export * from './style-library.js';
|
|
14
16
|
export * from './model-facts.js';
|
|
15
17
|
export * from './character-sheet.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export type ReferenceKind = 'character' | 'environment' | 'style' | 'pinned' | 'first-frame' | 'last-frame' | 'video';
|
|
2
|
+
export interface ReferenceMedia {
|
|
3
|
+
path: string;
|
|
4
|
+
mediaKind: 'image' | 'video';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A named bucket of reference media that can be @mentioned. The whole definition
|
|
8
|
+
* of a reference. It does NOT mandate a structure — one photo or eight angles,
|
|
9
|
+
* the composer treats them all as "this is one named thing".
|
|
10
|
+
*/
|
|
11
|
+
export interface ReferenceGroup {
|
|
12
|
+
/** '@Marcus' | '@Cafe' | '#noir' | null (pinned / frames / picked video) */
|
|
13
|
+
token: string | null;
|
|
14
|
+
/** Display + citation name: 'Marcus' | 'the cafe' | 'noir'. Used verbatim. */
|
|
15
|
+
name: string;
|
|
16
|
+
kind: ReferenceKind;
|
|
17
|
+
/** A group can carry several images (e.g. turnaround + expression). */
|
|
18
|
+
media: ReferenceMedia[];
|
|
19
|
+
}
|
|
20
|
+
export interface ComposedReferences {
|
|
21
|
+
/** The composed prompt: user's words lead, references cited inline as "image N". */
|
|
22
|
+
prompt: string;
|
|
23
|
+
/** Free-reference image paths in cited order — flatten yields "image 1..N". */
|
|
24
|
+
orderedImagePaths: string[];
|
|
25
|
+
/** Video reference paths in cited order — "video 1..M". */
|
|
26
|
+
orderedVideoPaths: string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compose the raw prompt (mentions intact) + an ORDERED list of reference groups
|
|
30
|
+
* into the named prompt text + ordered media the API receives. The group order
|
|
31
|
+
* IS the send order — image numbers are assigned by walking the list, so the
|
|
32
|
+
* caller controls numbering by ordering the list (default: pinned/base first,
|
|
33
|
+
* then @mentions in first-appearance order, then #style last).
|
|
34
|
+
*
|
|
35
|
+
* @param rawPrompt the user's prompt with @mentions / #tags still in it
|
|
36
|
+
* @param groups the single ordered ReferenceGroup[] (rail + prompt read this)
|
|
37
|
+
* @param opts.startImageNumber images already attached AHEAD of these groups
|
|
38
|
+
* (e.g. a grid-cell base that is "image 1" before the free-refs). Free-ref
|
|
39
|
+
* numbering and orderedImagePaths begin after it. Default 0.
|
|
40
|
+
*/
|
|
41
|
+
export interface ComposeOptions {
|
|
42
|
+
startImageNumber?: number;
|
|
43
|
+
startVideoNumber?: number;
|
|
44
|
+
}
|
|
45
|
+
export declare function composeReferences(rawPrompt: string, groups: ReferenceGroup[], opts?: ComposeOptions): ComposedReferences;
|
|
46
|
+
//# sourceMappingURL=reference-composer.d.ts.map
|