@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,364 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: animation
|
|
3
|
+
description: Step-by-step reveal and transition patterns for slidenerds slides
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Animation skill
|
|
7
|
+
|
|
8
|
+
Use this skill when a deck needs motion, sequencing, or narrative pacing. The runtime exposes one core control surface: `data-step`. Every animation in this skill maps to deterministic HTML, CSS, and step order.
|
|
9
|
+
|
|
10
|
+
## Runtime contract
|
|
11
|
+
|
|
12
|
+
- Every slide is a `section` with `data-slide`.
|
|
13
|
+
- Every revealable element has `data-step`.
|
|
14
|
+
- The runtime toggles hidden and visible state by step index.
|
|
15
|
+
- The presenter controls pace through keyboard or click.
|
|
16
|
+
|
|
17
|
+
Do not rely on autoplay animation timelines for core meaning. If animation carries meaning, tie it to `data-step`.
|
|
18
|
+
|
|
19
|
+
## Keynote-style animation support matrix
|
|
20
|
+
|
|
21
|
+
This table maps classic Apple Keynote patterns to reliable slidenerds implementations.
|
|
22
|
+
|
|
23
|
+
| Keynote family | Effects to support | slidenerds implementation |
|
|
24
|
+
| ---------------- | ---------------------------------------- | -------------------------------------------------------------- |
|
|
25
|
+
| Build in | Appear, Fade In, Move In, Scale In | `data-step` + CSS opacity, transform, scale transitions |
|
|
26
|
+
| Build out | Disappear, Fade Out, Move Out, Scale Out | Pair old/new layers across consecutive `data-step` wrappers |
|
|
27
|
+
| Action | Move, Rotate, Pulse, Color emphasis | `data-step` wrapper with CSS transitions on transform/color |
|
|
28
|
+
| Emphasis | Pulse, Highlight, Bounce | Short CSS keyframes triggered when step becomes visible |
|
|
29
|
+
| Slide transition | Dissolve, Push, Wipe style feel | Simulate with full-bleed transition elements on entering slide |
|
|
30
|
+
| Magic Move | Object morph between slides | Use the disciplined Magic Move emulation pattern below |
|
|
31
|
+
|
|
32
|
+
## Animation primitives
|
|
33
|
+
|
|
34
|
+
Use these classes globally in deck CSS.
|
|
35
|
+
|
|
36
|
+
```css
|
|
37
|
+
[data-step] {
|
|
38
|
+
visibility: hidden;
|
|
39
|
+
opacity: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
[data-step].step-fade {
|
|
43
|
+
transition:
|
|
44
|
+
opacity 280ms ease,
|
|
45
|
+
visibility 280ms ease;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
[data-step].step-move-up {
|
|
49
|
+
transform: translateY(16px);
|
|
50
|
+
transition:
|
|
51
|
+
opacity 320ms ease,
|
|
52
|
+
transform 320ms ease,
|
|
53
|
+
visibility 320ms ease;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
[data-step].step-scale-in {
|
|
57
|
+
transform: scale(0.96);
|
|
58
|
+
transition:
|
|
59
|
+
opacity 260ms ease,
|
|
60
|
+
transform 260ms ease,
|
|
61
|
+
visibility 260ms ease;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
[data-step].step-emphasis {
|
|
65
|
+
animation: emphasis-pulse 360ms ease-out 1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@keyframes emphasis-pulse {
|
|
69
|
+
0% {
|
|
70
|
+
transform: scale(1);
|
|
71
|
+
}
|
|
72
|
+
45% {
|
|
73
|
+
transform: scale(1.04);
|
|
74
|
+
}
|
|
75
|
+
100% {
|
|
76
|
+
transform: scale(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The runtime toggles the `.step-visible` class when the step is active. The visible state override:
|
|
82
|
+
|
|
83
|
+
```css
|
|
84
|
+
[data-step].step-visible {
|
|
85
|
+
visibility: visible !important;
|
|
86
|
+
opacity: 1 !important;
|
|
87
|
+
transform: translateY(0) translateX(0) scale(1) !important;
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For emphasis entrance on big stats, combine with the `step-emphasis` class:
|
|
92
|
+
|
|
93
|
+
```css
|
|
94
|
+
[data-step].step-emphasis.step-visible {
|
|
95
|
+
animation: emphasis-land 500ms cubic-bezier(0.16, 1, 0.3, 1) 1;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@keyframes emphasis-land {
|
|
99
|
+
0% { transform: scale(0.85); opacity: 0; }
|
|
100
|
+
60% { transform: scale(1.03); }
|
|
101
|
+
100% { transform: scale(1); opacity: 1; }
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Build in patterns
|
|
106
|
+
|
|
107
|
+
### Fade in list items
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<ul className="space-y-3 text-xl">
|
|
111
|
+
<li data-step="" className="step-fade">
|
|
112
|
+
Problem is urgent
|
|
113
|
+
</li>
|
|
114
|
+
<li data-step="" className="step-fade">
|
|
115
|
+
Solution is differentiated
|
|
116
|
+
</li>
|
|
117
|
+
<li data-step="" className="step-fade">
|
|
118
|
+
Market timing is favorable
|
|
119
|
+
</li>
|
|
120
|
+
</ul>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Move in diagram nodes
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
<div className="grid grid-cols-3 gap-6">
|
|
127
|
+
<div data-step="" className="step-move-up rounded-xl p-6">
|
|
128
|
+
Acquire
|
|
129
|
+
</div>
|
|
130
|
+
<div data-step="" className="step-move-up rounded-xl p-6">
|
|
131
|
+
Activate
|
|
132
|
+
</div>
|
|
133
|
+
<div data-step="" className="step-move-up rounded-xl p-6">
|
|
134
|
+
Expand
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Build out patterns
|
|
140
|
+
|
|
141
|
+
Use paired layers. First step shows current object, next step shows replacement object in target state.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
<div className="relative h-48">
|
|
145
|
+
<div data-step="" className="step-fade absolute inset-0">
|
|
146
|
+
Current pricing: $49
|
|
147
|
+
</div>
|
|
148
|
+
<div data-step="" className="step-fade absolute inset-0">
|
|
149
|
+
New pricing: $99
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Action and emphasis patterns
|
|
155
|
+
|
|
156
|
+
### Emphasize one metric without changing slide
|
|
157
|
+
|
|
158
|
+
```tsx
|
|
159
|
+
<div data-step="" className="text-6xl font-bold step-emphasis">
|
|
160
|
+
143%
|
|
161
|
+
</div>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Animated chart reveal
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
<div data-step="" className="step-fade">
|
|
168
|
+
<ResponsiveContainer width="100%" height={360}>
|
|
169
|
+
<BarChart data={revenueData}>
|
|
170
|
+
<XAxis dataKey="quarter" />
|
|
171
|
+
<YAxis />
|
|
172
|
+
<Bar dataKey="arr" fill="var(--color-accent)" animationDuration={700} />
|
|
173
|
+
</BarChart>
|
|
174
|
+
</ResponsiveContainer>
|
|
175
|
+
</div>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Magic Move (slide to slide)
|
|
179
|
+
|
|
180
|
+
The runtime performs automatic FLIP animation between slides for elements that share a `data-magic-id`. When navigating from one slide to the next, elements with matching IDs animate smoothly from their old position, size, and scale to their new position.
|
|
181
|
+
|
|
182
|
+
### Protocol
|
|
183
|
+
|
|
184
|
+
1. Give shared elements the same `data-magic-id` value on both slides.
|
|
185
|
+
2. Keep typography tokens and brand colors identical across source and destination.
|
|
186
|
+
3. Change geometry (position, size) between source and destination -- the runtime animates the difference.
|
|
187
|
+
4. Put destination-only objects behind `data-step` on the destination slide.
|
|
188
|
+
5. The FLIP animation runs at 500ms with a cubic-bezier(0.4, 0, 0.2, 1) easing.
|
|
189
|
+
|
|
190
|
+
### Source slide
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
<section data-slide="">
|
|
194
|
+
<div className="relative min-h-screen" style={{ padding: 'var(--slide-padding)' }}>
|
|
195
|
+
<div data-magic-id="logo" className="absolute left-12 top-10">
|
|
196
|
+
Logo
|
|
197
|
+
</div>
|
|
198
|
+
<div data-magic-id="hero-chart" className="absolute left-20 top-28 w-[460px]">
|
|
199
|
+
Chart A
|
|
200
|
+
</div>
|
|
201
|
+
<h2 data-magic-id="headline" className="absolute left-20 bottom-24 text-5xl">
|
|
202
|
+
Before
|
|
203
|
+
</h2>
|
|
204
|
+
</div>
|
|
205
|
+
</section>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Destination slide
|
|
209
|
+
|
|
210
|
+
```tsx
|
|
211
|
+
<section data-slide="">
|
|
212
|
+
<div className="relative min-h-screen" style={{ padding: 'var(--slide-padding)' }}>
|
|
213
|
+
<div data-magic-id="logo" className="absolute right-12 top-10">
|
|
214
|
+
Logo
|
|
215
|
+
</div>
|
|
216
|
+
<div data-magic-id="hero-chart" className="absolute left-16 top-20 w-[760px]">
|
|
217
|
+
Chart B
|
|
218
|
+
</div>
|
|
219
|
+
<h2 data-magic-id="headline" className="absolute left-16 bottom-16 text-6xl">
|
|
220
|
+
After
|
|
221
|
+
</h2>
|
|
222
|
+
<p data-step="" className="step-fade absolute right-16 bottom-16">
|
|
223
|
+
Narration detail appears on click
|
|
224
|
+
</p>
|
|
225
|
+
</div>
|
|
226
|
+
</section>
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Magic Move quality checklist
|
|
230
|
+
|
|
231
|
+
- Same object names and semantic roles across both slides
|
|
232
|
+
- No random spacing changes outside intended movement
|
|
233
|
+
- Motion supports story progression, not decoration
|
|
234
|
+
- Presenter can explain the transform in one sentence
|
|
235
|
+
|
|
236
|
+
## Transition overlays for slide changes
|
|
237
|
+
|
|
238
|
+
To mimic dissolve or wipe feeling, reveal a transition layer as the first step on the destination slide.
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
<section data-slide="">
|
|
242
|
+
<div data-step="" className="step-fade absolute inset-0 bg-black/20" />
|
|
243
|
+
<div style={{ padding: 'var(--slide-padding)' }}>
|
|
244
|
+
<h2 className="text-5xl">New section</h2>
|
|
245
|
+
</div>
|
|
246
|
+
</section>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Auto-build animations
|
|
250
|
+
|
|
251
|
+
Auto-build animations trigger when a slide loads, with no click required. Use them for visual polish on slides where the content doesn't need pacing control.
|
|
252
|
+
|
|
253
|
+
### Available classes
|
|
254
|
+
|
|
255
|
+
| Class | Effect | Duration |
|
|
256
|
+
|-------|--------|----------|
|
|
257
|
+
| `auto-fade` | Fade in | 350ms |
|
|
258
|
+
| `auto-pop` | Scale up with overshoot bounce | 400ms |
|
|
259
|
+
| `auto-wipe-right` | Clip-path reveal left to right | 500ms |
|
|
260
|
+
| `auto-slide-down` | Slide down from above + fade | 500ms |
|
|
261
|
+
| `auto-slide-up` | Slide up from below + fade | 500ms |
|
|
262
|
+
|
|
263
|
+
### Staggering
|
|
264
|
+
|
|
265
|
+
Control stagger with inline `animationDelay`:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
{items.map((item, i) => (
|
|
269
|
+
<div key={item.id} className="auto-pop card-surface p-5"
|
|
270
|
+
style={{ animationDelay: `${200 + i * 100}ms` }}>
|
|
271
|
+
{item.content}
|
|
272
|
+
</div>
|
|
273
|
+
))}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Directional grid pattern
|
|
277
|
+
|
|
278
|
+
For grids, use opposing directions by row for a "closing curtain" effect:
|
|
279
|
+
|
|
280
|
+
```tsx
|
|
281
|
+
{items.map((item) => (
|
|
282
|
+
<div key={item.id}
|
|
283
|
+
className={`${item.row === 0 ? 'auto-slide-down' : 'auto-slide-up'} card-surface`}
|
|
284
|
+
style={{ animationDelay: '400ms' }}>
|
|
285
|
+
{item.content}
|
|
286
|
+
</div>
|
|
287
|
+
))}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### When to use auto-build vs click-to-reveal
|
|
291
|
+
|
|
292
|
+
- **Auto-build**: KPI grids, case study cards, icon grids, badge lists, product cards. Slides where the visual entrance is the point, not the pacing.
|
|
293
|
+
- **Click-to-reveal**: Bullet lists, table rows, comparison reveals, any content where the presenter wants to control the narrative.
|
|
294
|
+
- **Hybrid**: Use `data-auto-step` for elements that auto-reveal, then `data-step` for elements that wait for clicks. Auto-steps play first, then manual steps take over.
|
|
295
|
+
|
|
296
|
+
## Exit animations
|
|
297
|
+
|
|
298
|
+
Exit animations trigger when navigating away from a slide. The runtime adds `.exiting` to the slide and waits 400ms before transitioning.
|
|
299
|
+
|
|
300
|
+
### Auto exits
|
|
301
|
+
|
|
302
|
+
Add exit classes directly to elements. They animate when the slide gets `.exiting`:
|
|
303
|
+
|
|
304
|
+
| Class | Effect | Duration |
|
|
305
|
+
|-------|--------|----------|
|
|
306
|
+
| `exit-fade` | Fade out | 400ms |
|
|
307
|
+
| `exit-scale-out` | Scale down + fade out | 400ms |
|
|
308
|
+
| `exit-slide-up` | Slide up + fade out | 400ms |
|
|
309
|
+
| `exit-slide-down` | Slide down + fade out | 400ms |
|
|
310
|
+
| `exit-wipe-left` | Clip-path collapse right to left | 400ms |
|
|
311
|
+
|
|
312
|
+
### Author-controlled exits
|
|
313
|
+
|
|
314
|
+
Use `data-exit-step` for sequenced exits. After all entrance steps are revealed, subsequent clicks reveal exit steps (applying `exit-visible`), then transition to the next slide.
|
|
315
|
+
|
|
316
|
+
```tsx
|
|
317
|
+
<h2 data-exit-step="" className="exit-fade">This fades out before slide transition</h2>
|
|
318
|
+
<div data-exit-step="" className="exit-slide-up">This slides up after the h2 fades</div>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
## Auto-step sequencing
|
|
322
|
+
|
|
323
|
+
Use `data-auto-step="300ms"` for steps that reveal automatically on a timer. The value is the delay before revealing. Mix with `data-step` for hybrid sequences.
|
|
324
|
+
|
|
325
|
+
```tsx
|
|
326
|
+
<div data-auto-step="200ms" className="step-fade">Reveals after 200ms</div>
|
|
327
|
+
<div data-auto-step="300ms" className="step-fade">Reveals 300ms after previous</div>
|
|
328
|
+
<div data-step="" className="step-move-up">Waits for click</div>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Step groups
|
|
332
|
+
|
|
333
|
+
Use `data-step-group="name"` to reveal multiple elements with a single click. The runtime counts the group as one logical step.
|
|
334
|
+
|
|
335
|
+
```tsx
|
|
336
|
+
<div data-step="" data-step-group="metrics" className="step-pop"
|
|
337
|
+
style={{ animationDelay: '0ms' }}>Revenue: $4.2M</div>
|
|
338
|
+
<div data-step="" data-step-group="metrics" className="step-pop"
|
|
339
|
+
style={{ animationDelay: '100ms' }}>Growth: 142%</div>
|
|
340
|
+
<div data-step="" data-step-group="metrics" className="step-pop"
|
|
341
|
+
style={{ animationDelay: '200ms' }}>Users: 50K</div>
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## Animation QA checklist
|
|
345
|
+
|
|
346
|
+
- At least two distinct animation types in a deck: fade plus move, or fade plus scale
|
|
347
|
+
- At least one chart animation tied to `data-step`
|
|
348
|
+
- No animation duration above 800ms for presenter-controlled steps
|
|
349
|
+
- No infinite loops on content that appears in exports
|
|
350
|
+
- No clipping at common projector resolutions (1920x1080)
|
|
351
|
+
|
|
352
|
+
## Image and logo motion rules
|
|
353
|
+
|
|
354
|
+
- Avoid animating full-bleed background images with large scale transforms
|
|
355
|
+
- Animate logo opacity or small position shifts only
|
|
356
|
+
- Keep logo animation under 250ms
|
|
357
|
+
- Preserve contrast at all animation states
|
|
358
|
+
|
|
359
|
+
## What to avoid
|
|
360
|
+
|
|
361
|
+
- `backdrop-filter` and heavy blend modes, which degrade export reliability
|
|
362
|
+
- Delayed step transitions that make click timing ambiguous
|
|
363
|
+
- Parallel animations on more than 12 objects in one step
|
|
364
|
+
- Motion without narrative purpose
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brand
|
|
3
|
+
description: How to apply brand identity to a slidenerds deck by editing brand.config.ts and globals.css
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Brand skill
|
|
7
|
+
|
|
8
|
+
Use this skill when creating a new deck, rebranding an existing deck, or applying a company's visual identity. This skill tells you exactly which files to edit and what values to set.
|
|
9
|
+
|
|
10
|
+
## The branding system
|
|
11
|
+
|
|
12
|
+
Every slidenerds deck has two files that control brand:
|
|
13
|
+
|
|
14
|
+
1. **`brand.config.ts`** at the project root. This is the single source of truth for colors, fonts, and spacing. The layout template reads this file and injects CSS custom properties on the `<html>` element at build time.
|
|
15
|
+
2. **`app/globals.css`** for structural CSS, font imports, and derived color tokens. Add custom `@import` rules for web fonts here. Do not hardcode colors in slide content. Always use `var()` references.
|
|
16
|
+
|
|
17
|
+
Changing `brand.config.ts` rebrands the entire deck. No slide files need color or font edits.
|
|
18
|
+
|
|
19
|
+
## brand.config.ts structure
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import type { BrandConfig } from '@slidenerds/runtime'
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
colors: {
|
|
26
|
+
primary: '#0d0d0f',
|
|
27
|
+
accent: '#f59e0b',
|
|
28
|
+
background: '#111114',
|
|
29
|
+
surface: '#1a1a1f',
|
|
30
|
+
text: '#e8e6e3',
|
|
31
|
+
},
|
|
32
|
+
fonts: {
|
|
33
|
+
heading: 'Sora, system-ui, sans-serif',
|
|
34
|
+
body: 'DM Sans, system-ui, sans-serif',
|
|
35
|
+
mono: 'JetBrains Mono, ui-monospace, monospace',
|
|
36
|
+
},
|
|
37
|
+
spacing: {
|
|
38
|
+
slide: '5rem',
|
|
39
|
+
section: '2rem',
|
|
40
|
+
element: '1rem',
|
|
41
|
+
},
|
|
42
|
+
} satisfies BrandConfig
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## How layout.tsx wires brand to CSS
|
|
46
|
+
|
|
47
|
+
The generated `app/layout.tsx` imports `brand.config.ts` and injects CSS custom properties:
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
import brandConfig from '../brand.config'
|
|
51
|
+
|
|
52
|
+
const brandVars = {
|
|
53
|
+
'--color-primary': brandConfig.colors.primary,
|
|
54
|
+
'--color-accent': brandConfig.colors.accent,
|
|
55
|
+
'--color-background': brandConfig.colors.background,
|
|
56
|
+
'--color-surface': brandConfig.colors.surface,
|
|
57
|
+
'--color-text': brandConfig.colors.text,
|
|
58
|
+
'--slide-padding': brandConfig.spacing.slide,
|
|
59
|
+
'--font-heading': brandConfig.fonts.heading,
|
|
60
|
+
'--font-body': brandConfig.fonts.body,
|
|
61
|
+
'--font-mono': brandConfig.fonts.mono,
|
|
62
|
+
} as React.CSSProperties
|
|
63
|
+
|
|
64
|
+
export default function RootLayout({ children }) {
|
|
65
|
+
return (
|
|
66
|
+
<html lang="en" style={brandVars}>
|
|
67
|
+
<body>
|
|
68
|
+
<SlideRuntime>{children}</SlideRuntime>
|
|
69
|
+
</body>
|
|
70
|
+
</html>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This means every CSS `var()` reference resolves to the brand.config.ts values. No manual wiring needed.
|
|
76
|
+
|
|
77
|
+
## What each color controls
|
|
78
|
+
|
|
79
|
+
| Token | CSS variable | Used by |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `primary` | `--color-primary` | Section divider backgrounds, darkest surfaces |
|
|
82
|
+
| `accent` | `--color-accent` | Section labels, stat numbers, shape strokes, active indicators, chart fills, timeline dots, table highlights |
|
|
83
|
+
| `background` | `--color-background` | Slide canvas, body background |
|
|
84
|
+
| `surface` | `--color-surface` | Card backgrounds for charts, tables, code blocks |
|
|
85
|
+
| `text` | `--color-text` | Primary body text, headings |
|
|
86
|
+
|
|
87
|
+
## Derived colors
|
|
88
|
+
|
|
89
|
+
Some slides need colors derived from the base palette. Define these in `globals.css`:
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
:root {
|
|
93
|
+
--color-accent-dim: rgba(245, 158, 11, 0.12);
|
|
94
|
+
--color-text-secondary: rgba(232, 230, 227, 0.6);
|
|
95
|
+
--color-text-tertiary: rgba(232, 230, 227, 0.4);
|
|
96
|
+
--color-border: rgba(255, 255, 255, 0.06);
|
|
97
|
+
--color-surface-elevated: #222228;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
When rebranding, extract the RGB values from the new accent and text colors and recompute these at the correct opacities.
|
|
102
|
+
|
|
103
|
+
## How to rebrand step by step
|
|
104
|
+
|
|
105
|
+
### Given a brand kit (colors + fonts)
|
|
106
|
+
|
|
107
|
+
1. **Edit `brand.config.ts`**: Set the five core colors and three font stacks.
|
|
108
|
+
2. **Update derived colors in `globals.css`**: Recompute accent-dim, text-secondary, text-tertiary, border, and surface-elevated using the new base values.
|
|
109
|
+
3. **Add font imports in `globals.css`**: Add Google Fonts `@import` rules before the Tailwind import.
|
|
110
|
+
4. **Done.** No slide files need editing.
|
|
111
|
+
|
|
112
|
+
### Given only a logo or single brand color
|
|
113
|
+
|
|
114
|
+
Derive the full palette from one color:
|
|
115
|
+
|
|
116
|
+
- **accent**: The brand color itself.
|
|
117
|
+
- **background**: Near-black with a subtle hue tint toward the accent. Example: for amber accent, use `#111114` (neutral) or `#13120e` (warm).
|
|
118
|
+
- **surface**: One step lighter than background. Add 5-8% lightness.
|
|
119
|
+
- **primary**: Same as background or slightly darker.
|
|
120
|
+
- **text**: Off-white, not pure `#fff`. Use `#e8e6e3` or similar with a slight warm or cool bias matching the accent.
|
|
121
|
+
|
|
122
|
+
### Light theme decks
|
|
123
|
+
|
|
124
|
+
Invert the relationships:
|
|
125
|
+
|
|
126
|
+
- **background**: Near-white (`#fafafa` to `#f5f5f5`)
|
|
127
|
+
- **surface**: White (`#ffffff`)
|
|
128
|
+
- **primary**: The brand's darkest color
|
|
129
|
+
- **text**: Near-black (`#1a1a1a` to `#2a2a2a`)
|
|
130
|
+
- **accent**: The brand color (ensure 4.5:1 contrast against background)
|
|
131
|
+
- Derived text opacities use the text color base, not white
|
|
132
|
+
- Change `--color-border` to `rgba(0, 0, 0, 0.06)` instead of white-based
|
|
133
|
+
|
|
134
|
+
## Font pairing rules
|
|
135
|
+
|
|
136
|
+
- **Same family, weight contrast**: Use 800 heading, 400 body. Good for Inter, DM Sans, Plus Jakarta Sans.
|
|
137
|
+
- **Geometric heading + humanist body**: Sora or Space Grotesk headings, DM Sans or Source Sans body.
|
|
138
|
+
- **Serif heading + sans body**: Playfair Display or Fraunces headings, Inter or DM Sans body. For editorial or luxury brands.
|
|
139
|
+
- **Mono accent**: Always include a monospace font. JetBrains Mono, Fira Code, or Berkeley Mono.
|
|
140
|
+
|
|
141
|
+
Set all three in `brand.config.ts`. The layout injects them as `--font-heading`, `--font-body`, and `--font-mono`.
|
|
142
|
+
|
|
143
|
+
## Where brand tokens appear in slide code
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
{/* Section label -- accent color, uppercase, wide tracking */}
|
|
147
|
+
<p className="section-label">Revenue</p>
|
|
148
|
+
|
|
149
|
+
{/* Title -- heading font inherited from body, tight tracking */}
|
|
150
|
+
<h2 className="text-[2.5rem] font-bold">ARR trajectory</h2>
|
|
151
|
+
|
|
152
|
+
{/* Body text -- secondary opacity */}
|
|
153
|
+
<p style={{ color: 'var(--color-text-secondary)' }}>Supporting detail</p>
|
|
154
|
+
|
|
155
|
+
{/* Stat number -- accent color with glow */}
|
|
156
|
+
<p className="stat-glow" style={{ color: 'var(--color-accent)' }}>$4.2M</p>
|
|
157
|
+
|
|
158
|
+
{/* Card surface for charts */}
|
|
159
|
+
<div className="card-surface p-8">...</div>
|
|
160
|
+
|
|
161
|
+
{/* Shape with brand colors */}
|
|
162
|
+
<SlideShape shape="hexagon" size={100}
|
|
163
|
+
fill="var(--color-surface)" stroke="var(--color-accent)" strokeWidth={1.5} />
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Never hardcode hex colors in slide content. Always use CSS variables.
|
|
167
|
+
|
|
168
|
+
## Gradient mesh backgrounds
|
|
169
|
+
|
|
170
|
+
For atmospheric depth, use radial gradients with the accent at low opacity:
|
|
171
|
+
|
|
172
|
+
```css
|
|
173
|
+
.bg-mesh-warm {
|
|
174
|
+
background:
|
|
175
|
+
radial-gradient(ellipse at 15% 60%, rgba(R, G, B, 0.07) 0%, transparent 50%),
|
|
176
|
+
radial-gradient(ellipse at 85% 25%, rgba(R, G, B, 0.03) 0%, transparent 40%),
|
|
177
|
+
var(--color-background);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Replace R, G, B with the accent color's RGB components when rebranding.
|
|
182
|
+
|
|
183
|
+
## Checklist after rebranding
|
|
184
|
+
|
|
185
|
+
- [ ] Five colors set in `brand.config.ts`
|
|
186
|
+
- [ ] Derived colors updated in `globals.css`
|
|
187
|
+
- [ ] Font imports added to `globals.css`
|
|
188
|
+
- [ ] Three font stacks set in `brand.config.ts`
|
|
189
|
+
- [ ] Gradient mesh backgrounds updated with new accent RGB
|
|
190
|
+
- [ ] No hardcoded hex values in slide content (search for `#` in page.tsx)
|
|
191
|
+
- [ ] Accent color has at least 4.5:1 contrast against background
|
|
192
|
+
- [ ] Text color has at least 7:1 contrast against background
|
|
193
|
+
|
|
194
|
+
## Common mistakes
|
|
195
|
+
|
|
196
|
+
- Hardcoding `#f59e0b` instead of `var(--color-accent)` in slide files
|
|
197
|
+
- Editing `globals.css` colors instead of `brand.config.ts`
|
|
198
|
+
- Using pixel values for slide padding instead of `var(--slide-padding)`
|
|
199
|
+
- Using a font not declared in `brand.config.ts`
|
|
200
|
+
- Forgetting to update derived opacity colors after changing the base palette
|