@lalalic/markcut 1.1.1 → 2.0.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 (69) hide show
  1. package/AGENTS.md +39 -15
  2. package/README.md +7 -3
  3. package/SKILL.md +26 -172
  4. package/docs/edit-mode.md +1 -1
  5. package/docs/label-mode.md +6 -4
  6. package/docs/markdown-descriptive.md +46 -1
  7. package/docs/system-prompt-edit.md +16 -0
  8. package/package.json +1 -1
  9. package/src/config.mjs +8 -3
  10. package/src/descriptive/compiler.test.ts +42 -42
  11. package/src/descriptive/compiler.ts +41 -52
  12. package/src/descriptive/markdown.ts +8 -4
  13. package/src/descriptive/resolve.test.ts +14 -7
  14. package/src/descriptive/resolve.ts +148 -20
  15. package/src/entry.tsx +8 -2
  16. package/src/player/browser.tsx +178 -54
  17. package/src/player/bundle/player.js +1168 -566
  18. package/src/player/components/EditControls.tsx +92 -0
  19. package/src/player/components/HeaderBar.tsx +60 -0
  20. package/src/player/components/LabelControls.tsx +367 -0
  21. package/src/player/components/SceneThumbnails.tsx +87 -0
  22. package/src/player/components/VariantBar.tsx +39 -0
  23. package/src/player/components/index.ts +5 -0
  24. package/src/player/pipeline.mjs +130 -66
  25. package/src/player/pipeline.ts +3 -1
  26. package/src/player/server-shared.mjs +5 -7
  27. package/src/player/server.mjs +194 -187
  28. package/src/render/cli.mjs +66 -13
  29. package/src/schema/index.ts +20 -23
  30. package/src/types/Audio.tsx +25 -33
  31. package/src/types/Component.tsx +18 -24
  32. package/src/types/Effect.tsx +31 -39
  33. package/src/types/Image.tsx +23 -30
  34. package/src/types/Include.tsx +70 -76
  35. package/src/types/Map.tsx +48 -44
  36. package/src/types/Rhythm.tsx +19 -27
  37. package/src/types/Video.tsx +40 -47
  38. package/src/utils/component-import-map.ts +93 -0
  39. package/src/utils/index.ts +23 -10
  40. package/src/vision/cli.mjs +6 -6
  41. package/templates/courseware/TEMPLATE.md +317 -0
  42. package/templates/courseware/agents/reviewer.md +84 -0
  43. package/templates/courseware/prompts/fix.md +30 -0
  44. package/templates/courseware/prompts/outline.md +53 -0
  45. package/templates/courseware/prompts/scene.md +64 -0
  46. package/tests/fixtures/audio.json +4 -2
  47. package/tests/fixtures/basic.json +2 -1
  48. package/tests/fixtures/component-all.json +4 -2
  49. package/tests/fixtures/components.json +4 -2
  50. package/tests/fixtures/effects.json +12 -6
  51. package/tests/fixtures/full.json +8 -4
  52. package/tests/fixtures/map.json +2 -1
  53. package/tests/fixtures/md/dialogue.md +12 -0
  54. package/tests/fixtures/md/edge-cases.md +9 -0
  55. package/tests/fixtures/scenes.json +4 -2
  56. package/tests/fixtures/subtitle.json +6 -3
  57. package/tests/fixtures/subvideo.json +11 -6
  58. package/tests/fixtures/templates/courseware.md +61 -4
  59. package/tests/fixtures/tween-visual.json +2 -6
  60. package/tests/fixtures/video-series.json +6 -14
  61. package/tests/md-descriptive.test.ts +170 -0
  62. package/tests/render.test.ts +32 -16
  63. package/tests/schema.test.ts +6 -3
  64. package/tests/server.test.ts +9 -6
  65. package/tests/utils.ts +4 -4
  66. package/docs/dynamic-components.md +0 -191
  67. package/docs/templates.md +0 -52
  68. package/scripts/artlist-dl.mjs +0 -190
  69. package/src/player/label-server.mjs +0 -599
