@ztffn/presentation-generator-plugin 1.3.2 → 1.3.5

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.
@@ -9,24 +9,43 @@ description: >
9
9
 
10
10
  # Presentation Generator
11
11
 
12
- Orchestrates a three-agent pipeline to produce a complete, navigable presentation graph JSON from a user brief and optional source documents.
12
+ Orchestrates a two-agent + script pipeline to produce a complete, navigable presentation graph JSON from a user brief and optional source documents.
13
13
 
14
14
  ## Pipeline Overview
15
15
 
16
16
  ```
17
17
  User Brief + Documents
18
18
 
19
- [1] Content Extraction → _temp/presentation-content-brief.json
19
+ [1] Content Extraction → _temp/presentation-content-brief.json
20
20
 
21
- [2] Narrative Design → _temp/presentation-outline.md
21
+ [2] Narrative Design → _temp/presentation-outline.md
22
22
 
23
- [3] User Approval → confirm or revise structure
23
+ [3] User Approval → confirm or revise structure
24
24
 
25
- [4] Design & JSON _temp/presentation-draft.json
25
+ [4] Graph Generation presentations/{slug}/{slug}.json (script)
26
26
 
27
- [5] Delivery import instructions + media checklist
27
+ [5] Visual Styling styled JSON (agent)
28
+
29
+ [6] Delivery → import instructions + media checklist
28
30
  ```
29
31
 
32
+ ## Phase 0 — Locate Plugin Root
33
+
34
+ Before any other phase, resolve the plugin root directory. Check the local project path first, then the global path:
35
+
36
+ ```bash
37
+ if [ -f ".claude/plugins/presentation-generator/scripts/outline_to_graph.py" ]; then
38
+ PLUGIN_ROOT=".claude/plugins/presentation-generator"
39
+ elif [ -f "$HOME/.claude/plugins/presentation-generator/scripts/outline_to_graph.py" ]; then
40
+ PLUGIN_ROOT="$HOME/.claude/plugins/presentation-generator"
41
+ else
42
+ echo "ERROR: presentation-generator-plugin not found" && exit 1
43
+ fi
44
+ echo "Plugin root: $PLUGIN_ROOT"
45
+ ```
46
+
47
+ Store `PLUGIN_ROOT` for all subsequent phases. All skill files, scripts, and agent references use this path.
48
+
30
49
  ## Phase 1 — Context Gathering
31
50
 
32
51
  Parse the user's request to identify:
@@ -41,6 +60,7 @@ If no documents are provided, skip Phase 2 and construct a minimal content brief
41
60
  - If goal is unclear, ask what outcome they want
42
61
 
43
62
  ## Phase 2 — Content Extraction
63
+ Announce to the user that you are **Executing Phase 2 — Subagent: Content Extraction**
44
64
 
45
65
  Delegate content extraction to the specialist agent using the Task tool:
46
66
 
@@ -49,8 +69,8 @@ Task tool:
49
69
  subagent_type: "presentation-content"
50
70
  description: "Extract content brief"
51
71
  prompt: |
52
- Step 1: Load your skill file. Find and read the file matching
53
- **/presentation-generator/skills/content-signals/SKILL.md
72
+ Step 1: Load your skill file. Read this file:
73
+ {PLUGIN_ROOT}/skills/content-signals/SKILL.md
54
74
  — it defines the content brief schema, signal priorities, and validation rules.
55
75
 
56
76
  Step 2: Read these source documents and extract a structured content brief:
@@ -88,6 +108,7 @@ After the content brief is written, read `_temp/presentation-content-brief.json`
88
108
  If any check fails, ask the user ONE targeted question to fill the gap. Do not pass a weak brief to the narrative agent.
89
109
 
90
110
  ## Phase 3 — Narrative Design
111
+ Announce to the user that you are **Executing Phase 3 — Subagent: Narrative Design**
91
112
 
92
113
  Delegate narrative design to the specialist agent using the Task tool:
93
114
 
@@ -96,10 +117,10 @@ Task tool:
96
117
  subagent_type: "presentation-narrative"
97
118
  description: "Design narrative outline"
98
119
  prompt: |
