@slatesvideo/shared 0.6.11 → 0.7.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.
Files changed (82) hide show
  1. package/dist/auth.js +2 -2
  2. package/dist/clients/cloud.js +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/manual/content.d.ts +1 -1
  6. package/dist/manual/content.js +1 -1
  7. package/dist/operations/index.d.ts +817 -16
  8. package/dist/operations/index.js +1410 -360
  9. package/dist/operations/surface.d.ts +3 -1
  10. package/dist/operations/surface.js +37 -10
  11. package/dist/prompts/ad-presets.d.ts +77 -0
  12. package/dist/prompts/ad-presets.js +43 -0
  13. package/dist/prompts/agent-doctrine.js +5 -4
  14. package/dist/prompts/banned-tokens.d.ts +4 -29
  15. package/dist/prompts/banned-tokens.js +29 -204
  16. package/dist/prompts/craft-cards.js +2 -2
  17. package/dist/prompts/generation-policy.d.ts +41 -0
  18. package/dist/prompts/generation-policy.js +53 -0
  19. package/dist/prompts/guide-retrieval.d.ts +9 -0
  20. package/dist/prompts/guide-retrieval.js +53 -0
  21. package/dist/prompts/index.d.ts +1 -0
  22. package/dist/prompts/index.js +1 -0
  23. package/dist/prompts/model-capabilities.d.ts +18 -1
  24. package/dist/prompts/model-capabilities.js +72 -19
  25. package/dist/prompts/model-facts.d.ts +34 -2
  26. package/dist/prompts/model-facts.js +66 -5
  27. package/dist/prompts/partials.generated.js +8 -2
  28. package/dist/prompts/prompting-tips.d.ts +1 -1
  29. package/dist/prompts/prompting-tips.js +61 -16
  30. package/dist/prompts/reference-composer.d.ts +2 -0
  31. package/dist/prompts/reference-composer.js +51 -50
  32. package/dist/prompts/script-document.d.ts +165 -0
  33. package/dist/prompts/script-document.js +11 -0
  34. package/dist/prompts/shot-grammar.d.ts +4 -4
  35. package/dist/prompts/shot-grammar.js +3 -3
  36. package/dist/prompts/shot-spec.d.ts +13 -0
  37. package/dist/prompts/shot-spec.js +23 -5
  38. package/dist/skills/content.js +26 -23
  39. package/exports/slates-chatgpt-images/generated/SKILL.md +107 -0
  40. package/exports/slates-chatgpt-images/generated/slates-chatgpt-images.skill +0 -0
  41. package/exports/slates-prompt-builder/generated/SKILL.md +1 -1
  42. package/exports/slates-prompt-builder/generated/reference-character.md +9 -1
  43. package/exports/slates-prompt-builder/generated/reference-kling.md +3 -3
  44. package/exports/slates-prompt-builder/generated/reference-nano-banana.md +22 -10
  45. package/exports/slates-prompt-builder/generated/reference-seedance.md +4 -4
  46. package/exports/slates-prompt-builder/generated/slates-prompt-builder-manifest.json +17 -17
  47. package/exports/slates-prompt-builder/generated/slates-prompt-builder.skill +0 -0
  48. package/package.json +10 -4
  49. package/skills/_partials/cinematic-card.md +8 -0
  50. package/skills/_partials/cinematic-routes-short.md +2 -0
  51. package/skills/_partials/cinematic-tips-short.md +2 -0
  52. package/skills/_partials/decision-log.md +1 -13
  53. package/skills/_partials/image-defaults.md +11 -0
  54. package/skills/_partials/lens-video-split.md +1 -0
  55. package/skills/_partials/reference-rules-core.md +1 -1
  56. package/skills/_partials/sheet-tool-defaults.md +6 -0
  57. package/skills/slates-character-identity.md +9 -1
  58. package/skills/slates-chatgpt-images.md +107 -0
  59. package/skills/slates-cinematic-look.md +237 -0
  60. package/skills/slates-cost-discipline.md +18 -12
  61. package/skills/slates-direct-response-ad.md +13 -53
  62. package/skills/slates-edit-and-iterate.md +1 -1
  63. package/skills/slates-model-selection.md +20 -14
  64. package/skills/slates-one-prompt-film.md +19 -77
  65. package/skills/slates-project-organization.md +7 -3
  66. package/skills/slates-prompting-flux-2-max.md +15 -4
  67. package/skills/slates-prompting-gpt-image-2-5.md +41 -28
  68. package/skills/slates-prompting-kling-v3.md +3 -3
  69. package/skills/slates-prompting-lip-sync.md +1 -1
  70. package/skills/slates-prompting-minimax-h3.md +30 -17
  71. package/skills/slates-prompting-motion-transfer.md +1 -1
  72. package/skills/slates-prompting-nano-banana-2.md +24 -11
  73. package/skills/slates-prompting-seedance-2-5.md +7 -6
  74. package/skills/slates-prompting-seedance.md +5 -5
  75. package/skills/slates-prompting-seedream-5-lite.md +14 -3
  76. package/skills/slates-prompting-veo-3.md +1 -1
  77. package/skills/slates-script-craft.md +45 -0
  78. package/skills/slates-shot-variety.md +11 -40
  79. package/skills/slates-storyboard-from-script.md +14 -66
  80. package/skills/slates-style-prompting.md +54 -54
  81. package/skills/slates-ugc-influencer-ad.md +32 -309
  82. package/skills/slates-vision-feedback-loop.md +2 -1
