Slides — prompt decks into a presentable app
This repo is a complete slide studio. Author content into it.
/ — in the Bolt preview iframe (and local Vite): studio. Side panel
(S) and grid (G) reorder / duplicate / delete; the dock holds notes,
Download (PDF or JSON), Speaker view, and Present. Present opens a new
tab (/?present=1); the studio stays put. Grid selection is the
start slide. The published site at / is the audience deck (notes
stripped). P opens speaker view in a new tab.
/?presenter=1 — speaker view (current slide, up next, notes
read-only, timer, note text size). /present is the same route.
Your job is CONTENT. A deck is deck.json. Write that file (and
src/styles/tokens.css when theming). Layout props follow
src/data/layoutProps.ts.
Hard rules
- Write
deck.json and src/styles/tokens.css. Those are the
authoring files. Colors, fonts, sizes, spacing in a deck request mean
deck accent / font or tokens.css :root values. If they want a
studio or engine change, say so and wait.
- Author from the user's REAL input. Topic, brand, facts, numbers.
Never invent a placeholder company for a real subject. Brand given →
derive theme colors/fonts from it (fetch the site or use its known
palette) and say what you used.
- One solid accent.
--accent is a hex, never a gradient. Use it
sparingly.
layout is an exact LayoutName. Pick a camelCase key from
LAYOUT_NAMES in src/data/layoutProps.ts (cover, bigNumber,
statGrid, …) and put it on the layout field.
- Homonym keys follow that layout's
*Props type. Chart
kind: "line" points is a pipe string of numbers
("12 | 18 | 26"). Insight takeaways points are
{label, body}[]. Insight line series is points_line. Contrast
bullets are string[] on left.points / right.points. Logos
items is one pipe string ("Acme | Globex"); every other
layout's items is an object array.
Step 0 · bootstrap (mandatory, first)
Read deck.json. If boltSlidesId is missing or null, set it to a new
uuid (crypto.randomUUID() or equivalent) and write the file. Keep
boltSlidesVersion at 1. Then patch content.
Workflow
- Theme only if needed:
:root values in src/styles/tokens.css.
- Read
deck.json so you keep studio-side reorder / duplicate / delete.
- Patch when they already have slides; replace
slides only for a new
deck. Keep boltSlidesId once it exists.
props follow Layout props below; other slide fields follow Deck JSON.
position is 0-based. Always set background on every slide (never omit).
Default: background {"type":"color","color":"var(--bg)"},
animation cascade, status none, transition null, nav
null, notes "".
- Ask the user to look at the studio to see the result: side panel
or grid to reorder / duplicate / delete, notes, Present, Download.
Read first. Replacing all of props drops keys you omit; change one
field by patching that key. Empty notes erases what was there. Replace
the slides array only when replacing the whole deck.
Deck JSON
Repo-root deck.json:
{
"boltSlidesVersion": 1,
"boltSlidesId": "…", // uuid; mint on first write if missing
"deck": {
"title": "Acme — Series A",
"transition": "fade", // deck default: fade | slide | rise | zoom | none
"font": "inter", // inter | space | sora | manrope | dm | outfit | playfair | fraunces
"accent": "#1688FC" // optional — deck-wide accent (solid hex); omit for the tokens.css default
},
"slides": [
{
"id": "s1", // stable string; new slides get a new id
"position": 0,
"layout": "cover", // LayoutName from src/data/layoutProps.ts
"props": { ... }, // that layout's *Props type in the same file
// every layout also accepts "scale": "lg" | "xl"
"animation": "cascade", // cascade | rise | fade | zoom | none
"transition": "zoom", // optional per-slide override (or null to inherit)
"background": { "type": "color", "color": "var(--bg)" },
"nav": null,
"notes": "Open with the hook.", // speaker notes (presenter console)
"status": "draft" // optional review state: none (default) |
// draft | in-progress | review | approved
}
]
}
Rich text in any text prop: ==accent== renders in the accent color,
**bold** bold, _italic_ italic, {c:#ff6b6b}text{/c} a specific text
color ({c:accent} works too), {s:1.4}text{/s} font size as an em
multiplier (0.4–4 — stays responsive), \n line break. A whole field can
override its alignment with a {a:l} / {a:c} / {a:r} prefix (rarely
needed — layouts already align deliberately). Markers nest across types. Discipline: == on the one or two words that carry each headline;
custom colors and sizes are for rare, deliberate moments — the theme does the
typography.
Backgrounds — always set on every slide (studio, thumbs, and present share
the same opaque surface; never leave the field off):
{"type":"color","color":"var(--bg)"} (default — theme surface; follows
tokens.css),
{"type":"color","color":"#0b1020"},
{"type":"gradient","from":"#…","to":"#…","angle":160},
{"type":"image","url":"https://…","dim":0.45} (omit dim for 0.45; engine floors below 0.4),
{"type":"none"} (legacy alias for the theme surface — prefer color +
var(--bg) in new decks). Most slides use var(--bg); save gradient / image
for moments (a section break, a photo cover). Photos:
https://images.unsplash.com/...?w=1600&q=80.
Animation is per-slide and user-changeable later — pick deliberately:
cascade (default — the layout's designed staggers) for almost everything;
fade for quotes/statements you want to land quietly; rise or zoom as an
occasional emphasis beat; none only for dense reference slides.
Transitions: set ONE deck default (usually fade); override per-slide
sparingly (zoom into section dividers works well).
Numbers animate themselves: any figure-like string ("$3T", "48%",
"1,200+") counts up on reveal automatically. Just write the string.
Layout props
Open src/data/layoutProps.ts. layout is a LayoutName. props is the
type of the same name (cover → CoverProps, insight → InsightProps).
Use that type. Homonym keys (points, items, values) are hard
rule 5 — each layout's type is the shape.
Pick by purpose:
- Rhythm —
cover (opener / closing CTA), section (chapter divider),
statement (one thought), bigNumber (drama beat), manifesto
(editorial breather; empty lower half is the layout), quote.
- Structure —
agenda, steps, pillars (focus areas, not a process),
timeline, contrast (before / after), comparison, table (real data;
≤5 cols, ≤7 rows), tabs, accordion (interactive FAQ), qa (flat FAQ),
pricing (highlight exactly one tier), team, logos.
- Visual —
bento (feature grid), statGrid, figures (editorial
numbers), poster, story, speaker, persona, chart, insight
(chart + takeaways), chat, code.
Deck design discipline
- 10–16 slides. Arc: hook → problem → shift → product proof → numbers →
plan → team/ask. Alternate dense layouts with statement-scale beats.
- Titles ≤ 8 words, benefit-first. Bodies ≤ 2 sentences. If a slide needs a
paragraph, it's two slides.
- Every deck: one
bigNumber, one contrast or comparison, and section
dividers every 4–6 slides. Never two dense grids back-to-back.
- The editorial set —
manifesto, poster, story, speaker, persona,
figures, pillars, large qa — is what makes a deck feel designed
rather than generated: use two or three of them for texture, and let their
empty space breathe (it's part of the layout, not waste).
- Write
notes for the presenter on every content slide — one or two lines of
what to SAY, not a repeat of the slide.
- After writing, tell the user to look at the studio: drag to reorder,
••• or right-click a thumbnail to duplicate/delete, grid (G) to pick a
slide then Present, notes and Download on the dock.
Theming (tokens.css :root)
Prefer the deck-level accent and font (Deck JSON above) over editing
tokens. For deeper theming: all color/type/radius/motion live in
src/styles/tokens.css. Change VALUES, never names. --accent =
--primary = one solid hex. --bg-grad-1, --bg-grad-2, and --glow
must stay color-mix of --accent so atmosphere follows the deck accent.
Dark default; for a light deck set --bg /
--fg in tokens.css. Fonts: set the deck-level font pairing (Google Fonts,
loaded automatically; playfair/fraunces for editorial serifs, space/
sora/outfit for technical, manrope/dm for friendly).
1---2name: slides-23description: Author a premium slide deck in Bolt Slides. Slides live in repo-root deck.json; the studio lets the user reorder, duplicate, delete, edit speaker notes, Present, and download PDF/JSON. Use this whenever the user asks for a deck, a pitch, slides, or a presentation in this project.4---56# Slides — prompt decks into a presentable app78This repo is a complete slide **studio**. Author content into it.910- `/` — in the Bolt preview iframe (and local Vite): studio. Side panel11 (S) and grid (G) reorder / duplicate / delete; the dock holds notes,12 Download (PDF or JSON), Speaker view, and Present. Present opens a new13 tab (`/?present=1`); the studio stays put. Grid selection is the14 start slide. The published site at `/` is the audience deck (notes15 stripped). **P** opens speaker view in a new tab.16- `/?presenter=1` — speaker view (current slide, up next, notes17 read-only, timer, note text size). `/present` is the same route.1819**Your job is CONTENT.** A deck is `deck.json`. Write that file (and20`src/styles/tokens.css` when theming). Layout `props` follow21`src/data/layoutProps.ts`.2223## Hard rules24251. **Write `deck.json` and `src/styles/tokens.css`.** Those are the26 authoring files. Colors, fonts, sizes, spacing in a deck request mean27 deck `accent` / `font` or `tokens.css` `:root` values. If they want a28 studio or engine change, say so and wait.292. **Author from the user's REAL input.** Topic, brand, facts, numbers.30 Never invent a placeholder company for a real subject. Brand given →31 derive theme colors/fonts from it (fetch the site or use its known32 palette) and say what you used.333. **One solid accent.** `--accent` is a hex, never a gradient. Use it34 sparingly.354. **`layout` is an exact `LayoutName`.** Pick a camelCase key from36 `LAYOUT_NAMES` in `src/data/layoutProps.ts` (`cover`, `bigNumber`,37 `statGrid`, …) and put it on the `layout` field.385. **Homonym keys follow that layout's `*Props` type.** Chart39 `kind: "line"` `points` is a pipe string of numbers40 (`"12 | 18 | 26"`). Insight takeaways `points` are41 `{label, body}[]`. Insight line series is `points_line`. Contrast42 bullets are `string[]` on `left.points` / `right.points`. Logos43 `items` is one pipe string (`"Acme | Globex"`); every other44 layout's `items` is an object array.4546## Step 0 · bootstrap (mandatory, first)4748Read `deck.json`. If `boltSlidesId` is missing or null, set it to a new49uuid (`crypto.randomUUID()` or equivalent) and write the file. Keep50`boltSlidesVersion` at `1`. Then patch content.5152## Workflow53541. Theme only if needed: `:root` values in `src/styles/tokens.css`.552. Read `deck.json` so you keep studio-side reorder / duplicate / delete.563. Patch when they already have slides; replace `slides` only for a new57 deck. Keep `boltSlidesId` once it exists.5859`props` follow **Layout props** below; other slide fields follow **Deck JSON**.60`position` is 0-based. Always set `background` on every slide (never omit).61Default: `background` `{"type":"color","color":"var(--bg)"}`,62`animation` `cascade`, `status` `none`, `transition` `null`, `nav`63`null`, `notes` `""`.64654. Ask the user to look at the studio to see the result: side panel66 or grid to reorder / duplicate / delete, notes, Present, Download.6768Read first. Replacing all of `props` drops keys you omit; change one69field by patching that key. Empty `notes` erases what was there. Replace70the `slides` array only when replacing the whole deck.7172## Deck JSON7374Repo-root `deck.json`:7576```jsonc77{78 "boltSlidesVersion": 1,79 "boltSlidesId": "…", // uuid; mint on first write if missing80 "deck": {81 "title": "Acme — Series A",82 "transition": "fade", // deck default: fade | slide | rise | zoom | none83 "font": "inter", // inter | space | sora | manrope | dm | outfit | playfair | fraunces84 "accent": "#1688FC" // optional — deck-wide accent (solid hex); omit for the tokens.css default85 },86 "slides": [87 {88 "id": "s1", // stable string; new slides get a new id89 "position": 0,90 "layout": "cover", // LayoutName from src/data/layoutProps.ts91 "props": { ... }, // that layout's *Props type in the same file92 // every layout also accepts "scale": "lg" | "xl"93 "animation": "cascade", // cascade | rise | fade | zoom | none94 "transition": "zoom", // optional per-slide override (or null to inherit)95 "background": { "type": "color", "color": "var(--bg)" },96 "nav": null,97 "notes": "Open with the hook.", // speaker notes (presenter console)98 "status": "draft" // optional review state: none (default) |99 // draft | in-progress | review | approved100 }101 ]102}103```104105**Rich text** in any text prop: `==accent==` renders in the accent color,106`**bold**` bold, `_italic_` italic, `{c:#ff6b6b}text{/c}` a specific text107color (`{c:accent}` works too), `{s:1.4}text{/s}` font size as an em108multiplier (0.4–4 — stays responsive), `\n` line break. A whole field can109override its alignment with a `{a:l}` / `{a:c}` / `{a:r}` prefix (rarely110needed — layouts already align deliberately). Markers nest across types. Discipline: `==` on the one or two words that carry each headline;111custom colors and sizes are for rare, deliberate moments — the theme does the112typography.113114**Backgrounds** — always set on every slide (studio, thumbs, and present share115the same opaque surface; never leave the field off):116`{"type":"color","color":"var(--bg)"}` (default — theme surface; follows117`tokens.css`),118`{"type":"color","color":"#0b1020"}`,119`{"type":"gradient","from":"#…","to":"#…","angle":160}`,120`{"type":"image","url":"https://…","dim":0.45}` (omit dim for 0.45; engine floors below 0.4),121`{"type":"none"}` (legacy alias for the theme surface — prefer `color` +122`var(--bg)` in new decks). Most slides use `var(--bg)`; save gradient / image123for moments (a section break, a photo cover). Photos:124`https://images.unsplash.com/...?w=1600&q=80`.125126**Animation** is per-slide and user-changeable later — pick deliberately:127`cascade` (default — the layout's designed staggers) for almost everything;128`fade` for quotes/statements you want to land quietly; `rise` or `zoom` as an129occasional emphasis beat; `none` only for dense reference slides.130**Transitions**: set ONE deck default (usually `fade`); override per-slide131sparingly (`zoom` into section dividers works well).132133**Numbers animate themselves**: any figure-like string (`"$3T"`, `"48%"`,134`"1,200+"`) counts up on reveal automatically. Just write the string.135136## Layout props137138Open `src/data/layoutProps.ts`. `layout` is a `LayoutName`. `props` is the139type of the same name (`cover` → `CoverProps`, `insight` → `InsightProps`).140Use that type. Homonym keys (`points`, `items`, `values`) are hard141rule 5 — each layout's type is the shape.142143Pick by purpose:144145- **Rhythm** — `cover` (opener / closing CTA), `section` (chapter divider),146 `statement` (one thought), `bigNumber` (drama beat), `manifesto`147 (editorial breather; empty lower half is the layout), `quote`.148- **Structure** — `agenda`, `steps`, `pillars` (focus areas, not a process),149 `timeline`, `contrast` (before / after), `comparison`, `table` (real data;150 ≤5 cols, ≤7 rows), `tabs`, `accordion` (interactive FAQ), `qa` (flat FAQ),151 `pricing` (highlight exactly one tier), `team`, `logos`.152- **Visual** — `bento` (feature grid), `statGrid`, `figures` (editorial153 numbers), `poster`, `story`, `speaker`, `persona`, `chart`, `insight`154 (chart + takeaways), `chat`, `code`.155156## Deck design discipline157158- **10–16 slides.** Arc: hook → problem → shift → product proof → numbers →159 plan → team/ask. Alternate dense layouts with statement-scale beats.160- Titles ≤ 8 words, benefit-first. Bodies ≤ 2 sentences. If a slide needs a161 paragraph, it's two slides.162- Every deck: one `bigNumber`, one `contrast` or `comparison`, and section163 dividers every 4–6 slides. Never two dense grids back-to-back.164- The editorial set — `manifesto`, `poster`, `story`, `speaker`, `persona`,165 `figures`, `pillars`, large `qa` — is what makes a deck feel designed166 rather than generated: use two or three of them for texture, and let their167 empty space breathe (it's part of the layout, not waste).168- Write `notes` for the presenter on every content slide — one or two lines of169 what to SAY, not a repeat of the slide.170- After writing, tell the user to look at the studio: drag to reorder,171 ••• or right-click a thumbnail to duplicate/delete, grid (G) to pick a172 slide then Present, notes and Download on the dock.173174## Theming (`tokens.css` `:root`)175176Prefer the deck-level `accent` and `font` (Deck JSON above) over editing177tokens. For deeper theming: all color/type/radius/motion live in178`src/styles/tokens.css`. Change VALUES, never names. `--accent` =179`--primary` = one solid hex. `--bg-grad-1`, `--bg-grad-2`, and `--glow`180must stay `color-mix` of `--accent` so atmosphere follows the deck accent.181Dark default; for a light deck set `--bg` /182`--fg` in tokens.css. Fonts: set the deck-level `font` pairing (Google Fonts,183loaded automatically; `playfair`/`fraunces` for editorial serifs, `space`/184`sora`/`outfit` for technical, `manrope`/`dm` for friendly).