99
- Step 1: Load your skill files. Find and read these three files:
100
- - **/presentation-generator/skills/frameworks/SKILL.md
101
- - **/presentation-generator/skills/slide-content/SKILL.md
102
- - **/presentation-generator/skills/graph-topology/SKILL.md
120
+ Step 1: Load your skill files. Read these three files:
121
+ - {PLUGIN_ROOT}/skills/frameworks/SKILL.md
122
+ - {PLUGIN_ROOT}/skills/slide-content/SKILL.md
123
+ - {PLUGIN_ROOT}/skills/graph-topology/SKILL.md
103
124
 
104
125
  Step 2: Read the content brief at _temp/presentation-content-brief.json
105
126
 
@@ -116,6 +137,7 @@ Task tool:
116
137
  The narrative agent selects a story framework, designs the spine and drill-down structure, and writes a detailed slide outline.
117
138
 
118
139
  ## Phase 4 — User Approval
140
+ Announce to the user that you are **Executing Phase 4 — Getting User Approval**
119
141
 
120
142
  Read `_temp/presentation-outline.md` and render it as a folder tree for the user:
121
143
 
@@ -145,38 +167,59 @@ Wait for the user to respond:
145
167
 
146
168
  This loop continues until the user explicitly approves.
147
169
 
148
- ## Phase 5Design and JSON Generation
170
+ ## Phase 5AGraph Generation (script)
171
+ Announce to the user that you are **Executing Phase 5A — Generating Graph JSON from Outline**
149
172
 
150
- Delegate design and JSON generation to the specialist agent using the Task tool:
173
+ Run the deterministic outline-to-graph converter directly via Bash:
174
+
175
+ ```bash
176
+ python3 "$PLUGIN_ROOT/scripts/outline_to_graph.py" _temp/presentation-outline.md -o presentations/{slug}/{slug}.json
177
+ ```
178
+
179
+ The script:
180
+ - Parses the outline markdown
181
+ - Generates all nodes with correct wrappers, positions, and data fields
182
+ - Wires all edges with bidirectional pairs
183
+ - Runs the validator internally
184
+ - Exits 0 if valid, 1 with errors
185
+
186
+ If exit non-zero, review the errors and fix the outline. If zero, proceed to Phase 5B.
187
+
188
+ ## Phase 5B — Visual Styling (agent)
189
+ Announce to the user that you are **Executing Phase 5B — Subagent: Visual Styling**
190
+
191
+ Delegate visual styling to the specialist agent using the Task tool:
151
192
 
152
193
  ```
153
194
  Task tool:
154
- subagent_type: "presentation-design"
155
- description: "Generate presentation JSON"
195
+ subagent_type: "presentation-style"
196
+ description: "Apply visual treatments"
156
197
  prompt: |
157
- Step 1: Load your skill file. Find and read the file matching
158
- **/presentation-generator/skills/graph-json-spec/SKILL.md
159
- it defines the complete JSON schema, allowed fields, banned fields,
160
- edge wiring, handle IDs, and positioning grid.
198
+ Step 1: Load your skill files. Read these two files:
199
+ - {PLUGIN_ROOT}/skills/slide-recipes/SKILL.md
200
+ - {PLUGIN_ROOT}/skills/graph-json-spec/SKILL.md
161
201
 
162
- Step 2: Read the approved outline at _temp/presentation-outline.md
202
+ Step 2: Read the structurally valid presentation JSON at
203
+ presentations/{slug}/{slug}.json
163
204
 
164
- Step 3: Translate the outline into a complete presentation graph JSON.
165
- Presentation slug: {slug}
205
+ Step 3: Read the outline at _temp/presentation-outline.md for context
206
+ on each slide's purpose and visual intent.
166
207
 
167
- Step 4: Write the JSON to presentations/{slug}/{slug}.json
208
+ Step 4: Apply visual treatments to each slide based on the slide-recipes
209
+ Visual Intent Mapping. Edit only data fields using the Edit tool.
210
+ Never modify node wrappers, edges, or positions.
168
211
 
169
- Step 5: Run the validator script and fix any errors until it passes:
170
- VALIDATE=$(find -L .claude ~/.claude -path "*/presentation-generator/scripts/validate_draft.py" 2>/dev/null | head -1)
171
- python3 "$VALIDATE" presentations/{slug}/{slug}.json
212
+ Step 5: Run the validator script and fix any errors:
213
+ python3 "{PLUGIN_ROOT}/scripts/validate_draft.py" presentations/{slug}/{slug}.json
172
214
 
173
215
  Step 6: Report back with the exact validator terminal output,
174
- output path, node count, edge count, and any video placeholders.
216
+ number of slides styled, and any video/image placeholders.
175
217
  ```