@@ -0,0 +1,317 @@
1
+ ---
2
+ name: courseware
3
+ description: Turn a topic or teaching material into a professional slide-based course video with TTS narration, bullet-reveal slides, and a reviewer quality gate.
4
+ when-to-use: lessons, lectures, training, tutorials, explainers — 1-5 minute educational videos built from slides + narration
5
+ test:
6
+ ---
7
+
8
+ # Courseware Template
9
+
10
+ Follow this file top to bottom. It defines **what** a professional courseware video is and **how** to produce one. It does not re-teach the engine — markcut markdown syntax comes from the markcut skill (`SKILL.md` → `docs/markdown-descriptive.md`). Read those first if you have not.
11
+
12
+ Layout of this template package:
13
+
14
+ | Path | Runs in | Purpose |
15
+ |---|---|---|
16
+ | `TEMPLATE.md` | your context | everything: inputs, structure, rules, workflow, quality gate |
17
+ | `prompts/*.md` | **your own (orchestrator) context** | fill-in prompt templates you execute yourself |
18
+ | `agents/*.md` | **separate agent session** | subagent definitions (system prompt + task template) |
19
+
20
+ ## 0. Prerequisites
21
+
22
+ - markcut skill loaded (engine contract: `SKILL.md` + `docs/markdown-descriptive.md`)
23
+ - `npx @lalalic/markcut` runnable
24
+ - For the reviewer gate: `ffmpeg`/`ffprobe`, an STT CLI (e.g. whisper), and image-understanding capability
25
+
26
+ ## 1. Inputs — collect before starting
27
+
28
+ | Input | Required | Default | Notes |
29
+ |---|---|---|---|
30
+ | Topic / source material | **yes** | — | plain topic, outline, doc, or article |
31
+ | Audience level | no | beginner | beginner / intermediate / expert |
32
+ | Language(s) | no | en | extra languages become variants (see §3) |
33
+ | Target duration | no | 2 min | 1–5 min |
34
+ | Accent color | no | `#61dafb` | theme knob, see §4 |
35
+
36
+ **Rule:** if the topic/material is missing or ambiguous, ask the user. Never invent course content beyond the given material plus well-established knowledge of the topic. Never invent facts, numbers, or citations.
37
+
38
+ ## 2. Scene grammar — mandatory structure
39
+
40
+ ```
41
+ # video ← root: width:1920 height:1080 fps:30 layout:series
42
+ │ subtitle:{fontSize:"20px"} tts:"<edge-tts CLI template>"
43
+ ├── ## Hook ← 3–5s attention grabber, fixed duration
44
+ ├── ## Slides ← layout:transitionSeries transition:fade(0.5)
45
+ │ ├── ### TitleSlide ← transitionSeries, bullet-reveal (1 beat)
46
+ │ ├── ### <Concept> × 3–6 ← transitionSeries, bullet-reveal (1 beat per bullet)
47
+ │ └── ### Summary ← transitionSeries, bullet-reveal (1 beat per takeaway)
48
+ └── ## Thanks ← fixed duration:6, no script
49
+ ```
50
+
51
+ Scene rules:
52
+
53
+ - **Hook**: `- image duration:3 prompt:"<vivid visual, cinematic>"` (or `video`). If no TTI/TTV CLI is configured, use a `<Slide>` hook with a provocative question instead — never leave a broken `prompt:` node.
54
+ - **Every scene inside Slides (TitleSlide, concepts, Summary)** uses the **bullet-reveal pattern** — this is mandatory, not optional:
55
+
56
+ ```
57
+ ### <SceneName>
58
+ layout:transitionSeries transition:fade(0.5)
59
+ - component id:<shortId> isBackground:true jsx:"<Slide current={current}>{source}</Slide>"
60
+ ~~~md source
61
+ ## Title
62
+ - 🎯 **Key point 1** — elaboration
63
+ - 🎯 **Key point 2** — elaboration
64
+ - 🎯 **Key point 3** — elaboration
65
+ ~~~
66
+ - script "Paragraph expanding bullet 1..." on:(start, <shortId>.current=1)
67
+ - script "Paragraph expanding bullet 2..." on:(start, <shortId>.current=2)
68
+ - script "Paragraph expanding bullet 3..." on:(start, <shortId>.current=3)
69
+ ```
70
+
71
+ - `id` must be unique per scene (e.g. `t`, `c1`, `c2`, `s`). The `id` connects the component to the script events.
72
+ - `current={current}` on the Slide component reads the event-driven bullet index and highlights the matching `<li>`.
73
+ - Each `- script "..."` node is one beat in the `transitionSeries`, so it gets a fade transition. The TTS duration of that script determines the segment length.
74
+ - The component has `isBackground:true` so its `<Slide>` spans all beats of the scene.
75
+ - **Beat count = bullet count**: TitleSlide gets 1 beat (just the welcome line), concept scenes get 1 beat per bullet, Summary gets 1 beat per row in the comparison table or per major takeaway.
76
+
77
+ - **Thanks**: fixed-visual, `duration:6`, no script.
78
+
79
+ - **Mermaid diagrams inside slides**: Fenced mermaid code blocks (` ```mermaid `) inside `~~~md source` are rendered by the `<Slide>` component (see §4). Use for flowcharts, architecture diagrams, sequence diagrams, timeline visualizations. The diagram renders as inline SVG — place it after bullet points or on its own.
80
+
81
+ - **Duration is TTS-driven**: never set explicit `duration` on scenes that have a script. Only fixed-visual scenes (Hook, Thanks) get `duration:`.
82
+
83
+ ### make expressful slide
84
+ - use chart to explain when making sense
85
+ - group script and images/videos to make slide more expressful
86
+ - select different transition
87
+ - apply effects
88
+ - control tts with emotion,breaks, speed for natural speech
89
+
90
+ ## 3. Authoring rules — the professional bar
91
+
92
+ Slide content:
93
+
94
+ - One idea per slide. ≤ 6 bullets. Bullet shape: `🔹 **bold key phrase** — short elaboration`.
95
+ - Emoji bullet prefixes for scannability (🤖 📊 🔄 🏷️ 💡 ⚡ …), consistent within the course.
96
+ - Use a markdown **table** whenever content is comparative (applications, methods, milestones).
97
+ - Use a `>` quote block for the one memorable takeaway line.
98
+ - Code blocks only when actually teaching code; keep ≤ 10 lines per slide.
99
+
100
+ Narration script:
101
+
102
+ - **One paragraph per bullet.** Never merge bullets into a single monolithic script. Each bullet gets its own `- script "..."` node with `on:(start, id.current=N)`.
103
+ - Paragraph length ≈ **15–30 words** per beat (≈6–12 seconds at 2.5 w/s). Total words = target minutes × 150.
104
+ - Each paragraph **expands** that bullet — never reads it verbatim. The paragraph plus all sibling paragraphs must touch every bullet on the slide.
105
+ - The concrete example gets its own bullet and its own script paragraph. Never bury the example in a generic paragraph.
106
+ - Bullet ordering: concepts first (what/why), example last (concrete reinforcement). The example is the final beat before advancing to the next scene.
107
+ - Summary: each row in the comparison table gets one beat. The final beat closes the course ("Thank you for watching…").
108
+
109
+ Mermaid diagrams:
110
+
111
+ - Use ` ```mermaid ` fenced code blocks inside `~~~md source` for charts, flowcharts, architecture diagrams, sequence diagrams, and timelines.
112
+ - Place mermaid blocks after the bullet list, separated by a blank line.
113
+ - The Slide component (see §4) renders mermaid code blocks as inline SVG. Ensure the diagram fits within the slide (keep node labels short, max 1–2 sentences per node).
114
+ - For complex diagrams that take time to render, pre-render them as SVG files via `mmdc` (mermaid-cli) or your TTI CLI, and reference as `- image src:...` instead — this is more reliable for final render.
115
+
116
+ Multi-language (variants):
117
+
118
+ - For each extra language: a `<lang>:"..."` twin on every script node, a `~~~md <lang>-source` fence beside every `~~~md source`, and a `# <lang>` root block at the end of the file carrying that language's `tts:` voice.
119
+ - See the worked example in §7 for the exact shape (`zh` variant).
120
+
121
+ ## 4. Components & styles — canonical, copy verbatim
122
+
123
+ Copy both blocks into the generated `course.md` unchanged (except the theme knobs below).
124
+
125
+ ~~~~text
126
+ ~~~js imports
127
+ import ReactMarkdown from 'react-markdown';
128
+ import remarkGfm from 'remark-gfm'
129
+ import mermaid from 'mermaid'
130
+ import React from 'react'
131
+ import { delayRender, continueRender } from 'remotion'
132
+
133
+ // Initialize mermaid once. Theme matches the slide deck's dark scheme.
134
+ mermaid.initialize({ startOnLoad: false, theme: 'dark', securityLevel: 'loose' })
135
+
136
+ /**
137
+ * Renders a mermaid diagram as inline SVG.
138
+ * Uses Remotion's delayRender/continueRender so the diagram is guaranteed
139
+ * to be ready before the frame is captured.
140
+ */
141
+ export function Mermaid({ source }) {
142
+ const ref = React.useRef(null)
143
+
144
+ React.useEffect(() => {
145
+ if (!source || !ref.current) return
146
+ const handle = delayRender('Mermaid rendering')
147
+ mermaid.render('mmd-' + Math.random().toString(36).slice(2), source)
148
+ .then((result) => {
149
+ if (ref.current) ref.current.innerHTML = result.svg
150
+ continueRender(handle)
151
+ })
152
+ .catch((err) => {
153
+ console.error('Mermaid error:', err)
154
+ continueRender(handle)
155
+ })
156
+ }, [source])
157
+
158
+ return (<divref={ref}style={{ width: '100%', maxWidth: 960, margin: '20px auto' }}/> )
159
+ }
160
+
161
+ /**
162
+ * Courseware slide component.
163
+ * - Renders markdown via react-markdown
164
+ * - Highlights the Nth bullet when `current=N`
165
+ * - Renders mermaid code blocks ( ```mermaid ...``` ) as inline diagrams
166
+ */
167
+ export function Slide({ current = 0, children }) {
168
+ let idx = 1
169
+ return (
170
+ <div className="slide">
171
+ <ReactMarkdown remarkPlugins={[remarkGfm]}
172
+ components={{
173
+ li: ({ children }) => {
174
+ const highlight = idx === current; idx++
175
+ return <li className={highlight ? 'highlight' : ''}>{children}</li>
176
+ },
177
+ // Fenced code blocks — detect mermaid, render as diagram
178
+ pre: ({ children }) => {
179
+ const code = React.Children.toArray(children)[0]
180
+ if (code?.props?.className === 'language-mermaid') {
181
+ return <Mermaid source={String(code.props.children)} />
182
+ }
183
+ return <pre>{children}</pre>
184
+ },
185
+ }}>{children}</ReactMarkdown>
186
+ </div>
187
+ )
188
+ }
189
+ ~~~
190
+ ~~~~
191
+
192
+ ~~~~text
193
+ ~~~css stylesheet
194
+ /* Container sizing for a perfect 16:9 widescreen presentation slide */
195
+ .slide {
196
+ color: #f5f5f7;
197
+ padding: 40px;
198
+ display: flex;
199
+ flex-direction: column;
200
+ justify-content: center;
201
+ align-items: flex-start;
202
+ font-family: 'Helvetica Neue', Arial, sans-serif;
203
+ font-size: 30px;
204
+
205
+ /* Typography rules optimized for visibility from a distance */
206
+ h1 {
207
+ font-size: 2.8em;
208
+ color: #61dafb;
209
+ margin-top: 0;
210
+ margin-bottom: 20px;
211
+ line-height: 1.2;
212
+ }
213
+
214
+ h2 {
215
+ font-size: 2em;
216
+ color: #a8dadc;
217
+ margin-top: 0;
218
+ margin-bottom: 15px;
219
+ }
220
+
221
+ p {
222
+ font-size: 1.3em;
223
+ line-height: 1.6;
224
+ color: #e0e0e6;
225
+ margin-bottom: 15px;
226
+ }
227
+
228
+ /* List styling specific to presentation bullet points */
229
+ ul, ol {
230
+ margin-left: 25px;
231
+ margin-bottom: 20px;
232
+ }
233
+
234
+ li {
235
+ font-size: 1.3em;
236
+ line-height: 1.8;
237
+ margin-bottom: 10px;
238
+ color: #e0e0e6;
239
+ list-style-type: none; /* Remove default bullets for custom styling */
240
+
241
+ /* Highlighted list item for event-driven bullet reveal */
242
+ &.highlight {
243
+ color: red;
244
+ font-weight: 700;
245
+ }
246
+ }
247
+
248
+ /* Code block handling inside slides */
249
+ pre {
250
+ background-color: #2d2d34;
251
+ padding: 15px;
252
+ border-radius: 6px;
253
+ width: 100%;
254
+ box-sizing: border-box;
255
+ overflow-x: auto;
256
+ }
257
+
258
+ code {
259
+ font-family: 'Courier New', Courier, monospace;
260
+ font-size: 1.1em;
261
+ color: #ffb703;
262
+ }
263
+
264
+ table {
265
+ width: 100%;
266
+ border-collapse: collapse;
267
+ margin-bottom: 20px;
268
+
269
+ th, td {
270
+ border: 1px solid #444;
271
+ padding: 10px;
272
+ text-align: left;
273
+ }
274
+ }
275
+ }
276
+ ~~~
277
+ ~~~~
278
+
279
+ Theme knobs — change **values only**, never the structure:
280
+
281
+ | Knob | Selector | Default |
282
+ |---|---|---|
283
+ | Accent (h1) | `.slide h1 { color }` | `#61dafb` |
284
+ | Secondary (h2) | `.slide h2 { color }` | `#a8dadc` |
285
+ | Reveal highlight | `.slide li.highlight { color }` | `red` |
286
+ | Deck background | `.slide { background }` | transparent |
287
+ | Font | `.slide { font-family }` | Helvetica Neue |
288
+
289
+ ## 5. Workflow
290
+
291
+ Prompts in `prompts/` are fill-in templates: replace every `{placeholder}`, then execute the prompt **in your own context**. `agents/` definitions run in a **separate session** (e.g. a fresh-context subagent).
292
+
293
+ 1. **Outline** — fill `prompts/outline.md` → course outline. **Present the outline to the user and get confirmation** before continuing.
294
+ 2. **Scenes** — for each outline section, fill `prompts/scene.md` → slide source + narration script (all languages).
295
+ 3. **Assemble** — write `course.md`: §2 grammar, §3 rules, §4 blocks verbatim, root config line with the user's width/height/fps/voice.
296
+ 4. **Render** — `npx @lalalic/markcut render course.md`. On engine errors: fix and re-render, max 3 attempts per error, then ask the user.
297
+ 5. **Review (quality gate)** — run `agents/reviewer.md` in a fresh separate session. Give it absolute paths to: `course.md`, the rendered MP4, this `TEMPLATE.md`, plus target duration and language(s). It returns `{verdict, findings[]}` and never edits anything.
298
+ 6. **Fix loop** — on FAIL: fill `prompts/fix.md` with the findings, apply the edits yourself, go back to step 4. Max **3** review iterations, then escalate to the user with the open findings.
299
+
300
+ ## 6. Quality gate — exit criteria
301
+
302
+ Done only when ALL hold:
303
+
304
+ - [ ] reviewer verdict = `PASS` (zero blocker/major findings)
305
+ - [ ] total duration within ±15% of target
306
+ - [ ] structure matches §2 (hook, title, 3–6 concepts, summary, thanks)
307
+ - [ ] no blank/black frames at scene boundaries; slides legible at target resolution
308
+ - [ ] STT transcript of rendered audio matches scripts (≥90% content match)
309
+ - [ ] each bullet should be narrated
310
+ - [ ] expressful slides applied
311
+ - [ ] 80% slides have charts/image/...
312
+
313
+
314
+
315
+ ## 7. Reference — worked example
316
+
317
+ Golden example: [`tests/fixtures/templates/courseware.md`](../../tests/fixtures/templates/courseware.md) — a bilingual (en + zh) "Introduction to Machine Learning" course demonstrating every rule above: hook with generated image, bullet-reveal with `on:(start, slide1.current=N)`, comparative tables, summary with selection guide, and the `# zh` variant block.
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: courseware-reviewer
3
+ description: Read-only quality gate for videos produced from the courseware template. Runs in a separate session with fresh context.
4
+ context: fresh
5
+ mode: read-only
6
+ tools: read file, bash (ffmpeg/ffprobe, STT CLI), image understanding
7
+ ---
8
+
9
+ # System prompt
10
+
11
+ You are a strict, evidence-based QA reviewer for slide-based course videos. You review; you **never edit** any file. Every finding must cite concrete evidence (a frame image, an STT excerpt, a line in the source, a measured number). If you cannot verify a check, report it as a finding with severity `minor` and say why — never silently skip it.
12
+
13
+ ## Inputs (provided in the task)
14
+
15
+ - `course_md` — absolute path to the generated courseware markdown
16
+ - `mp4` — absolute path to the rendered video
17
+ - `template_md` — absolute path to the courseware `TEMPLATE.md` (the rulebook: §2 grammar, §3 authoring rules, §6 exit criteria)
18
+ - `duration_min` — target duration in minutes
19
+ - `languages` — expected language(s)
20
+
21
+ ## Procedure
22
+
23
+ ### 1. Static review (source vs rulebook)
24
+
25
+ Read `template_md` §2/§3, then check `course_md`:
26
+
27
+ - structure: hook → title → 3–6 concepts → summary → thanks
28
+ - every concept scene: `layout:parallel` (or `transitionSeries` when bullet-reveal), one `isBackground:true` slide component + script node(s)
29
+ - bullet-reveal wiring: `id:slideN` ↔ `on:(start, slideN.current=K)` pairs are consistent and in order
30
+ - slide rules: ≤6 bullets, bold-key-phrase shape, table where comparative, one idea per slide
31
+ - script rules: word count ≈ scene budget (2.5 w/s), expands rather than reads the slide, concrete example present per concept
32
+ - imports/stylesheet blocks match the template canon (only theme-knob values may differ)
33
+ - language variants complete and mirrored (every script has its `<lang>:` twin, every source its `<lang>-source`)
34
+ - factual sanity: no obviously invented facts, numbers, or citations
35
+
36
+ ### 2. Dynamic review (rendered artifact)
37
+
38
+ - `ffprobe` the MP4: duration (compare to `duration_min` ±15%), resolution, fps, audio stream present
39
+ - Extract frames: one at each scene midpoint plus each scene boundary ±0.5s (estimate boundaries from scene order and TTS-driven durations; evenly-spaced sampling of ~2× scene count is an acceptable fallback). For each frame, verify with image understanding:
40
+ - not blank/black
41
+ - it shows the expected slide for that timestamp (match heading/bullets against `course_md`)
42
+ - legibility: text within safe margins, no overflow/clipping, readable contrast
43
+ - Extract audio (`ffmpeg` → wav), transcribe with the STT CLI, and compare against the scripts in `course_md`: ≥90% content match, correct language, scene order correct
44
+ - Spot-check subtitle overlay in ≥2 frames if subtitles are configured
45
+
46
+ ### 3. Report
47
+
48
+ Severity: `blocker` (broken output: blank frames, missing audio, wrong structure, unrendered scene) · `major` (professional-bar violation: slide/script mismatch, pacing off-budget >20%, illegible slide, missing example, variant out of sync) · `minor` (polish: emoji inconsistency, wording, small overflow).
49
+
50
+ ## Output — exactly this JSON, nothing after it
51
+
52
+ ```json
53
+ {
54
+ "verdict": "PASS | FAIL",
55
+ "measured": { "duration_s": 0, "target_s": 0, "resolution": "", "stt_match_pct": 0 },
56
+ "findings": [
57
+ {
58
+ "id": "F1",
59
+ "severity": "blocker | major | minor",
60
+ "scene": "<scene heading or 'global'>",
61
+ "check": "<which rule/check from the procedure>",
62
+ "issue": "<what is wrong>",
63
+ "evidence": "<frame path / STT excerpt / source line / measurement>",
64
+ "fix_hint": "<one-line suggestion for the orchestrator>"
65
+ }
66
+ ]
67
+ }
68
+ ```
69
+
70
+ `PASS` requires zero `blocker` and zero `major` findings.
71
+
72
+ # Task template (orchestrator fills and sends)
73
+
74
+ ```
75
+ Review a courseware video against its template.
76
+
77
+ course_md: {course_md}
78
+ mp4: {mp4}
79
+ template_md: {template_md}
80
+ duration_min: {duration_min}
81
+ languages: {languages}
82
+
83
+ Follow your procedure. Output the verdict JSON only.
84
+ ```
@@ -0,0 +1,30 @@
1
+ # Prompt: Apply Reviewer Findings
2
+
3
+ > Fill every `{placeholder}`, then execute in your own (orchestrator) context.
4
+ > Used in TEMPLATE.md §5 step 6 after a FAIL verdict. You edit; the reviewer never does.
5
+
6
+ ---
7
+
8
+ You are fixing a courseware video that failed review. Apply the findings below to `{course_md_path}` with **minimal, targeted edits** — do not rewrite passing scenes.
9
+
10
+ Reviewer findings (JSON):
11
+
12
+ {findings_json}
13
+
14
+ Rules:
15
+
16
+ - Address every `blocker` and `major` finding. Address `minor` findings only when the fix is trivial and local.
17
+ - Each fix must respect TEMPLATE.md §2 scene grammar and §3 authoring rules — a fix that breaks a rule elsewhere is not a fix.
18
+ - Slide/script mismatch → prefer fixing the **script** (cheaper: TTS regenerates; slide layout stays validated).
19
+ - Pacing/duration findings → adjust script word counts toward budget (target duration × 150 words total).
20
+ - Blank/illegible frame findings → check the scene's node (missing `isBackground:true`, broken `src`/`prompt`, oversized content) before touching styles.
21
+ - Never modify the `~~~js imports` or `~~~css stylesheet` blocks except the documented theme knobs (TEMPLATE.md §4).
22
+ - Keep all language variants in sync: an edit to a script or slide must be mirrored in every `<lang>:`/`<lang>-source` twin.
23
+
24
+ After editing, list what changed:
25
+
26
+ ```
27
+ - <finding id>: <file location> — <one-line description of the edit>
28
+ ```
29
+
30
+ Then re-render and re-review (TEMPLATE.md §5 steps 4–5).
@@ -0,0 +1,53 @@
1
+ # Prompt: Course Outline
2
+
3
+ > Fill every `{placeholder}`, then execute in your own (orchestrator) context.
4
+ > Output feeds `prompts/scene.md` and must be confirmed by the user before scene writing.
5
+
6
+ ---
7
+
8
+ You are an instructional designer planning a {duration_min}-minute video course.
9
+
10
+ Topic / source material:
11
+
12
+ {material}
13
+
14
+ Audience: {audience}
15
+ Language(s): {languages}
16
+
17
+ Requirements:
18
+
19
+ - Structure: 1 hook + 1 title slide + 3–6 concept sections + 1 summary.
20
+ - Total narration budget ≈ {duration_min} × 150 words. Allocate a word budget per section; the sum must fit the budget.
21
+ - Per concept section provide:
22
+ - title (≤ 5 words)
23
+ - 3–6 key points, each as `**bold key phrase** — short elaboration`
24
+ - one concrete example (real product, scenario, or story) — gets its own key point
25
+ - whether the content is comparative → table (if yes, name the columns)
26
+ - whether a mermaid diagram would help (flowchart, architecture, timeline)
27
+ - word budget
28
+ - Summary: one comparison table spanning all concepts (name the columns) + a selection/decision guide ("If X → use Y").
29
+ - Hook: one vivid visual idea usable as an image/video generation prompt, OR a provocative question if generation is unavailable.
30
+ - Stay strictly within the given material plus well-established knowledge. No invented facts, numbers, or citations.
31
+
32
+ Output format (markdown):
33
+
34
+ ```
35
+ ## Hook
36
+ - visual: <generation prompt or question>
37
+
38
+ ## Concept 1: <title>
39
+ - points:
40
+ - **<key phrase>** — <elaboration>
41
+ - ... (last point = the concrete example)
42
+ - table: no | yes (<col1>, <col2>, ...)
43
+ - mermaid: no | yes (<type and description of diagram>)
44
+ - words: <n>
45
+
46
+ ## Concept 2: ...
47
+
48
+ ## Summary
49
+ - table columns: <dimension>, <per-concept columns...>
50
+ - guide:
51
+ - <condition> → <concept>
52
+ - words: <n>
53
+ ```
@@ -0,0 +1,64 @@
1
+ # Prompt: Concept Scene (slide + script)
2
+
3
+ > Fill every `{placeholder}`, then execute in your own (orchestrator) context.
4
+ > Run once per outline section (TitleSlide, each Concept, Summary).
5
+ > Constraints below mirror TEMPLATE.md §2/§3 — the reviewer checks against them.
6
+
7
+ ---
8
+
9
+ You are writing one scene of a {duration_min}-minute course for a {audience} audience.
10
+
11
+ Outline section:
12
+
13
+ {outline_section}
14
+
15
+ Course context (for continuity — do not repeat content already covered):
16
+
17
+ {outline_full}
18
+
19
+ Produce, for language(s) {languages}:
20
+
21
+ **A. Slide source** (markdown, rendered by `<Slide>`):
22
+
23
+ - `##` heading = section title
24
+ - ≤ 6 bullets, shape: `<emoji> **bold key phrase** — short elaboration`
25
+ - consistent emoji set across the course: {emoji_set}
26
+ - markdown table if the outline marks this section comparative
27
+ - `>` quote block only for a single memorable takeaway line
28
+ - no bullet may exceed one line at 1.3em / 1920px width (~90 chars)
29
+ - Optional mermaid diagram: add a fenced mermaid code block after the bullet list (` ```mermaid ...``` `) for flowcharts or architecture visuals.
30
+
31
+ **B. Narration script** (per language, **one paragraph per bullet**):
32
+
33
+ - **One paragraph per bullet** — never merge bullets into a single script. Each paragraph becomes a separate `- script "..."` node with `on:(start, <sceneId>.current=N)`.
34
+ - Paragraph length ≈ **15–30 words** per beat (~6–12s at 2.5 w/s).
35
+ - Each paragraph **expands** its bullet — never reads it verbatim.
36
+ - Spoken register: short sentences, no markdown, no stage directions.
37
+ - The concrete example gets its own bullet and its own paragraph. Place it last (final beat of the scene).
38
+ - For TitleSlide: 1 paragraph (just the welcome/introduction line).
39
+ - For Summary: 1 paragraph per row in the comparison table + 1 final closing paragraph ("Thank you for watching…").
40
+
41
+ Output format:
42
+
43
+ ```
44
+ ### <SceneName (PascalCase, no spaces)>
45
+
46
+ ~~~md source
47
+ <slide markdown>
48
+ ~~~
49
+ <one extra fenced block per additional language: ~~~md <lang>-source>
50
+
51
+ script (en):
52
+ <p1: describes bullet 1>
53
+
54
+ <p2: describes bullet 2>
55
+
56
+ <p3: describes bullet 3 — concrete example>
57
+
58
+ script (<lang>):
59
+ <p1 translation>
60
+
61
+ <p2 translation>
62
+
63
+ <p3 translation>
64
+ ```
@@ -12,14 +12,16 @@
12
12
  "src": "assets/bgm/ambient-loop.mp3",
13
13
  "volume": 0.3,
14
14
  "isBackground": true,
15
- "actions": [{ "start": 0, "end": 3 }]
15
+ "start": 0,
16
+ "end": 3
16
17
  },
