@slatesvideo/shared 0.5.2 → 0.5.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/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/operations/index.d.ts +24 -0
- package/dist/operations/index.js +67 -3
- package/dist/prompts/index.d.ts +1 -0
- package/dist/prompts/index.js +4 -0
- package/dist/prompts/prompting-tips.d.ts +23 -0
- package/dist/prompts/prompting-tips.js +345 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { SKILLS } from './skills/content.js';
|
|
|
5
5
|
export * as operations from './operations/index.js';
|
|
6
6
|
export { ALL_OPERATIONS, VIDEO_MODELS, defaultContext, type Operation, type OperationContext, type OperationResult } from './operations/index.js';
|
|
7
7
|
export { MODEL_FACTS, getModelFact, type ModelFact } from './prompts/model-facts.js';
|
|
8
|
+
export { PROMPTING_TIPS, getPromptingTips, type PromptingTipsEntry, type PromptingTipCard, type PromptingTipsKey } from './prompts/prompting-tips.js';
|
|
8
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,7 @@ export { ALL_OPERATIONS, VIDEO_MODELS, defaultContext } from './operations/index
|
|
|
8
8
|
// prompt derives its MODEL ROUTING doctrine from (kind: image vs video,
|
|
9
9
|
// default/premium/niche notes). Edit model-facts.ts, never prose copies.
|
|
10
10
|
export { MODEL_FACTS, getModelFact } from './prompts/model-facts.js';
|
|
11
|
+
// Per-model prompting tips — the SSOT for the desktop "See prompting tips"
|
|
12
|
+
// modals. The desktop renders these; it never hand-writes tips content.
|
|
13
|
+
export { PROMPTING_TIPS, getPromptingTips } from './prompts/prompting-tips.js';
|
|
11
14
|
//# sourceMappingURL=index.js.map
|
|
@@ -297,6 +297,30 @@ export declare const reorderClips: Operation<{
|
|
|
297
297
|
export declare const removeClip: Operation<{
|
|
298
298
|
clipId: string;
|
|
299
299
|
}>;
|
|
300
|
+
export declare const addTimelineTrack: Operation<{
|
|
301
|
+
projectId: string;
|
|
302
|
+
type?: 'video' | 'audio';
|
|
303
|
+
name?: string;
|
|
304
|
+
}>;
|
|
305
|
+
export declare const updateTimelineTrack: Operation<{
|
|
306
|
+
projectId: string;
|
|
307
|
+
trackId: string;
|
|
308
|
+
name?: string;
|
|
309
|
+
muted?: boolean;
|
|
310
|
+
locked?: boolean;
|
|
311
|
+
volume?: number;
|
|
312
|
+
}>;
|
|
313
|
+
export declare const removeTimelineTrack: Operation<{
|
|
314
|
+
projectId: string;
|
|
315
|
+
trackId: string;
|
|
316
|
+
}>;
|
|
317
|
+
export declare const updateTimelineSettings: Operation<{
|
|
318
|
+
projectId: string;
|
|
319
|
+
width?: number;
|
|
320
|
+
height?: number;
|
|
321
|
+
frameRate?: 24 | 30 | 60;
|
|
322
|
+
masterVolume?: number;
|
|
323
|
+
}>;
|
|
300
324
|
export declare const exportVideo: Operation<{
|
|
301
325
|
projectId?: string;
|
|
302
326
|
timelineId?: string;
|
package/dist/operations/index.js
CHANGED
|
@@ -2260,11 +2260,11 @@ export const getTimeline = {
|
|
|
2260
2260
|
};
|
|
2261
2261
|
export const addClipToTimeline = {
|
|
2262
2262
|
id: 'slates_add_clip_to_timeline',
|
|
2263
|
-
description: "Append a video asset from the project to the project's timeline (or place it at an explicit startFrame). Defaults match the desktop UI:
|
|
2263
|
+
description: "Append a video or audio asset from the project to the project's timeline (or place it at an explicit startFrame). Defaults match the desktop UI: video clips go to the end of the first video track; audio clips (music, voiceover, AI audio) go after the last clip on the first AUDIO track and are mixed under the video on export. An empty timeline auto-adopts the first video clip's resolution and frame rate; later higher-resolution clips raise the canvas. Overlapping video clips resolve top-track-wins. Optionally trim with sourceInFrame/sourceOutFrame (frames at the SOURCE fps). Use slates_get_timeline first to see current clips and pick positions.",
|
|
2264
2264
|
input: z.object({
|
|
2265
2265
|
projectId: z.string().uuid(),
|
|
2266
|
-
assetId: z.string().uuid().describe('Video asset already in the project.'),
|
|
2267
|
-
trackId: z.string().uuid().optional().describe('Target track. Default: the first
|
|
2266
|
+
assetId: z.string().uuid().describe('Video or audio asset already in the project.'),
|
|
2267
|
+
trackId: z.string().uuid().optional().describe('Target track (type must match the asset: video asset → video track, audio asset → audio track). Default: the first track of the matching type.'),
|
|
2268
2268
|
startFrame: z.number().int().min(0).optional().describe('Timeline frame to place the clip at. Default: append after the last clip.'),
|
|
2269
2269
|
sourceInFrame: z.number().int().min(0).optional(),
|
|
2270
2270
|
sourceOutFrame: z.number().int().min(1).optional(),
|
|
@@ -2315,6 +2315,66 @@ export const removeClip = {
|
|
|
2315
2315
|
return ok(await desktop.post('/agent/timeline/remove-clip', input));
|
|
2316
2316
|
},
|
|
2317
2317
|
};
|
|
2318
|
+
export const addTimelineTrack = {
|
|
2319
|
+
id: 'slates_add_timeline_track',
|
|
2320
|
+
description: "Add a track to the project's timeline (default: an audio track, for layering voiceover + music + AI audio). The new track is appended below existing tracks. Returns the new track and the full timeline.",
|
|
2321
|
+
input: z.object({
|
|
2322
|
+
projectId: z.string().uuid(),
|
|
2323
|
+
type: z.enum(['video', 'audio']).optional().describe('Default: audio.'),
|
|
2324
|
+
name: z.string().optional().describe("Default: 'Audio N' / 'Video N'."),
|
|
2325
|
+
}),
|
|
2326
|
+
async run(input, ctx) {
|
|
2327
|
+
const desktop = ctx.desktop();
|
|
2328
|
+
await desktop.requireCapability('timeline-tracks', 'timeline tracks + audio mixing');
|
|
2329
|
+
return ok(await desktop.post('/agent/timeline/add-track', input));
|
|
2330
|
+
},
|
|
2331
|
+
};
|
|
2332
|
+
export const updateTimelineTrack = {
|
|
2333
|
+
id: 'slates_update_timeline_track',
|
|
2334
|
+
description: 'Update a timeline track: rename, mute/unmute, lock/unlock, or set its volume fader (linear gain, -∞ to +12 dB). Track volume applies to both preview and MP4 export — audio-track clips are mixed at this gain; a muted video track still shows video but its embedded audio is silenced.',
|
|
2335
|
+
input: z.object({
|
|
2336
|
+
projectId: z.string().uuid(),
|
|
2337
|
+
trackId: z.string().uuid(),
|
|
2338
|
+
name: z.string().optional(),
|
|
2339
|
+
muted: z.boolean().optional(),
|
|
2340
|
+
locked: z.boolean().optional(),
|
|
2341
|
+
volume: z.number().min(0).max(4).optional().describe('Track fader as LINEAR gain: 0 = -∞ (silent), 1 = 0 dB (unity), ~3.98 = +12 dB (max boost).'),
|
|
2342
|
+
}),
|
|
2343
|
+
async run(input, ctx) {
|
|
2344
|
+
const desktop = ctx.desktop();
|
|
2345
|
+
await desktop.requireCapability('timeline-tracks', 'timeline tracks + audio mixing');
|
|
2346
|
+
return ok(await desktop.post('/agent/timeline/update-track', input));
|
|
2347
|
+
},
|
|
2348
|
+
};
|
|
2349
|
+
export const removeTimelineTrack = {
|
|
2350
|
+
id: 'slates_remove_timeline_track',
|
|
2351
|
+
description: 'Remove an EMPTY timeline track (fails if it still has clips, or if it is the last track of its type).',
|
|
2352
|
+
input: z.object({
|
|
2353
|
+
projectId: z.string().uuid(),
|
|
2354
|
+
trackId: z.string().uuid(),
|
|
2355
|
+
}),
|
|
2356
|
+
async run(input, ctx) {
|
|
2357
|
+
const desktop = ctx.desktop();
|
|
2358
|
+
await desktop.requireCapability('timeline-tracks', 'timeline tracks + audio mixing');
|
|
2359
|
+
return ok(await desktop.post('/agent/timeline/remove-track', input));
|
|
2360
|
+
},
|
|
2361
|
+
};
|
|
2362
|
+
export const updateTimelineSettings = {
|
|
2363
|
+
id: 'slates_update_timeline_settings',
|
|
2364
|
+
description: "Update the project timeline's output settings: resolution, frame rate (24/30/60 — all clips are conformed to it on export), and masterVolume, the output fader (linear gain, -∞ to +12 dB) applied to the final mix in both preview and MP4 export (use it to prevent clipping when stacking loud tracks). Note these are normally auto-managed: the first video clip sets fps + resolution, and higher-res clips raise the canvas. Changing frameRate after clips are placed retimes them — avoid unless the timeline is empty.",
|
|
2365
|
+
input: z.object({
|
|
2366
|
+
projectId: z.string().uuid(),
|
|
2367
|
+
width: z.number().int().min(16).optional(),
|
|
2368
|
+
height: z.number().int().min(16).optional(),
|
|
2369
|
+
frameRate: z.union([z.literal(24), z.literal(30), z.literal(60)]).optional(),
|
|
2370
|
+
masterVolume: z.number().min(0).max(4).optional().describe('Output fader as LINEAR gain: 0 = -∞ (silent), 1 = 0 dB (unity), ~3.98 = +12 dB (max boost).'),
|
|
2371
|
+
}),
|
|
2372
|
+
async run(input, ctx) {
|
|
2373
|
+
const desktop = ctx.desktop();
|
|
2374
|
+
await desktop.requireCapability('timeline-tracks', 'timeline tracks + audio mixing');
|
|
2375
|
+
return ok(await desktop.post('/agent/timeline/update-settings', input));
|
|
2376
|
+
},
|
|
2377
|
+
};
|
|
2318
2378
|
// ── Export ──────────────────────────────────────────────────────
|
|
2319
2379
|
const ABSOLUTE_PATH_RE = /^([A-Za-z]:[\\/]|\/)/;
|
|
2320
2380
|
export const exportVideo = {
|
|
@@ -2773,6 +2833,10 @@ export const ALL_OPERATIONS = [
|
|
|
2773
2833
|
addClipToTimeline,
|
|
2774
2834
|
reorderClips,
|
|
2775
2835
|
removeClip,
|
|
2836
|
+
addTimelineTrack,
|
|
2837
|
+
updateTimelineTrack,
|
|
2838
|
+
removeTimelineTrack,
|
|
2839
|
+
updateTimelineSettings,
|
|
2776
2840
|
exportVideo,
|
|
2777
2841
|
exportTimelineXml,
|
|
2778
2842
|
revealFile,
|
package/dist/prompts/index.d.ts
CHANGED
package/dist/prompts/index.js
CHANGED
|
@@ -16,4 +16,8 @@ export * from './style-library.js';
|
|
|
16
16
|
export * from './model-facts.js';
|
|
17
17
|
export * from './character-sheet.js';
|
|
18
18
|
export * from './environment-sheet.js';
|
|
19
|
+
// Exported from the `./prompts` subpath (not just the root barrel) because the
|
|
20
|
+
// desktop RENDERER imports the tips — the root barrel re-exports auth.js
|
|
21
|
+
// (node:fs/os/path), which breaks browser bundling. `./prompts` stays Node-free.
|
|
22
|
+
export * from './prompting-tips.js';
|
|
19
23
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface PromptingTipCard {
|
|
2
|
+
heading: string;
|
|
3
|
+
/** Monospace example line(s). \n renders as a line break. */
|
|
4
|
+
example?: string;
|
|
5
|
+
note: string;
|
|
6
|
+
/** Render highlighted as a critical/mandatory card. */
|
|
7
|
+
critical?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface PromptingTipsEntry {
|
|
10
|
+
/** Family label for the modal title ("Prompting Tips — {label}"). */
|
|
11
|
+
label: string;
|
|
12
|
+
/** Intro paragraphs above the cards. */
|
|
13
|
+
intro: string[];
|
|
14
|
+
/** Two columns of tip cards. */
|
|
15
|
+
columns: [PromptingTipCard[], PromptingTipCard[]];
|
|
16
|
+
/** Footer callout paragraphs. */
|
|
17
|
+
footer?: string[];
|
|
18
|
+
}
|
|
19
|
+
export type PromptingTipsKey = 'seedance' | 'kling' | 'kling-edit' | 'veo' | 'omni-flash' | 'omni-flash-edit' | 'nano-banana' | 'nano-banana-lite';
|
|
20
|
+
export declare const PROMPTING_TIPS: Record<PromptingTipsKey, PromptingTipsEntry>;
|
|
21
|
+
/** Null when no tips exist for the key — callers render an honest fallback. */
|
|
22
|
+
export declare function getPromptingTips(key: string): PromptingTipsEntry | null;
|
|
23
|
+
//# sourceMappingURL=prompting-tips.d.ts.map
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
// Per-model PROMPTING TIPS — the user-facing card content rendered by the
|
|
2
|
+
// desktop app's "See prompting tips" modals. SINGLE SOURCE OF TRUTH: this
|
|
3
|
+
// file. The desktop renders whatever this exports (no hand-written tips JSX
|
|
4
|
+
// in slate — that's how the Omni Flash / Veo / Kling chimera modal shipped).
|
|
5
|
+
//
|
|
6
|
+
// Relationship to the skills: packages/shared/skills/slates-prompting-*.md
|
|
7
|
+
// are the LONG-FORM agent guidance; these tips are the curated end-user
|
|
8
|
+
// subset of the same knowledge. When a skill's rules change, update the
|
|
9
|
+
// matching entry here in the same pass. Keys are model FAMILIES — the
|
|
10
|
+
// desktop maps concrete model ids to a family key with its MODEL_REGISTRY
|
|
11
|
+
// helpers (the runtime truth for ids lives in slate/src/shared/pricing.ts).
|
|
12
|
+
const SEEDANCE = {
|
|
13
|
+
label: 'Seedance 2.0',
|
|
14
|
+
intro: [
|
|
15
|
+
'Seedance 2.0 wants natural prose with narrative timing beats. Not shot brackets, not bullet points. Audio is always generated alongside video at no extra cost.',
|
|
16
|
+
"Follow ByteDance's official 6-step formula: Subject, Action, Environment, Camera, Style, Constraints. Sweet spot 60-150 words for single shots, longer for multi-shot.",
|
|
17
|
+
],
|
|
18
|
+
columns: [
|
|
19
|
+
[
|
|
20
|
+
{
|
|
21
|
+
heading: 'Pin the subject in the first sentence',
|
|
22
|
+
example: 'A matte black earbud case sits on a polished obsidian surface...',
|
|
23
|
+
note: "The first 20-30 words are the identity anchor. If the subject isn't locked in immediately, Seedance will hallucinate new subjects mid-generation.",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
heading: 'Narrative timing beats',
|
|
27
|
+
example: 'At 2 seconds, the camera begins a slow dolly forward. At 4 seconds, the lid opens in slow-motion...',
|
|
28
|
+
note: 'Use "At N seconds" — not SHOT brackets. 2 beats for a 5s clip, 3 for 10s, 4-5 for 15s.',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
heading: 'Lighting is the #1 quality lever',
|
|
32
|
+
example: 'A cool-white diagonal beam from upper left, dust particles drifting through...',
|
|
33
|
+
note: 'ByteDance says lighting has the biggest impact on quality of any prompt element. Describe it before or alongside the subject.',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
{
|
|
38
|
+
heading: '8 supported camera moves',
|
|
39
|
+
example: 'push-in · pull-out · pan · tracking · orbit · aerial · handheld · fixed',
|
|
40
|
+
note: 'Use these exact terms. "Dolly in" not "zoom in." "Orbit" not "circle." One primary camera move per beat — never stack them.',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
heading: 'Slow-motion works ("fast" doesn\'t)',
|
|
44
|
+
example: 'the lid opens in slow-motion · the blade whips through the air',
|
|
45
|
+
note: 'Speed ramps and slow-motion are supported in natural language. Avoid the word "fast" — it\'s ByteDance\'s #1 quality-degrading keyword.',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
heading: 'Separate camera from subject motion',
|
|
49
|
+
example: 'The earbud rises smoothly. The camera tracks upward.',
|
|
50
|
+
note: 'Two different sentences. Mixing them ("the camera speed ramps as the earbud rises") is the #1 cause of shaky, glitchy output.',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
],
|
|
54
|
+
footer: [
|
|
55
|
+
'Style block at the end: one primary anchor plus 2-3 supporting details. End with "Single continuous take" if you want one shot with no cuts. Never write "no cut" or "seamless transition" — those aren\'t in the training vocabulary.',
|
|
56
|
+
'Multi-modal: up to 9 images + 1 video + audio refs. Reference in prompt with @character, @environment, @audio1. Max length: 4,000 characters.',
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
const KLING = {
|
|
60
|
+
label: 'Kling 3.0',
|
|
61
|
+
intro: [
|
|
62
|
+
'Kling 3.0 features native audio-visual co-generation with dialogue, sound effects, and music (Omni tier). Define your core subjects clearly at the beginning of the prompt and keep descriptions consistent across shots.',
|
|
63
|
+
],
|
|
64
|
+
columns: [
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
heading: 'Dialogue',
|
|
68
|
+
example: 'Character says, "exact words here"',
|
|
69
|
+
note: 'Use quotation marks for precise speech. Languages (Omni only): English, Chinese, Japanese, Korean, Spanish.',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
heading: 'Voice Quality',
|
|
73
|
+
example: 'with a trembling voice, "I\'m scared"',
|
|
74
|
+
note: "Describe emotional tone, pitch, or speaking style before the dialogue. No pronouns or synonyms after a character's first introduction — they cause voice drift.",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
heading: 'Sound Effects',
|
|
78
|
+
example: 'SFX: heavy boots on wet pavement, distant siren wailing',
|
|
79
|
+
note: 'Use the "SFX:" prefix, with physical-cause specificity — "SFX: footsteps" is too vague.',
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
heading: 'Multi-Character Dialogue (Omni)',
|
|
85
|
+
example: 'Alice says in English, "Hello!" Immediately, Bob replies in Spanish, "¡Hola!"',
|
|
86
|
+
note: 'The "Immediately" keyword makes lines back-to-back; without it Kling adds a natural conversational beat.',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
heading: 'Ambient Noise & Music',
|
|
90
|
+
example: 'Ambient noise: city traffic, birds chirping\nBackground music: tense orchestral strings',
|
|
91
|
+
note: 'Set the background soundscape and request specific music styles or moods.',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
heading: 'Multi-shot',
|
|
95
|
+
example: 'Shot 1: ... Shot 2: ...',
|
|
96
|
+
note: 'Max 6 cuts, 15s total. One primary action and ONE camera move per shot; describe the subject identically in every shot block.',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
],
|
|
100
|
+
footer: [
|
|
101
|
+
'Keep dialogue concise (under 10 seconds per line). Use the Language and Accent settings in Audio Controls to control speech characteristics.',
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
const KLING_EDIT = {
|
|
105
|
+
...KLING,
|
|
106
|
+
label: 'Kling O3 Edit',
|
|
107
|
+
columns: [
|
|
108
|
+
KLING.columns[0],
|
|
109
|
+
[
|
|
110
|
+
...KLING.columns[1],
|
|
111
|
+
{
|
|
112
|
+
heading: 'Video edit — name the change, keep the rest',
|
|
113
|
+
example: 'Replace the man in @Video1 with @Element1, keeping his walk cycle, the camera move, and the rain unchanged.',
|
|
114
|
+
note: '@Video1 is your clip; attached subject refs compile to @Element1..; style refs to @Image1.. (max 4 combined). One edit intent per pass — chain passes for compound changes. Original audio is preserved verbatim.',
|
|
115
|
+
critical: true,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
const VEO = {
|
|
121
|
+
label: 'Veo 3.1',
|
|
122
|
+
intro: [
|
|
123
|
+
'Veo 3.1 generates synchronized audio directly with video. Aspect ratio: 16:9 only (for 9:16 vertical, use Kling or Seedance). Native single-clip duration: 4, 6, or 8 seconds — longer durations require chaining clips via last-frame reuse.',
|
|
124
|
+
'Official Cloud formula: [Cinematography] + [Subject] + [Action] + [Context] + [Style & Ambiance]. Sweet spot ~50-150 words.',
|
|
125
|
+
],
|
|
126
|
+
columns: [
|
|
127
|
+
[
|
|
128
|
+
{
|
|
129
|
+
heading: 'Dialogue',
|
|
130
|
+
example: 'Character says, "exact words"',
|
|
131
|
+
note: 'Use quotation marks for exact speech. Keep voice direction terse: "says in a weary voice", "whispers", "shouts". 2-3 speakers max — sync degrades past that.',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
heading: 'Sound Effects — with cause',
|
|
135
|
+
example: 'SFX: thunder cracks in the distance',
|
|
136
|
+
note: 'Always specify direction or distance — "SFX: thunder" alone is too vague.',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
heading: 'Ambient is mandatory',
|
|
140
|
+
example: 'Soft office ambience. · Wind on the open ridge.',
|
|
141
|
+
note: 'Include an ambience line in every scene — without it the audio mix feels dead.',
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
{
|
|
146
|
+
heading: 'No subtitles — MANDATORY',
|
|
147
|
+
example: 'The founder says, "..." (no subtitles). Soft office ambience.',
|
|
148
|
+
note: 'Without (no subtitles) after every dialogue line, Veo bakes subtitle text into the video. This is genuinely critical and underspecified in most guides.',
|
|
149
|
+
critical: true,
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
heading: 'Cinematography vocabulary',
|
|
153
|
+
example: '85mm · shallow depth of field · Rembrandt lighting · dolly in · whip pan',
|
|
154
|
+
note: 'Veo responds to real lens, lighting, and camera-move terms — lead the prompt with them.',
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
],
|
|
158
|
+
footer: [
|
|
159
|
+
"First-frame + last-frame is Veo's strongest workflow. Generate a start frame, generate an end frame, then animate with both as anchors. Motion-Lock hack: keep ~60% of the same background pixels between start and end to prevent latent drift.",
|
|
160
|
+
'Keep dialogue under one natural breath — lines fit the 8s clip ceiling. Texture-realism phrases: fine skin pores, visible fabric weave, subtle contrast, no gloss or sharpening.',
|
|
161
|
+
],
|
|
162
|
+
};
|
|
163
|
+
const OMNI_FLASH = {
|
|
164
|
+
label: 'Gemini Omni Flash',
|
|
165
|
+
intro: [
|
|
166
|
+
'Gemini Omni Flash is the cheap 720p tier with native synced audio included — dialogue, SFX, and ambient generate WITH the video at no extra cost. 3-10s, 16:9 or 9:16. Text-to-video, one start frame, or up to 7 reference images. No last frame, no video/audio references.',
|
|
167
|
+
],
|
|
168
|
+
columns: [
|
|
169
|
+
[
|
|
170
|
+
{
|
|
171
|
+
heading: 'Structure like a shot brief',
|
|
172
|
+
example: 'subject + action + setting + camera + lighting + tone',
|
|
173
|
+
note: 'Descriptive prompts are fine for generation (the short-prompt rule is edit-only).',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
heading: 'Dialogue',
|
|
177
|
+
example: 'The barista says, "Your usual?"',
|
|
178
|
+
note: 'Audio is prompt-driven — there are no audio parameters. Dialogue in quotes.',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
heading: 'Sound in plain language',
|
|
182
|
+
example: 'rain patters on the tin roof · distant traffic hum',
|
|
183
|
+
note: 'Describe sounds directly in the prose — no SFX: prefix needed.',
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
[
|
|
187
|
+
{
|
|
188
|
+
heading: 'Name references inline',
|
|
189
|
+
example: 'Marcus (images 1 and 2) walks into the cafe...',
|
|
190
|
+
note: 'Up to 7 reference images merge into one list — refer to them by number in the prompt.',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
heading: 'Negatives as plain instructions',
|
|
194
|
+
example: 'Do not show text.',
|
|
195
|
+
note: 'No negative-prompt field — write what to avoid as a direct instruction.',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
heading: 'Know its seat',
|
|
199
|
+
note: 'Cheap drafts, iteration volume, and audio-in-one-gen at low cost. For hero shots, Kling 3.0 (general default) or Seedance 2.0 (premium/physics) still win.',
|
|
200
|
+
},
|
|
201
|
+
],
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
const OMNI_FLASH_EDIT = {
|
|
205
|
+
label: 'Omni Flash Edit',
|
|
206
|
+
intro: [
|
|
207
|
+
'Omni Flash Edit changes what the prompt names in an existing 3-10s clip, footage-synced — prop, effect, environment, and lighting swaps. Prompt + source clip only: no reference images (identity swaps that need refs → Kling O3 Edit). 720p output; voice editing unsupported.',
|
|
208
|
+
],
|
|
209
|
+
columns: [
|
|
210
|
+
[
|
|
211
|
+
{
|
|
212
|
+
heading: 'One short change — MANDATORY',
|
|
213
|
+
example: 'Small magical flames appear on his fingertips when he snaps his fingers, and vanish when he blows on them. Keep everything else the same.',
|
|
214
|
+
note: "Google's own doc: simple prompts work best; overly descriptive prompts cause unintended changes. Long \"keep every frame identical\" preambles make drift WORSE. One change, then the magic phrase.",
|
|
215
|
+
critical: true,
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
heading: 'Always end with the preservation phrase',
|
|
219
|
+
example: '...Keep everything else the same.',
|
|
220
|
+
note: 'The one documented preservation lever. Every edit prompt ends with it.',
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
heading: 'Never name objects as metaphors',
|
|
224
|
+
example: '❌ a candle-like flame → ✅ small magical flames on his fingertips',
|
|
225
|
+
note: '"Candle-like" renders a literal candle in his hand. Describe the effect itself.',
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
{
|
|
230
|
+
heading: 'No conditional timing cues',
|
|
231
|
+
example: '❌ ...appears WHEN he calls it, perches AS he walks',
|
|
232
|
+
note: "Beat-by-beat stage directions cued to moments in the footage hard-fail the request. Collapse to one continuous action; the model syncs it to the footage's own motion.",
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
heading: 'Frame effects as harmless VFX',
|
|
236
|
+
example: '❌ his fingertips catch fire → ✅ magical flames appear on his fingertips',
|
|
237
|
+
note: "Google's safety filter is strict about harm-to-person phrasing. Magical/harmless framing passes.",
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
heading: 'Expect a possible tail artifact',
|
|
241
|
+
note: "Occasional jitter or a doubled final speech beat in the last ~0.5s. Trim the tail on the timeline — don't burn a re-roll on it.",
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
],
|
|
245
|
+
footer: [
|
|
246
|
+
'Ship via segment-splice: edit only the seconds where the change happens (Trim / Split first), then splice back over the original on the timeline with the original audio underneath. Chain edits one change at a time — each edit saves as a new clip linked to its parent.',
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
const NANO_BANANA = {
|
|
250
|
+
label: 'Nano Banana 2',
|
|
251
|
+
intro: [
|
|
252
|
+
'Nano Banana 2 is a language model that outputs pixels. Brief it like a creative director, not like a Stable-Diffusion tag tool. The biggest realism lever: specificity that mimics how real photographers describe their work.',
|
|
253
|
+
"Google's 4 official rules: Be specific. Use positive framing (describe what you want, not what you don't). Control the camera with cinematic terms. Iterate conversationally.",
|
|
254
|
+
],
|
|
255
|
+
columns: [
|
|
256
|
+
[
|
|
257
|
+
{
|
|
258
|
+
heading: 'Cinematic prompt formula',
|
|
259
|
+
example: 'Film still from [Director] [genre]. Shot on [camera] with [lens]. [Subject + action]. [3-5 details]. [Lighting]. [Color palette]. [Film stock].',
|
|
260
|
+
note: 'Specific gear beats generic descriptors. "ARRI Alexa 65 with Panavision anamorphic" outperforms "cinematic camera."',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
heading: 'Named lenses + apertures',
|
|
264
|
+
example: '85mm f/1.4 · 135mm f/2.8 · 50mm f/1.2 · 35mm f/2 · Panavision anamorphic · 400mm telephoto',
|
|
265
|
+
note: '135mm f/2.8 is the cheat code for skin texture and intimate compression. Anamorphic for cinematic width + horizontal flares.',
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
heading: 'Named film stocks (one per prompt)',
|
|
269
|
+
example: 'Kodak Portra 400 · Fuji Velvia 50 · Ilford HP5 Plus · CineStill 800T',
|
|
270
|
+
note: 'Portra = natural skin warmth. Velvia = saturated landscape. HP5 = gritty B&W grain. CineStill 800T = tungsten night with halation. Never mix stocks.',
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
heading: 'Physics-based lighting',
|
|
274
|
+
example: 'Single key light at 45 degrees from upper left. Color temperature 4500K. Crisp catchlights in the eyes.',
|
|
275
|
+
note: 'Direction + Kelvin temp + named source. "Single key light at 10 o\'clock" beats "soft lighting" every time.',
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
heading: 'Imperfection vocabulary',
|
|
279
|
+
example: 'visible pores · peach fuzz · ISO noise · sweat beading · slight hyperpigmentation · unretouched raw photography',
|
|
280
|
+
note: 'Forces the model away from AI-clean skin. The default is too smooth — you have to ask for the imperfections that real photos have.',
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
[
|
|
284
|
+
{
|
|
285
|
+
heading: '❌ The anti-list — avoid these',
|
|
286
|
+
example: '8k · masterpiece · hyperrealistic · ultra-detailed · trending on ArtStation · perfect skin · flawless · airbrushed · cinematic (alone)',
|
|
287
|
+
note: 'Tag-soup phrases from the Stable-Diffusion era. Measured success ~60-70% with these vs ~95%+ with positive description. Always specify which cinema — director, lens, era, stock.',
|
|
288
|
+
critical: true,
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
heading: 'No negative-prompt field',
|
|
292
|
+
example: '✅ "empty street" not "no cars"\n✅ "without people, vehicles, or signage"\n❌ "not anime, not cartoon, not 3D"',
|
|
293
|
+
note: 'Reframe positively first. Use inline "without" / "free of" only when positive framing can\'t suppress the unwanted element.',
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
heading: 'Reference images — label every role',
|
|
297
|
+
example: 'Image 1: Character ref — facial features, body proportions\nImage 2: Environment ref — architecture, lighting\nImage 3: Style ref — mood, aesthetic',
|
|
298
|
+
note: "Up to 14 refs (10 object + 4 character — caps don't trade). The @ and # mention system labels these automatically. Start with 2-3 focused refs.",
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
heading: 'Common fixes',
|
|
302
|
+
example: 'Hands → "five fingers, natural proportions"\nText → quote-wrap "HEADLINE" + specify font\nLeft/right → "from the character\'s perspective"',
|
|
303
|
+
note: "Default left/right is the viewer's perspective. Surreal prompts trip uncanny valley — the model drags toward realism. For surrealism, lean hard into \"painted\" / \"illustrated\".",
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
heading: 'Resolution tactics',
|
|
307
|
+
example: '1k = drafts · 2k = hero · 4k = print/final',
|
|
308
|
+
note: 'Pick by need. 2K+ allocates more tokens to surface detail, so texture vocab (pores, fabric weave, grain) compounds at higher resolution.',
|
|
309
|
+
},
|
|
310
|
+
],
|
|
311
|
+
],
|
|
312
|
+
footer: [
|
|
313
|
+
'Boring vs Cinema. Boring: "Wide shot of man on dock looking at forest." Cinema: "Direct overhead drone shot on weathered dock. Single figure climbing up frame bottom. Boot prints leading toward shore. Pale winter light. Anamorphic flare. Desaturated blue/slate palette. Kodak Portra 400 grain. Map of threat."',
|
|
314
|
+
"3-strike rule. If three iterations on the same prompt haven't landed, stop. The slot machine doesn't converge — the prompt structure is wrong, not the seed.",
|
|
315
|
+
],
|
|
316
|
+
};
|
|
317
|
+
const NANO_BANANA_LITE = {
|
|
318
|
+
...NANO_BANANA,
|
|
319
|
+
label: 'Nano Banana 2 Lite',
|
|
320
|
+
columns: [
|
|
321
|
+
NANO_BANANA.columns[0],
|
|
322
|
+
NANO_BANANA.columns[1].map((card) => card.heading === 'Resolution tactics'
|
|
323
|
+
? {
|
|
324
|
+
heading: 'Resolution tactics',
|
|
325
|
+
example: '1k only on Lite',
|
|
326
|
+
note: 'Lite outputs 1K only — use it for iteration volume and drafts, then switch to Nano Banana 2 for 2K/4K finals.',
|
|
327
|
+
}
|
|
328
|
+
: card),
|
|
329
|
+
],
|
|
330
|
+
};
|
|
331
|
+
export const PROMPTING_TIPS = {
|
|
332
|
+
seedance: SEEDANCE,
|
|
333
|
+
kling: KLING,
|
|
334
|
+
'kling-edit': KLING_EDIT,
|
|
335
|
+
veo: VEO,
|
|
336
|
+
'omni-flash': OMNI_FLASH,
|
|
337
|
+
'omni-flash-edit': OMNI_FLASH_EDIT,
|
|
338
|
+
'nano-banana': NANO_BANANA,
|
|
339
|
+
'nano-banana-lite': NANO_BANANA_LITE,
|
|
340
|
+
};
|
|
341
|
+
/** Null when no tips exist for the key — callers render an honest fallback. */
|
|
342
|
+
export function getPromptingTips(key) {
|
|
343
|
+
return PROMPTING_TIPS[key] ?? null;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=prompting-tips.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slatesvideo/shared",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.3",
|
|
4
4
|
"description": "Shared operations layer for the Slates MCP server and CLI: auth, cloud/desktop clients, and the single tool surface both consume. Most users want @slatesvideo/mcp-server or @slatesvideo/cli instead.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|