@ztffn/presentation-generator-plugin 1.1.5 → 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.
@@ -1,310 +0,0 @@
1
- # Layout Templates & Design Decisions
2
-
3
- Decision guide for the design agent. Maps content signals from the slide outline
4
- to the correct visual treatment in the graph JSON.
5
-
6
- ## Slide Type Selection
7
-
8
- | Content Signal | `type` | Key Fields |
9
- |---|---|---|
10
- | Standard text, bullets, headings | `"content"` (default) | `content`, `layout` |
11
- | Full-viewport data visualization | `"chart"` | `chart` (ChartConfig) |
12
- | Interactive 3D scene | `"r3f"` | `scene` (R3FSceneConfig) |
13
-
14
- Most slides are `"content"`. Use `"chart"` or `"r3f"` only when the content is primarily a visualization.
15
-
16
- ## Layout Decisions
17
-
18
- ### When to Use `two-column`
19
-
20
- Set `layout: "two-column"` and split content on `---` when:
21
-
22
- - **Comparison:** before/after, old/new, us/them
23
- - **Pros/cons:** advantages on left, considerations on right
24
- - **Text + chart:** explanation on left, `[chart:name]` on right
25
- - **Text + media:** bullets on left, `![](image)` on right
26
- - **Dual evidence:** two independent supporting points side by side
27
-
28
- Do not force two-column when content is naturally sequential.
29
-
30
- ### When to Center
31
-
32
- Set `centered: true` for:
33
-
34
- - **Cover slides:** Title + subtitle, branded
35
- - **Call-to-action slides:** Single message, end of presentation
36
- - **Single-message impact slides:** One powerful statement or quote
37
- - **Transition slides:** Brief pause between major sections
38
-
39
- Set `centered: false` for:
40
-
41
- - **Content-heavy slides:** Bullets, tables, code, multiple paragraphs
42
- - **Data slides:** Charts with explanatory text
43
- - **Comparison slides:** Two-column layouts
44
-
45
- ### When to Use Brand Font
46
-
47
- Set `brandFont: true` for:
48
-
49
- - Cover slide (first slide)
50
- - Closing/CTA slide (last slide)
51
- - High-impact single-message slides
52
-
53
- Do not use on content-heavy or data slides — brand fonts are display fonts, not body fonts.
54
-
55
- ### When to Show Branding
56
-
57
- Set `showBranding: true` and `brandingText: "huma.energy"` (or client name) for:
58
-
59
- - Cover slide
60
- - Closing slide
61
- - Any slide where the audience might screenshot or reference later
62
-
63
- Default is `true`, so only set `showBranding: false` for immersive slides (R3F, full-bleed video) where the overlay is distracting.
64
-
65
- ## Background Treatment
66
-
67
- ### Background Image
68
-
69
- Use `backgroundImage` when the outline indicates:
70
- - A mood or atmosphere for a section opener
71
- - Visual evidence (photo of a product, facility, or result)
72
- - Impact slide where imagery reinforces the message
73
-
74
- Set `backgroundImageOverlay: true` and `lightText: true` when text appears over the image.
75
-
76
- **Image sourcing:** Use external URLs directly. Unsplash with query params works well:
77
- ```
78
- https://images.unsplash.com/photo-XXXXX?w=1920&q=80
79
- ```
80
-
81
- ### Background Video
82
-
83
- Use `backgroundVideo` for cinematic section openers or demo context.
84
-
85
- **Video sourcing is deferred.** For any slide requiring background video:
86
- 1. Set `backgroundVideo` to a placeholder: `"PLACEHOLDER: [description of needed video]"`
87
- 2. Set `backgroundVideoFit: "cover"` and `backgroundVideoLoop: true`
88
- 3. Add the slide title to the delivery summary for manual upload
89
-
90
- ### Inline Video
91
-
92
- For videos embedded in slide content (via `![alt](url)` in markdown):
93
- 1. Set the URL to a placeholder: `"PLACEHOLDER: [description]"`
94
- 2. Configure `inlineVideoControls`, `inlineVideoAutoplay`, `inlineVideoLoop` as appropriate
95
- 3. Add to delivery summary
96
-
97
- ### Text Contrast
98
-
99
- Set `lightText: true` whenever the background is dark:
100
- - Dark `style.backgroundColor`
101
- - `backgroundImage` with `backgroundImageOverlay: true`
102
- - `backgroundVideo` slides
103
- - `type: "r3f"` with dark scene background
104
-
105
- ## Chart Decisions
106
-
107
- ### Full-Viewport Chart (`type: "chart"`)
108
-
109
- Use when the data IS the slide — the chart is the primary message, not supporting evidence.
110
-
111
- ```json
112
- {
113
- "type": "chart",
114
- "chart": {
115
- "chartType": "bar",
116
- "data": [...],
117
- "config": { "xKey": "quarter", "yKeys": ["revenue", "cost"], "showGrid": true, "showLegend": true }
118
- },
119
- "content": "Optional caption below the chart"
120
- }
121
- ```
122
-
123
- ### Inline Chart (`[chart:name]` in content)
124
-
125
- Use when data supports a text argument — the chart is evidence, not the headline.
126
-
127
- ```json
128
- {
129
- "content": "## Why this approach wins\n\n[chart:comparison]\n\nAdapt to the audience. Deliver with confidence.",
130
- "charts": {
131
- "comparison": {
132
- "chartType": "radar",
133
- "data": [...],
134
- "config": { "xKey": "axis", "yKeys": ["ours", "theirs"], "showLegend": true }
135
- }
136
- }
137
- }
138
- ```
139
-
140
- ### Chart Title Rule
141
-
142
- A chart's `label` field states the insight, not the data category. The audience should understand your point before reading the chart.
143
-
144
- | Weak (category label) | Strong (insight claim) |
145
- |---|---|
146
- | "Revenue Data" | "Revenue grew 40% QoQ after the pricing change" |
147
- | "Response Time" | "Response time dropped 60% after caching rollout" |
148
- | "User Growth" | "1M users in 6 months — 2× ahead of plan" |
149
-
150
- The label is your assertion. The chart is your evidence.
151
-
152
- ### Chart Type Selection
153
-
154
- | Data Pattern | Chart Type |
155
- |---|---|
156
- | Trend over time | `"line"` or `"area"` |
157
- | Category comparison | `"bar"` |
158
- | Multi-axis comparison | `"radar"` |
159
- | Part-of-whole | `"pie"` |
160
- | Volume trend | `"area"` |
161
-
162
- ## R3F Scene Decisions
163
-
164
- Use `type: "r3f"` when the outline calls for a 3D demo or visual impact.
165
-
166
- Available scenes:
167
- - `"rotating-cube"` — interactive cube, good for tech demos. Set `scene.controls: true`.
168
- - `"particle-field"` — atmospheric particle cloud. Set `scene.controls: false`.
169
-
170
- Always set `lightText: true` for R3F slides (dark backgrounds). Content renders as an overlay on top of the 3D scene.
171
-
172
- ## Topic Badge Conventions
173
-
174
- Use `topic` to group slides by section. Format: `"NN / Section Name"` for numbered sections:
175
-
176
- - `"01 / Problem"`
177
- - `"02 / Solution"`
178
- - `"03 / Value"`
179
- - `"04 / Evidence"`
180
-
181
- Or plain text for non-numbered groupings: `"Huma Showcase"`, `"Technical Deep Dive"`.
182
-
183
- ## Slide Recipes
184
-
185
- Complete `data` field patterns for common pitch slide types. Combine with `node-schema.md` for the full field reference.
186
-
187
- ### Cover / Call to Action
188
-
189
- Cover = first spine node. CTA = last. Both: centered, branded, no bullets. The only difference is the label and content.
190
-
191
- ```json
192
- {
193
- "label": "[Title or Ask]",
194
- "topic": "[Company or Meeting Context]",
195
- "content": "One sentence: what this is and for whom. (Cover) — or — what happens next and when. (CTA)",
196
- "centered": true,
197
- "brandFont": true,
198
- "showBranding": true,
199
- "brandingText": "[company.domain]"
200
- }
201
- ```
202
-
203
- ### Standard Bullets — Workhorse
204
-
205
- Default for problem, solution, evidence, and detail nodes.
206
-
207
- ```json
208
- {
209
- "label": "Headline claim that makes the point",
210
- "topic": "01 / Problem",
211
- "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.",
212
- "notes": "Talking point not on screen. Objection signal: 'If they ask X, navigate to [node-id].' Time: 2 minutes max.",
213
- "centered": false
214
- }
215
- ```
216
-
217
- ### Impact Statement
218
-
219
- Single message, no bullets. Use for named shifts, "why now" openers, or bold claims that stand alone.
220
-
221
- ```json
222
- {
223
- "label": "The Shift",
224
- "topic": "01 / Problem",
225
- "content": "The market has permanently changed.\n\n**Batch scheduling is structurally incompatible with same-day delivery expectations.**",
226
- "notes": "Pause. Do not advance immediately. If the room agrees, the rest is inevitable.",
227
- "centered": true
228
- }
229
- ```
230
-
231
- ### Two-Column Comparison
232
-
233
- Before/after, us/them, or two parallel arguments. Content splits on `---`; left column renders first.
234
-
235
- ```json
236
- {
237
- "label": "Old Way vs. New Way",
238
- "topic": "02 / Solution",
239
- "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",
240
- "layout": "two-column",
241
- "centered": false
242
- }
243
- ```
244
-
245
- ### Text + Inline Chart
246
-
247
- Text on left makes the claim; chart on right is the evidence. Chart is supporting, not the headline.
248
-
249
- ```json
250
- {
251
- "label": "The Data Confirms It",
252
- "topic": "03 / Evidence",
253
- "content": "## Continuous monitoring outperforms batch on every metric\n\nThree field studies. Same result each time.\n\n---\n\n[chart:comparison]",
254
- "charts": {
255
- "comparison": {
256
- "chartType": "bar",
257
- "data": [{ "metric": "Uptime %", "ours": 98.2, "baseline": 91.5 }],
258
- "config": { "xKey": "metric", "yKeys": ["ours", "baseline"], "showGrid": true, "showLegend": true }
259
- }
260
- },
261
- "layout": "two-column",
262
- "centered": false
263
- }
264
- ```
265
-
266
- ### Proof Point — Customer Quote
267
-
268
- Named case study or customer quote. Blockquote (`>`) renders as a styled pull quote — lead with it before the numbers.
269
-
270
- ```json
271
- {
272
- "label": "Summit Health: Year One",
273
- "topic": "04 / Proof",
274
- "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",
275
- "notes": "If they ask about rollout timeline, the drill-down below has the full breakdown.",
276
- "centered": false
277
- }
278
- ```
279
-
280
- ### Section Opener — Background Image
281
-
282
- Spine node opening a new chapter. Sets atmosphere. Max 3 bullet points on an image slide.
283
-
284
- ```json
285
- {
286
- "label": "The Opportunity",
287
- "topic": "03 / Opportunity",
288
- "content": "## A $40B market with no dominant platform\n\nEvery competitor is solving scheduling.\nNobody is solving the coordination layer.",
289
- "backgroundImage": "https://images.unsplash.com/photo-XXXXX?w=1920&q=80",
290
- "backgroundImageFit": "cover",
291
- "backgroundImageOverlay": true,
292
- "lightText": true,
293
- "centered": false
294
- }
295
- ```
296
-
297
- ## Media Delivery Summary
298
-
299
- After generating the JSON, list any slides with placeholder media:
300
-
301
- ```
302
- Slides requiring manual media upload:
303
- - "Cover" — background video: [description]
304
- - "Demo" — inline video: [description]
305
-
306
- Upload via POST /api/slide-images/upload (multipart/form-data, field: "file")
307
- Returns { ok: true, key, url } — replace placeholder with returned url
308
- Accepted: all image/*, video/mp4, video/webm, video/quicktime
309
- Max size: 50MB
310
- ```
@@ -1,130 +0,0 @@
1
- # Node Schema Reference
2
-
3
- Authoritative reference for the `SlideNodeData` interface.
4
- Derived from `src/types/presentation.ts`. All fields, types, and defaults documented here.
5
-
6
- ## Node Wrapper
7
-
8
- Every node in the graph has this structure:
9
-
10
- ```json
11
- {
12
- "id": "unique-slug",
13
- "type": "huma",
14
- "position": { "x": 0, "y": 0 },
15
- "data": { /* SlideNodeData fields below */ },
16
- "style": { "width": 180, "height": 70 },
17
- "measured": { "width": 180, "height": 70 }
18
- }
19
- ```
20
-
21
- - `id`: Kebab-case slug (e.g. `"cover"`, `"problem-detail"`, `"feat-3d"`)
22
- - `type`: Always `"huma"` — the custom node type with directional handles
23
- - `position`: `{ x, y }` in graph canvas coordinates (see `positioning.md`)
24
- - `style.width`: Always `180`. `style.height`: Always `70`.
25
- - `measured`: Must mirror `style` — `{ width: 180, height: 70 }`
26
- - Optional: `style.backgroundColor` — hex string for node background in the graph editor (also applied as slide background)
27
-
28
- ## SlideNodeData Fields
29
-
30
- ### Content Fields
31
-
32
- | Field | Type | Default | Description |
33
- |---|---|---|---|
34
- | `label` | `string?` | — | Slide title displayed in graph editor and as slide heading |
35
- | `topic` | `string?` | — | Section badge on the slide (e.g. `"01 / Problem"`, `"Solution"`) |
36
- | `content` | `string?` | — | Markdown body. Supports headings, bullets, bold, code, tables, `[chart:name]` embeds, `![](url)` images/videos, `[text](#nodeId)` navigation links |
37
- | `notes` | `string?` | — | Speaker notes, shown only in the presenter panel |
38
-
39
- ### Slide Type
40
-
41
- | Field | Type | Default | Description |
42
- |---|---|---|---|
43
- | `type` | `"content" \| "r3f" \| "chart" \| "custom"` | `"content"` | Slide renderer. `"content"` for standard text, `"r3f"` for 3D scene, `"chart"` for full-viewport chart |
44
-
45
- ### Layout & Display
46
-
47
- | Field | Type | Default | Description |
48
- |---|---|---|---|
49
- | `centered` | `boolean?` | `true` | Center content vertically and horizontally |
50
- | `layout` | `"single" \| "two-column"` | `"single"` | Content layout. `"two-column"` splits on `---` delimiter in content |
51
- | `lightText` | `boolean?` | `false` | Force white text for dark backgrounds |
52
- | `brandFont` | `boolean?` | `false` | Use HumaDisplay display font for the title |
53
- | `showBranding` | `boolean?` | `true` | Show branding overlay |
54
- | `brandingText` | `string?` | — | Bottom-left branding label (e.g. `"huma.energy"`) |
55
-
56
- ### Background Media
57
-
58
- | Field | Type | Default | Description |
59
- |---|---|---|---|
60
- | `backgroundImage` | `string?` | — | URL to background image |
61
- | `backgroundImageFit` | `"cover" \| "contain"` | `"cover"` | How image fills the slide |
62
- | `backgroundImageOverlay` | `boolean?` | `false` | Dark scrim over background image for text readability |
63
- | `backgroundVideo` | `string?` | — | URL to background video |
64
- | `backgroundVideoFit` | `"cover" \| "contain"` | `"cover"` | How video fills the slide |
65
- | `backgroundVideoLoop` | `boolean?` | `true` | Loop background video |
66
-
67
- ### Inline Video
68
-
69
- | Field | Type | Default | Description |
70
- |---|---|---|---|
71
- | `inlineVideoControls` | `boolean?` | `true` | Show controls on inline videos in `content` |
72
- | `inlineVideoAutoplay` | `boolean?` | `true` | Autoplay inline videos |
73
- | `inlineVideoLoop` | `boolean?` | `true` | Loop inline videos |
74
-
75
- ### R3F Scene (when `type: "r3f"`)
76
-
77
- | Field | Type | Default | Description |
78
- |---|---|---|---|
79
- | `scene.component` | `string` | — | Registry key (e.g. `"rotating-cube"`, `"particle-field"`) |
80
- | `scene.props` | `Record<string, unknown>?` | — | Props passed to the scene component |
81
- | `scene.controls` | `boolean?` | — | Enable OrbitControls for user interaction |
82
- | `scene.background` | `string?` | — | Scene background hex color |
83
-
84
- ### Charts
85
-
86
- **Full-viewport chart** (when `type: "chart"`):
87
-
88
- | Field | Type | Default | Description |
89
- |---|---|---|---|
90
- | `chart.chartType` | `"bar" \| "line" \| "area" \| "pie" \| "radar"` | — | Chart renderer |
91
- | `chart.data` | `Array<Record<string, unknown>>` | — | Data array |
92
- | `chart.config.xKey` | `string?` | — | X-axis data key |
93
- | `chart.config.yKeys` | `string[]?` | — | Y-axis data keys |
94
- | `chart.config.colors` | `string[]?` | — | Series colors |
95
- | `chart.config.showGrid` | `boolean?` | — | Show grid lines |
96
- | `chart.config.showLegend` | `boolean?` | — | Show legend |
97
-
98
- **Inline charts** (referenced via `[chart:name]` in content):
99
-
100
- | Field | Type | Default | Description |
101
- |---|---|---|---|
102
- | `charts` | `Record<string, ChartConfig>` | — | Named chart configurations. Key is referenced in content as `[chart:keyname]` |
103
-
104
- Each `ChartConfig` has the same shape as `chart` above.
105
-
106
- ## Available R3F Scene Components
107
-
108
- | Registry Key | Description |
109
- |---|---|
110
- | `rotating-cube` | Interactive rotating cube with OrbitControls |
111
- | `particle-field` | Animated particle cloud background |
112
-
113
- ## Content Markdown Features
114
-
115
- The `content` field supports:
116
-
117
- - `## Heading` — headings (ATX style only, no setext)
118
- - `- bullet` or `* bullet` — unordered lists
119
- - `1. item` — ordered lists
120
- - `` ```language ``` `` — syntax-highlighted code blocks
121
- - `> blockquote` — styled blockquotes
122
- - `**bold**` and `*italic*` — inline formatting
123
- - `| col | col |` — GFM tables
124
- - `![alt](url)` — images; `.mp4/.webm/.mov` URLs render as inline video
125
- - `[text](url)` — external links (open in new tab)
126
- - `[text](#nodeId)` — navigation links to other slides
127
- - `[chart:name]` — inline chart embed (must be on its own line)
128
- - `---` — column delimiter when `layout: "two-column"`
129
- - Single newline = visible line break (not collapsed)
130
- - Multiple blank lines = visible vertical spacing
@@ -1,84 +0,0 @@
1
- # Node Positioning
2
-
3
- How to place nodes on the graph canvas for a clean, readable layout in the editor.
4
- Position affects visual arrangement only — navigation is determined by edges.
5
-
6
- ## Grid System
7
-
8
- | Parameter | Value |
9
- |---|---|
10
- | Horizontal spacing | 240px |
11
- | Vertical spacing | 150px |
12
- | Node width | 180px (in `style` and `measured`) |
13
- | Node height | 70px (in `style` and `measured`) |
14
-
15
- ## Spine Row
16
-
17
- All spine nodes sit at `y: 0`, starting at `x: 0`, incrementing by 240 per node.
18
-
19
- ```
20
- x: 0 240 480 720 960 1200
21
- y: 0 [Cover] [Problem] [Solution] [Value] [Features] [CTA]
22
- ```
23
-
24
- ## Drill-Down Rows
25
-
26
- Drill-down children are placed directly below their parent:
27
-
28
- - First level: `y: 150`
29
- - Second level: `y: 300`
30
-
31
- The first child inherits the parent's `x` position. Additional siblings at the same depth increment `x` by 240.
32
-
33
- ```
34
- x: 240 480
35
- y:0 [Problem] [Solution]
36
- ↓ ↓
37
- y:150 [Detail] [How It Works]
38
-
39
- y:300 [Root Cause]
40
- ```
41
-
42
- ### Multiple Siblings in a Branch
43
-
44
- When a spine node has multiple drill-down children at the same depth:
45
-
46
- ```
47
- x: 720 960
48
- y:0 [Value]
49
-
50
- y:150 [Case A] [Case B]
51
- ```
52
-
53
- - First child: same `x` as parent (720)
54
- - Second child: parent `x` + 240 (960)
55
- - Third child: parent `x` + 480 (1200)
56
-
57
- ## Position Template
58
-
59
- ```json
60
- {
61
- "position": { "x": 0, "y": 0 }
62
- }
63
- ```
64
-
65
- Quick reference for a 5-node spine with one drill-down each:
66
-
67
- | Node | x | y | Role |
68
- |---|---|---|---|
69
- | cover | 0 | 0 | Spine 1 |
70
- | problem | 240 | 0 | Spine 2 |
71
- | problem-detail | 240 | 150 | Drill-down under problem |
72
- | solution | 480 | 0 | Spine 3 |
73
- | solution-how | 480 | 150 | Drill-down under solution |
74
- | value | 720 | 0 | Spine 4 |
75
- | value-case | 720 | 150 | Drill-down under value |
76
- | cta | 960 | 0 | Spine 5 |
77
-
78
- ## Rules
79
-
80
- 1. Position reflects visual layout in the editor — it has no effect on navigation
81
- 2. Navigation is determined solely by edges and their handle assignments
82
- 3. Spine nodes must be at `y: 0` for visual clarity
83
- 4. Drill-downs must be below their parent for the folder-tree metaphor to hold
84
- 5. No two nodes should overlap (maintain at least 240px horizontal, 150px vertical separation)