17
18
  {
18
19
  "id": "bg",
19
20
  "type": "image",
20
21
  "src": "https://picsum.photos/seed/audio-test/640/480",
21
22
  "fit": "cover",
22
- "actions": [{ "start": 0, "end": 3 }]
23
+ "start": 0,
24
+ "end": 3
23
25
  }
24
26
  ]
25
27
  }
@@ -19,7 +19,8 @@
19
19
  "type": "image",
20
20
  "src": "https://picsum.photos/seed/test-basic/640/480",
21
21
  "fit": "cover",
22
- "actions": [{ "start": 0, "end": 2 }]
22
+ "start": 0,
23
+ "end": 2
23
24
  }
24
25
  ]
25
26
  }
@@ -16,7 +16,8 @@
16
16
  "id": "c-hello",
17
17
  "type": "component",
18
18
  "jsx": "<div style={{color:'#fff',fontSize:28,textAlign:'center'}}>Hello World</div>",
19
- "actions": [{ "start": 0, "end": 2 }]
19
+ "start": 0,
20
+ "end": 2
20
21
  }
21
22
  ]
22
23
  },
@@ -30,7 +31,8 @@
30
31
  "id": "c-tween",
31
32
  "type": "component",
32
33
  "jsx": "<svg width=\"200\" height=\"200\" viewBox=\"0 0 200 200\"><rect x=\"0\" y={tween(0,150)} width=\"50\" height={tween(50,200)} fill=\"#667eea\" /><rect x=\"70\" y={tween(50,100)} width=\"50\" height={tween(100,50)} fill=\"#764ba2\" /><rect x=\"140\" y={tween(100,0)} width=\"50\" height={tween(50,200)} fill=\"#f093fb\" /></svg>",
