@deckio/deck-engine 0.2.2 → 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.
- package/instructions/AGENTS.md +12 -0
- package/instructions/deck-project.instructions.md +6 -0
- package/instructions/shadcn-components.instructions.md +283 -0
- package/instructions/shadcn-setup.instructions.md +117 -0
- package/instructions/slide-css.instructions.md +8 -0
- package/instructions/slide-jsx.instructions.md +20 -0
- package/package.json +2 -1
- package/scripts/sync-version-from-npm.mjs +68 -0
- package/skills/deck-add-slide/SKILL.md +29 -0
- package/skills/deck-validate-project/SKILL.md +38 -0
- package/themes/descriptors/funky-punk.md +231 -0
- package/themes/descriptors/shadcn-design-system.md +467 -0
- package/themes/descriptors/shadcn.md +356 -106
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Theme Descriptor — Funky Punk
|
|
2
|
+
|
|
3
|
+
## Metadata
|
|
4
|
+
|
|
5
|
+
- **Theme id:** `funky-punk`
|
|
6
|
+
- **Primary slide authoring pattern:** `default`
|
|
7
|
+
- **Compatible design systems:** `default`
|
|
8
|
+
- **Mood:** loud, neon, rebellious, anti-corporate, punk-zine, high-energy
|
|
9
|
+
- **Read this file when:** `deck.config.js` uses `theme: 'funky-punk'` and you need to create, inspect, validate, or generate assets for slides
|
|
10
|
+
|
|
11
|
+
## Slide personality
|
|
12
|
+
|
|
13
|
+
Funky-punk slides scream rebellion. Jet-black canvas, hot-pink borders, electric-lime accents, offset neon text-shadows, and razor-sharp edges. Nothing is subtle — every element shouts. Think punk zine meets neon sign shop: clashing colors on purpose, uppercase everything, zero rounded corners. The built-in scanline overlay and heading text-shadows fire automatically; don't fight them, lean into the chaos.
|
|
14
|
+
|
|
15
|
+
Headings are **Bebas Neue**, always uppercase with wide letter-spacing. Body/mono text is **Space Mono**. Bullet lists use ✘ markers (styled by the theme). Horizontal rules are rainbow neon gradients. Links have wavy underlines in electric lime.
|
|
16
|
+
|
|
17
|
+
## Exact JSX skeleton
|
|
18
|
+
|
|
19
|
+
Use this exact starting structure for new slides:
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
import { BottomBar, Slide } from '@deckio/deck-engine'
|
|
23
|
+
import styles from './MyNewSlide.module.css'
|
|
24
|
+
|
|
25
|
+
export default function MyNewSlide({ index, project }) {
|
|
26
|
+
return (
|
|
27
|
+
<Slide index={index} className={styles.myNewSlide}>
|
|
28
|
+
<div className="accent-bar" />
|
|
29
|
+
<div className={`orb ${styles.orb1}`} />
|
|
30
|
+
<div className={`orb ${styles.orb2}`} />
|
|
31
|
+
|
|
32
|
+
<div className={`${styles.body} content-frame content-gutter`}>
|
|
33
|
+
{/* Slide content */}
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<BottomBar text="Project Footer Text" />
|
|
37
|
+
</Slide>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Required child order inside `<Slide>`
|
|
43
|
+
|
|
44
|
+
1. `<div className="accent-bar" />` — renders as hot pink via `var(--primary)`
|
|
45
|
+
2. `2–4` decorative orb elements using the global `orb` class plus local positioning classes — use the neon palette for maximum clash
|
|
46
|
+
3. One content wrapper using `content-frame content-gutter`
|
|
47
|
+
4. `<BottomBar text="..." />` as the last child
|
|
48
|
+
|
|
49
|
+
## Exact CSS skeleton
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
.myNewSlide {
|
|
53
|
+
background: var(--background);
|
|
54
|
+
padding: 0 0 44px 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.orb1 {
|
|
58
|
+
width: 500px;
|
|
59
|
+
height: 500px;
|
|
60
|
+
top: -120px;
|
|
61
|
+
right: -80px;
|
|
62
|
+
background: radial-gradient(
|
|
63
|
+
circle at 40% 40%,
|
|
64
|
+
var(--pink),
|
|
65
|
+
color-mix(in srgb, var(--pink) 30%, transparent) 50%,
|
|
66
|
+
transparent 70%
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.orb2 {
|
|
71
|
+
width: 380px;
|
|
72
|
+
height: 380px;
|
|
73
|
+
bottom: -60px;
|
|
74
|
+
left: -40px;
|
|
75
|
+
background: radial-gradient(
|
|
76
|
+
circle at 50% 50%,
|
|
77
|
+
var(--cyan),
|
|
78
|
+
color-mix(in srgb, var(--purple) 25%, transparent) 55%,
|
|
79
|
+
transparent 75%
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.body {
|
|
84
|
+
position: relative;
|
|
85
|
+
z-index: 10;
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-direction: column;
|
|
88
|
+
gap: 24px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.cards {
|
|
92
|
+
display: grid;
|
|
93
|
+
grid-template-columns: repeat(3, 1fr);
|
|
94
|
+
gap: 24px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.card {
|
|
98
|
+
position: relative;
|
|
99
|
+
overflow: hidden;
|
|
100
|
+
background: var(--card);
|
|
101
|
+
border: 2px solid var(--border);
|
|
102
|
+
border-radius: var(--radius-md);
|
|
103
|
+
padding: 24px;
|
|
104
|
+
box-shadow: var(--shadow-elevated);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.card::before {
|
|
108
|
+
content: '';
|
|
109
|
+
position: absolute;
|
|
110
|
+
top: 0;
|
|
111
|
+
left: 0;
|
|
112
|
+
right: 0;
|
|
113
|
+
height: 3px;
|
|
114
|
+
background: linear-gradient(90deg, var(--pink), var(--accent), var(--cyan), var(--purple));
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Key CSS rules for funky-punk
|
|
119
|
+
|
|
120
|
+
- **Sharp edges everywhere.** `border-radius` must be `0px`–`4px` max. Use `var(--radius-md)` (2px) or `var(--radius-sm)` (0px). Never round off corners.
|
|
121
|
+
- **Borders are neon.** Use `var(--border)` which resolves to hot pink. Make borders `2px solid` not `1px solid`.
|
|
122
|
+
- **Shadows glow pink/lime.** Use `var(--shadow-elevated)` for neon glow or hand-craft with `var(--glow-primary)` / `var(--glow-ring)`.
|
|
123
|
+
- **Card top-stripe is rainbow.** The `::before` gradient should use multiple neon stops: `var(--pink)`, `var(--accent)`, `var(--cyan)`, `var(--purple)`.
|
|
124
|
+
- **Transitions are snappy.** Use `var(--transition-fast)` (0.08s) or `var(--transition-base)` (0.15s). Nothing slow or floaty.
|
|
125
|
+
|
|
126
|
+
## Token table
|
|
127
|
+
|
|
128
|
+
### Use these tokens
|
|
129
|
+
|
|
130
|
+
| Token | Value | When to use |
|
|
131
|
+
|---|---|---|
|
|
132
|
+
| `var(--background)` | `#0a0a0a` | Slide backgrounds, deep surfaces |
|
|
133
|
+
| `var(--foreground)` | `#f0f0f0` | Primary text, headings |
|
|
134
|
+
| `var(--card)` | `#1a1a1a` | Card / panel backgrounds |
|
|
135
|
+
| `var(--card-foreground)` | `#f0f0f0` | Text inside cards |
|
|
136
|
+
| `var(--primary)` | `#ff2d6f` | Hot pink — hero elements, accent bar, key actions |
|
|
137
|
+
| `var(--primary-foreground)` | `#000000` | Text on primary-colored surfaces |
|
|
138
|
+
| `var(--secondary)` | `#1c1c2e` | Secondary card/panel backgrounds |
|
|
139
|
+
| `var(--secondary-foreground)` | `#e0ff00` | Text on secondary surfaces (electric lime) |
|
|
140
|
+
| `var(--accent)` | `#e0ff00` | Electric lime — highlights, emphasis, links |
|
|
141
|
+
| `var(--accent-foreground)` | `#000000` | Text on accent surfaces |
|
|
142
|
+
| `var(--muted)` | `#2a2a2a` | Muted backgrounds, input fields |
|
|
143
|
+
| `var(--muted-foreground)` | `#888888` | Subdued text, timestamps, footnotes |
|
|
144
|
+
| `var(--border)` | `#ff2d6f` | Hot pink borders — all borders scream |
|
|
145
|
+
| `var(--ring)` | `rgba(224, 255, 0, 0.6)` | Focus rings, interactive outlines |
|
|
146
|
+
| `var(--radius)` | `2px` | Base radius — sharp, not smooth |
|
|
147
|
+
| `var(--destructive)` | `#ff0040` | Error / danger states |
|
|
148
|
+
| `var(--blue-glow)` | `#00e5ff` | Cyan decorative glow |
|
|
149
|
+
| `var(--purple)` | `#bf00ff` | Purple decorative accent |
|
|
150
|
+
| `var(--purple-deep)` | `#7b00cc` | Deeper purple for orbs, gradients |
|
|
151
|
+
| `var(--pink)` | `#ff2d6f` | Hot pink decorative (alias of primary) |
|
|
152
|
+
| `var(--cyan)` | `#00e5ff` | Cyan decorative (alias of blue-glow) |
|
|
153
|
+
| `var(--green)` | `#e0ff00` | Electric lime decorative (alias of accent) |
|
|
154
|
+
| `var(--surface-overlay)` | `rgba(10, 10, 10, 0.85)` | Translucent dark overlay panels |
|
|
155
|
+
| `var(--surface-overlay-heavy)` | `rgba(10, 10, 10, 0.95)` | Near-opaque overlay for modals |
|
|
156
|
+
| `var(--border-subtle)` | `rgba(255, 45, 111, 0.35)` | Softer pink border for secondary elements |
|
|
157
|
+
| `var(--glow-primary)` | `rgba(255, 45, 111, 0.3)` | Pink glow for box-shadow / drop-shadow |
|
|
158
|
+
| `var(--glow-primary-strong)` | `rgba(255, 45, 111, 0.45)` | Stronger pink glow for hover states |
|
|
159
|
+
| `var(--glow-ring)` | `rgba(224, 255, 0, 0.3)` | Lime glow for emphasis borders |
|
|
160
|
+
| `var(--glow-accent)` | `rgba(224, 255, 0, 0.15)` | Subtle lime glow, background washes |
|
|
161
|
+
| `var(--glow-purple)` | `rgba(191, 0, 255, 0.2)` | Purple glow for decorative depth |
|
|
162
|
+
| `var(--glow-cyan)` | `rgba(0, 229, 255, 0.15)` | Cyan glow for cool-tone accents |
|
|
163
|
+
| `var(--dot-color)` | `rgba(255, 45, 111, 0.2)` | Dot-grid pattern fill |
|
|
164
|
+
| `var(--shadow-elevated)` | multi-stop pink + lime glow | Elevated card shadows |
|
|
165
|
+
|
|
166
|
+
### Never regress to
|
|
167
|
+
|
|
168
|
+
- `var(--bg-deep)` — removed legacy token
|
|
169
|
+
- `var(--surface)` — removed legacy token
|
|
170
|
+
- `var(--text)` or `var(--text-muted)` — removed legacy tokens
|
|
171
|
+
- Hardcoded `rgba(...)` or `#hex` values when a token exists — always use the token
|
|
172
|
+
|
|
173
|
+
## Typography tokens
|
|
174
|
+
|
|
175
|
+
| Token | Value | Usage |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| `var(--font-family)` | `'Bebas Neue', 'Impact', 'Arial Black', sans-serif` | Headings, display text |
|
|
178
|
+
| `var(--font-family-mono)` | `'Space Mono', 'Courier New', monospace` | Code, technical labels |
|
|
179
|
+
| `var(--font-size-display)` | `clamp(48px, 8vw, 80px)` | Hero / title text |
|
|
180
|
+
| `var(--font-size-2xl)` | `40px` | Section headings |
|
|
181
|
+
| `var(--font-size-xl)` | `28px` | Sub-headings |
|
|
182
|
+
| `var(--font-size-lg)` | `22px` | Large body / lead text |
|
|
183
|
+
| `var(--font-size-base)` | `17px` | Body copy |
|
|
184
|
+
| `var(--font-weight-extrabold)` | `900` | Headings, bold emphasis |
|
|
185
|
+
| `var(--font-weight-bold)` | `700` | Strong text |
|
|
186
|
+
| `var(--letter-spacing-wide)` | `3px` | Default heading spacing |
|
|
187
|
+
| `var(--letter-spacing-wider)` | `5px` | Screaming subheadings |
|
|
188
|
+
| `var(--letter-spacing-widest)` | `8px` | Labels, eyebrow text |
|
|
189
|
+
| `var(--line-height-tight)` | `1.1` | Headings |
|
|
190
|
+
| `var(--line-height-normal)` | `1.4` | Body text |
|
|
191
|
+
|
|
192
|
+
## Decorative elements available
|
|
193
|
+
|
|
194
|
+
| Element | How to use it |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `accent-bar` | Required first child — renders in hot pink via `var(--primary)` |
|
|
197
|
+
| `orb` | Required ambient decoration; 2–4 per slide using neon palette clashes (pink + cyan, lime + purple) |
|
|
198
|
+
| Scanlines | **Automatic** — the theme injects a fixed scanline overlay via `:root::after`. No JSX needed. |
|
|
199
|
+
| Rainbow `<hr>` | Use `<hr />` in JSX — theme styles it as a 4-stop neon gradient (pink → lime → cyan → purple) |
|
|
200
|
+
| `✘` bullet markers | Use `<ul><li>` — theme replaces default bullets with hot-pink ✘ |
|
|
201
|
+
| Heading text-shadows | **Automatic** — `h1` gets offset lime + cyan shadows; `h2` gets pink shadow. No extra CSS needed. |
|
|
202
|
+
| Wavy links | **Automatic** — `<a>` tags get lime wavy underlines with cyan hover. No extra CSS needed. |
|
|
203
|
+
| `grid-dots` | Optional — subtle dot-grid pattern using `var(--dot-color)` |
|
|
204
|
+
| Card top rainbow stripe | Apply via `.card::before` — 4-stop gradient matching `<hr>` |
|
|
205
|
+
| Neon box-shadow | Use `var(--shadow-elevated)` for pink + lime dual-glow lift |
|
|
206
|
+
|
|
207
|
+
## Available components
|
|
208
|
+
|
|
209
|
+
| Resource | Import path |
|
|
210
|
+
|---|---|
|
|
211
|
+
| `Slide`, `BottomBar`, `Navigation`, `SlideProvider`, `useSlides`, `GenericThankYouSlide` | `'@deckio/deck-engine'` |
|
|
212
|
+
| Data / logos | `'../data/<file>'` |
|
|
213
|
+
|
|
214
|
+
## Anti-patterns
|
|
215
|
+
|
|
216
|
+
1. **Rounded corners** — `border-radius` above `4px` violates the sharp-edge punk identity. Never use `--radius-lg: 16px` patterns from other themes.
|
|
217
|
+
2. **Missing `accent-bar`** — every slide must have it as the first child.
|
|
218
|
+
3. **Missing orb decoration** — use 2–4 orbs with clashing neon colors.
|
|
219
|
+
4. **Missing `content-frame content-gutter`** — body wrapper must use these globals.
|
|
220
|
+
5. **Missing `BottomBar`** — required as the last child.
|
|
221
|
+
6. **Clean / editorial / corporate style** — never use shadcn's minimal editorial aesthetic, calm whitespace, or restrained color palettes. This theme is the opposite of tasteful restraint.
|
|
222
|
+
7. **Subtle borders** — borders should be visible and neon (`2px solid var(--border)`), not hairline or muted.
|
|
223
|
+
8. **Slow transitions** — everything snaps. Never use transitions above `0.3s`. Prefer `var(--transition-fast)` (0.08s).
|
|
224
|
+
9. **Lowercase headings** — the theme forces `text-transform: uppercase` on headings. Don't fight it with `text-transform: none`.
|
|
225
|
+
10. **Serif or neutral fonts** — the theme uses Bebas Neue + Space Mono. Don't import or specify other font families.
|
|
226
|
+
11. **Single-color schemes** — punk thrives on clash. Always use at least 2–3 neon colors from the decorative palette per slide.
|
|
227
|
+
12. **Importing shadcn UI components** — this is a `default` design-system theme; shadcn components are incompatible.
|
|
228
|
+
|
|
229
|
+
## Example slide direction
|
|
230
|
+
|
|
231
|
+
A strong funky-punk slide slams a massive uppercase Bebas Neue heading (with automatic neon text-shadow) over a jet-black canvas peppered with clashing pink and cyan orbs. Content cards sit in sharp-edged boxes with hot-pink borders and rainbow top-stripes. The scanline overlay adds CRT texture. Everything feels like a screen-printed concert poster: loud, layered, unapologetic. Readable from across the room because contrast is maxed out and type is enormous.
|
|
@@ -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?"**
|