@@ -0,0 +1,165 @@
1
+ /** Script document wire contract. Spoken text has one home: the scene string. */
2
+ export interface Block {
3
+ id: string;
4
+ kind: 'paragraph' | 'heading' | 'direction';
5
+ start: number;
6
+ end: number;
7
+ /** Only non-spoken blocks own text here. Paragraph text lives in Scene.script. */
8
+ label?: string;
9
+ level?: number;
10
+ marks: Array<{
11
+ start: number;
12
+ end: number;
13
+ type: 'strong' | 'em';
14
+ }>;
15
+ }
16
+ export interface Scene {
17
+ id: string;
18
+ name: string;
19
+ script: string;
20
+ blocks: Block[];
21
+ }
22
+ export interface Shot {
23
+ id: string;
24
+ sceneId: string;
25
+ range: [number, number] | null;
26
+ label: string;
27
+ prompt: string;
28
+ speaker: string;
29
+ }
30
+ export interface Document {
31
+ storyboardId: string;
32
+ recovered?: boolean;
33
+ version: 1;
34
+ revision: number;
35
+ title: string;
36
+ scenes: Scene[];
37
+ shots: Shot[];
38
+ }
39
+ export interface DocumentEdit {
40
+ sceneId: string;
41
+ at: number;
42
+ removed: number;
43
+ text: string;
44
+ }
45
+ export interface DocumentWrite {
46
+ expectedRevision: number;
47
+ edits: DocumentEdit[];
48
+ structures?: Array<{
49
+ sceneId: string;
50
+ blocks: Block[];
51
+ }>;
52
+ move?: {
53
+ sceneId: string;
54
+ blockId: string;
55
+ delta: -1 | 1;
56
+ };
57
+ makeShots?: Array<SectionFragment & {
58
+ waitingShotId?: string;
59
+ }>;
60
+ restoreRevision?: number;
61
+ sceneAction?: {
62
+ kind: 'split';
63
+ sceneId: string;
64
+ at: number;
65
+ } | {
66
+ kind: 'merge';
67
+ sceneId: string;
68
+ };
69
+ }
70
+ export interface SectionFragment {
71
+ sceneId: string;
72
+ start: number;
73
+ end: number;
74
+ }
75
+ export interface Section {
76
+ id: string;
77
+ storyboardId: string;
78
+ parentId: string | null;
79
+ label: string;
80
+ tags: string[];
81
+ fragments: SectionFragment[];
82
+ activeAlternativeId: string | null;
83
+ locallyChanged: boolean;
84
+ sourceSectionId?: string | null;
85
+ sourceRevisionId?: string | null;
86
+ alternatives: Array<{
87
+ id: string;
88
+ label: string;
89
+ revisionId: string;
90
+ }>;
91
+ }
92
+ /** `rename` and `archive` act on the section, or on one alternative when
93
+ * alternativeId is given. Archiving a section keeps its words on the page. */
94
+ export interface SectionInput {
95
+ expectedRevision: number;
96
+ action: 'create' | 'alternative' | 'choose' | 'save' | 'reuse' | 'updateUses' | 'rename' | 'archive' | 'tags';
97
+ sectionId?: string;
98
+ alternativeId?: string;
99
+ parentId?: string;
100
+ label?: string;
101
+ tags?: string[];
102
+ fragments?: SectionFragment[];
103
+ target?: {
104
+ sceneId: string;
105
+ at: number;
106
+ expectedRevision: number;
107
+ };
108
+ uses?: Array<{
109
+ sectionId: string;
110
+ expectedRevision: number;
111
+ }>;
112
+ }
113
+ /** A proposed replacement for exact words. It moves with edits around it and
114
+ * applies only while those words are unchanged (`stale` says they are not).
115
+ * Suggesting never edits the document; accepting is one undoable write. */
116
+ export interface ScriptSuggestion {
117
+ id: string;
118
+ storyboardId: string;
119
+ sceneId: string;
120
+ start: number;
121
+ end: number;
122
+ original: string;
123
+ replacement: string;
124
+ note: string;
125
+ status: 'pending' | 'accepted' | 'dismissed';
126
+ stale: boolean;
127
+ baseRevision: number;
128
+ }
129
+ export interface SuggestionInput {
130
+ expectedRevision: number;
131
+ action: 'create' | 'accept' | 'dismiss';
132
+ suggestions?: Array<{
133
+ sceneId: string;
134
+ start: number;
135
+ end: number;
136
+ original: string;
137
+ replacement: string;
138
+ note?: string;
139
+ }>;
140
+ suggestionId?: string;
141
+ }
142
+ export interface VariationChoice {
143
+ sectionId: string;
144
+ alternativeId: string;
145
+ }
146
+ /** Enumerate only on demand; even a large Cartesian set costs one row of memory. */
147
+ export declare function variationCombinations(axes: VariationChoice[][], prefix?: VariationChoice[]): Generator<VariationChoice[]>;
148
+ export interface VariationInput {
149
+ expectedRevision: number;
150
+ name: string;
151
+ choices: VariationChoice[];
152
+ /** When present, this sequence replaces the arrangement: omission and repetition are deliberate. */
153
+ arrangement?: VariationChoice[];
154
+ itemOverrides?: Array<{
155
+ from: string;
156
+ to: string;
157
+ voice: 'keep' | 'replace';
158
+ }>;
159
+ assetOverrides?: Array<{
160
+ from: string;
161
+ to: string;
162
+ }>;
163
+ idempotencyKey?: string;
164
+ }
165
+ //# sourceMappingURL=script-document.d.ts.map
@@ -0,0 +1,11 @@
1
+ /** Enumerate only on demand; even a large Cartesian set costs one row of memory. */
2
+ export function* variationCombinations(axes, prefix = []) {
3
+ if (!axes.length) {
4
+ yield prefix;
5
+ return;
6
+ }
7
+ const [head, ...tail] = axes;
8
+ for (const choice of head)
9
+ yield* variationCombinations(tail, [...prefix, choice]);
10
+ }
11
+ //# sourceMappingURL=script-document.js.map
@@ -87,7 +87,7 @@ export interface SpeechRate {
87
87
  */
88
88
  export declare const SPEECH_RATE_QUERY: string;
89
89
  /** When the numbers below were last derived from the query above. */
90
- export declare const SPEECH_RATE_MEASURED_ON = "2026-09-04";
90
+ export declare const SPEECH_RATE_MEASURED_ON = "2026-09-30";
91
91
  /**
92
92
  * 🔑 THE REGISTER SPLIT IS REAL AND MEASURED, which is why there is no single
93
93
  * number. the performed, genre-acted reads run a median of 133 wpm;
@@ -102,8 +102,8 @@ export declare const SPEECH_RATE: {
102
102
  readonly segment: "speech_rate = 'performed'";
103
103
  };
104
104
  readonly conversational: {
105
- readonly wpm: 159;
106
- readonly n: 41;
105
+ readonly wpm: 153;
106
+ readonly n: 43;
107
107
  readonly segment: "speech_rate = 'conversational'";
108
108
  };
109
109
  readonly direct_response: {
@@ -119,7 +119,7 @@ export declare const SPEECH_RATE: {
119
119
  */
120
120
  readonly ceiling: {
121
121
  readonly wpm: 283;
122
- readonly n: 65;
122
+ readonly n: 67;
123
123
  readonly segment: "max over every marked row";
124
124
  };
125
125
  };
