@deckio/deck-engine 0.2.1 → 0.2.3

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.
@@ -0,0 +1,467 @@
1
+ # Design System Supplement — shadcn
2
+
3
+ ## Metadata
4
+
5
+ - **Design system id:** `shadcn`
6
+ - **Supplements theme descriptors:** `shadcn.md` (primary), but orthogonal to theme choice
7
+ - **Activates when:** `deck.config.js` includes `designSystem: 'shadcn'`
8
+ - **Read this file when:** You need to understand how shadcn/ui components compose together in slide context, how to maintain visual coherence across a deck, or how the design system layer relates to the theme layer
9
+
10
+ ---
11
+
12
+ ## What this file is
13
+
14
+ This is the **design system supplement** — it documents how components work _together_ to build coherent slides. The theme descriptor (`shadcn.md`) covers what's available and how to use individual components. This file covers **composition patterns, visual rhythm, and design system coherence**.
15
+
16
+ The design system layer is orthogonal to theme choice:
17
+ - `theme` controls visual appearance (colors, tokens, mood)
18
+ - `designSystem` controls component infrastructure (what components exist, how they compose)
19
+ - You can have `theme: "shadcn"` with or without `designSystem: "shadcn"`
20
+ - When `designSystem: "shadcn"` is active, this supplement applies regardless of theme
21
+
22
+ ---
23
+
24
+ ## Component composition patterns
25
+
26
+ ### Slide anatomy
27
+
28
+ Every shadcn slide follows this structural hierarchy:
29
+
30
+ ```
31
+ Slide (engine primitive — positioning, transitions)
32
+ └── content-frame + content-gutter (engine layout — max-width, padding)
33
+ └── Slide body (CSS module — flex column, gap)
34
+ ├── Header region (Badge + heading + subtitle)
35
+ ├── Content region (Cards, Alerts, Separators, custom blocks)
36
+ ├── Action region (Buttons)
37
+ └── BottomBar (engine primitive — deck title, page number)
38
+ ```
39
+
40
+ **Rules:**
41
+ - `Slide` + `BottomBar` always come from `@deckio/deck-engine`
42
+ - `content-frame` and `content-gutter` are required CSS classes on the body wrapper
43
+ - Everything between header and actions is the content region — compose freely with components
44
+
45
+ ### Header pattern
46
+
47
+ The header is the most consistent element across slides. Always follow this order:
48
+
49
+ ```jsx
50
+ <div className={styles.header}>
51
+ <Badge variant="secondary">Category label</Badge> {/* optional kicker */}
52
+ <h2 className={styles.title}>Main heading</h2> {/* required */}
53
+ <p className={styles.subtitle}>Supporting text</p> {/* optional */}
54
+ </div>
55
+ ```
56
+
57
+ - Badge kickers use `variant="secondary"` or `variant="outline"` — never `default` (too heavy for a label)
58
+ - Title uses `var(--foreground)`, clamp sizing `clamp(28px, 3.2vw, 36px)`
59
+ - Subtitle uses `var(--muted-foreground)`, clamp sizing `clamp(16px, 1.6vw, 19px)`
60
+ - Header gap: 12px between elements
61
+
62
+ ### Card grid pattern
63
+
64
+ Cards are the primary content container. Use grids of 2–4 columns:
65
+
66
+ ```jsx
67
+ <div className={styles.grid}>
68
+ <Card>
69
+ <CardHeader>
70
+ <CardTitle>Title</CardTitle>
71
+ <CardDescription>Detail</CardDescription>
72
+ </CardHeader>
73
+ <CardContent>
74
+ <p>Body content</p>
75
+ </CardContent>
76
+ </Card>
77
+ {/* ... more cards */}
78
+ </div>
79
+ ```
80
+
81
+ ```css
82
+ .grid {
83
+ display: grid;
84
+ grid-template-columns: repeat(2, minmax(0, 1fr)); /* 2-col default */
85
+ gap: var(--spacing-md, 20px);
86
+ }
87
+
88
+ /* 3-col for feature showcases */
89
+ .gridThree { grid-template-columns: repeat(3, minmax(0, 1fr)); }
90
+
91
+ /* 4-col for metric dashboards (tight) */
92
+ .gridFour { grid-template-columns: repeat(4, minmax(0, 1fr)); }
93
+ ```
94
+
95
+ **Visual rhythm rules:**
96
+ - 2 columns: general content, comparisons, before/after
97
+ - 3 columns: feature showcases, step sequences
98
+ - 4 columns: metric dashboards, KPI rows (use sparingly — tight at 1280×720)
99
+ - Never mix column counts within a single slide
100
+ - Card gap: 20px (consistent across all grid sizes)
101
+
102
+ ### Alert as framing device
103
+
104
+ Alerts work as contextual framing — use them to set up the content that follows:
105
+
106
+ ```jsx
107
+ <Alert>
108
+ <Info className="size-4" />
109
+ <AlertTitle>Context setter</AlertTitle>
110
+ <AlertDescription>
111
+ Frame the problem or key insight before diving into detail cards.
112
+ </AlertDescription>
113
+ </Alert>
114
+
115
+ <Separator />
116
+
117
+ <div className={styles.grid}>
118
+ {/* Detail cards follow the alert */}
119
+ </div>
120
+ ```
121
+
122
+ - Place alerts **before** card grids, not inside them
123
+ - Use `<Separator />` between alert and grid for visual breathing room
124
+ - Destructive variant (`variant="destructive"`) only for genuine warnings
125
+ - One alert per slide maximum
126
+
127
+ ### Button action row
128
+
129
+ Buttons anchor the bottom of the content region:
130
+
131
+ ```jsx
132
+ <div className={styles.actions}>
133
+ <Button>Primary action</Button>
134
+ <Button variant="outline">Secondary action</Button>
135
+ <Button variant="ghost">Tertiary</Button>
136
+ </div>
137
+ ```
138
+
139
+ - Maximum 3 buttons per action row
140
+ - Primary (default variant) always comes first
141
+ - `variant="outline"` for secondary actions
142
+ - `variant="ghost"` for tertiary/de-emphasized actions
143
+ - Gap: 12px between buttons
144
+ - Align left (`justify-content: flex-start`) — never center button rows
145
+
146
+ ### Separator usage
147
+
148
+ Separators create visual breaks between content sections:
149
+
150
+ ```jsx
151
+ <Header />
152
+ <Alert />
153
+ <Separator /> {/* between framing and detail */}
154
+ <CardGrid />
155
+ <Separator /> {/* between detail and actions */}
156
+ <Actions />
157
+ ```
158
+
159
+ - Maximum 2 separators per slide
160
+ - Never stack separators adjacent to each other
161
+ - Horizontal orientation (default) for content breaks
162
+ - Vertical orientation for inline element separation (rare in slides)
163
+
164
+ ---
165
+
166
+ ## Variant usage guide
167
+
168
+ ### Button variants in slide context
169
+
170
+ | Variant | Slide use case | Visual weight |
171
+ |---|---|---|
172
+ | `default` | Primary CTA, "next step", key action | Heavy — filled primary color |
173
+ | `destructive` | Delete, remove, warning actions | Heavy — filled destructive color |
174
+ | `outline` | Secondary action, "learn more", alternatives | Medium — bordered |
175
+ | `secondary` | Supplementary action, metadata links | Medium — muted fill |
176
+ | `ghost` | Tertiary action, navigation hints | Light — text only |
177
+ | `link` | Inline text links within content | Minimal — underlined text |
178
+
179
+ ### Badge variants in slide context
180
+
181
+ | Variant | Slide use case |
182
+ |---|---|
183
+ | `secondary` | Default kicker/label above headings |
184
+ | `outline` | Subtle categorization, metadata tags |
185
+ | `default` | Status indicators (use sparingly — high contrast) |
186
+ | `destructive` | Warning/error status |
187
+ | `ghost` | Rarely used in slides; available for custom overlays |
188
+ | `link` | Rarely used in slides; available for badge links |
189
+
190
+ ### Alert variants in slide context
191
+
192
+ | Variant | Slide use case |
193
+ |---|---|
194
+ | `default` | Context-setting, key insight framing, pro tips |
195
+ | `destructive` | Critical warnings, breaking changes, blockers |
196
+
197
+ ---
198
+
199
+ ## Composition with Radix primitives
200
+
201
+ Preinstalled components build on Radix UI. When adding components via CLI/MCP, they follow the same patterns:
202
+
203
+ ### `asChild` pattern
204
+
205
+ `asChild` replaces the default rendered element with the child element, forwarding all props:
206
+
207
+ ```jsx
208
+ {/* Button renders as <a> tag with Button styling */}
209
+ <Button asChild variant="outline">
210
+ <a href="https://github.com/project" target="_blank">
211
+ View on GitHub
212
+ </a>
213
+ </Button>
214
+
215
+ {/* Badge renders as <a> tag */}
216
+ <Badge asChild variant="secondary">
217
+ <a href="/changelog">v2.0</a>
218
+ </Badge>
219
+ ```
220
+
221
+ **When to use:** Links that should look like buttons, or any case where the semantic HTML element differs from the visual component.
222
+
223
+ ### Compound component composition
224
+
225
+ shadcn components use the compound component pattern — compose by nesting:
226
+
227
+ ```jsx
228
+ {/* Card with action button in header (v4 pattern) */}
229
+ <Card>
230
+ <CardHeader>
231
+ <CardTitle>Feature</CardTitle>
232
+ <CardDescription>Description</CardDescription>
233
+ <CardAction>
234
+ <Button variant="outline" size="sm">Edit</Button>
235
+ </CardAction>
236
+ </CardHeader>
237
+ <CardContent>
238
+ <p>Content</p>
239
+ </CardContent>
240
+ <CardFooter>
241
+ <Button>Save</Button>
242
+ </CardFooter>
243
+ </Card>
244
+ ```
245
+
246
+ - Always maintain the nesting order: Header → Content → Footer
247
+ - `CardAction` goes inside `CardHeader` (v4 auto-positions it)
248
+ - Don't skip levels (no `CardTitle` outside `CardHeader`)
249
+
250
+ ### `data-slot` styling hooks
251
+
252
+ Every component emits `data-slot` for external styling:
253
+
254
+ ```css
255
+ /* Override Card background in a specific slide */
256
+ .specialSlide [data-slot="card"] {
257
+ background: color-mix(in srgb, var(--card) 80%, var(--accent) 20%);
258
+ }
259
+
260
+ /* Style all badges in this slide */
261
+ .specialSlide [data-slot="badge"] {
262
+ text-transform: uppercase;
263
+ letter-spacing: 0.05em;
264
+ }
265
+ ```
266
+
267
+ **Prefer this over className overrides** when you need slide-scoped component styling. It targets component identity, not implementation-specific class names.
268
+
269
+ ---
270
+
271
+ ## Mixing preinstalled + added components
272
+
273
+ When you add new components via `npx shadcn@latest add`, they automatically inherit the token system. Visual coherence is maintained because:
274
+
275
+ 1. **Same token foundation** — all shadcn components read from `--background`, `--foreground`, `--border`, `--radius`, etc.
276
+ 2. **Same utility layer** — Tailwind classes resolve to the same theme bridge
277
+ 3. **Same `cn()` utility** — className composition is consistent
278
+ 4. **Same `data-slot` convention** — styling hooks work the same way
279
+
280
+ ### Coherence checklist when adding components
281
+
282
+ - ✅ The new component reads from the same CSS variables — no configuration needed
283
+ - ✅ Border radius matches via `--radius` token
284
+ - ✅ Colors match via semantic tokens (not hardcoded values)
285
+ - ⚠️ Check font sizing — some components may use `text-sm` which maps to Tailwind's scale. Verify it aligns with slide heading/body sizes
286
+ - ⚠️ Check spacing — component internal padding uses Tailwind spacing. Verify it doesn't look cramped or loose at 1280×720 slide dimensions
287
+ - ⚠️ Animation — added components may include transitions. Ensure they don't conflict with ReactBits animations on the same slide
288
+
289
+ ### Example: adding Dialog for a detail overlay
290
+
291
+ ```bash
292
+ npx shadcn@latest add dialog
293
+ ```
294
+
295
+ ```jsx
296
+ import { Button } from '@/components/ui/button'
297
+ import {
298
+ Dialog, DialogContent, DialogDescription,
299
+ DialogHeader, DialogTitle, DialogTrigger
300
+ } from '@/components/ui/dialog'
301
+
302
+ {/* Inside your slide content */}
303
+ <Dialog>
304
+ <DialogTrigger asChild>
305
+ <Button variant="outline">View details</Button>
306
+ </DialogTrigger>
307
+ <DialogContent>
308
+ <DialogHeader>
309
+ <DialogTitle>Feature deep-dive</DialogTitle>
310
+ <DialogDescription>
311
+ Extended information that doesn't fit on the slide surface.
312
+ </DialogDescription>
313
+ </DialogHeader>
314
+ <p>Detailed content here.</p>
315
+ </DialogContent>
316
+ </Dialog>
317
+ ```
318
+
319
+ Note: Dialogs render as overlays — they work in dev mode but may not export/screenshot correctly. Use with awareness of the export pipeline.
320
+
321
+ ---
322
+
323
+ ## Deck-specific design tokens
324
+
325
+ These tokens extend the shadcn vocabulary for presentation-specific needs. They are defined in the theme CSS (`shadcn.css`), not by shadcn/ui itself:
326
+
327
+ ### Slide composition tokens
328
+
329
+ | Token | Purpose | Default (shadcn theme) |
330
+ |---|---|---|
331
+ | `--slide-bg` | Full slide background behind content frame | Same as `--background` |
332
+ | `--content-max-width` | Maximum width of `content-frame` | `1100px` |
333
+ | `--content-gutter` | Horizontal padding inside `content-gutter` | `48px` |
334
+ | `--surface-overlay` | Card/surface overlay for frosted effects | Translucent white/black |
335
+ | `--surface-overlay-heavy` | Stronger overlay for modal-like surfaces | Higher opacity overlay |
336
+ | `--border-subtle` | Lighter border for decorative separation | Lower opacity border |
337
+ | `--shadow-elevated` | Elevated card shadow | Subtle box-shadow value |
338
+
339
+ ### Typography tokens
340
+
341
+ | Token | Purpose |
342
+ |---|---|
343
+ | `--font-family-body` | Body text font (Inter / system) |
344
+ | `--font-family-mono` | Code block font |
345
+ | `--font-size-body` | Base body text size |
346
+ | `--font-size-small` | Caption/small text |
347
+ | `--font-weight-normal` | Body weight |
348
+ | `--font-weight-semibold` | Heading weight |
349
+ | `--font-weight-bold` | Strong emphasis weight |
350
+ | `--line-height-body` | Body line height |
351
+
352
+ ### Spacing tokens
353
+
354
+ | Token | Purpose |
355
+ |---|---|
356
+ | `--spacing-xs` | Tight spacing (4px) |
357
+ | `--spacing-sm` | Small spacing (8–12px) |
358
+ | `--spacing-md` | Medium spacing (16–20px) |
359
+ | `--spacing-lg` | Large spacing (24–32px) |
360
+ | `--spacing-xl` | Section spacing (40–48px) |
361
+
362
+ These tokens are **safe to use in CSS modules** alongside shadcn's Tailwind utilities. They bridge the gap between the component library's utility-first approach and the deck engine's CSS variable system.
363
+
364
+ ---
365
+
366
+ ## Visual coherence rules
367
+
368
+ These rules ensure every slide in a deck feels like it belongs to the same family:
369
+
370
+ ### Typography hierarchy
371
+
372
+ 1. **Slide title:** `clamp(28px, 3.2vw, 36px)`, weight 700, `var(--foreground)`
373
+ 2. **Card titles:** Let `CardTitle` handle it (built-in `text-lg font-semibold`)
374
+ 3. **Body text:** `clamp(14px, 1.2vw, 16px)`, `var(--foreground)` or `var(--muted-foreground)`
375
+ 4. **Labels/kickers:** Badge component — never manual `font-size: 12px` spans
376
+ 5. **Code:** `var(--font-family-mono)`, `text-sm`
377
+
378
+ ### Color usage
379
+
380
+ | Role | Token | When to use |
381
+ |---|---|---|
382
+ | Page background | `--background` | Slide surface |
383
+ | Primary text | `--foreground` | Headings, body text |
384
+ | Secondary text | `--muted-foreground` | Subtitles, descriptions, metadata |
385
+ | Content surfaces | `--card` / `--card-foreground` | Card backgrounds |
386
+ | Interactive | `--primary` / `--primary-foreground` | Buttons (default variant), links |
387
+ | Neutral interactive | `--secondary` / `--secondary-foreground` | Badge kickers, secondary buttons |
388
+ | Emphasis | `--accent` / `--accent-foreground` | Hover states, highlights |
389
+ | Error/warning | `--destructive` / `--destructive-foreground` | Destructive buttons, error alerts |
390
+ | Borders | `--border` | Card borders, separators |
391
+ | Focus | `--ring` | Focus rings on interactive elements |
392
+
393
+ **Never use decorative palette tokens** (`--blue-glow`, `--purple`, etc.) for content structure. They exist for optional ambient effects only.
394
+
395
+ ### Spacing rhythm
396
+
397
+ - Header-to-content gap: 24px (`--spacing-lg`)
398
+ - Between content blocks: 20px (`--spacing-md`)
399
+ - Inside card headers/content: handled by component (don't override)
400
+ - Action row gap: 12px (`--spacing-sm`)
401
+ - Slide bottom padding: 44px (BottomBar clearance)
402
+
403
+ ### Border radius
404
+
405
+ - All components use `--radius` (0.625rem in shadcn theme)
406
+ - Don't mix `border-radius: var(--radius)` with hardcoded values
407
+ - Pill shapes (`border-radius: 9999px`) only for Badge — it handles this internally
408
+
409
+ ### Animation discipline
410
+
411
+ - ReactBits components handle their own animation — don't layer CSS animations on top
412
+ - Entrance animations (stagger, fade-in) belong in CSS modules, not inline styles
413
+ - Maximum 2 animated elements per slide to avoid visual noise
414
+ - Prefer `opacity` + `transform` animations (GPU-accelerated) over `width`/`height`/`margin`
415
+
416
+ ---
417
+
418
+ ## Decision: CSS modules vs Tailwind utilities
419
+
420
+ Both are valid in shadcn slides. Here's when to use which:
421
+
422
+ | Use CSS modules for | Use Tailwind utilities for |
423
+ |---|---|
424
+ | Slide-level layout (grid, flex, positioning) | Component className overrides |
425
+ | Slide-specific animations (keyframes, stagger) | Quick spacing/color tweaks on components |
426
+ | Complex responsive patterns | One-off utility classes on wrapper divs |
427
+ | Anything that needs a named class for `styles.x` | Anything the component already supports via `className` |
428
+
429
+ **Example of correct mixing:**
430
+
431
+ ```jsx
432
+ {/* CSS module for layout, Tailwind for component tweaks */}
433
+ <div className={styles.grid}>
434
+ <Card className="shadow-md"> {/* Tailwind override */}
435
+ <CardHeader>
436
+ <CardTitle className="text-xl">Big</CardTitle> {/* Tailwind override */}
437
+ </CardHeader>
438
+ <CardContent>
439
+ <p>Content</p>
440
+ </CardContent>
441
+ </Card>
442
+ </div>
443
+ ```
444
+
445
+ **Never do this:**
446
+ ```jsx
447
+ {/* Don't rebuild Card with CSS modules */}
448
+ <div className={styles.card}>
449
+ <div className={styles.cardHeader}>...</div>
450
+ </div>
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Relationship to other descriptors
456
+
457
+ ```
458
+ deck.config.js
459
+ ├── theme: 'shadcn' → loads shadcn.md (theme descriptor)
460
+ │ ↳ tokens, visual identity, what to import
461
+ ├── designSystem: 'shadcn' → loads shadcn-design-system.md (this file)
462
+ │ ↳ composition patterns, coherence rules
463
+ └── both active together → full shadcn authoring experience
464
+ ```
465
+
466
+ The theme descriptor answers: **"What do I have and how do I use each piece?"**
467
+ This supplement answers: **"How do the pieces work together to make a coherent deck?"**