@strategicnerds/slide-nerds 0.1.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/dist/cli/commands/analytics.d.ts +6 -0
- package/dist/cli/commands/analytics.d.ts.map +1 -0
- package/dist/cli/commands/analytics.js +44 -0
- package/dist/cli/commands/analytics.js.map +1 -0
- package/dist/cli/commands/create.d.ts +4 -0
- package/dist/cli/commands/create.d.ts.map +1 -0
- package/dist/cli/commands/create.js +87 -0
- package/dist/cli/commands/create.js.map +1 -0
- package/dist/cli/commands/export.d.ts +6 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +109 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/template-path.d.ts +4 -0
- package/dist/cli/template-path.d.ts.map +1 -0
- package/dist/cli/template-path.js +13 -0
- package/dist/cli/template-path.js.map +1 -0
- package/dist/runtime/export-api.d.ts +15 -0
- package/dist/runtime/export-api.d.ts.map +1 -0
- package/dist/runtime/export-api.js +21 -0
- package/dist/runtime/export-api.js.map +1 -0
- package/dist/runtime/index.d.ts +12 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +8 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/light-table.d.ts +8 -0
- package/dist/runtime/light-table.d.ts.map +1 -0
- package/dist/runtime/light-table.js +104 -0
- package/dist/runtime/light-table.js.map +1 -0
- package/dist/runtime/presenter-view.d.ts +7 -0
- package/dist/runtime/presenter-view.d.ts.map +1 -0
- package/dist/runtime/presenter-view.js +62 -0
- package/dist/runtime/presenter-view.js.map +1 -0
- package/dist/runtime/slide-context.d.ts +16 -0
- package/dist/runtime/slide-context.d.ts.map +1 -0
- package/dist/runtime/slide-context.js +18 -0
- package/dist/runtime/slide-context.js.map +1 -0
- package/dist/runtime/slide-controls.d.ts +3 -0
- package/dist/runtime/slide-controls.d.ts.map +1 -0
- package/dist/runtime/slide-controls.js +177 -0
- package/dist/runtime/slide-controls.js.map +1 -0
- package/dist/runtime/slide-dom.d.ts +17 -0
- package/dist/runtime/slide-dom.d.ts.map +1 -0
- package/dist/runtime/slide-dom.js +89 -0
- package/dist/runtime/slide-dom.js.map +1 -0
- package/dist/runtime/slide-runtime.d.ts +7 -0
- package/dist/runtime/slide-runtime.d.ts.map +1 -0
- package/dist/runtime/slide-runtime.js +125 -0
- package/dist/runtime/slide-runtime.js.map +1 -0
- package/dist/runtime/slide-shape.d.ts +21 -0
- package/dist/runtime/slide-shape.d.ts.map +1 -0
- package/dist/runtime/slide-shape.js +115 -0
- package/dist/runtime/slide-shape.js.map +1 -0
- package/dist/runtime/types.d.ts +150 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +38 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/use-presenter-mode.d.ts +14 -0
- package/dist/runtime/use-presenter-mode.d.ts.map +1 -0
- package/dist/runtime/use-presenter-mode.js +52 -0
- package/dist/runtime/use-presenter-mode.js.map +1 -0
- package/dist/runtime/use-slide-navigation.d.ts +13 -0
- package/dist/runtime/use-slide-navigation.d.ts.map +1 -0
- package/dist/runtime/use-slide-navigation.js +230 -0
- package/dist/runtime/use-slide-navigation.js.map +1 -0
- package/package.json +64 -0
- package/skills/accessibility/SKILL.md +236 -0
- package/skills/advanced-layouts/SKILL.md +429 -0
- package/skills/analytics/SKILL.md +97 -0
- package/skills/animation/SKILL.md +364 -0
- package/skills/brand/SKILL.md +200 -0
- package/skills/data-visualization/SKILL.md +533 -0
- package/skills/deck-templates/SKILL.md +93 -0
- package/skills/diagrams/SKILL.md +395 -0
- package/skills/export/SKILL.md +119 -0
- package/skills/interactive/SKILL.md +292 -0
- package/skills/layout/SKILL.md +178 -0
- package/skills/narrative-frameworks/SKILL.md +250 -0
- package/skills/react-component-embeds/SKILL.md +73 -0
- package/skills/slide-types/SKILL.md +384 -0
- package/skills/slidenerds-runtime/SKILL.md +163 -0
- package/skills/speaker-notes/SKILL.md +128 -0
- package/skills/strategic-frameworks/SKILL.md +392 -0
- package/skills/visual-design/SKILL.md +373 -0
- package/templates/analytics/custom.tsx.tmpl +20 -0
- package/templates/analytics/ga4.tsx.tmpl +15 -0
- package/templates/analytics/gtm.tsx.tmpl +9 -0
- package/templates/analytics/plausible.tsx.tmpl +10 -0
- package/templates/analytics/posthog.tsx.tmpl +14 -0
- package/templates/next-app/CLAUDE.md.tmpl +574 -0
- package/templates/next-app/README.md.tmpl +35 -0
- package/templates/next-app/app/globals.css.tmpl +274 -0
- package/templates/next-app/app/layout.tsx.tmpl +31 -0
- package/templates/next-app/app/page.tsx.tmpl +38 -0
- package/templates/next-app/brand.config.ts.tmpl +32 -0
- package/templates/next-app/package.json.tmpl +25 -0
- package/templates/next-app/postcss.config.mjs.tmpl +8 -0
- package/templates/next-app/tsconfig.json.tmpl +21 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-visualization
|
|
3
|
+
description: Chart types, KPI cards, dashboard patterns, and data styling rules for slidenerds slides using Recharts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Data visualization skill
|
|
7
|
+
|
|
8
|
+
Use this skill when a slide needs charts, graphs, KPI displays, or any quantitative data visualization. All patterns use Recharts (React charting library) with brand-aware styling.
|
|
9
|
+
|
|
10
|
+
## Recharts setup
|
|
11
|
+
|
|
12
|
+
Install Recharts in the deck project:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install recharts
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Import components as needed:
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
import {
|
|
22
|
+
BarChart, Bar, LineChart, Line, AreaChart, Area,
|
|
23
|
+
PieChart, Pie, Cell, RadarChart, Radar, PolarGrid,
|
|
24
|
+
PolarAngleAxis, ScatterChart, Scatter,
|
|
25
|
+
XAxis, YAxis, CartesianGrid, Tooltip,
|
|
26
|
+
ResponsiveContainer, ComposedChart,
|
|
27
|
+
} from 'recharts'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Global chart styling rules
|
|
31
|
+
|
|
32
|
+
Every chart on a slide must follow these rules for consistency and projection readability.
|
|
33
|
+
|
|
34
|
+
### Axes
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
<XAxis
|
|
38
|
+
dataKey="name"
|
|
39
|
+
stroke="transparent"
|
|
40
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 13, fontFamily: 'var(--font-heading)' }}
|
|
41
|
+
tickLine={false}
|
|
42
|
+
axisLine={false}
|
|
43
|
+
/>
|
|
44
|
+
<YAxis
|
|
45
|
+
stroke="transparent"
|
|
46
|
+
tick={{ fill: 'rgba(255,255,255,0.35)', fontSize: 12 }}
|
|
47
|
+
tickLine={false}
|
|
48
|
+
axisLine={false}
|
|
49
|
+
width={50}
|
|
50
|
+
/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Remove axis lines and tick lines. They add noise.
|
|
54
|
+
- X-axis labels at 50% opacity. Y-axis labels at 35%.
|
|
55
|
+
- Use the heading font for x-axis labels (they are category names the audience reads).
|
|
56
|
+
- Set explicit `width` on YAxis to prevent layout shifts.
|
|
57
|
+
|
|
58
|
+
### Grid
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- Barely visible. 4% white opacity. The grid orients the eye without competing with data.
|
|
65
|
+
- Always dashed, never solid.
|
|
66
|
+
|
|
67
|
+
### Tooltip
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
<Tooltip
|
|
71
|
+
contentStyle={{
|
|
72
|
+
background: 'var(--color-surface-elevated)',
|
|
73
|
+
border: '1px solid var(--color-border)',
|
|
74
|
+
borderRadius: 10,
|
|
75
|
+
}}
|
|
76
|
+
labelStyle={{ color: 'rgba(255,255,255,0.5)' }}
|
|
77
|
+
itemStyle={{ color: 'var(--color-accent)' }}
|
|
78
|
+
/>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Container
|
|
82
|
+
|
|
83
|
+
Always wrap charts in a card surface and use `ResponsiveContainer`:
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
<div className="card-surface p-8">
|
|
87
|
+
<ResponsiveContainer width="100%" height={400}>
|
|
88
|
+
{/* Chart */}
|
|
89
|
+
</ResponsiveContainer>
|
|
90
|
+
</div>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- Fixed pixel height (300-420px). Never use `height="100%"` -- it breaks when the parent is hidden.
|
|
94
|
+
- Card surface provides visual containment and depth.
|
|
95
|
+
|
|
96
|
+
### Animation
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
<Bar animationDuration={800} animationEasing="ease-out" />
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- Duration: 600-800ms. Fast enough for presentation pacing, slow enough to be noticed.
|
|
103
|
+
- Easing: `ease-out` (decelerating). Never `linear`.
|
|
104
|
+
- Reveal the chart with `data-step` so the animation plays when the presenter advances.
|
|
105
|
+
|
|
106
|
+
### Color
|
|
107
|
+
|
|
108
|
+
- Primary data series: `var(--color-accent)` or the accent hex value.
|
|
109
|
+
- Secondary series: Use opacity variants (80%, 60%, 40%) of the accent.
|
|
110
|
+
- For multi-series charts, use the color-blind safe palette from the accessibility skill.
|
|
111
|
+
- Maximum 4 data series per chart. More is unreadable.
|
|
112
|
+
|
|
113
|
+
### Data point limits
|
|
114
|
+
|
|
115
|
+
| Chart type | Max data points | Why |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| Bar chart | 8-10 bars | Labels overlap beyond 10 |
|
|
118
|
+
| Line chart | 12-15 points | More becomes a dense mess |
|
|
119
|
+
| Pie / donut | 5-6 slices | Small slices are meaningless |
|
|
120
|
+
| Radar | 5-8 axes | More creates visual noise |
|
|
121
|
+
| Scatter | 20-30 points | More requires a dashboard, not a slide |
|
|
122
|
+
|
|
123
|
+
## Bar chart
|
|
124
|
+
|
|
125
|
+
Use for: comparisons across categories, revenue by quarter, feature usage.
|
|
126
|
+
|
|
127
|
+
### Vertical bar chart
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
<ResponsiveContainer width="100%" height={400}>
|
|
131
|
+
<BarChart data={data} barCategoryGap="20%">
|
|
132
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
133
|
+
<XAxis dataKey="name" stroke="transparent"
|
|
134
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 13 }}
|
|
135
|
+
tickLine={false} axisLine={false} />
|
|
136
|
+
<YAxis stroke="transparent"
|
|
137
|
+
tick={{ fill: 'rgba(255,255,255,0.35)', fontSize: 12 }}
|
|
138
|
+
tickLine={false} axisLine={false} width={50} />
|
|
139
|
+
<Tooltip contentStyle={{ background: '#222228', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 10 }} />
|
|
140
|
+
<Bar dataKey="value" fill="var(--color-accent)" radius={[6, 6, 0, 0]}
|
|
141
|
+
animationDuration={800} />
|
|
142
|
+
</BarChart>
|
|
143
|
+
</ResponsiveContainer>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `radius={[6, 6, 0, 0]}` rounds top corners. Looks modern.
|
|
147
|
+
- `barCategoryGap="20%"` gives bars breathing room.
|
|
148
|
+
|
|
149
|
+
### Horizontal bar chart
|
|
150
|
+
|
|
151
|
+
Use for: rankings, survey results, comparisons where labels are long.
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
<BarChart data={data} layout="vertical" barCategoryGap="25%">
|
|
155
|
+
<XAxis type="number" stroke="transparent"
|
|
156
|
+
tick={{ fill: 'rgba(255,255,255,0.35)', fontSize: 12 }}
|
|
157
|
+
tickLine={false} axisLine={false} />
|
|
158
|
+
<YAxis type="category" dataKey="name" stroke="transparent"
|
|
159
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 13 }}
|
|
160
|
+
tickLine={false} axisLine={false} width={120} />
|
|
161
|
+
<Bar dataKey="value" fill="var(--color-accent)" radius={[0, 6, 6, 0]}
|
|
162
|
+
animationDuration={800} />
|
|
163
|
+
</BarChart>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Stacked bar chart
|
|
167
|
+
|
|
168
|
+
Use for: composition breakdown (revenue by segment, traffic by source).
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
<BarChart data={data}>
|
|
172
|
+
{/* ... axes */}
|
|
173
|
+
<Bar dataKey="segment1" stackId="a" fill="var(--color-accent)" />
|
|
174
|
+
<Bar dataKey="segment2" stackId="a" fill="rgba(245,158,11,0.6)" />
|
|
175
|
+
<Bar dataKey="segment3" stackId="a" fill="rgba(245,158,11,0.3)"
|
|
176
|
+
radius={[6, 6, 0, 0]} />
|
|
177
|
+
</BarChart>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- Only the top bar gets `radius`. Lower bars have flat tops.
|
|
181
|
+
- Use opacity variants of the accent for segment colors.
|
|
182
|
+
- Max 3-4 segments. More is noise.
|
|
183
|
+
|
|
184
|
+
## Line chart
|
|
185
|
+
|
|
186
|
+
Use for: trends over time, growth trajectories, comparisons across time periods.
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<ResponsiveContainer width="100%" height={380}>
|
|
190
|
+
<LineChart data={data}>
|
|
191
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
192
|
+
<XAxis dataKey="month" stroke="transparent"
|
|
193
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 12 }}
|
|
194
|
+
tickLine={false} axisLine={false} />
|
|
195
|
+
<YAxis stroke="transparent"
|
|
196
|
+
tick={{ fill: 'rgba(255,255,255,0.35)', fontSize: 12 }}
|
|
197
|
+
tickLine={false} axisLine={false} width={50} />
|
|
198
|
+
<Line type="monotone" dataKey="value" stroke="var(--color-accent)"
|
|
199
|
+
strokeWidth={2.5} dot={{ fill: 'var(--color-accent)', r: 4, strokeWidth: 0 }}
|
|
200
|
+
animationDuration={800} />
|
|
201
|
+
</LineChart>
|
|
202
|
+
</ResponsiveContainer>
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Multi-line chart
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
<Line type="monotone" dataKey="revenue" stroke="#f59e0b" strokeWidth={2.5}
|
|
209
|
+
dot={{ r: 3 }} />
|
|
210
|
+
<Line type="monotone" dataKey="costs" stroke="rgba(255,255,255,0.3)" strokeWidth={1.5}
|
|
211
|
+
dot={{ r: 2 }} strokeDasharray="5 5" />
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
- Primary metric: solid line, thick (2.5px), accent color, larger dots.
|
|
215
|
+
- Secondary metric: dashed line, thin (1.5px), muted color, smaller dots.
|
|
216
|
+
- Max 3 lines. Beyond that, use separate slides.
|
|
217
|
+
|
|
218
|
+
## Area chart
|
|
219
|
+
|
|
220
|
+
Use for: volume over time, emphasizing magnitude, cumulative data.
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
<AreaChart data={data}>
|
|
224
|
+
<defs>
|
|
225
|
+
<linearGradient id="areaGrad" x1="0" y1="0" x2="0" y2="1">
|
|
226
|
+
<stop offset="0%" stopColor="var(--color-accent)" stopOpacity={0.25} />
|
|
227
|
+
<stop offset="100%" stopColor="var(--color-accent)" stopOpacity={0} />
|
|
228
|
+
</linearGradient>
|
|
229
|
+
</defs>
|
|
230
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
231
|
+
{/* ... axes */}
|
|
232
|
+
<Area type="monotone" dataKey="users" stroke="var(--color-accent)"
|
|
233
|
+
strokeWidth={2.5} fill="url(#areaGrad)" animationDuration={800}
|
|
234
|
+
dot={{ fill: 'var(--color-accent)', r: 4, strokeWidth: 0 }} />
|
|
235
|
+
</AreaChart>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
- Always use a gradient fill (accent color fading to transparent).
|
|
239
|
+
- The gradient creates visual weight that says "this is growing."
|
|
240
|
+
|
|
241
|
+
## Pie / donut chart
|
|
242
|
+
|
|
243
|
+
Use for: market share, budget allocation, composition at a point in time.
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
const COLORS = ['#f59e0b', 'rgba(245,158,11,0.6)', 'rgba(245,158,11,0.35)', 'rgba(255,255,255,0.15)']
|
|
247
|
+
|
|
248
|
+
<ResponsiveContainer width="100%" height={350}>
|
|
249
|
+
<PieChart>
|
|
250
|
+
<Pie data={data} dataKey="value" nameKey="name"
|
|
251
|
+
cx="50%" cy="50%" innerRadius={80} outerRadius={130}
|
|
252
|
+
paddingAngle={2} animationDuration={800}>
|
|
253
|
+
{data.map((_, i) => (
|
|
254
|
+
<Cell key={i} fill={COLORS[i % COLORS.length]} />
|
|
255
|
+
))}
|
|
256
|
+
</Pie>
|
|
257
|
+
<Tooltip contentStyle={{ background: '#222228', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 10 }} />
|
|
258
|
+
</PieChart>
|
|
259
|
+
</ResponsiveContainer>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
- Use donut (with `innerRadius`) rather than full pie. Donuts look more modern and leave space for a central label.
|
|
263
|
+
- Max 5-6 slices. Group small slices into "Other."
|
|
264
|
+
- `paddingAngle={2}` adds visual separation between slices.
|
|
265
|
+
|
|
266
|
+
### Central label for donut
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
<text x="50%" y="48%" textAnchor="middle" dominantBaseline="middle"
|
|
270
|
+
fill="var(--color-text)" fontSize={28} fontWeight={700}>
|
|
271
|
+
100%
|
|
272
|
+
</text>
|
|
273
|
+
<text x="50%" y="58%" textAnchor="middle" dominantBaseline="middle"
|
|
274
|
+
fill="rgba(255,255,255,0.4)" fontSize={12}>
|
|
275
|
+
Total allocation
|
|
276
|
+
</text>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Radar / spider chart
|
|
280
|
+
|
|
281
|
+
Use for: multi-dimensional comparison, team assessment, product scoring.
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
<ResponsiveContainer width="100%" height={350}>
|
|
285
|
+
<RadarChart data={data}>
|
|
286
|
+
<PolarGrid stroke="rgba(255,255,255,0.08)" />
|
|
287
|
+
<PolarAngleAxis dataKey="axis"
|
|
288
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 12 }} />
|
|
289
|
+
<Radar dataKey="score" stroke="var(--color-accent)" strokeWidth={2}
|
|
290
|
+
fill="var(--color-accent)" fillOpacity={0.15} animationDuration={800} />
|
|
291
|
+
</RadarChart>
|
|
292
|
+
</ResponsiveContainer>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
- 5-8 axes maximum. Fewer looks sparse. More creates visual noise.
|
|
296
|
+
- Use `fillOpacity={0.15}` for a subtle area fill.
|
|
297
|
+
|
|
298
|
+
## Scatter / bubble chart
|
|
299
|
+
|
|
300
|
+
Use for: correlation analysis, competitive positioning, portfolio mapping.
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
<ResponsiveContainer width="100%" height={400}>
|
|
304
|
+
<ScatterChart>
|
|
305
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
306
|
+
<XAxis dataKey="x" name="Revenue" stroke="transparent"
|
|
307
|
+
tick={{ fill: 'rgba(255,255,255,0.5)', fontSize: 12 }}
|
|
308
|
+
tickLine={false} axisLine={false} />
|
|
309
|
+
<YAxis dataKey="y" name="Growth" stroke="transparent"
|
|
310
|
+
tick={{ fill: 'rgba(255,255,255,0.35)', fontSize: 12 }}
|
|
311
|
+
tickLine={false} axisLine={false} />
|
|
312
|
+
<Scatter data={data} fill="var(--color-accent)" animationDuration={800}>
|
|
313
|
+
{data.map((entry, i) => (
|
|
314
|
+
<Cell key={i} r={entry.size || 8} />
|
|
315
|
+
))}
|
|
316
|
+
</Scatter>
|
|
317
|
+
</ScatterChart>
|
|
318
|
+
</ResponsiveContainer>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
For bubble charts, vary the `r` (radius) prop on each `Cell` based on a third data dimension.
|
|
322
|
+
|
|
323
|
+
## Combo chart (bar + line)
|
|
324
|
+
|
|
325
|
+
Use for: revenue bars with margin line, volume with average overlay.
|
|
326
|
+
|
|
327
|
+
```tsx
|
|
328
|
+
<ResponsiveContainer width="100%" height={400}>
|
|
329
|
+
<ComposedChart data={data}>
|
|
330
|
+
<CartesianGrid strokeDasharray="3 3" stroke="rgba(255,255,255,0.04)" />
|
|
331
|
+
{/* ... axes */}
|
|
332
|
+
<Bar dataKey="revenue" fill="var(--color-accent)" radius={[6, 6, 0, 0]}
|
|
333
|
+
animationDuration={800} />
|
|
334
|
+
<Line type="monotone" dataKey="margin" stroke="rgba(255,255,255,0.6)"
|
|
335
|
+
strokeWidth={2} dot={{ r: 3, fill: 'rgba(255,255,255,0.6)' }}
|
|
336
|
+
strokeDasharray="5 5" />
|
|
337
|
+
</ComposedChart>
|
|
338
|
+
</ResponsiveContainer>
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
- Bar is the primary metric (solid, accent color).
|
|
342
|
+
- Line is the secondary metric (dashed, muted color).
|
|
343
|
+
- Requires a second Y-axis if scales differ: `<YAxis yAxisId="right" orientation="right" />`.
|
|
344
|
+
|
|
345
|
+
## Waterfall chart
|
|
346
|
+
|
|
347
|
+
Use for: revenue bridges, P&L walks, budget variance analysis.
|
|
348
|
+
|
|
349
|
+
Recharts does not have a native waterfall component. Build with calculated offsets:
|
|
350
|
+
|
|
351
|
+
```tsx
|
|
352
|
+
const waterfallData = [
|
|
353
|
+
{ name: 'Q4 Revenue', value: 3100, isTotal: false },
|
|
354
|
+
{ name: 'New customers', value: 800, isTotal: false },
|
|
355
|
+
{ name: 'Expansion', value: 450, isTotal: false },
|
|
356
|
+
{ name: 'Churn', value: -350, isTotal: false },
|
|
357
|
+
{ name: 'Q1 Revenue', value: 4000, isTotal: true },
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
// Calculate offsets for stacking
|
|
361
|
+
const processedData = waterfallData.reduce((acc, item, i) => {
|
|
362
|
+
if (item.isTotal) {
|
|
363
|
+
acc.push({ ...item, offset: 0, fill: 'var(--color-accent)' })
|
|
364
|
+
} else if (i === 0) {
|
|
365
|
+
acc.push({ ...item, offset: 0, fill: 'var(--color-accent)' })
|
|
366
|
+
} else {
|
|
367
|
+
const prevTop = acc[i - 1].offset + Math.abs(acc[i - 1].value)
|
|
368
|
+
const offset = item.value >= 0 ? prevTop : prevTop - Math.abs(item.value)
|
|
369
|
+
acc.push({
|
|
370
|
+
...item,
|
|
371
|
+
offset: item.value >= 0 ? prevTop : offset,
|
|
372
|
+
fill: item.value >= 0 ? '#22c55e' : '#ef4444',
|
|
373
|
+
})
|
|
374
|
+
}
|
|
375
|
+
return acc
|
|
376
|
+
}, [] as Array<typeof waterfallData[0] & { offset: number; fill: string }>)
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Use stacked bars: an invisible "offset" bar + the visible "value" bar:
|
|
380
|
+
|
|
381
|
+
```tsx
|
|
382
|
+
<BarChart data={processedData}>
|
|
383
|
+
<Bar dataKey="offset" stackId="a" fill="transparent" />
|
|
384
|
+
<Bar dataKey="value" stackId="a" radius={[4, 4, 0, 0]}>
|
|
385
|
+
{processedData.map((entry, i) => (
|
|
386
|
+
<Cell key={i} fill={entry.fill} />
|
|
387
|
+
))}
|
|
388
|
+
</Bar>
|
|
389
|
+
</BarChart>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Funnel chart
|
|
393
|
+
|
|
394
|
+
Use for: sales pipeline, conversion rates, user activation funnel.
|
|
395
|
+
|
|
396
|
+
Recharts does not have a native funnel. Build with CSS trapezoids:
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
<div className="flex flex-col items-center gap-1" style={{ maxWidth: 500 }}>
|
|
400
|
+
{[
|
|
401
|
+
{ label: 'Visitors', value: '10,000', width: '100%' },
|
|
402
|
+
{ label: 'Signups', value: '2,400', width: '75%' },
|
|
403
|
+
{ label: 'Activated', value: '1,100', width: '50%' },
|
|
404
|
+
{ label: 'Paid', value: '420', width: '30%' },
|
|
405
|
+
].map((stage, i) => (
|
|
406
|
+
<div key={stage.label} data-step="" className="step-fade text-center"
|
|
407
|
+
style={{ width: stage.width }}>
|
|
408
|
+
<div className="py-3 rounded-lg flex items-center justify-between px-6"
|
|
409
|
+
style={{
|
|
410
|
+
background: `rgba(245,158,11,${0.4 - i * 0.08})`,
|
|
411
|
+
border: '1px solid var(--color-accent)',
|
|
412
|
+
borderColor: `rgba(245,158,11,${0.6 - i * 0.1})`,
|
|
413
|
+
}}>
|
|
414
|
+
<span className="text-sm font-semibold">{stage.label}</span>
|
|
415
|
+
<span className="text-sm font-bold" style={{ color: 'var(--color-accent)' }}>{stage.value}</span>
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
))}
|
|
419
|
+
</div>
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Gauge / radial progress
|
|
423
|
+
|
|
424
|
+
Use for: NPS scores, completion percentages, health indicators.
|
|
425
|
+
|
|
426
|
+
Build with custom SVG:
|
|
427
|
+
|
|
428
|
+
```tsx
|
|
429
|
+
const GaugeChart: React.FC<{ value: number; max: number; label: string }> = ({ value, max, label }) => {
|
|
430
|
+
const pct = value / max
|
|
431
|
+
const circumference = Math.PI * 80 // half-circle, radius 80
|
|
432
|
+
const offset = circumference * (1 - pct)
|
|
433
|
+
|
|
434
|
+
return (
|
|
435
|
+
<svg width={200} height={120} viewBox="0 0 200 120">
|
|
436
|
+
{/* Background arc */}
|
|
437
|
+
<path d="M 20,100 A 80,80 0 0,1 180,100"
|
|
438
|
+
fill="none" stroke="rgba(255,255,255,0.08)" strokeWidth={12} strokeLinecap="round" />
|
|
439
|
+
{/* Value arc */}
|
|
440
|
+
<path d="M 20,100 A 80,80 0 0,1 180,100"
|
|
441
|
+
fill="none" stroke="var(--color-accent)" strokeWidth={12} strokeLinecap="round"
|
|
442
|
+
strokeDasharray={`${circumference}`}
|
|
443
|
+
strokeDashoffset={offset}
|
|
444
|
+
style={{ transition: 'stroke-dashoffset 800ms ease-out' }} />
|
|
445
|
+
{/* Value text */}
|
|
446
|
+
<text x="100" y="85" textAnchor="middle" fill="var(--color-text)"
|
|
447
|
+
fontSize={28} fontWeight={700}>{value}</text>
|
|
448
|
+
<text x="100" y="105" textAnchor="middle" fill="rgba(255,255,255,0.4)"
|
|
449
|
+
fontSize={11}>{label}</text>
|
|
450
|
+
</svg>
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
## KPI card with sparkline
|
|
456
|
+
|
|
457
|
+
Use for: dashboard slides where each metric needs a trend indicator.
|
|
458
|
+
|
|
459
|
+
```tsx
|
|
460
|
+
<div className="card-surface p-5 flex items-end justify-between">
|
|
461
|
+
<div>
|
|
462
|
+
<p className="text-xs font-semibold tracking-[0.15em] uppercase"
|
|
463
|
+
style={{ color: 'var(--color-text-tertiary)' }}>Revenue</p>
|
|
464
|
+
<p className="text-3xl font-bold mt-2"
|
|
465
|
+
style={{ fontFamily: 'var(--font-heading)' }}>$4.2M</p>
|
|
466
|
+
<p className="text-sm mt-1" style={{ color: '#22c55e' }}>+142% YoY</p>
|
|
467
|
+
</div>
|
|
468
|
+
<ResponsiveContainer width={80} height={40}>
|
|
469
|
+
<LineChart data={sparkData}>
|
|
470
|
+
<Line type="monotone" dataKey="v" stroke="var(--color-accent)"
|
|
471
|
+
strokeWidth={1.5} dot={false} />
|
|
472
|
+
</LineChart>
|
|
473
|
+
</ResponsiveContainer>
|
|
474
|
+
</div>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
- Sparkline has no axes, no grid, no tooltip. Just the line.
|
|
478
|
+
- Width: 60-100px. Height: 30-50px.
|
|
479
|
+
- The sparkline shows direction, not values. The number beside it shows the value.
|
|
480
|
+
|
|
481
|
+
## Chart selection guide
|
|
482
|
+
|
|
483
|
+
| Question to answer | Chart type | Why |
|
|
484
|
+
|---|---|---|
|
|
485
|
+
| How does X compare across categories? | Bar chart (vertical) | Direct comparison |
|
|
486
|
+
| How does X rank? | Bar chart (horizontal) | Long labels fit better |
|
|
487
|
+
| What is the trend over time? | Line chart | Shows direction and velocity |
|
|
488
|
+
| What is the volume over time? | Area chart | Emphasizes magnitude |
|
|
489
|
+
| What is the composition? | Pie/donut or stacked bar | Shows parts of a whole |
|
|
490
|
+
| How do two metrics correlate? | Scatter chart | Shows relationship |
|
|
491
|
+
| How does X score across dimensions? | Radar chart | Multi-axis comparison |
|
|
492
|
+
| What are the revenue drivers? | Waterfall chart | Shows additive/subtractive components |
|
|
493
|
+
| What is the conversion rate? | Funnel chart | Shows progressive narrowing |
|
|
494
|
+
| What is the health score? | Gauge chart | Single metric with context |
|
|
495
|
+
| What is the trend direction? | Sparkline (in KPI card) | Inline trend indicator |
|
|
496
|
+
| Bar + line overlay? | Combo chart | Two metrics, different scales |
|
|
497
|
+
|
|
498
|
+
## Annotation patterns
|
|
499
|
+
|
|
500
|
+
### Callout annotation
|
|
501
|
+
|
|
502
|
+
Add a text annotation next to a specific data point:
|
|
503
|
+
|
|
504
|
+
```tsx
|
|
505
|
+
<text x={dataPointX} y={dataPointY - 15}
|
|
506
|
+
fill="var(--color-accent)" fontSize={12} fontWeight={600}
|
|
507
|
+
textAnchor="middle">Peak: $4.2M</text>
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Trend line / target line
|
|
511
|
+
|
|
512
|
+
Add a horizontal reference line:
|
|
513
|
+
|
|
514
|
+
```tsx
|
|
515
|
+
import { ReferenceLine } from 'recharts'
|
|
516
|
+
|
|
517
|
+
<ReferenceLine y={3000} stroke="rgba(255,255,255,0.2)"
|
|
518
|
+
strokeDasharray="5 5" label={{
|
|
519
|
+
value: 'Target',
|
|
520
|
+
fill: 'rgba(255,255,255,0.3)',
|
|
521
|
+
fontSize: 11,
|
|
522
|
+
position: 'right',
|
|
523
|
+
}} />
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
## What to avoid
|
|
527
|
+
|
|
528
|
+
- More than one chart per slide (except dashboard slides).
|
|
529
|
+
- Pie charts for more than 6 categories.
|
|
530
|
+
- 3D effects on any chart. They distort data.
|
|
531
|
+
- Legend below the chart when labels on the chart itself would work.
|
|
532
|
+
- `height="100%"` on ResponsiveContainer. Use fixed pixel heights.
|
|
533
|
+
- Animating charts that are already visible. Only animate on reveal via `data-step`.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deck-templates
|
|
3
|
+
description: Narrative outlines and slide structures for common presentation types
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Deck templates skill
|
|
7
|
+
|
|
8
|
+
Scaffolding outlines for common deck types. Use these as a starting structure and fill content with the user.
|
|
9
|
+
|
|
10
|
+
## Investor pitch
|
|
11
|
+
|
|
12
|
+
10-12 slides. 15-20 minutes. Every slide should advance the narrative toward the ask.
|
|
13
|
+
|
|
14
|
+
1. **Title** -- company name, tagline, presenter name
|
|
15
|
+
2. **Problem** -- the pain point, who feels it, how big it is
|
|
16
|
+
3. **Solution** -- what you build, one sentence
|
|
17
|
+
4. **Demo / product** -- screenshots or live product, keep it to 2-3 screens
|
|
18
|
+
5. **Market size** -- TAM, SAM, SOM with sources
|
|
19
|
+
6. **Traction** -- metrics that prove momentum (revenue, users, growth rate)
|
|
20
|
+
7. **Business model** -- how you make money, pricing, unit economics
|
|
21
|
+
8. **Competition** -- positioning matrix, why you win
|
|
22
|
+
9. **Team** -- founders and key hires, relevant experience
|
|
23
|
+
10. **Financials** -- projections, burn rate, runway
|
|
24
|
+
11. **Ask** -- how much, what for, expected milestones
|
|
25
|
+
12. **Contact** -- email, website, calendar link
|
|
26
|
+
|
|
27
|
+
### Seed variant
|
|
28
|
+
|
|
29
|
+
Focus on vision and team. Less emphasis on financials (you probably don't have much data yet). Replace the financials slide with a "Why now" slide explaining market timing.
|
|
30
|
+
|
|
31
|
+
### Series A variant
|
|
32
|
+
|
|
33
|
+
Focus on traction and unit economics. Add a slide after traction showing cohort analysis or retention curves. The financials slide should show a clear path to profitability or next fundraise.
|
|
34
|
+
|
|
35
|
+
## Product launch
|
|
36
|
+
|
|
37
|
+
6-8 slides. 10-15 minutes. Build to the "aha" moment, then make adoption easy.
|
|
38
|
+
|
|
39
|
+
1. **Title** -- product name, launch date
|
|
40
|
+
2. **Context** -- the world before this product, what's hard today
|
|
41
|
+
3. **Problem** -- specific pain, with a story or data point
|
|
42
|
+
4. **Solution** -- the product, what it does in one line
|
|
43
|
+
5. **Demo** -- 3-5 screenshots or a video embed showing the flow
|
|
44
|
+
6. **How it works** -- technical or conceptual overview, keep it simple
|
|
45
|
+
7. **Adoption path** -- how to get started, pricing if applicable
|
|
46
|
+
8. **Call to action** -- one clear next step
|
|
47
|
+
|
|
48
|
+
## Internal metrics review
|
|
49
|
+
|
|
50
|
+
5-7 slides. 10 minutes. Honest, data-driven, forward-looking.
|
|
51
|
+
|
|
52
|
+
1. **Title** -- team name, review period, date
|
|
53
|
+
2. **Context** -- what we set out to do this quarter
|
|
54
|
+
3. **Key results** -- 3-5 metrics, actual vs. target, with trend
|
|
55
|
+
4. **What worked** -- 2-3 wins with supporting data
|
|
56
|
+
5. **What didn't** -- 2-3 misses, honest root causes
|
|
57
|
+
6. **Learnings** -- what we'd do differently
|
|
58
|
+
7. **Next quarter** -- goals and priorities
|
|
59
|
+
|
|
60
|
+
## Conference talk
|
|
61
|
+
|
|
62
|
+
8-15 slides. 20-30 minutes. Teach one thing well.
|
|
63
|
+
|
|
64
|
+
1. **Title** -- talk title, speaker name, event name
|
|
65
|
+
2. **Hook** -- a surprising fact, a question, or a demo that gets attention in the first 30 seconds
|
|
66
|
+
3. **Thesis** -- the one thing the audience should remember
|
|
67
|
+
4. **Argument 1** -- first supporting point with evidence
|
|
68
|
+
5. **Argument 2** -- second supporting point with evidence
|
|
69
|
+
6. **Argument 3** -- third supporting point with evidence
|
|
70
|
+
7. **Demo** (optional) -- live demonstration that proves the thesis
|
|
71
|
+
8. **Counterargument** -- acknowledge the strongest objection, address it
|
|
72
|
+
9. **Takeaways** -- 3 bullet points the audience can act on Monday
|
|
73
|
+
10. **Q&A / Contact** -- how to reach you, resources
|
|
74
|
+
|
|
75
|
+
### Pacing notes
|
|
76
|
+
|
|
77
|
+
- Spend 60% of time on arguments 1-3
|
|
78
|
+
- Keep the demo under 5 minutes
|
|
79
|
+
- Leave 5 minutes for Q&A
|
|
80
|
+
- One slide per 2-3 minutes is a good cadence
|
|
81
|
+
|
|
82
|
+
## Sales deck
|
|
83
|
+
|
|
84
|
+
6-8 slides. 15-20 minutes. Customer-centric, not product-centric.
|
|
85
|
+
|
|
86
|
+
1. **Title** -- your company, their company, date
|
|
87
|
+
2. **Their problem** -- research their specific pain, show you understand
|
|
88
|
+
3. **Proof points** -- logos, case studies, metrics from similar customers
|
|
89
|
+
4. **Solution** -- how your product solves their specific problem
|
|
90
|
+
5. **How it works** -- enough technical detail to build confidence, not so much it overwhelms
|
|
91
|
+
6. **Pricing** -- transparent, with clear tiers
|
|
92
|
+
7. **Next steps** -- specific actions and timeline
|
|
93
|
+
8. **Appendix** -- detailed specs, security docs, compliance certs (don't present these, have them ready)
|