@ztffn/presentation-generator-plugin 1.2.0 → 1.3.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.
- package/.claude/settings.local.json +9 -0
- package/.claude-plugin/plugin.json +1 -1
- package/CONTEXT.md +110 -0
- package/HANDOFF.md +49 -0
- package/PLAN-consolidate-design-skills.md +238 -0
- package/README.md +15 -17
- package/agents/presentation-design.md +55 -8
- package/package.json +1 -1
- package/skills/graph-json-spec/SKILL.md +812 -0
- package/skills/presentation-generator/SKILL.md +1 -1
- package/skills/slide-content/SKILL.md +45 -0
- package/skills/edge-conventions/SKILL.md +0 -97
- package/skills/layout-templates/SKILL.md +0 -315
- package/skills/node-schema/SKILL.md +0 -135
- package/skills/pitch-reference/SKILL.md +0 -164
- package/skills/positioning/SKILL.md +0 -89
|
@@ -187,7 +187,7 @@ Replace the PLACEHOLDER string with the returned URL after upload.
|
|
|
187
187
|
|---|---|---|
|
|
188
188
|
| `presentation-content` | `content-signals` | Extract structured brief from documents |
|
|
189
189
|
| `presentation-narrative` | `frameworks`, `slide-content`, `graph-topology` | Design story structure and slide content |
|
|
190
|
-
| `presentation-design` | `
|
|
190
|
+
| `presentation-design` | `graph-json-spec` | Translate outline to valid graph JSON |
|
|
191
191
|
|
|
192
192
|
## Working Without Documents
|
|
193
193
|
|
|
@@ -196,3 +196,48 @@ Same content, different quality. Study what changed and why.
|
|
|
196
196
|
| Bullets | Generic descriptions | Named roles with concrete hour counts |
|
|
197
197
|
| Implication | Absent | Explicit (→ connector) |
|
|
198
198
|
| Speaker notes | Repetition of screen content | Anticipation, objection routing, time guidance |
|
|
199
|
+
|
|
200
|
+
## Visual Rhythm
|
|
201
|
+
|
|
202
|
+
Presentations that feel designed — not generated — alternate between dense and light slides. A deck of wall-to-wall bullets is exhausting. A deck of nothing but images is empty. The rhythm between them is what holds attention.
|
|
203
|
+
|
|
204
|
+
### The Rhythm Principle
|
|
205
|
+
|
|
206
|
+
Alternate content-heavy slides with breathing-room slides. After 2-3 slides carrying bullets, data, or detailed argument, insert a visual reset: an image slide, an impact statement, or a centered single thought. This gives the audience a moment to absorb before the next dense block.
|
|
207
|
+
|
|
208
|
+
Think of it as chapters in a book. Dense paragraphs need white space between them. A presentation spine needs the same cadence.
|
|
209
|
+
|
|
210
|
+
### Visual Intent Annotations
|
|
211
|
+
|
|
212
|
+
The narrative agent should annotate each slide in the outline with a `**Visual intent:**` line indicating the slide's visual role. These labels communicate pacing intent to the design agent without prescribing any specific layout or JSON treatment.
|
|
213
|
+
|
|
214
|
+
| Label | Purpose |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `chapter-opener` | Full-bleed image, centered text, sets mood for a new section |
|
|
217
|
+
| `impact` | Single bold statement, centered, no bullets, emotional weight |
|
|
218
|
+
| `workhorse` | Standard bullets/content, the default |
|
|
219
|
+
| `evidence` | Data-forward: chart, table, or comparison |
|
|
220
|
+
| `bookend` | Cover or CTA, branded, symmetrical with its pair |
|
|
221
|
+
| `breathing-room` | Minimal text over image or color, resets attention after dense slides |
|
|
222
|
+
|
|
223
|
+
Example annotation in an outline:
|
|
224
|
+
|
|
225
|
+
```
|
|
226
|
+
Slide 4: "Response time dropped 60% — infrastructure cost followed"
|
|
227
|
+
Key message: The platform delivers measurable speed and cost gains.
|
|
228
|
+
**Visual intent:** evidence
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Pacing Rules
|
|
232
|
+
|
|
233
|
+
1. **No three-in-a-row.** Never place 3 or more `workhorse` slides consecutively without a visual reset (`impact`, `chapter-opener`, or `breathing-room`).
|
|
234
|
+
|
|
235
|
+
2. **Alternate dense and light.** The spine should weave between heavy and light visual weight. `workhorse` → `evidence` → `impact` → `workhorse` is better than `workhorse` → `workhorse` → `workhorse` → `impact`.
|
|
236
|
+
|
|
237
|
+
3. **Chapter openers at section boundaries.** When the spine moves to a new major topic, mark the transitional slide as `chapter-opener`. This signals a mood shift and gives the audience a visual cue that the argument is entering new territory.
|
|
238
|
+
|
|
239
|
+
4. **Bookends mirror each other.** The cover slide and the closing CTA should feel symmetrical in visual weight. Both are `bookend` — they frame the presentation as a pair.
|
|
240
|
+
|
|
241
|
+
5. **Breathing room after sustained density.** If the outline has a run of `workhorse` and `evidence` slides (detailed argument, data, comparison), follow it with a `breathing-room` or `impact` slide before continuing. The audience needs a reset.
|
|
242
|
+
|
|
243
|
+
These annotations describe intent only. How the design agent translates them into layout, background, and typography is not the narrative agent's concern.
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: edge-conventions
|
|
3
|
-
description: Authoritative reference for wiring navigation edges — handle IDs, bidirectional pairs, and validation checklist.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Edge Conventions
|
|
7
|
-
|
|
8
|
-
Authoritative reference for wiring navigation edges in the presentation graph.
|
|
9
|
-
Edges define valid navigation paths — without correct edges, arrow keys won't work.
|
|
10
|
-
|
|
11
|
-
## Handle IDs
|
|
12
|
-
|
|
13
|
-
Eight handle IDs exist, four source and four target:
|
|
14
|
-
|
|
15
|
-
| Handle ID | Type | Position | Navigation |
|
|
16
|
-
|---|---|---|---|
|
|
17
|
-
| `s-right` | source | Right side | Pressing **right arrow** follows this edge |
|
|
18
|
-
| `s-left` | source | Left side | Pressing **left arrow** follows this edge |
|
|
19
|
-
| `s-bottom` | source | Bottom | Pressing **down arrow** follows this edge |
|
|
20
|
-
| `s-top` | source | Top | Pressing **up arrow** follows this edge |
|
|
21
|
-
| `t-right` | target | Right side | Arrived via **left arrow** from source |
|
|
22
|
-
| `t-left` | target | Left side | Arrived via **right arrow** from source |
|
|
23
|
-
| `t-bottom` | target | Bottom | Arrived via **up arrow** from source |
|
|
24
|
-
| `t-top` | target | Top | Arrived via **down arrow** from source |
|
|
25
|
-
|
|
26
|
-
## Bidirectional Pair Rule
|
|
27
|
-
|
|
28
|
-
**Every navigation edge must have a return edge** with swapped source/target and swapped handles.
|
|
29
|
-
|
|
30
|
-
If the user can press right to go from A to B, they must be able to press left to go from B back to A.
|
|
31
|
-
|
|
32
|
-
## Standard Edge Pairs
|
|
33
|
-
|
|
34
|
-
### Horizontal Forward/Back (Spine Navigation)
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{ "id": "e-a-b", "source": "a", "target": "b", "sourceHandle": "s-right", "targetHandle": "t-left" }
|
|
38
|
-
{ "id": "e-b-a", "source": "b", "target": "a", "sourceHandle": "s-left", "targetHandle": "t-right" }
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
A → (right) → B and B → (left) → A
|
|
42
|
-
|
|
43
|
-
### Drill-Down / Return-to-Parent
|
|
44
|
-
|
|
45
|
-
```json
|
|
46
|
-
{ "id": "e-parent-child", "source": "parent", "target": "child", "sourceHandle": "s-bottom", "targetHandle": "t-top" }
|
|
47
|
-
{ "id": "e-child-parent", "source": "child", "target": "parent", "sourceHandle": "s-top", "targetHandle": "t-bottom" }
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
Parent → (down) → Child and Child → (up) → Parent
|
|
51
|
-
|
|
52
|
-
### Horizontal Within a Drill-Down Branch
|
|
53
|
-
|
|
54
|
-
Siblings within a drill-down branch use the same horizontal pattern:
|
|
55
|
-
|
|
56
|
-
```json
|
|
57
|
-
{ "id": "e-child1-child2", "source": "child1", "target": "child2", "sourceHandle": "s-right", "targetHandle": "t-left" }
|
|
58
|
-
{ "id": "e-child2-child1", "source": "child2", "target": "child1", "sourceHandle": "s-left", "targetHandle": "t-right" }
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Edge ID Convention
|
|
62
|
-
|
|
63
|
-
Use descriptive hyphenated strings:
|
|
64
|
-
|
|
65
|
-
- `e-cover-problem` — cover to problem
|
|
66
|
-
- `e-problem-cover` — problem back to cover
|
|
67
|
-
- `e-problem-detail` — problem drill-down to detail
|
|
68
|
-
- `e-detail-problem` — detail return to problem
|
|
69
|
-
|
|
70
|
-
Pattern: `e-{source}-{target}` using the node IDs or abbreviated forms.
|
|
71
|
-
|
|
72
|
-
## Validation Checklist
|
|
73
|
-
|
|
74
|
-
Run this checklist before writing the final JSON:
|
|
75
|
-
|
|
76
|
-
1. **Every node has at least one outgoing edge** — no dead ends
|
|
77
|
-
2. **Every forward edge has a paired return edge** — source/target swapped, handles swapped
|
|
78
|
-
3. **All handle IDs are from the valid set** — only the 8 IDs listed above
|
|
79
|
-
4. **Source handles start with `s-`** and target handles start with `t-`
|
|
80
|
-
5. **The first spine node has no incoming `s-right` edge** — it's the leftmost entry point
|
|
81
|
-
6. **The last spine node has no outgoing `s-right` edge** (or loops back to cover)
|
|
82
|
-
7. **Drill-down children always have `s-top`/`t-bottom` return edge to parent**
|
|
83
|
-
8. **No duplicate edge IDs**
|
|
84
|
-
|
|
85
|
-
## Edge Object Structure
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"id": "e-cover-problem",
|
|
90
|
-
"source": "cover",
|
|
91
|
-
"target": "problem",
|
|
92
|
-
"sourceHandle": "s-right",
|
|
93
|
-
"targetHandle": "t-left"
|
|
94
|
-
}
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
All four fields (`source`, `target`, `sourceHandle`, `targetHandle`) are required. Edges without explicit handles will have direction inferred from node positions, but this is a fallback — always set handles explicitly.
|
|
@@ -1,315 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: layout-templates
|
|
3
|
-
description: Decision guide mapping content signals to slide type, layout, background treatment, and visual configuration.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Layout Templates & Design Decisions
|
|
7
|
-
|
|
8
|
-
Decision guide for the design agent. Maps content signals from the slide outline
|
|
9
|
-
to the correct visual treatment in the graph JSON.
|
|
10
|
-
|
|
11
|
-
## Slide Type Selection
|
|
12
|
-
|
|
13
|
-
| Content Signal | `type` | Key Fields |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| Standard text, bullets, headings | `"content"` (default) | `content`, `layout` |
|
|
16
|
-
| Full-viewport data visualization | `"chart"` | `chart` (ChartConfig) |
|
|
17
|
-
| Interactive 3D scene | `"r3f"` | `scene` (R3FSceneConfig) |
|
|
18
|
-
|
|
19
|
-
Most slides are `"content"`. Use `"chart"` or `"r3f"` only when the content is primarily a visualization.
|
|
20
|
-
|
|
21
|
-
## Layout Decisions
|
|
22
|
-
|
|
23
|
-
### When to Use `two-column`
|
|
24
|
-
|
|
25
|
-
Set `layout: "two-column"` and split content on `---` when:
|
|
26
|
-
|
|
27
|
-
- **Comparison:** before/after, old/new, us/them
|
|
28
|
-
- **Pros/cons:** advantages on left, considerations on right
|
|
29
|
-
- **Text + chart:** explanation on left, `[chart:name]` on right
|
|
30
|
-
- **Text + media:** bullets on left, `` on right
|
|
31
|
-
- **Dual evidence:** two independent supporting points side by side
|
|
32
|
-
|
|
33
|
-
Do not force two-column when content is naturally sequential.
|
|
34
|
-
|
|
35
|
-
### When to Center
|
|
36
|
-
|
|
37
|
-
Set `centered: true` for:
|
|
38
|
-
|
|
39
|
-
- **Cover slides:** Title + subtitle, branded
|
|
40
|
-
- **Call-to-action slides:** Single message, end of presentation
|
|
41
|
-
- **Single-message impact slides:** One powerful statement or quote
|
|
42
|
-
- **Transition slides:** Brief pause between major sections
|
|
43
|
-
|
|
44
|
-
Set `centered: false` for:
|
|
45
|
-
|
|
46
|
-
- **Content-heavy slides:** Bullets, tables, code, multiple paragraphs
|
|
47
|
-
- **Data slides:** Charts with explanatory text
|
|
48
|
-
- **Comparison slides:** Two-column layouts
|
|
49
|
-
|
|
50
|
-
### When to Use Brand Font
|
|
51
|
-
|
|
52
|
-
Set `brandFont: true` for:
|
|
53
|
-
|
|
54
|
-
- Cover slide (first slide)
|
|
55
|
-
- Closing/CTA slide (last slide)
|
|
56
|
-
- High-impact single-message slides
|
|
57
|
-
|
|
58
|
-
Do not use on content-heavy or data slides — brand fonts are display fonts, not body fonts.
|
|
59
|
-
|
|
60
|
-
### When to Show Branding
|
|
61
|
-
|
|
62
|
-
Set `showBranding: true` and `brandingText: "huma.energy"` (or client name) for:
|
|
63
|
-
|
|
64
|
-
- Cover slide
|
|
65
|
-
- Closing slide
|
|
66
|
-
- Any slide where the audience might screenshot or reference later
|
|
67
|
-
|
|
68
|
-
Default is `true`, so only set `showBranding: false` for immersive slides (R3F, full-bleed video) where the overlay is distracting.
|
|
69
|
-
|
|
70
|
-
## Background Treatment
|
|
71
|
-
|
|
72
|
-
### Background Image
|
|
73
|
-
|
|
74
|
-
Use `backgroundImage` when the outline indicates:
|
|
75
|
-
- A mood or atmosphere for a section opener
|
|
76
|
-
- Visual evidence (photo of a product, facility, or result)
|
|
77
|
-
- Impact slide where imagery reinforces the message
|
|
78
|
-
|
|
79
|
-
Set `backgroundImageOverlay: true` and `lightText: true` when text appears over the image.
|
|
80
|
-
|
|
81
|
-
**Image sourcing:** Use external URLs directly. Unsplash with query params works well:
|
|
82
|
-
```
|
|
83
|
-
https://images.unsplash.com/photo-XXXXX?w=1920&q=80
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Background Video
|
|
87
|
-
|
|
88
|
-
Use `backgroundVideo` for cinematic section openers or demo context.
|
|
89
|
-
|
|
90
|
-
**Video sourcing is deferred.** For any slide requiring background video:
|
|
91
|
-
1. Set `backgroundVideo` to a placeholder: `"PLACEHOLDER: [description of needed video]"`
|
|
92
|
-
2. Set `backgroundVideoFit: "cover"` and `backgroundVideoLoop: true`
|
|
93
|
-
3. Add the slide title to the delivery summary for manual upload
|
|
94
|
-
|
|
95
|
-
### Inline Video
|
|
96
|
-
|
|
97
|
-
For videos embedded in slide content (via `` in markdown):
|
|
98
|
-
1. Set the URL to a placeholder: `"PLACEHOLDER: [description]"`
|
|
99
|
-
2. Configure `inlineVideoControls`, `inlineVideoAutoplay`, `inlineVideoLoop` as appropriate
|
|
100
|
-
3. Add to delivery summary
|
|
101
|
-
|
|
102
|
-
### Text Contrast
|
|
103
|
-
|
|
104
|
-
Set `lightText: true` whenever the background is dark:
|
|
105
|
-
- Dark `style.backgroundColor`
|
|
106
|
-
- `backgroundImage` with `backgroundImageOverlay: true`
|
|
107
|
-
- `backgroundVideo` slides
|
|
108
|
-
- `type: "r3f"` with dark scene background
|
|
109
|
-
|
|
110
|
-
## Chart Decisions
|
|
111
|
-
|
|
112
|
-
### Full-Viewport Chart (`type: "chart"`)
|
|
113
|
-
|
|
114
|
-
Use when the data IS the slide — the chart is the primary message, not supporting evidence.
|
|
115
|
-
|
|
116
|
-
```json
|
|
117
|
-
{
|
|
118
|
-
"type": "chart",
|
|
119
|
-
"chart": {
|
|
120
|
-
"chartType": "bar",
|
|
121
|
-
"data": [...],
|
|
122
|
-
"config": { "xKey": "quarter", "yKeys": ["revenue", "cost"], "showGrid": true, "showLegend": true }
|
|
123
|
-
},
|
|
124
|
-
"content": "Optional caption below the chart"
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Inline Chart (`[chart:name]` in content)
|
|
129
|
-
|
|
130
|
-
Use when data supports a text argument — the chart is evidence, not the headline.
|
|
131
|
-
|
|
132
|
-
```json
|
|
133
|
-
{
|
|
134
|
-
"content": "## Why this approach wins\n\n[chart:comparison]\n\nAdapt to the audience. Deliver with confidence.",
|
|
135
|
-
"charts": {
|
|
136
|
-
"comparison": {
|
|
137
|
-
"chartType": "radar",
|
|
138
|
-
"data": [...],
|
|
139
|
-
"config": { "xKey": "axis", "yKeys": ["ours", "theirs"], "showLegend": true }
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Chart Title Rule
|
|
146
|
-
|
|
147
|
-
A chart's `label` field states the insight, not the data category. The audience should understand your point before reading the chart.
|
|
148
|
-
|
|
149
|
-
| Weak (category label) | Strong (insight claim) |
|
|
150
|
-
|---|---|
|
|
151
|
-
| "Revenue Data" | "Revenue grew 40% QoQ after the pricing change" |
|
|
152
|
-
| "Response Time" | "Response time dropped 60% after caching rollout" |
|
|
153
|
-
| "User Growth" | "1M users in 6 months — 2× ahead of plan" |
|
|
154
|
-
|
|
155
|
-
The label is your assertion. The chart is your evidence.
|
|
156
|
-
|
|
157
|
-
### Chart Type Selection
|
|
158
|
-
|
|
159
|
-
| Data Pattern | Chart Type |
|
|
160
|
-
|---|---|
|
|
161
|
-
| Trend over time | `"line"` or `"area"` |
|
|
162
|
-
| Category comparison | `"bar"` |
|
|
163
|
-
| Multi-axis comparison | `"radar"` |
|
|
164
|
-
| Part-of-whole | `"pie"` |
|
|
165
|
-
| Volume trend | `"area"` |
|
|
166
|
-
|
|
167
|
-
## R3F Scene Decisions
|
|
168
|
-
|
|
169
|
-
Use `type: "r3f"` when the outline calls for a 3D demo or visual impact.
|
|
170
|
-
|
|
171
|
-
Available scenes:
|
|
172
|
-
- `"rotating-cube"` — interactive cube, good for tech demos. Set `scene.controls: true`.
|
|
173
|
-
- `"particle-field"` — atmospheric particle cloud. Set `scene.controls: false`.
|
|
174
|
-
|
|
175
|
-
Always set `lightText: true` for R3F slides (dark backgrounds). Content renders as an overlay on top of the 3D scene.
|
|
176
|
-
|
|
177
|
-
## Topic Badge Conventions
|
|
178
|
-
|
|
179
|
-
Use `topic` to group slides by section. Format: `"NN / Section Name"` for numbered sections:
|
|
180
|
-
|
|
181
|
-
- `"01 / Problem"`
|
|
182
|
-
- `"02 / Solution"`
|
|
183
|
-
- `"03 / Value"`
|
|
184
|
-
- `"04 / Evidence"`
|
|
185
|
-
|
|
186
|
-
Or plain text for non-numbered groupings: `"Huma Showcase"`, `"Technical Deep Dive"`.
|
|
187
|
-
|
|
188
|
-
## Slide Recipes
|
|
189
|
-
|
|
190
|
-
Complete `data` field patterns for common pitch slide types. Combine with `node-schema.md` for the full field reference.
|
|
191
|
-
|
|
192
|
-
### Cover / Call to Action
|
|
193
|
-
|
|
194
|
-
Cover = first spine node. CTA = last. Both: centered, branded, no bullets. The only difference is the label and content.
|
|
195
|
-
|
|
196
|
-
```json
|
|
197
|
-
{
|
|
198
|
-
"label": "[Title or Ask]",
|
|
199
|
-
"topic": "[Company or Meeting Context]",
|
|
200
|
-
"content": "One sentence: what this is and for whom. (Cover) — or — what happens next and when. (CTA)",
|
|
201
|
-
"centered": true,
|
|
202
|
-
"brandFont": true,
|
|
203
|
-
"showBranding": true,
|
|
204
|
-
"brandingText": "[company.domain]"
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
### Standard Bullets — Workhorse
|
|
209
|
-
|
|
210
|
-
Default for problem, solution, evidence, and detail nodes.
|
|
211
|
-
|
|
212
|
-
```json
|
|
213
|
-
{
|
|
214
|
-
"label": "Headline claim that makes the point",
|
|
215
|
-
"topic": "01 / Problem",
|
|
216
|
-
"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.",
|
|
217
|
-
"notes": "Talking point not on screen. Objection signal: 'If they ask X, navigate to [node-id].' Time: 2 minutes max.",
|
|
218
|
-
"centered": false
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Impact Statement
|
|
223
|
-
|
|
224
|
-
Single message, no bullets. Use for named shifts, "why now" openers, or bold claims that stand alone.
|
|
225
|
-
|
|
226
|
-
```json
|
|
227
|
-
{
|
|
228
|
-
"label": "The Shift",
|
|
229
|
-
"topic": "01 / Problem",
|
|
230
|
-
"content": "The market has permanently changed.\n\n**Batch scheduling is structurally incompatible with same-day delivery expectations.**",
|
|
231
|
-
"notes": "Pause. Do not advance immediately. If the room agrees, the rest is inevitable.",
|
|
232
|
-
"centered": true
|
|
233
|
-
}
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Two-Column Comparison
|
|
237
|
-
|
|
238
|
-
Before/after, us/them, or two parallel arguments. Content splits on `---`; left column renders first.
|
|
239
|
-
|
|
240
|
-
```json
|
|
241
|
-
{
|
|
242
|
-
"label": "Old Way vs. New Way",
|
|
243
|
-
"topic": "02 / Solution",
|
|
244
|
-
"content": "## Today\n- 3 systems, no shared state\n- 11 hours/week reconciling exports\n- Reports are always one day stale\n\n---\n\n## With [Product]\n- Single live record across all systems\n- Reports update in real time\n- Finance, ops, and leadership see the same data",
|
|
245
|
-
"layout": "two-column",
|
|
246
|
-
"centered": false
|
|
247
|
-
}
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Text + Inline Chart
|
|
251
|
-
|
|
252
|
-
Text on left makes the claim; chart on right is the evidence. Chart is supporting, not the headline.
|
|
253
|
-
|
|
254
|
-
```json
|
|
255
|
-
{
|
|
256
|
-
"label": "The Data Confirms It",
|
|
257
|
-
"topic": "03 / Evidence",
|
|
258
|
-
"content": "## Continuous monitoring outperforms batch on every metric\n\nThree field studies. Same result each time.\n\n---\n\n[chart:comparison]",
|
|
259
|
-
"charts": {
|
|
260
|
-
"comparison": {
|
|
261
|
-
"chartType": "bar",
|
|
262
|
-
"data": [{ "metric": "Uptime %", "ours": 98.2, "baseline": 91.5 }],
|
|
263
|
-
"config": { "xKey": "metric", "yKeys": ["ours", "baseline"], "showGrid": true, "showLegend": true }
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
"layout": "two-column",
|
|
267
|
-
"centered": false
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Proof Point — Customer Quote
|
|
272
|
-
|
|
273
|
-
Named case study or customer quote. Blockquote (`>`) renders as a styled pull quote — lead with it before the numbers.
|
|
274
|
-
|
|
275
|
-
```json
|
|
276
|
-
{
|
|
277
|
-
"label": "Summit Health: Year One",
|
|
278
|
-
"topic": "04 / Proof",
|
|
279
|
-
"content": "## 2.3 hours of admin time eliminated per nurse per shift\n\n> \"The conflicts surfaced automatically — we'd been creating them for years without knowing it.\"\n> — VP Operations, Summit Health (42 facilities)\n\n- 38% reduction in shift coverage failures\n- Full rollout across 6 units in 11 weeks",
|
|
280
|
-
"notes": "If they ask about rollout timeline, the drill-down below has the full breakdown.",
|
|
281
|
-
"centered": false
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
### Section Opener — Background Image
|
|
286
|
-
|
|
287
|
-
Spine node opening a new chapter. Sets atmosphere. Max 3 bullet points on an image slide.
|
|
288
|
-
|
|
289
|
-
```json
|
|
290
|
-
{
|
|
291
|
-
"label": "The Opportunity",
|
|
292
|
-
"topic": "03 / Opportunity",
|
|
293
|
-
"content": "## A $40B market with no dominant platform\n\nEvery competitor is solving scheduling.\nNobody is solving the coordination layer.",
|
|
294
|
-
"backgroundImage": "https://images.unsplash.com/photo-XXXXX?w=1920&q=80",
|
|
295
|
-
"backgroundImageFit": "cover",
|
|
296
|
-
"backgroundImageOverlay": true,
|
|
297
|
-
"lightText": true,
|
|
298
|
-
"centered": false
|
|
299
|
-
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
## Media Delivery Summary
|
|
303
|
-
|
|
304
|
-
After generating the JSON, list any slides with placeholder media:
|
|
305
|
-
|
|
306
|
-
```
|
|
307
|
-
Slides requiring manual media upload:
|
|
308
|
-
- "Cover" — background video: [description]
|
|
309
|
-
- "Demo" — inline video: [description]
|
|
310
|
-
|
|
311
|
-
Upload via POST /api/slide-images/upload (multipart/form-data, field: "file")
|
|
312
|
-
Returns { ok: true, key, url } — replace placeholder with returned url
|
|
313
|
-
Accepted: all image/*, video/mp4, video/webm, video/quicktime
|
|
314
|
-
Max size: 50MB
|
|
315
|
-
```
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: node-schema
|
|
3
|
-
description: Authoritative reference for SlideNodeData interface — all fields, types, and defaults for graph presentation nodes.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Node Schema Reference
|
|
7
|
-
|
|
8
|
-
Authoritative reference for the `SlideNodeData` interface.
|
|
9
|
-
Derived from `src/types/presentation.ts`. All fields, types, and defaults documented here.
|
|
10
|
-
|
|
11
|
-
## Node Wrapper
|
|
12
|
-
|
|
13
|
-
Every node in the graph has this structure:
|
|
14
|
-
|
|
15
|
-
```json
|
|
16
|
-
{
|
|
17
|
-
"id": "unique-slug",
|
|
18
|
-
"type": "huma",
|
|
19
|
-
"position": { "x": 0, "y": 0 },
|
|
20
|
-
"data": { /* SlideNodeData fields below */ },
|
|
21
|
-
"style": { "width": 180, "height": 70 },
|
|
22
|
-
"measured": { "width": 180, "height": 70 }
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
- `id`: Kebab-case slug (e.g. `"cover"`, `"problem-detail"`, `"feat-3d"`)
|
|
27
|
-
- `type`: Always `"huma"` — the custom node type with directional handles
|
|
28
|
-
- `position`: `{ x, y }` in graph canvas coordinates (see `positioning.md`)
|
|
29
|
-
- `style.width`: Always `180`. `style.height`: Always `70`.
|
|
30
|
-
- `measured`: Must mirror `style` — `{ width: 180, height: 70 }`
|
|
31
|
-
- Optional: `style.backgroundColor` — hex string for node background in the graph editor (also applied as slide background)
|
|
32
|
-
|
|
33
|
-
## SlideNodeData Fields
|
|
34
|
-
|
|
35
|
-
### Content Fields
|
|
36
|
-
|
|
37
|
-
| Field | Type | Default | Description |
|
|
38
|
-
|---|---|---|---|
|
|
39
|
-
| `label` | `string?` | — | Slide title displayed in graph editor and as slide heading |
|
|
40
|
-
| `topic` | `string?` | — | Section badge on the slide (e.g. `"01 / Problem"`, `"Solution"`) |
|
|
41
|
-
| `content` | `string?` | — | Markdown body. Supports headings, bullets, bold, code, tables, `[chart:name]` embeds, `` images/videos, `[text](#nodeId)` navigation links |
|
|
42
|
-
| `notes` | `string?` | — | Speaker notes, shown only in the presenter panel |
|
|
43
|
-
|
|
44
|
-
### Slide Type
|
|
45
|
-
|
|
46
|
-
| Field | Type | Default | Description |
|
|
47
|
-
|---|---|---|---|
|
|
48
|
-
| `type` | `"content" \| "r3f" \| "chart" \| "custom"` | `"content"` | Slide renderer. `"content"` for standard text, `"r3f"` for 3D scene, `"chart"` for full-viewport chart |
|
|
49
|
-
|
|
50
|
-
### Layout & Display
|
|
51
|
-
|
|
52
|
-
| Field | Type | Default | Description |
|
|
53
|
-
|---|---|---|---|
|
|
54
|
-
| `centered` | `boolean?` | `true` | Center content vertically and horizontally |
|
|
55
|
-
| `layout` | `"single" \| "two-column"` | `"single"` | Content layout. `"two-column"` splits on `---` delimiter in content |
|
|
56
|
-
| `lightText` | `boolean?` | `false` | Force white text for dark backgrounds |
|
|
57
|
-
| `brandFont` | `boolean?` | `false` | Use HumaDisplay display font for the title |
|
|
58
|
-
| `showBranding` | `boolean?` | `true` | Show branding overlay |
|
|
59
|
-
| `brandingText` | `string?` | — | Bottom-left branding label (e.g. `"huma.energy"`) |
|
|
60
|
-
|
|
61
|
-
### Background Media
|
|
62
|
-
|
|
63
|
-
| Field | Type | Default | Description |
|
|
64
|
-
|---|---|---|---|
|
|
65
|
-
| `backgroundImage` | `string?` | — | URL to background image |
|
|
66
|
-
| `backgroundImageFit` | `"cover" \| "contain"` | `"cover"` | How image fills the slide |
|
|
67
|
-
| `backgroundImageOverlay` | `boolean?` | `false` | Dark scrim over background image for text readability |
|
|
68
|
-
| `backgroundVideo` | `string?` | — | URL to background video |
|
|
69
|
-
| `backgroundVideoFit` | `"cover" \| "contain"` | `"cover"` | How video fills the slide |
|
|
70
|
-
| `backgroundVideoLoop` | `boolean?` | `true` | Loop background video |
|
|
71
|
-
|
|
72
|
-
### Inline Video
|
|
73
|
-
|
|
74
|
-
| Field | Type | Default | Description |
|
|
75
|
-
|---|---|---|---|
|
|
76
|
-
| `inlineVideoControls` | `boolean?` | `true` | Show controls on inline videos in `content` |
|
|
77
|
-
| `inlineVideoAutoplay` | `boolean?` | `true` | Autoplay inline videos |
|
|
78
|
-
| `inlineVideoLoop` | `boolean?` | `true` | Loop inline videos |
|
|
79
|
-
|
|
80
|
-
### R3F Scene (when `type: "r3f"`)
|
|
81
|
-
|
|
82
|
-
| Field | Type | Default | Description |
|
|
83
|
-
|---|---|---|---|
|
|
84
|
-
| `scene.component` | `string` | — | Registry key (e.g. `"rotating-cube"`, `"particle-field"`) |
|
|
85
|
-
| `scene.props` | `Record<string, unknown>?` | — | Props passed to the scene component |
|
|
86
|
-
| `scene.controls` | `boolean?` | — | Enable OrbitControls for user interaction |
|
|
87
|
-
| `scene.background` | `string?` | — | Scene background hex color |
|
|
88
|
-
|
|
89
|
-
### Charts
|
|
90
|
-
|
|
91
|
-
**Full-viewport chart** (when `type: "chart"`):
|
|
92
|
-
|
|
93
|
-
| Field | Type | Default | Description |
|
|
94
|
-
|---|---|---|---|
|
|
95
|
-
| `chart.chartType` | `"bar" \| "line" \| "area" \| "pie" \| "radar"` | — | Chart renderer |
|
|
96
|
-
| `chart.data` | `Array<Record<string, unknown>>` | — | Data array |
|
|
97
|
-
| `chart.config.xKey` | `string?` | — | X-axis data key |
|
|
98
|
-
| `chart.config.yKeys` | `string[]?` | — | Y-axis data keys |
|
|
99
|
-
| `chart.config.colors` | `string[]?` | — | Series colors |
|
|
100
|
-
| `chart.config.showGrid` | `boolean?` | — | Show grid lines |
|
|
101
|
-
| `chart.config.showLegend` | `boolean?` | — | Show legend |
|
|
102
|
-
|
|
103
|
-
**Inline charts** (referenced via `[chart:name]` in content):
|
|
104
|
-
|
|
105
|
-
| Field | Type | Default | Description |
|
|
106
|
-
|---|---|---|---|
|
|
107
|
-
| `charts` | `Record<string, ChartConfig>` | — | Named chart configurations. Key is referenced in content as `[chart:keyname]` |
|
|
108
|
-
|
|
109
|
-
Each `ChartConfig` has the same shape as `chart` above.
|
|
110
|
-
|
|
111
|
-
## Available R3F Scene Components
|
|
112
|
-
|
|
113
|
-
| Registry Key | Description |
|
|
114
|
-
|---|---|
|
|
115
|
-
| `rotating-cube` | Interactive rotating cube with OrbitControls |
|
|
116
|
-
| `particle-field` | Animated particle cloud background |
|
|
117
|
-
|
|
118
|
-
## Content Markdown Features
|
|
119
|
-
|
|
120
|
-
The `content` field supports:
|
|
121
|
-
|
|
122
|
-
- `## Heading` — headings (ATX style only, no setext)
|
|
123
|
-
- `- bullet` or `* bullet` — unordered lists
|
|
124
|
-
- `1. item` — ordered lists
|
|
125
|
-
- `` ```language ``` `` — syntax-highlighted code blocks
|
|
126
|
-
- `> blockquote` — styled blockquotes
|
|
127
|
-
- `**bold**` and `*italic*` — inline formatting
|
|
128
|
-
- `| col | col |` — GFM tables
|
|
129
|
-
- `` — images; `.mp4/.webm/.mov` URLs render as inline video
|
|
130
|
-
- `[text](url)` — external links (open in new tab)
|
|
131
|
-
- `[text](#nodeId)` — navigation links to other slides
|
|
132
|
-
- `[chart:name]` — inline chart embed (must be on its own line)
|
|
133
|
-
- `---` — column delimiter when `layout: "two-column"`
|
|
134
|
-
- Single newline = visible line break (not collapsed)
|
|
135
|
-
- Multiple blank lines = visible vertical spacing
|