promptslide 0.2.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/index.d.ts +377 -0
- package/dist/index.js +963 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
- package/src/commands/build.mjs +73 -0
- package/src/commands/create.mjs +197 -0
- package/src/commands/preview.mjs +22 -0
- package/src/commands/studio.mjs +27 -0
- package/src/core/animated.tsx +153 -0
- package/src/core/animation-config.ts +98 -0
- package/src/core/animation-context.tsx +54 -0
- package/src/core/index.ts +73 -0
- package/src/core/layouts/shared-footer.tsx +43 -0
- package/src/core/morph.tsx +153 -0
- package/src/core/slide-deck.tsx +430 -0
- package/src/core/slide-error-boundary.tsx +50 -0
- package/src/core/theme-context.tsx +48 -0
- package/src/core/transitions.ts +200 -0
- package/src/core/types.ts +136 -0
- package/src/core/use-slide-navigation.ts +142 -0
- package/src/core/utils.ts +8 -0
- package/src/index.mjs +70 -0
- package/src/utils/ansi.mjs +5 -0
- package/src/utils/colors.mjs +44 -0
- package/src/utils/prompts.mjs +50 -0
- package/src/utils/tsconfig.mjs +35 -0
- package/src/vite/config.mjs +40 -0
- package/src/vite/plugin.mjs +66 -0
- package/templates/default/AGENTS.md +453 -0
- package/templates/default/README.md +35 -0
- package/templates/default/package.json +26 -0
- package/templates/default/public/logo.svg +7 -0
- package/templates/default/src/App.tsx +11 -0
- package/templates/default/src/deck-config.ts +8 -0
- package/templates/default/src/globals.css +157 -0
- package/templates/default/src/layouts/slide-layout-centered.tsx +59 -0
- package/templates/default/src/slides/slide-example.tsx +53 -0
- package/templates/default/src/slides/slide-title.tsx +27 -0
- package/templates/default/src/theme.ts +8 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire } from "node:module"
|
|
2
|
+
import { resolve, dirname } from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
import tailwindcss from "@tailwindcss/postcss"
|
|
6
|
+
import react from "@vitejs/plugin-react"
|
|
7
|
+
|
|
8
|
+
import { promptslidePlugin } from "./plugin.mjs"
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
11
|
+
const require = createRequire(import.meta.url)
|
|
12
|
+
|
|
13
|
+
// Resolve tailwindcss from CLI's deps so @import "tailwindcss" in user CSS works
|
|
14
|
+
// even when the user's project doesn't have tailwindcss as a direct dependency.
|
|
15
|
+
const tailwindPath = resolve(dirname(require.resolve("tailwindcss")), "..")
|
|
16
|
+
|
|
17
|
+
// Resolve promptslide core from source so Vite uses TS directly without a build step
|
|
18
|
+
const promptslidePath = resolve(__dirname, "../core/index.ts")
|
|
19
|
+
|
|
20
|
+
export function createViteConfig({ cwd, mode = "development" }) {
|
|
21
|
+
return {
|
|
22
|
+
configFile: false,
|
|
23
|
+
root: cwd,
|
|
24
|
+
mode,
|
|
25
|
+
plugins: [react(), promptslidePlugin()],
|
|
26
|
+
resolve: {
|
|
27
|
+
alias: {
|
|
28
|
+
"@": resolve(cwd, "src"),
|
|
29
|
+
promptslide: promptslidePath,
|
|
30
|
+
// CSS @import "tailwindcss" → resolved from CLI package
|
|
31
|
+
tailwindcss: tailwindPath
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
css: {
|
|
35
|
+
postcss: {
|
|
36
|
+
plugins: [tailwindcss()]
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const VIRTUAL_ENTRY_ID = "virtual:promptslide-entry"
|
|
2
|
+
const RESOLVED_VIRTUAL_ENTRY_ID = "\0" + VIRTUAL_ENTRY_ID
|
|
3
|
+
|
|
4
|
+
function getHtmlTemplate() {
|
|
5
|
+
return `<!doctype html>
|
|
6
|
+
<html lang="en" class="dark">
|
|
7
|
+
<head>
|
|
8
|
+
<meta charset="UTF-8" />
|
|
9
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
10
|
+
<title>PromptSlide</title>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script type="module" src="/@id/${VIRTUAL_ENTRY_ID}"></script>
|
|
15
|
+
</body>
|
|
16
|
+
</html>`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getEntryModule() {
|
|
20
|
+
return `
|
|
21
|
+
import { StrictMode, createElement } from "react"
|
|
22
|
+
import { createRoot } from "react-dom/client"
|
|
23
|
+
import "./src/globals.css"
|
|
24
|
+
import App from "./src/App"
|
|
25
|
+
|
|
26
|
+
createRoot(document.getElementById("root")).render(
|
|
27
|
+
createElement(StrictMode, null, createElement(App))
|
|
28
|
+
)
|
|
29
|
+
`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function promptslidePlugin() {
|
|
33
|
+
return {
|
|
34
|
+
name: "promptslide",
|
|
35
|
+
enforce: "pre",
|
|
36
|
+
|
|
37
|
+
resolveId(id) {
|
|
38
|
+
if (id === VIRTUAL_ENTRY_ID) {
|
|
39
|
+
return RESOLVED_VIRTUAL_ENTRY_ID
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
load(id) {
|
|
44
|
+
if (id === RESOLVED_VIRTUAL_ENTRY_ID) {
|
|
45
|
+
return getEntryModule()
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
configureServer(server) {
|
|
50
|
+
return () => {
|
|
51
|
+
server.middlewares.use(async (req, res, next) => {
|
|
52
|
+
if (req.url === "/" || req.url === "/index.html") {
|
|
53
|
+
const html = await server.transformIndexHtml(req.url, getHtmlTemplate())
|
|
54
|
+
res.setHeader("Content-Type", "text/html")
|
|
55
|
+
res.statusCode = 200
|
|
56
|
+
res.end(html)
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
next()
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { VIRTUAL_ENTRY_ID, getHtmlTemplate }
|
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# PromptSlide — Agent Documentation
|
|
2
|
+
|
|
3
|
+
This file documents the slide presentation framework for coding agents (Claude Code, Cursor, Windsurf, etc.). Read this before creating or modifying slides.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
To create a new slide:
|
|
8
|
+
|
|
9
|
+
1. Create a file in `src/slides/` (e.g., `src/slides/slide-market.tsx`)
|
|
10
|
+
2. Import from `promptslide` and `@/layouts/slide-layout-centered`
|
|
11
|
+
3. Add it to `src/deck-config.ts`
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
// src/slides/slide-market.tsx
|
|
15
|
+
import type { SlideProps } from "promptslide";
|
|
16
|
+
import { SlideLayoutCentered } from "@/layouts/slide-layout-centered";
|
|
17
|
+
|
|
18
|
+
export function SlideMarket({ slideNumber, totalSlides }: SlideProps) {
|
|
19
|
+
return (
|
|
20
|
+
<SlideLayoutCentered
|
|
21
|
+
slideNumber={slideNumber}
|
|
22
|
+
totalSlides={totalSlides}
|
|
23
|
+
eyebrow="MARKET OPPORTUNITY"
|
|
24
|
+
title="$50B Total Addressable Market"
|
|
25
|
+
>
|
|
26
|
+
<div className="flex h-full flex-col justify-center">
|
|
27
|
+
<p className="text-muted-foreground text-lg">Your content here</p>
|
|
28
|
+
</div>
|
|
29
|
+
</SlideLayoutCentered>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// src/deck-config.ts
|
|
36
|
+
import type { SlideConfig } from "promptslide";
|
|
37
|
+
import { SlideTitle } from "@/slides/slide-title";
|
|
38
|
+
import { SlideMarket } from "@/slides/slide-market";
|
|
39
|
+
|
|
40
|
+
export const slides: SlideConfig[] = [
|
|
41
|
+
{ component: SlideTitle, steps: 0 },
|
|
42
|
+
{ component: SlideMarket, steps: 0 },
|
|
43
|
+
];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Vite will hot-reload — the new slide appears instantly in the browser.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
src/
|
|
54
|
+
├── layouts/ # Slide layouts (customizable)
|
|
55
|
+
│ └── slide-layout-centered.tsx # Base centered layout with header/footer
|
|
56
|
+
│
|
|
57
|
+
├── slides/ # YOUR SLIDES GO HERE
|
|
58
|
+
│ └── slide-title.tsx # Example starter slide
|
|
59
|
+
│
|
|
60
|
+
├── theme.ts # Theme config (brand, colors, fonts, assets)
|
|
61
|
+
├── deck-config.ts # Slide order + step counts (modify this)
|
|
62
|
+
├── App.tsx # Root component (theme provider)
|
|
63
|
+
└── globals.css # Theme colors (customize here)
|
|
64
|
+
|
|
65
|
+
promptslide (npm package) # CLI + slide engine — stable, upgradeable
|
|
66
|
+
├── Animated, AnimatedGroup # Step animations (click-to-reveal)
|
|
67
|
+
├── Morph, MorphGroup, MorphItem # Shared element transitions
|
|
68
|
+
├── SlideDeck # Presentation viewer/controller
|
|
69
|
+
├── SlideThemeProvider # Theme context (colors, logos, fonts, assets)
|
|
70
|
+
├── useSlideNavigation # Navigation state machine
|
|
71
|
+
├── SlideProps, SlideConfig # TypeScript types
|
|
72
|
+
├── ThemeConfig # Theme configuration type
|
|
73
|
+
└── Layouts # ContentLayout, TitleLayout, SectionLayout,
|
|
74
|
+
# TwoColumnLayout, ImageLayout, QuoteLayout
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Key principle**: The presentation engine and CLI live in `promptslide` (stable, upgradeable via npm). Layouts and slides are local files you customize freely.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Animation System
|
|
82
|
+
|
|
83
|
+
The framework provides three types of animations:
|
|
84
|
+
|
|
85
|
+
| Type | Purpose | Import |
|
|
86
|
+
| --------------------- | ------------------------------------------------ | ----------------------------------- |
|
|
87
|
+
| **Slide Transitions** | Animations between slides (fade, slide, zoom) | `promptslide` |
|
|
88
|
+
| **Step Animations** | Within-slide reveal animations (click to reveal) | `Animated` from `promptslide` |
|
|
89
|
+
| **Morph Animations** | Shared element transitions across slides | `Morph` from `promptslide` |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 1. SlideLayoutCentered Component
|
|
94
|
+
|
|
95
|
+
Every slide should use `SlideLayoutCentered` as its wrapper. It provides consistent padding, header, and footer.
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { SlideLayoutCentered } from "@/layouts/slide-layout-centered";
|
|
99
|
+
|
|
100
|
+
<SlideLayoutCentered
|
|
101
|
+
slideNumber={slideNumber}
|
|
102
|
+
totalSlides={totalSlides}
|
|
103
|
+
eyebrow="CATEGORY" // Optional small label above title
|
|
104
|
+
title="Slide Title" // Optional main heading
|
|
105
|
+
subtitle="Description" // Optional subtitle
|
|
106
|
+
hideFooter // Optional: hide footer with logo + slide number
|
|
107
|
+
>
|
|
108
|
+
{/* Your slide content */}
|
|
109
|
+
</SlideLayoutCentered>;
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Slide dimensions**: 1280x720 (16:9 aspect ratio). Design content for this size — it will be scaled to fit the viewport in presentation mode.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 2. Step Animations (click-to-reveal)
|
|
117
|
+
|
|
118
|
+
Use `<Animated>` to reveal content on clicks:
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { Animated } from "promptslide"
|
|
122
|
+
|
|
123
|
+
// Always visible content (no wrapper needed)
|
|
124
|
+
<h2>Main Title</h2>
|
|
125
|
+
|
|
126
|
+
// Appears on first click
|
|
127
|
+
<Animated step={1} animation="fade">
|
|
128
|
+
<p>First point</p>
|
|
129
|
+
</Animated>
|
|
130
|
+
|
|
131
|
+
// Appears on second click
|
|
132
|
+
<Animated step={2} animation="slide-up">
|
|
133
|
+
<p>Second point</p>
|
|
134
|
+
</Animated>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Animation types**: `fade`, `slide-up`, `slide-down`, `slide-left`, `slide-right`, `scale`
|
|
138
|
+
|
|
139
|
+
**Props:**
|
|
140
|
+
| Prop | Type | Default | Description |
|
|
141
|
+
|------|------|---------|-------------|
|
|
142
|
+
| `step` | number | required | Which click reveals this (1-indexed) |
|
|
143
|
+
| `animation` | AnimationType | `"slide-up"` | Animation style |
|
|
144
|
+
| `duration` | number | `0.4` | Duration in seconds |
|
|
145
|
+
| `delay` | number | `0` | Delay after trigger |
|
|
146
|
+
| `className` | string | — | Additional CSS classes |
|
|
147
|
+
|
|
148
|
+
### AnimatedGroup (staggered children)
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { AnimatedGroup } from "promptslide";
|
|
152
|
+
|
|
153
|
+
<AnimatedGroup startStep={1} animation="slide-up" staggerDelay={0.1}>
|
|
154
|
+
<Card>First</Card>
|
|
155
|
+
<Card>Second</Card>
|
|
156
|
+
<Card>Third</Card>
|
|
157
|
+
</AnimatedGroup>;
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Step Count Rules
|
|
161
|
+
|
|
162
|
+
- Steps are **1-indexed** (step 1 = first click)
|
|
163
|
+
- Multiple elements can share the same step (appear together)
|
|
164
|
+
- **Critical**: The `steps` value in `deck-config.ts` must equal the highest step number used
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// If your slide uses step={1} and step={2}:
|
|
168
|
+
{ component: MySlide, steps: 2 }
|
|
169
|
+
|
|
170
|
+
// If your slide has no animations:
|
|
171
|
+
{ component: MySlide, steps: 0 }
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 3. Morph Animations
|
|
177
|
+
|
|
178
|
+
Morph animations smoothly transition shared elements between consecutive slides.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
import { Morph, MorphText } from "promptslide"
|
|
182
|
+
|
|
183
|
+
// Slide 1 - Large version
|
|
184
|
+
<Morph layoutId="hero-title">
|
|
185
|
+
<h1 className="text-6xl">Title</h1>
|
|
186
|
+
</Morph>
|
|
187
|
+
|
|
188
|
+
// Slide 2 - Small version (same layoutId = morphs between them)
|
|
189
|
+
<Morph layoutId="hero-title">
|
|
190
|
+
<h1 className="text-2xl">Title</h1>
|
|
191
|
+
</Morph>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
**Note**: Morph is currently disabled in fullscreen presentation mode due to CSS transform conflicts with Framer Motion's layoutId calculations.
|
|
195
|
+
|
|
196
|
+
### MorphGroup + MorphItem
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
import { MorphGroup, MorphItem } from "promptslide";
|
|
200
|
+
|
|
201
|
+
<MorphGroup groupId="card">
|
|
202
|
+
<MorphItem id="icon">
|
|
203
|
+
<Icon />
|
|
204
|
+
</MorphItem>
|
|
205
|
+
<MorphItem id="title">
|
|
206
|
+
<h2>Title</h2>
|
|
207
|
+
</MorphItem>
|
|
208
|
+
</MorphGroup>;
|
|
209
|
+
// Generates layoutIds: "card-icon", "card-title"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 4. Deck Configuration (`deck-config.ts`)
|
|
215
|
+
|
|
216
|
+
This file controls which slides appear and in what order.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import type { SlideConfig } from "promptslide";
|
|
220
|
+
import { SlideTitle } from "@/slides/slide-title";
|
|
221
|
+
import { SlideProblem } from "@/slides/slide-problem";
|
|
222
|
+
import { SlideSolution } from "@/slides/slide-solution";
|
|
223
|
+
|
|
224
|
+
export const slides: SlideConfig[] = [
|
|
225
|
+
{ component: SlideTitle, steps: 0 },
|
|
226
|
+
{ component: SlideProblem, steps: 2 }, // Has 2 click-to-reveal steps
|
|
227
|
+
{ component: SlideSolution, steps: 0 },
|
|
228
|
+
];
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Enriched SlideConfig (optional)
|
|
232
|
+
|
|
233
|
+
Each slide config supports optional metadata fields:
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
{
|
|
237
|
+
component: SlideProblem,
|
|
238
|
+
steps: 2,
|
|
239
|
+
title: "The Problem", // Grid view labels, navigation
|
|
240
|
+
section: "Introduction", // Chapter grouping in grid view
|
|
241
|
+
transition: "zoom", // Per-slide transition override
|
|
242
|
+
notes: "Talk about market gap", // Speaker notes (future)
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Managing slides
|
|
247
|
+
|
|
248
|
+
- **Add a slide**: Import it and add to the array
|
|
249
|
+
- **Remove a slide**: Remove from the array (keep the file if you want it later)
|
|
250
|
+
- **Reorder**: Change position in the array
|
|
251
|
+
- **The `steps` value** must match the highest `step` number in `<Animated>` components
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## 5. Theme Customization (`globals.css`)
|
|
256
|
+
|
|
257
|
+
Colors use OKLCH format in CSS variables. Edit `src/globals.css` to change the theme.
|
|
258
|
+
|
|
259
|
+
**Change your brand color** by modifying `--primary`:
|
|
260
|
+
|
|
261
|
+
```css
|
|
262
|
+
:root {
|
|
263
|
+
/* Blue brand (default) */
|
|
264
|
+
--primary: oklch(0.55 0.2 250);
|
|
265
|
+
|
|
266
|
+
/* Orange brand */
|
|
267
|
+
/* --primary: oklch(0.661 0.201 41.38); */
|
|
268
|
+
|
|
269
|
+
/* Green brand */
|
|
270
|
+
/* --primary: oklch(0.6 0.2 145); */
|
|
271
|
+
|
|
272
|
+
/* Purple brand */
|
|
273
|
+
/* --primary: oklch(0.55 0.2 300); */
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
OKLCH format: `oklch(lightness chroma hue)`
|
|
278
|
+
|
|
279
|
+
- **Lightness**: 0 (black) to 1 (white)
|
|
280
|
+
- **Chroma**: 0 (gray) to ~0.4 (vivid)
|
|
281
|
+
- **Hue**: 0–360 (color wheel: 0=red, 120=green, 250=blue)
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 6. Theme & Branding (`theme.ts`)
|
|
286
|
+
|
|
287
|
+
Configure your brand identity in `src/theme.ts`:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
import type { ThemeConfig } from "promptslide";
|
|
291
|
+
|
|
292
|
+
export const theme: ThemeConfig = {
|
|
293
|
+
name: "Acme Inc",
|
|
294
|
+
logo: {
|
|
295
|
+
full: "/logo.svg", // Footer logo
|
|
296
|
+
icon: "/icon.svg", // Compact variant (title slides)
|
|
297
|
+
fullLight: "/logo-white.svg", // For dark backgrounds
|
|
298
|
+
},
|
|
299
|
+
colors: {
|
|
300
|
+
primary: "oklch(0.55 0.2 250)",
|
|
301
|
+
},
|
|
302
|
+
fonts: {
|
|
303
|
+
heading: "Inter",
|
|
304
|
+
body: "Inter",
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Everything is optional except `name`. Omitted values fall back to `globals.css` defaults. Logo files go in `public/`.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## 7. Slide Transitions
|
|
314
|
+
|
|
315
|
+
The `SlideDeck` component accepts a `transition` prop:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
<SlideDeck
|
|
319
|
+
slides={slides}
|
|
320
|
+
transition="slide-left" // Transition type
|
|
321
|
+
directionalTransition={true} // Reverse on back navigation
|
|
322
|
+
/>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Available transitions**: `fade` (default), `slide-left`, `slide-right`, `slide-up`, `slide-down`, `zoom`, `zoom-fade`, `none`
|
|
326
|
+
|
|
327
|
+
Per-slide transitions can also be set in `deck-config.ts` via the `transition` field on individual slide configs.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 8. Keyboard Shortcuts
|
|
332
|
+
|
|
333
|
+
| Key | Action |
|
|
334
|
+
| -------------- | ----------------------------------------- |
|
|
335
|
+
| `→` or `Space` | Advance (next step or next slide) |
|
|
336
|
+
| `←` | Go back (previous step or previous slide) |
|
|
337
|
+
| `F` | Toggle fullscreen presentation mode |
|
|
338
|
+
| `G` | Toggle grid view |
|
|
339
|
+
| `Escape` | Exit fullscreen |
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## 9. View Modes
|
|
344
|
+
|
|
345
|
+
1. **Slide view** (default): Single slide with navigation controls
|
|
346
|
+
2. **Grid view**: Thumbnail overview — click any slide to jump to it
|
|
347
|
+
3. **List view**: Vertical scroll — optimized for PDF export via browser print
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 10. Design Best Practices
|
|
352
|
+
|
|
353
|
+
### Layout tips
|
|
354
|
+
|
|
355
|
+
- Use `flex h-full` on content containers to fill available space
|
|
356
|
+
- Use Tailwind's responsive classes (`md:`, `lg:`) for adaptive layouts
|
|
357
|
+
- Content should look good at 1280x720 — it's scaled in presentation mode
|
|
358
|
+
|
|
359
|
+
### Preserve layout with className
|
|
360
|
+
|
|
361
|
+
```tsx
|
|
362
|
+
// BAD — animation wrapper breaks flex centering
|
|
363
|
+
<div className="flex justify-center">
|
|
364
|
+
<Animated step={1}>
|
|
365
|
+
<Content />
|
|
366
|
+
</Animated>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
// GOOD — pass layout classes to Animated
|
|
370
|
+
<Animated step={1} className="flex justify-center">
|
|
371
|
+
<Content />
|
|
372
|
+
</Animated>
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Color classes
|
|
376
|
+
|
|
377
|
+
Use semantic color classes from the theme:
|
|
378
|
+
|
|
379
|
+
- `text-foreground` — primary text
|
|
380
|
+
- `text-muted-foreground` — secondary text
|
|
381
|
+
- `text-primary` — brand color text
|
|
382
|
+
- `bg-background` — page background
|
|
383
|
+
- `bg-card` — card backgrounds
|
|
384
|
+
- `border-border` — borders
|
|
385
|
+
|
|
386
|
+
### Visual Variety Checklist
|
|
387
|
+
|
|
388
|
+
Before generating a multi-slide deck, plan visual diversity. Aim for:
|
|
389
|
+
|
|
390
|
+
- At least 2 different background treatments across the deck (plain, gradient mesh, split solid, spotlight)
|
|
391
|
+
- At least 2 different card/panel styles (not all `rounded-xl border border-border bg-card`)
|
|
392
|
+
- At least 3 different animation types used (not all `slide-up`)
|
|
393
|
+
- At least 1 slide using `AnimatedGroup` instead of manual `Animated` stagger
|
|
394
|
+
- At least 1 asymmetric layout (not all equal-column grids)
|
|
395
|
+
- At least 1 typography-driven slide (where text IS the visual, no cards)
|
|
396
|
+
- No two consecutive slides using the same layout pattern
|
|
397
|
+
|
|
398
|
+
### Layout & Card Recipes
|
|
399
|
+
|
|
400
|
+
Refer to `references/slide-patterns.md` for ready-to-use recipes including:
|
|
401
|
+
|
|
402
|
+
- **Backgrounds:** Gradient mesh, split screen, spotlight vignette
|
|
403
|
+
- **Card styles:** Glass (`backdrop-blur-md`), gradient, elevated (shadow), accent-border
|
|
404
|
+
- **Layouts:** Bento grid, vertical timeline, comparison/before-after, asymmetric columns
|
|
405
|
+
- **Data viz:** Big numbers + progress bars, CSS bar charts, SVG donut rings
|
|
406
|
+
- **Typography:** Large quotes, headline-only with accent word
|
|
407
|
+
|
|
408
|
+
### Animation Selection Guide
|
|
409
|
+
|
|
410
|
+
Match animation types to layout styles:
|
|
411
|
+
|
|
412
|
+
| Layout | Animation | Why |
|
|
413
|
+
| ------------ | ---------------------------- | ------------------------- |
|
|
414
|
+
| Hero/Title | `scale` or `fade` | Dramatic, non-directional |
|
|
415
|
+
| Split Screen | `slide-right` + `slide-left` | Panels enter from edges |
|
|
416
|
+
| Card Grids | `AnimatedGroup` + `scale` | Uniform pop-in |
|
|
417
|
+
| Timeline | `fade` | Clean, no movement |
|
|
418
|
+
| Comparison | `slide-right` + `slide-left` | Opposing directions |
|
|
419
|
+
| Metrics | `slide-up` | Vertical reveal |
|
|
420
|
+
| Quote | `fade` | Let words speak |
|
|
421
|
+
|
|
422
|
+
**Prefer `AnimatedGroup`** over manually wrapping each child in `<Animated>` for grids and collections — it's cleaner and produces better stagger timing.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 11. Animation Configuration Constants
|
|
427
|
+
|
|
428
|
+
From `promptslide`:
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
SLIDE_TRANSITION_DURATION = 0.3; // Between slides
|
|
432
|
+
MORPH_DURATION = 0.8; // Layout morphs
|
|
433
|
+
STEP_ANIMATION_DURATION = 0.4; // Within-slide steps
|
|
434
|
+
STAGGER_DELAY = 0.1; // Group stagger
|
|
435
|
+
|
|
436
|
+
SPRING_SNAPPY = { stiffness: 300, damping: 30 };
|
|
437
|
+
SPRING_SMOOTH = { stiffness: 200, damping: 25 };
|
|
438
|
+
SPRING_BOUNCY = { stiffness: 400, damping: 20 };
|
|
439
|
+
|
|
440
|
+
SLIDE_DIMENSIONS = { width: 1280, height: 720 };
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## 12. Available Icon Library
|
|
446
|
+
|
|
447
|
+
[Lucide React](https://lucide.dev) is included. Import icons directly:
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
import { ArrowRight, CheckCircle, TrendingUp } from "lucide-react";
|
|
451
|
+
|
|
452
|
+
<TrendingUp className="h-6 w-6 text-primary" />;
|
|
453
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
A slide deck built with [PromptSlide](https://github.com/prompticeu/promptslide) — React + Tailwind + Framer Motion.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun install
|
|
9
|
+
bun run dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Then open your coding agent (Claude Code, Cursor, Windsurf, etc.) and say:
|
|
13
|
+
|
|
14
|
+
> "Create me a 10-slide pitch deck for [your topic]"
|
|
15
|
+
|
|
16
|
+
The agent reads `AGENTS.md`, generates slide files in `src/slides/`, and Vite hot-reloads them instantly.
|
|
17
|
+
|
|
18
|
+
## Customization
|
|
19
|
+
|
|
20
|
+
- **Brand color**: Edit `--primary` in `src/globals.css`
|
|
21
|
+
- **Company name**: Edit branding in `src/App.tsx`
|
|
22
|
+
- **Logo**: Replace `public/logo.svg`
|
|
23
|
+
|
|
24
|
+
## Keyboard Shortcuts
|
|
25
|
+
|
|
26
|
+
| Key | Action |
|
|
27
|
+
| ------------- | ---------------------- |
|
|
28
|
+
| `→` / `Space` | Next step or slide |
|
|
29
|
+
| `←` | Previous step or slide |
|
|
30
|
+
| `F` | Toggle fullscreen |
|
|
31
|
+
| `G` | Toggle grid view |
|
|
32
|
+
|
|
33
|
+
## Learn More
|
|
34
|
+
|
|
35
|
+
See `AGENTS.md` for full framework documentation.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{PROJECT_SLUG}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "promptslide studio",
|
|
8
|
+
"build": "promptslide build",
|
|
9
|
+
"preview": "promptslide preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"promptslide": "^0.2.0",
|
|
13
|
+
"clsx": "^2.1.1",
|
|
14
|
+
"framer-motion": "^12.23.22",
|
|
15
|
+
"lucide-react": "^0.552.0",
|
|
16
|
+
"react": "^19.2.4",
|
|
17
|
+
"react-dom": "^19.2.4",
|
|
18
|
+
"tailwind-merge": "^3.3.1",
|
|
19
|
+
"tw-animate-css": "^1.4.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/react": "^19.0.0",
|
|
23
|
+
"@types/react-dom": "^19.0.0",
|
|
24
|
+
"typescript": "^5.9.2"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
|
|
2
|
+
<rect width="32" height="32" rx="6" fill="currentColor" opacity="0.1"/>
|
|
3
|
+
<rect x="6" y="8" width="20" height="14" rx="2" stroke="currentColor" stroke-width="2" fill="none"/>
|
|
4
|
+
<line x1="6" y1="25" x2="26" y2="25" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
|
5
|
+
<rect x="10" y="12" width="8" height="2" rx="1" fill="currentColor" opacity="0.6"/>
|
|
6
|
+
<rect x="10" y="16" width="12" height="1.5" rx="0.75" fill="currentColor" opacity="0.3"/>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SlideThemeProvider, SlideDeck } from "promptslide";
|
|
2
|
+
import { slides } from "@/deck-config";
|
|
3
|
+
import { theme } from "@/theme";
|
|
4
|
+
|
|
5
|
+
export default function App() {
|
|
6
|
+
return (
|
|
7
|
+
<SlideThemeProvider theme={theme}>
|
|
8
|
+
<SlideDeck slides={slides} />
|
|
9
|
+
</SlideThemeProvider>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SlideConfig } from "promptslide";
|
|
2
|
+
import { SlideTitle } from "@/slides/slide-title";
|
|
3
|
+
import { SlideExample } from "@/slides/slide-example";
|
|
4
|
+
|
|
5
|
+
export const slides: SlideConfig[] = [
|
|
6
|
+
{ component: SlideTitle, steps: 0 },
|
|
7
|
+
{ component: SlideExample, steps: 2 },
|
|
8
|
+
];
|