176
218
 
177
- The design agent translates each slide into a fully specified graph node, wires all edges with bidirectional pairs, and validates the result.
219
+ The styling agent reads the valid JSON and applies visual treatments (two-column layouts, centered slides, background images, charts) by editing only `data` fields. It cannot break structure.
178
220
 
179
221
  ## Phase 6 — Delivery
222
+ Announce to the user that you are **Executing Phase 6 — Packaging Presentation**
180
223
 
181
224
  After `presentations/{slug}/{slug}.json` is written:
182
225
 
@@ -189,10 +232,12 @@ After `presentations/{slug}/{slug}.json` is written:
189
232
 
190
233
  ```
191
234
  Import your presentation:
192
- 1. Open the graph editor at /present/plan
235
+ 1. Open the graph editor at https://humagreenfield.netlify.app/present/plan
193
236
  2. Click "New presentation"
194
237
  3. Choose "Import JSON"
195
238
  4. Select presentations/{slug}/{slug}.json
239
+ 5. Click "Create presentation"
240
+ 6. Make final adjustments and manual uploads.
196
241
  ```
197
242
 
198
243
  3. If any slides have video placeholders, list them:
@@ -212,7 +257,9 @@ Replace the PLACEHOLDER string with the returned URL after upload.
212
257
  |---|---|---|
213
258
  | `presentation-content` | `content-signals` | Extract structured brief from documents |
214
259
  | `presentation-narrative` | `frameworks`, `slide-content`, `graph-topology` | Design story structure and slide content |
215
- | `presentation-design` | `graph-json-spec` | Translate outline to valid graph JSON |
260
+ | `presentation-style` | `graph-json-spec`, `slide-recipes` | Apply visual treatments to valid graph JSON |
261
+
262
+ Note: Graph structure (nodes, edges, positions) is generated deterministically by `scripts/outline_to_graph.py` in Phase 5A. The `presentation-style` agent in Phase 5B only modifies visual `data` fields.
216
263
 
217
264
  ## Working Without Documents
218
265
 
@@ -241,9 +288,9 @@ All intermediate and output files:
241
288
  | File | Created By | Read By |
242
289
  |---|---|---|
243
290
  | `_temp/presentation-content-brief.json` | Content agent or orchestrator | Narrative agent |
244
- | `_temp/presentation-outline.md` | Narrative agent | Design agent, orchestrator |
291
+ | `_temp/presentation-outline.md` | Narrative agent | Script + styling agent, orchestrator |
245
292
  | `_temp/presentation-plan.md` | Orchestrator | User (approval) |
246
- | `presentations/{slug}/{slug}.json` | Design agent | User (import) |
293
+ | `presentations/{slug}/{slug}.json` | Script (structure) + styling agent (visuals) | User (import) |
247
294
  | `presentations/{slug}/content-brief.json` | Orchestrator (Phase 6) | Reference |
248
295
  | `presentations/{slug}/outline.md` | Orchestrator (Phase 6) | Reference |
249
296
  | `presentations/{slug}/plan.md` | Orchestrator (Phase 6) | Reference |
@@ -138,7 +138,7 @@ Replace bullet lists with assertion + evidence. The assertion is the headline
138
138
  > *Headline:* Mid-market finance teams lose 11 hours a week reconciling what three systems can't agree on
139
139
  > [Chart or role-by-role breakdown of where those hours go]
140
140
 
141
- → Deep dive: *Assertion-Evidence Structure* — Michael Alley; *Presentation Design* — presentation-design skill
141
+ → Deep dive: *Assertion-Evidence Structure* — Michael Alley; *Slide Recipes* — slide-recipes skill
142
142
 
