storyforge 0.4.1 → 0.4.2
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.js +157 -78
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -44,19 +44,19 @@ function loadCredentials() {
|
|
|
44
44
|
|
|
45
45
|
// src/utils/script-prompt.ts
|
|
46
46
|
var STYLE_GUIDES = {
|
|
47
|
-
"3blue1brown": 'Mathematical
|
|
48
|
-
coldfusion: `
|
|
49
|
-
educative: "
|
|
50
|
-
wendover: '
|
|
51
|
-
veritasium: "
|
|
52
|
-
custom: "
|
|
47
|
+
"3blue1brown": 'Mathematical intuition, progressive building, "but why?" framing. Each section earns the next.',
|
|
48
|
+
coldfusion: `Investigative story, real-world stakes, "here's what happened and why it matters" framing.`,
|
|
49
|
+
educative: "Engineering clarity, structured deep-dive, teaches one mechanism deeply rather than many shallowly.",
|
|
50
|
+
wendover: 'Systemic reasoning, "the surprising reason" hooks, physical-world analogies for abstract systems.',
|
|
51
|
+
veritasium: "Counter-intuitive setup, audience misconception as target, reveal as payoff.",
|
|
52
|
+
custom: "Retention-first documentary: one strong metaphor, open loops, mid-roll re-hooks, specific examples."
|
|
53
53
|
};
|
|
54
54
|
function styleGuideFor(style) {
|
|
55
55
|
return STYLE_GUIDES[style] ?? STYLE_GUIDES.custom;
|
|
56
56
|
}
|
|
57
57
|
function buildScriptPrompt(args) {
|
|
58
|
-
const minMin = args.targetMinutesMin ??
|
|
59
|
-
const maxMin = args.targetMinutesMax ??
|
|
58
|
+
const minMin = args.targetMinutesMin ?? 16;
|
|
59
|
+
const maxMin = args.targetMinutesMax ?? 24;
|
|
60
60
|
const tagline = (args.channelTagline ?? "Documentary-quality explainers").trim();
|
|
61
61
|
const handle = (args.channelHandle ?? "@channel").trim();
|
|
62
62
|
const channel = (args.channelName ?? "this channel").trim();
|
|
@@ -81,101 +81,180 @@ function buildScriptPrompt(args) {
|
|
|
81
81
|
]).map((s) => ` - "${s}"`).join("\n");
|
|
82
82
|
const referenceBlock = args.referenceScript ? `
|
|
83
83
|
|
|
84
|
-
===
|
|
84
|
+
=== ONE CRAFT SAMPLE (voice calibration ONLY \u2014 do NOT copy its structure) ===
|
|
85
85
|
|
|
86
|
-
${args.referenceScript.slice(0,
|
|
86
|
+
${args.referenceScript.slice(0, 8e3)}
|
|
87
87
|
|
|
88
|
-
=== END
|
|
88
|
+
=== END SAMPLE ===
|
|
89
89
|
|
|
90
|
-
The script
|
|
91
|
-
- Hook structure (pattern of historical examples \u2192 reversal \u2192 stakes \u2192 bet).
|
|
92
|
-
- Evidence density (named companies, specific numbers, dollar amounts, dates).
|
|
93
|
-
- Section pacing (varying section lengths from 2s teasers to 200s deep dives).
|
|
94
|
-
- Sentence rhythm (mix of long flowing sentences and 4-word punches).` : "";
|
|
90
|
+
Use this ONLY to calibrate the channel's voice \u2014 sentence rhythm, tolerance for technical detail, willingness to name real things. Do NOT copy its structure. If the sample opens with historical examples and this topic works better with a counter-intuitive question or a single unfolding metaphor, choose the format that serves the topic. The best script for THIS topic may look structurally different from the sample, and that's correct.` : "";
|
|
95
91
|
return `You are a senior documentary scriptwriter for ${channel} (${handle}). The channel's promise: "${tagline}".
|
|
96
92
|
|
|
97
|
-
|
|
93
|
+
Your job is to write a script that EARNS attention from second 0 to the end. Every single chunk must justify its existence by either building comprehension or holding attention \u2014 ideally both.
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
\
|
|
101
|
-
|
|
95
|
+
TOPIC: "${args.topic}"
|
|
96
|
+
STYLE: ${args.style} \u2014 ${args.styleGuide}
|
|
97
|
+
TARGET LENGTH: ${minMin}-${maxMin} minutes (write to the topic's natural length \u2014 pad nothing, rush nothing).
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
100
|
+
RETENTION PRINCIPLES (these govern every decision you make)
|
|
101
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
105
102
|
|
|
106
|
-
|
|
103
|
+
1. OPEN LOOP: In the first 30 seconds, plant a question or claim that
|
|
104
|
+
feels counter-intuitive, stakes-laden, or genuinely confusing. DON'T
|
|
105
|
+
answer it yet. Pay it off 70-85% through the video. The viewer stays
|
|
106
|
+
because you promised them something they haven't gotten yet.
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
2. MID-ROLL RE-HOOKS: Every 3-4 minutes, re-state the stakes for the
|
|
109
|
+
viewer who just tuned in or drifted. "Remember, what we're really
|
|
110
|
+
asking is..." \u2014 a sentence that pulls the viewer back into the core
|
|
111
|
+
question. You should have 3-5 of these naturally distributed.
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
113
|
+
3. ONE DOMINANT METAPHOR: Pick ONE concrete analogy before you start
|
|
114
|
+
writing. Thread it through every section. Every time the mechanism
|
|
115
|
+
gets technical, bend back to the metaphor to scaffold understanding.
|
|
116
|
+
DO NOT use 3 different analogies. DO NOT mix "a library + a
|
|
117
|
+
chef + a highway". One metaphor, strong commitment.
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
Pick your metaphor in a pre-planning step before you write chunk 1.
|
|
120
|
+
Good metaphor tests: (a) can a non-expert picture it in 2 seconds?
|
|
121
|
+
(b) does it survive at least 3 levels of zoom-in? (c) does it map to
|
|
122
|
+
\u22655 of the mechanism's key components?
|
|
119
123
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
- Cite a specific year or product version.
|
|
125
|
-
- Reference a specific event or product launch.
|
|
124
|
+
4. SPECIFICITY BEATS SCALE: One vivid example explained deeply is
|
|
125
|
+
worth five examples listed shallowly. If you're tempted to write
|
|
126
|
+
"companies like X, Y, and Z do this", STOP. Pick ONE and explain
|
|
127
|
+
HOW they do it, with a real outcome.
|
|
126
128
|
|
|
127
|
-
|
|
129
|
+
5. EVIDENCE DENSITY: Every paragraph must satisfy ONE of:
|
|
130
|
+
- A specific named company / lab / paper / person
|
|
131
|
+
- A specific number with units (dollars, ms, parameters, tokens, GB)
|
|
132
|
+
- A specific year or product version
|
|
133
|
+
- A specific event (launch, paper publication, failure)
|
|
134
|
+
If a paragraph can't satisfy one, REMOVE IT. Don't write filler.
|
|
128
135
|
|
|
129
|
-
|
|
130
|
-
|
|
136
|
+
6. VARIABLE PACING: Sections must have DIFFERENT lengths. Rhythm wins
|
|
137
|
+
retention. A 300s deep-dive should be followed by a 45s breath
|
|
138
|
+
(short callback chunk) before another long section. Do NOT write
|
|
139
|
+
uniform 120s body chunks.
|
|
140
|
+
|
|
141
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
142
|
+
FORBIDDEN PHRASES (zero of these)
|
|
143
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
131
144
|
${banList}
|
|
132
145
|
|
|
133
|
-
|
|
146
|
+
Plus: no rhetorical questions opening sections, no "let's explore",
|
|
147
|
+
no "in this video we'll look at", no generic "welcome back" openers.
|
|
134
148
|
|
|
135
|
-
|
|
136
|
-
\
|
|
137
|
-
|
|
138
|
-
* Hook: 90-150s
|
|
139
|
-
* Channel intro / cold-open: 2-5s
|
|
140
|
-
* Body sections: 100-220s each
|
|
141
|
-
* Conclusion: 90-180s
|
|
142
|
-
* CTA: 8-15s
|
|
143
|
-
* Next-video teaser: 20-40s
|
|
144
|
-
* End-screen: 8-15s
|
|
145
|
-
- Total duration: ${minMin}-${maxMin} minutes.
|
|
149
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
150
|
+
STRUCTURE (choose the format that serves THIS topic \u2014 do NOT default)
|
|
151
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
\
|
|
149
|
-
- Conversational but authoritative. Speak in declarative sentences.
|
|
150
|
-
- Mix sentence lengths: occasionally drop a 4-word sentence after a long one for rhythm.
|
|
151
|
-
- No exclamation marks.
|
|
152
|
-
- "And" / "But" / "Because" can start sentences.
|
|
153
|
-
- End each section with a sentence that creates forward pull.
|
|
153
|
+
You have multiple formats available. Pick the one this topic is best
|
|
154
|
+
suited to. Do NOT default to Tesla-style "history \u2192 bet \u2192 stakes".
|
|
154
155
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
A. COUNTER-INTUITIVE (Veritasium mode)
|
|
157
|
+
Hook with a wrong-sounding claim. Challenge viewer's intuition.
|
|
158
|
+
Reveal the actual mechanism piece by piece. Best for topics where
|
|
159
|
+
common sense gets it wrong.
|
|
160
|
+
|
|
161
|
+
B. SINGLE METAPHOR UNFOLDING (3Blue1Brown mode)
|
|
162
|
+
Start with the metaphor. Let the mechanism emerge by asking what
|
|
163
|
+
the metaphor predicts. Perfect for algorithmic/mathematical topics.
|
|
164
|
+
|
|
165
|
+
C. MYSTERY / INVESTIGATION (Wendover mode)
|
|
166
|
+
Anomaly observed. Why? Progressive theories. Final reveal. Best
|
|
167
|
+
for systems-level topics where the answer isn't obvious.
|
|
168
|
+
|
|
169
|
+
D. CHASE (ColdFusion mode)
|
|
170
|
+
Two competing approaches. Timeline unfolds. Winner not obvious
|
|
171
|
+
until late. Best for technology races and paradigm shifts.
|
|
172
|
+
|
|
173
|
+
E. ZOOM (Johnny Harris / Kurzgesagt mode)
|
|
174
|
+
Start zoomed-all-the-way-out (something universal, human-scale).
|
|
175
|
+
Progressive zoom-in to the specific mechanism. Zoom back out to
|
|
176
|
+
stakes. Best for topics that need emotional hooks.
|
|
177
|
+
|
|
178
|
+
Pick ONE format. Name it in the first chunk's meta.format field.
|
|
179
|
+
|
|
180
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
181
|
+
CHUNK STRUCTURE
|
|
182
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
158
183
|
|
|
159
|
-
|
|
160
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
161
|
-
Return ONLY a valid JSON array, no markdown fences, no commentary. Each chunk:
|
|
184
|
+
14-22 chunks. Vary durations by purpose:
|
|
162
185
|
|
|
186
|
+
- HOOK (1 chunk, 45-90s): plant the open loop. End with a forward-pull
|
|
187
|
+
sentence. Do NOT introduce yourself here; that's the cold-open.
|
|
188
|
+
- COLD OPEN (1 chunk, 2-5s): 1-2 sentences of channel intro.
|
|
189
|
+
Usually: "Welcome to <channel>, where we <what>. Let's go."
|
|
190
|
+
OR embedded in the hook \u2014 if so, skip this chunk entirely.
|
|
191
|
+
- BODY SECTIONS (4-8 chunks, varied 45-300s each):
|
|
192
|
+
* Long sections (180-300s) build the mechanism
|
|
193
|
+
* Short sections (45-90s) are breaths, callbacks, or reveals
|
|
194
|
+
* Each section either advances the metaphor, advances the
|
|
195
|
+
mechanism, or re-hooks
|
|
196
|
+
- PAYOFF (1 chunk, 90-180s): close the open loop. The viewer should
|
|
197
|
+
feel the "oh" moment here.
|
|
198
|
+
- REFRAME (1 chunk, 60-120s): don't summarize. Reframe what the
|
|
199
|
+
viewer now knows so they walk away with a changed mental model.
|
|
200
|
+
- CTA (1 chunk, 8-15s): specific ask with reasoning.
|
|
201
|
+
- NEXT-VIDEO TEASER (1 chunk, 20-40s): preview the next topic with
|
|
202
|
+
a single provocative claim (re-opens a new loop for next video).
|
|
203
|
+
- END-SCREEN (1 chunk, 8-15s).
|
|
204
|
+
|
|
205
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
206
|
+
PER-CHUNK FIELDS (output JSON \u2014 no extra commentary, no markdown)
|
|
207
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
208
|
+
|
|
209
|
+
[
|
|
163
210
|
{
|
|
164
|
-
"id": "c01-hook"
|
|
165
|
-
"title":
|
|
166
|
-
"narrationText":
|
|
167
|
-
"durationEstimate":
|
|
211
|
+
"id": "c01-hook" | "c05-mechanism-one" | "c12-payoff" (kebab-case, semantic),
|
|
212
|
+
"title": short Title-Case phrase,
|
|
213
|
+
"narrationText": narration body, multiple paragraphs split by blank lines,
|
|
214
|
+
"durationEstimate": integer seconds per the chunk structure above,
|
|
215
|
+
"purpose": one of: "hook" | "cold-open" | "mechanism" | "metaphor-extension" | "mid-roll-rehook" | "example" | "payoff" | "reframe" | "cta" | "teaser" | "end",
|
|
216
|
+
"metaphor": the single video-wide metaphor you chose (string, same value on every chunk),
|
|
217
|
+
"openLoopId": present on the chunk that plants a loop + on the chunk that pays it off. Same id links them.
|
|
218
|
+
"imagePromptHints": [
|
|
219
|
+
"3-5 teaching-oriented image prompts for THIS chunk. Each should illustrate the concept, not decorate it. Example (KV Cache): 'A chef mid-service at a high-end restaurant, every ingredient prepped and labeled in steel containers, hands reaching without looking \u2014 represents instant key-value lookup.' NOT 'glowing neural network nodes over dark background.' Write prompts that a cinematographer could use to teach a 12-year-old the concept."
|
|
220
|
+
]
|
|
168
221
|
}
|
|
222
|
+
]
|
|
223
|
+
|
|
224
|
+
On chunk 1 ONLY, add a meta field:
|
|
225
|
+
"format": "counter-intuitive" | "single-metaphor" | "mystery" | "chase" | "zoom"
|
|
226
|
+
"plannedMetaphor": the dominant metaphor you committed to
|
|
227
|
+
"plannedOpenLoop": the question/claim you planted in the hook
|
|
228
|
+
"plannedPayoffChunkId": id of the chunk where the loop closes
|
|
229
|
+
|
|
230
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
231
|
+
VOICE
|
|
232
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
233
|
+
|
|
234
|
+
Conversational but authoritative. Second person ("you") for stakes
|
|
235
|
+
and emotional pivots. Mix sentence lengths \u2014 occasionally drop a
|
|
236
|
+
4-word sentence after a long one. No exclamation marks. "And", "But",
|
|
237
|
+
"Because" can start sentences. Every section ends with forward pull.
|
|
238
|
+
|
|
239
|
+
STYLE CALIBRATION: ${args.style.toUpperCase()}
|
|
240
|
+
${args.styleGuide}
|
|
241
|
+
${referenceBlock}
|
|
169
242
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
\u25A1
|
|
174
|
-
\u25A1
|
|
175
|
-
\u25A1
|
|
176
|
-
\u25A1
|
|
243
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
244
|
+
CRITICAL CHECKLIST (review before you return)
|
|
245
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
246
|
+
\u25A1 ONE format chosen (not a mash-up). Named in chunk 1's meta.
|
|
247
|
+
\u25A1 ONE metaphor committed to and threaded through every section.
|
|
248
|
+
\u25A1 Open loop planted in the hook, paid off at 70-85% mark, reframed at end.
|
|
249
|
+
\u25A1 3-5 mid-roll re-hooks spaced through body sections.
|
|
250
|
+
\u25A1 Section durations VARY (not uniform). At least one 45-90s breath chunk.
|
|
251
|
+
\u25A1 Every chunk has \u22653 teaching-oriented imagePromptHints.
|
|
252
|
+
\u25A1 Every paragraph has specific evidence (name / number / year / event).
|
|
253
|
+
\u25A1 ZERO forbidden phrases anywhere.
|
|
254
|
+
\u25A1 Conclusion REFRAMES \u2014 does not summarize.
|
|
255
|
+
\u25A1 Total duration: ${minMin * 60}-${maxMin * 60} seconds.
|
|
177
256
|
|
|
178
|
-
|
|
257
|
+
Write the script now. Output ONLY the JSON array \u2014 no preamble, no code fences.`;
|
|
179
258
|
}
|
|
180
259
|
|
|
181
260
|
// src/commands/dev.ts
|