@@ -124,7 +124,7 @@ SELECT id, speech_rate, duration_seconds, transcript
124
124
  -- statistic: median per register; ceiling = max over every marked row
125
125
  `.trim();
126
126
  /** When the numbers below were last derived from the query above. */
127
- export const SPEECH_RATE_MEASURED_ON = '2026-09-04';
127
+ export const SPEECH_RATE_MEASURED_ON = '2026-09-30';
128
128
  /**
129
129
  * 🔑 THE REGISTER SPLIT IS REAL AND MEASURED, which is why there is no single
130
130
  * number. the performed, genre-acted reads run a median of 133 wpm;
@@ -134,7 +134,7 @@ export const SPEECH_RATE_MEASURED_ON = '2026-09-04';
134
134
  */
135
135
  export const SPEECH_RATE = {
136
136
  performed: { wpm: 133, n: 4, segment: "speech_rate = 'performed'" },
137
- conversational: { wpm: 159, n: 41, segment: "speech_rate = 'conversational'" },
137
+ conversational: { wpm: 153, n: 43, segment: "speech_rate = 'conversational'" },
138
138
  direct_response: { wpm: 169, n: 20, segment: "speech_rate = 'direct_response'" },
139
139
  /**
140
140
  * The fastest read in the whole corpus. **The fit check flags only ABOVE
@@ -142,7 +142,7 @@ export const SPEECH_RATE = {
142
142
  * 250, not p90: those are rates real ads actually hit, and flagging an
143
143
  * achievable read is exactly how a check gets ignored.
144
144
  */
145
- ceiling: { wpm: 283, n: 65, segment: 'max over every marked row' },
145
+ ceiling: { wpm: 283, n: 67, segment: 'max over every marked row' },
146
146
  };
147
147
  /**
148
148
  * The default register, and there is deliberately no picker for it.
@@ -122,6 +122,9 @@ export interface ShotSpec {
122
122
  * only thing that may number anything, and a stored "image 3" would be a
123
123
  * lie the moment a reference is added, removed or reordered. */
124
124
  prompt: string;
125
+ /** Custom bytes remain recoverable when script mode is selected. */
126
+ recipeMode?: 'script' | 'custom';
127
+ promptScriptLine?: string | null;
125
128
  model: string | null;
126
129
  /**
127
130
  * The model the PROMPT WAS AUTHORED FOR. Never auto-rewritten.
@@ -229,6 +232,16 @@ export type ScriptTextField = (typeof SCRIPT_TEXT_FIELDS)[number];
229
232
  * Dialogue is quoted so a model receives it as speech rather than as
230
233
  * description — the one piece of grammar this adds, and the reason it is not
231
234
  * just `join(' ')`.
235
+ *
236
+ * 🚨 A LINE IS SPEECH ONLY WHEN THE SHOT SAYS WHO SPEAKS OR HOW (2026-09-27).
237
+ * Since the Script page became one continuous text (2026-09-19, "cues stay
238
+ * words"), `line` holds whatever script text a Shot's range covers, and most
239
+ * of a script is action. Composing every speaker-less line as `A voice says
240
+ * "…"` told the video model that someone speaks the stage direction: an ad
241
+ * script broken into four Shots sent four of them (first-hour walk finding 15).
242
+ * Unlabelled text now goes in as written; a speaker (VO included) or a
243
+ * delivery note still makes it quoted speech. Mirrored byte-for-byte in both
244
+ * repos, and `check:composer-mirror` compares the two outputs.
232
245
  */
233
246
  export declare function scriptPromptBody(spec: Pick<ShotSpec, ScriptTextField>): string;
234
247
  /**
@@ -68,6 +68,16 @@ export const SCRIPT_TEXT_FIELDS = [
68
68
  * Dialogue is quoted so a model receives it as speech rather than as
69
69
  * description — the one piece of grammar this adds, and the reason it is not
70
70
  * just `join(' ')`.
71
+ *
72
+ * 🚨 A LINE IS SPEECH ONLY WHEN THE SHOT SAYS WHO SPEAKS OR HOW (2026-09-27).
73
+ * Since the Script page became one continuous text (2026-09-19, "cues stay
74
+ * words"), `line` holds whatever script text a Shot's range covers, and most
75
+ * of a script is action. Composing every speaker-less line as `A voice says
76
+ * "…"` told the video model that someone speaks the stage direction: an ad
77
+ * script broken into four Shots sent four of them (first-hour walk finding 15).
78
+ * Unlabelled text now goes in as written; a speaker (VO included) or a
79
+ * delivery note still makes it quoted speech. Mirrored byte-for-byte in both
80
+ * repos, and `check:composer-mirror` compares the two outputs.
71
81
  */
72
82
  export function scriptPromptBody(spec) {
73
83
  const clean = (v) => (v ?? '').trim();
@@ -87,10 +97,16 @@ export function scriptPromptBody(spec) {
87
97
  if (line) {
88
98
  const speaker = clean(spec.speaker);
89
99
  const delivery = clean(spec.delivery).replace(/^\(|\)$/g, '').trim();
90
- // "VO" is a screenplay abbreviation, not something to send to a model.
91
- const who = !speaker || speaker.toUpperCase() === 'VO' ? 'A voice' : speaker;
92
- const how = delivery ? `, ${delivery},` : '';
93
- parts.push(`${who} says${how} "${line}"`);
100
+ if (!speaker && !delivery) {
101
+ // Script text with no one named to speak it: sent as written.
102
+ parts.push(line);
103
+ }
104
+ else {
105
+ // "VO" is a screenplay abbreviation, not something to send to a model.
106
+ const who = !speaker || speaker.toUpperCase() === 'VO' ? 'A voice' : speaker;
107
+ const how = delivery ? `, ${delivery},` : '';
108
+ parts.push(`${who} says${how} "${line}"`);
109
+ }
94
110
  }
95
111
  return parts.join(' ');
96
112
  }
@@ -101,7 +117,7 @@ export function scriptPromptBody(spec) {
101
117
  * while the row plainly has a script in it.
102
118
  */
103
119
  export function effectivePrompt(spec) {
104
- const authored = spec.prompt.trim();
120
+ const authored = spec.recipeMode === 'script' ? '' : spec.prompt.trim();
105
121
  return authored || scriptPromptBody(spec);
106
122
  }
107
123
  /** An empty Shot: a prompt bar nobody has touched. Every reader starts here and
@@ -247,6 +263,8 @@ export function normalizeShotSpec(raw) {
247
263
  }
248
264
  const out = {
249
265
  prompt: typeof v.prompt === 'string' ? v.prompt : '',
266
+ ...(v.recipeMode === 'script' || v.recipeMode === 'custom' ? { recipeMode: v.recipeMode } : {}),
267
+ ...(typeof v.promptScriptLine === 'string' || v.promptScriptLine === null ? { promptScriptLine: v.promptScriptLine } : {}),
250
268
  model: str(v.model),
251
269
  authoredFor: str(v.authoredFor),
252
270
  params: readParams(v.params),