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.
Files changed (2) hide show
  1. package/dist/index.js +157 -78
  2. 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 rigor, progressive intuition building, "but why?" framing. Build from first principles.',
48
- coldfusion: `Story-driven narrative, industry context, "here's what happened" framing. Data points, company names, real-world impact.`,
49
- educative: "System design interview structure. Functional vs non-functional requirements, architecture, deep dives.",
50
- wendover: 'Real-world logistics framing. "The surprising reason" hooks. Ground abstract concepts in physical analogies.',
51
- veritasium: "Counterintuitive hook or common misconception. Hypothesis, evidence, reveal. Challenge assumptions.",
52
- custom: "Documentary-quality educational content. Clear structure, dense evidence, engaging narration."
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 ?? 18;
59
- const maxMin = args.targetMinutesMax ?? 25;
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
- === REFERENCE SCRIPT (match this density and craft) ===
84
+ === ONE CRAFT SAMPLE (voice calibration ONLY \u2014 do NOT copy its structure) ===
85
85
 
86
- ${args.referenceScript.slice(0, 12e3)}
86
+ ${args.referenceScript.slice(0, 8e3)}
87
87
 
88
- === END REFERENCE ===
88
+ === END SAMPLE ===
89
89
 
90
- The script you write must match the reference's:
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
- You write the kind of script that earns 25 minutes of someone's attention. The kind where every paragraph adds load-bearing information. The kind where one historical example replaces three paragraphs of generic exposition.
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
- YOUR TASK
100
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
101
- Write a narrated documentary-style script on this topic:
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
- TOPIC: "${args.topic}"
104
- STYLE: ${args.style} \u2014 ${args.styleGuide}
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
- The video target length is ${minMin}-${maxMin} minutes. Don't pad. If the topic legitimately needs less, write less; if it needs more, write more. Anemic length comes from anemic thinking \u2014 go deeper, not shorter.
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
- HOW THE HOOK WORKS (this is non-negotiable)
109
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
110
- The first chunk is the hook. It is NOT "Imagine a world where..." or "In today's fast-paced..." or any LLM-template opener. The hook follows this structure:
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
- 1. PATTERN (4-6 sentences): Open with 3-5 SPECIFIC historical examples that share a common pattern. Real companies. Real years. Real outcomes.
113
- 2. REVERSAL: Name the surprising counter-pattern that connects to the topic.
114
- 3. STAKES: One paragraph naming the specific cost / consequence / scale.
115
- 4. BET: Frame the topic as a bet between two competing approaches with concrete numbers.
116
- 5. PROMISE: One sentence promising what the viewer will see in the next ${minMin}+ minutes.
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
- The hook is typically 90-150 seconds. Do NOT aim for a uniform short hook.
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
- EVIDENCE RULES (every paragraph must satisfy at least one)
121
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
122
- - Name a specific company / lab / paper / person.
123
- - Include a specific number with units (dollars, percent, milliseconds, GB, parameters, miles, etc.).
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
- If you cannot satisfy any of these for a paragraph, REMOVE the paragraph. Do not write filler.
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
- FORBIDDEN PHRASES (zero of them)
130
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
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
- Plus: no rhetorical questions opening sections, no "let's explore", no "in this video we'll look at".
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
- LENGTH + PACING
136
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
137
- - 14 to 22 chunks. Vary durations:
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
- NARRATION VOICE
148
- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
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
- STYLE: ${args.style.toUpperCase()}
156
- ${args.styleGuide}
157
- ${referenceBlock}
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
- OUTPUT FORMAT
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" or "c07-section-three-mechanism" (semantic, kebab-case),
165
- "title": "Hook \u2014 <Title>" or "Section Three. <Phrase>." etc.
166
- "narrationText": "Full narration body. Multiple paragraphs separated by blank lines.",
167
- "durationEstimate": <integer seconds>
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
- CRITICAL CHECKLIST:
171
- \u25A1 Hook follows pattern \u2192 reversal \u2192 stakes \u2192 bet \u2192 promise.
172
- \u25A1 Total duration is ${minMin * 60}-${maxMin * 60} seconds.
173
- \u25A1 Every paragraph has a specific number, name, year, or product reference.
174
- \u25A1 ZERO forbidden phrases.
175
- \u25A1 Section durations vary (not uniform 45s blocks).
176
- \u25A1 Conclusion connects back to the hook's pattern.
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
- Now write the script.`;
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyforge",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "StoryForge — local bridge for the Forge video production web app. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "bin": {