33
- "actions": [{ "start": 0, "end": 3 }]
34
+ "start": 0,
35
+ "end": 3
34
36
  }
35
37
  ]
36
38
  }
@@ -17,7 +17,8 @@
17
17
  "id": "headline",
18
18
  "type": "component",
19
19
  "jsx": "<div style={{background:'linear-gradient(135deg,#667eea,#764ba2)',padding:'40px',borderRadius:'16px',textAlign:'center'}}><h1 style={{color:'white',fontSize:'36px',margin:0}}>Component Test</h1><p style={{color:'rgba(255,255,255,0.7)',fontSize:'18px'}}>Built-in components render correctly</p></div>",
20
- "actions": [{ "start": 0, "end": 3 }]
20
+ "start": 0,
21
+ "end": 3
21
22
  }
22
23
  ]
23
24
  },
@@ -30,7 +31,8 @@
30
31
  "id": "stats",
31
32
  "type": "component",
32
33
  "jsx": "<div style={{background:'#1a1a2e',padding:'30px',borderRadius:'16px',textAlign:'center'}}><span style={{color:'#667eea',fontSize:'64px',fontWeight:'bold'}}>100%</span><p style={{color:'rgba(255,255,255,0.6)',fontSize:'16px'}}>Working</p></div>",
33
- "actions": [{ "start": 0, "end": 3 }]
34
+ "start": 0,
35
+ "end": 3
34
36
  }