143
143
  ### Headlines vs. Titles
144
144
 
@@ -301,7 +301,7 @@ For difficult questions: "That's a valid concern. Here's how we thought about it
301
301
  | Start in the Middle of Action | Merci Grace — *Giving Presentations* guest insights |
302
302
  | Make the Title the Takeaway | Andy Raskin — *Giving Presentations* guest insights |
303
303
  | Lead a Movement, Not Just Solve a Problem | Andy Raskin — *Brand Storytelling* guest insights |
304
- | Assertion-Evidence Structure | Michael Alley — *presentation-design* skill |
304
+ | Assertion-Evidence Structure | Michael Alley — *slide-recipes* skill |
305
305
  | State Changes Every 3–5 Slides | Wes Kao — *Giving Presentations* guest insights |
306
306
  | Stay in Character | Tristan de Montebello — *Giving Presentations* guest insights |
307
307
  | Accordion Method | Tristan de Montebello — *Giving Presentations* guest insights |
@@ -0,0 +1,326 @@
1
+ ---
2
+ name: slide-recipes
3
+ description: >
4
+ Design decision guide and slide recipes for presentation JSON generation.
5
+ Maps content signals to slide type, layout, and visual treatment.
6
+ Includes a reference example with all key patterns.
7
+ user-invocable: false
8
+ ---
9
+
10
+ # Slide Recipes
11
+
12
+ Design decisions and concrete patterns for presentation JSON. For node schema, edge wiring, and positioning grid, see `graph-json-spec`.
13
+
14
+ ## Visual Intent Mapping
15
+
16
+ The narrative agent annotates each slide with a `**Visual intent:**` label. Map them to JSON treatments:
17
+
18
+ | Visual Intent | type | centered | layout | brandFont | Background | lightText | Notes |
19
+ |---|---|---|---|---|---|---|---|
20
+ | `bookend` | content | true | single | true | optional image/color | if dark bg | Cover and CTA slides. showBranding: true |
21
+ | `chapter-opener` | content | false or true | single | false | backgroundImage + overlay | true | Full-bleed image, sets section mood. Max 3 bullet points. |
22
+ | `impact` | content | true | single | false | optional dark color | if dark bg | Single statement, no bullets. Let whitespace do the work. |
23
+ | `workhorse` | content | false | single or two-column | false | none | false | Standard bullets/content. The default treatment. |
24
+ | `evidence` | content or chart | false | single or two-column | false | none | false | Data-forward: chart, table, or comparison. |
25
+ | `breathing-room` | content | true | single | false | backgroundImage + overlay OR style.backgroundColor | true | Minimal text. Visual pause. Resets audience attention. |
26
+
27
+ When the outline lacks visual intent annotations, infer them:
28
+ - First slide → bookend
29
+ - Last slide → bookend
30
+ - Slide after 2+ consecutive bullet-heavy slides → breathing-room or impact
31
+ - Slide introducing a new topic section → chapter-opener
32
+ - Slide with chart data or comparison → evidence
33
+ - Everything else → workhorse
34
+
35
+ ---
36
+
37
+ ## Design Decisions
38
+
39
+ ### Slide Type Selection
40
+
41
+ | Content Signal | `type` | Key Fields |
42
+ |---|---|---|
43
+ | Standard text, bullets, headings | `"content"` (default) | `content`, `layout` |
44
+ | Full-viewport data visualization | `"chart"` | `chart` (ChartConfig) |
45
+ | Interactive 3D scene | `"r3f"` | `scene` (R3FSceneConfig) |
46
+
47
+ Most slides are `"content"`. Use `"chart"` or `"r3f"` only when the content is primarily a visualization.
48
+
49
+ ### Layout Decisions
50
+
51
+ **When to use `two-column`** — set `layout: "two-column"` and split content on `---`:
52
+ - Comparison: before/after, old/new, us/them
53
+ - Pros/cons: advantages on left, considerations on right
54
+ - Text + chart: explanation on left, `[chart:name]` on right
55
+ - Text + media: bullets on left, `![](image)` on right
56
+
57
+ Do not force two-column when content is naturally sequential.
58
+
59
+ **When to center** — set `centered: true` for:
60
+ - Cover and CTA slides
61
+ - Single-message impact slides
62
+ - Transition slides
63
+
64
+ Set `centered: false` for content-heavy, data, and comparison slides.
65
+
66
+ **When to use brand font** — set `brandFont: true` for:
67
+ - Cover slide, closing/CTA slide, high-impact single-message slides
68
+
69
+ Do not use on content-heavy or data slides.
70
+
71
+ **When to show branding** — set `showBranding: true` and `brandingText` for:
72
+ - Cover, closing, slides likely to be screenshotted
73
+
74
+ Set `showBranding: false` for immersive slides (R3F, full-bleed video).
75
+
76
+ ### Background Treatment
77
+
78
+ **Background image** — mood, atmosphere, visual evidence, or impact:
79
+ - Set `backgroundImageOverlay: true` and `lightText: true` when text appears over the image
80
+ - Use Unsplash URLs with `?w=1920&q=80`
81
+
82
+ **Background video** — cinematic section openers or demo context:
83
+ - Set URL to placeholder: `"PLACEHOLDER: [description of needed video]"`
84
+ - Set `backgroundVideoFit: "cover"`, `backgroundVideoLoop: true`
85
+ - Add to delivery summary
86
+
87
+ **Text contrast** — set `lightText: true` whenever background is dark:
88
+ - Dark `style.backgroundColor`, `backgroundImage` with overlay, `backgroundVideo`, `type: "r3f"` with dark scene
89
+
90
+ ### Chart Decisions
91
+
92
+ **Chart title rule** — `label` states the insight, not the data category:
93
+ - Weak: "Revenue Data" → Strong: "Revenue grew 40% QoQ after the pricing change"
94
+
95
+ **Full-viewport** (`type: "chart"`) — when the data IS the slide.
96
+ **Inline** (`[chart:name]` in content) — when data supports a text argument.
97
+
98
+ ### R3F Scene Decisions
99
+
100
+ Available scenes:
101
+ - `"rotating-cube"` — interactive cube, good for tech demos. Set `scene.controls: true`.
102
+ - `"particle-field"` — atmospheric particle cloud. Set `scene.controls: false`.
103
+
104
+ Always set `lightText: true` for R3F slides.
105
+
106
+ ### Topic Badge Conventions
107
+
108
+ Format: `"NN / Section Name"` for numbered sections (`"01 / Problem"`, `"02 / Solution"`).
109
+ Or plain text: `"Huma Showcase"`, `"Technical Deep Dive"`.
110
+
111
+ ---
112
+
113
+ ## Slide Recipes
114
+
115
+ Complete `data` field patterns. For field definitions, see `graph-json-spec`.
116
+
117
+ ### Cover / Call to Action
118
+
119
+ ```json
120
+ {
121
+ "label": "[Title or Ask]",
122
+ "topic": "[Company or Meeting Context]",
123
+ "content": "One sentence: what this is and for whom. (Cover) — or — what happens next. (CTA)",
124
+ "centered": true,
125
+ "brandFont": true,
126
+ "showBranding": true,
127
+ "brandingText": "[company.domain]"
128
+ }
129
+ ```
130
+
131
+ ### Standard Bullets
132
+
133
+ ```json
134
+ {
135
+ "label": "Headline claim that makes the point",
136
+ "topic": "01 / Problem",
137
+ "content": "## Headline claim in one sentence\n\n- Specific point with a number or named entity\n- Second point — consequence or contrast\n- Third point — the implication\n\nClosing sentence bridging to the next slide.",
138
+ "notes": "Talking point not on screen. Time: 2 minutes max.",
139
+ "centered": false
140
+ }
141
+ ```
142
+
143
+ ### Two-Column Comparison
144
+
145
+ ```json
146
+ {
147
+ "label": "Old Way vs. New Way",
148
+ "topic": "02 / Solution",
149
+ "content": "## Today\n- 3 systems, no shared state\n- 11 hours/week reconciling exports\n\n---\n\n## With [Product]\n- Single live record across all systems\n- Reports update in real time",
150
+ "layout": "two-column",
151
+ "centered": false
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Reference Example
158
+
159
+ A 7-node presentation demonstrating cover, content, two-column, inline chart, R3F, background image, and closing.
160
+
161
+ ```json
162
+ {
163
+ "meta": {
164
+ "name": "Graph-Based Presentations"
165
+ },
166
+ "nodes": [
167
+ {
168
+ "id": "cover",
169
+ "type": "huma",
170
+ "position": { "x": 0, "y": 0 },
171
+ "data": {
172
+ "label": "Graph-Based Presentations",
173
+ "topic": "Huma Showcase",
174
+ "content": "Non-linear storytelling for technical teams.\n\nNavigate with arrow keys. Press **down** to drill into any topic.",
175
+ "centered": true,
176
+ "brandFont": true,
177
+ "showBranding": true,
178
+ "brandingText": "huma.energy"
179
+ },
180
+ "style": { "width": 180, "height": 70 },
181
+ "measured": { "width": 180, "height": 70 }
182
+ },
183
+ {
184
+ "id": "problem",
185
+ "type": "huma",
186
+ "position": { "x": 240, "y": 0 },
187
+ "data": {
188
+ "label": "The Problem",
189
+ "topic": "01 / Problem",
190
+ "content": "## Linear tools break complex stories\n\n- Cannot branch based on audience questions\n- Skipping sections breaks the flow\n- No private view for speaker notes during screen share\n\nEvery meeting is different. The presentation should adapt.",
191
+ "notes": "Pause here and ask: 'Does this match your experience?'",
192
+ "centered": false
193
+ },
194
+ "style": { "width": 180, "height": 70 },
195
+ "measured": { "width": 180, "height": 70 }
196
+ },
197
+ {
198
+ "id": "problem-detail",
199
+ "type": "huma",
200
+ "position": { "x": 240, "y": 150 },
201
+ "data": {
202
+ "label": "Value Breakdown",
203
+ "topic": "03 / Value",
204
+ "content": "## Flexible narratives\nAdapt flow to audience type and questions in real time\n\n---\n\n## Consistent style\nReuse front-end web styling and components directly\n\n## Professional delivery\nSpeaker notes and timing without the audience seeing them",
205
+ "layout": "two-column",
206
+ "centered": false
207
+ },
208
+ "style": { "width": 180, "height": 70 },
209
+ "measured": { "width": 180, "height": 70 }
210
+ },
211
+ {
212
+ "id": "value",
213
+ "type": "huma",
214
+ "position": { "x": 480, "y": 0 },
215
+ "data": {
216
+ "label": "The Value",
217
+ "topic": "03 / Value",
218
+ "content": "## Why this approach wins\n\n[chart:value]\n\nAdapt to the audience. Reuse web components. Deliver with confidence.",
219
+ "charts": {
220
+ "value": {
221
+ "chartType": "radar",
222
+ "data": [
223
+ { "axis": "Flexibility", "graph": 95, "traditional": 30 },
224
+ { "axis": "Visual Quality", "graph": 90, "traditional": 50 },
225
+ { "axis": "Interactivity", "graph": 85, "traditional": 20 },
226
+ { "axis": "Ease of Use", "graph": 60, "traditional": 90 },
227
+ { "axis": "Consistency", "graph": 85, "traditional": 40 }
228
+ ],
229
+ "config": {
230
+ "xKey": "axis",
231
+ "yKeys": ["graph", "traditional"],
232
+ "showGrid": true,
233
+ "showLegend": true
234
+ }
235
+ }
236
+ },
237
+ "centered": false
238
+ },
239
+ "style": { "width": 180, "height": 70 },
240
+ "measured": { "width": 180, "height": 70 }
241
+ },
242
+ {
243
+ "id": "feat-3d",
244
+ "type": "huma",
245
+ "position": { "x": 720, "y": 0 },
246
+ "data": {
247
+ "label": "3D Scenes",
248
+ "topic": "04 / Features",
249
+ "type": "r3f",
250
+ "scene": {
251
+ "component": "rotating-cube",
252
+ "controls": true,
253
+ "background": "#1a1a2e"
254
+ },
255
+ "content": "Interactive React Three Fiber scene.\n\nDrag to rotate. Scroll to zoom.",
256
+ "lightText": true
257
+ },
258
+ "style": { "width": 180, "height": 70 },
259
+ "measured": { "width": 180, "height": 70 }
260
+ },
261
+ {
262
+ "id": "feat-bgimage",
263
+ "type": "huma",
264
+ "position": { "x": 960, "y": 0 },
265
+ "data": {
266
+ "label": "Background Image",
267
+ "topic": "04 / Features",
268
+ "content": "## Full-bleed imagery\n\nUpload any image as a slide background. Toggle overlay for text readability.\n\n- Cover/contain fit modes\n- Dark overlay toggle\n- Light text auto-detection",
269
+ "backgroundImage": "https://images.unsplash.com/photo-1451187580459-43490279c0fa?w=1920&q=80",
270
+ "backgroundImageFit": "cover",
271
+ "backgroundImageOverlay": true,
272
+ "lightText": true,
273
+ "centered": false
274
+ },
275
+ "style": { "width": 180, "height": 70 },
276
+ "measured": { "width": 180, "height": 70 }
277
+ },
278
+ {
279
+ "id": "end",
280
+ "type": "huma",
281
+ "position": { "x": 1200, "y": 0 },
282
+ "data": {
283
+ "label": "Get Started",
284
+ "content": "Fork this template to build your own.\n\nEvery slide, chart, and scene is editable in the graph editor.",
285
+ "centered": true,
286
+ "brandFont": true,
287
+ "showBranding": true,
288
+ "brandingText": "huma.energy"
289
+ },
290
+ "style": { "width": 180, "height": 70 },
291
+ "measured": { "width": 180, "height": 70 }
292
+ }
293
+ ],
294
+ "edges": [
295
+ { "id": "e-cover-problem", "source": "cover", "target": "problem", "sourceHandle": "s-right", "targetHandle": "t-left" },
296
+ { "id": "e-problem-cover", "source": "problem", "target": "cover", "sourceHandle": "s-left", "targetHandle": "t-right" },
297
+ { "id": "e-problem-value", "source": "problem", "target": "value", "sourceHandle": "s-right", "targetHandle": "t-left" },
298
+ { "id": "e-value-problem", "source": "value", "target": "problem", "sourceHandle": "s-left", "targetHandle": "t-right" },
299
+ { "id": "e-problem-detail", "source": "problem", "target": "problem-detail", "sourceHandle": "s-bottom", "targetHandle": "t-top" },
300
+ { "id": "e-detail-problem", "source": "problem-detail", "target": "problem", "sourceHandle": "s-top", "targetHandle": "t-bottom" },
301
+ { "id": "e-value-3d", "source": "value", "target": "feat-3d", "sourceHandle": "s-right", "targetHandle": "t-left" },
302
+ { "id": "e-3d-value", "source": "feat-3d", "target": "value", "sourceHandle": "s-left", "targetHandle": "t-right" },
303
+ { "id": "e-3d-bgimage", "source": "feat-3d", "target": "feat-bgimage", "sourceHandle": "s-right", "targetHandle": "t-left" },
304
+ { "id": "e-bgimage-3d", "source": "feat-bgimage", "target": "feat-3d", "sourceHandle": "s-left", "targetHandle": "t-right" },
305
+ { "id": "e-bgimage-end", "source": "feat-bgimage", "target": "end", "sourceHandle": "s-right", "targetHandle": "t-left" },
306
+ { "id": "e-end-bgimage", "source": "end", "target": "feat-bgimage", "sourceHandle": "s-left", "targetHandle": "t-right" }
307
+ ]
308
+ }
309
+ ```
310
+
311
+ ---
312
+
313
+ ## Media Delivery Summary Format
314
+
315
+ After generating the JSON, list any slides with placeholder media:
316
+
317
+ ```
318
+ Slides requiring manual media upload:
319
+ - "Cover" — background video: [description]
320
+ - "Demo" — inline video: [description]
321
+
322
+ Upload via POST /api/slide-images/upload (multipart/form-data, field: "file")
323
+ Returns { ok: true, key, url } — replace placeholder with returned url
324
+ Accepted: all image/*, video/mp4, video/webm, video/quicktime
325
+ Max size: 50MB
326
+ ```