35
37
  ]
36
38
  }
@@ -20,10 +20,12 @@
20
20
  "type": "image",
21
21
  "src": "https://picsum.photos/seed/effect-fade/640/480",
22
22
  "fit": "cover",
23
- "actions": [{ "start": 0, "end": 2 }]
23
+ "start": 0,
24
+ "end": 2
24
25
  }
25
26
  ],
26
- "actions": [{ "start": 0, "end": 2 }]
27
+ "start": 0,
28
+ "end": 2
27
29
  },
28
30
  {
29
31
  "id": "bounce",
@@ -35,10 +37,12 @@
35
37
  "type": "image",
36
38
  "src": "https://picsum.photos/seed/effect-bounce/640/480",
37
39
  "fit": "cover",
38
- "actions": [{ "start": 0, "end": 2 }]
40
+ "start": 0,
41
+ "end": 2
39
42
  }
40
43
  ],
41
- "actions": [{ "start": 0, "end": 2 }]
44
+ "start": 0,
45
+ "end": 2
42
46
  },
43
47
  {
44
48
  "id": "custom-kf",
@@ -55,10 +59,12 @@
55
59
  "type": "image",
56
60
  "src": "https://picsum.photos/seed/effect-custom/640/480",
57
61
  "fit": "cover",
58
- "actions": [{ "start": 0, "end": 2 }]
62
+ "start": 0,
63
+ "end": 2
59
64
  }
60
65
  ],
61
- "actions": [{ "start": 0, "end": 2 }]
66
+ "start": 0,
67
+ "end": 2
62
68
  }
63
69
  ]
64
70
  }