Skills-for-architects slide-deck-generator
Generate a polished HTML slide deck from a topic, outline, or data. Outputs a self-contained .html file with keyboard/touch navigation, responsive typography, and the ALPA (Alpaca Labs) design system — Helvetica, editorial layout, clean white backgrounds.
git clone https://github.com/AlpacaLabsLLC/skills-for-architects
T=$(mktemp -d) && git clone --depth=1 https://github.com/AlpacaLabsLLC/skills-for-architects "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/07-presentations/skills/slide-deck-generator" ~/.claude/skills/alpacalabsllc-skills-for-architects-slide-deck-generator && rm -rf "$T"
plugins/07-presentations/skills/slide-deck-generator/SKILL.mdPresentation Generator
You generate self-contained HTML slide presentations using the ALPA (Alpaca Labs) design system — editorial layout with Helvetica, left-aligned typography, generous whitespace, and a clean monochrome palette. The user provides a topic, outline, data, or document — you produce a complete
.html file they can open in any browser.
On Start
When invoked, list the available page types for the user before proceeding:
| # | Type | Layout | Background |
|---|---|---|---|
| 1 | Title (Image + Title) | Full bleed image, text overlay bottom-left | Image |
| 2 | Title (Text Only) | Left-aligned h1 + subtitle + credit | White |
| 3 | Heading + Body | Eyebrow + h2 + paragraph | White |
| 4 | Heading + List | Eyebrow + h2 + bullet list | White / Grey |
| 5 | Heading + Stats | Eyebrow + h2 + vertical stat lines | White |
| 6 | Stat Row | Large centered numbers in columns | White / Grey |
| 7 | Stat Comparison | Before/after with arrows | White / Grey |
| 8 | Heading + Stat Row | Eyebrow + h2 + stat columns (centered) | White / Grey |
| 9 | Statement (white) | Bold centered text | White |
| 10 | Statement (dark) | Bold centered text | Dark |
| 11 | Data Table | Eyebrow + h2 + table | Grey |
| 12 | Insight List | Eyebrow + h2 + numbered items | White |
| 13 | Bar Chart | Eyebrow + h2 + horizontal bars | White |
| 14 | Timeline | Eyebrow + h2 + phased dots (centered) | White |
| 15 | Two Column | Eyebrow + h2 + side-by-side text | White / Grey |
| 16 | Comparison | Eyebrow + h2 + before/after boxes (centered) | White |
| 17 | Image — Full Bleed | Single image, edge to edge | Image |
| 18 | Image — Full Bleed + Title | Full image with gradient + overlaid text | Image |
| 19 | Image — Split 2 | Two images side by side | White border |
| 20 | Image — Split 3 | Three images in a row | White border |
| 21 | Image — Split 4 | 2×2 grid | White border |
| 22 | Image — Split 6 | 3×2 grid | White border |
Any slide can include a Callout (footnote annotation) appended below the main content.
A sample deck demonstrating every type is at
~/.claude/skills/alpa-presentation/sample.html.
Workflow
-
Understand the input. The user may provide:
- A topic or title (you research/generate content)
- An outline or bullet points (you expand into slides)
- A document or report (you distill into a deck)
- Data or analysis results (you visualize as stats/tables/charts)
- Local image files or a folder (use as image slides — see Image Handling below)
-
Plan the deck. Before writing HTML, decide:
- How many slides (aim for 10-20, never fewer than 6)
- Which slide type and components each slide uses
- The narrative arc: setup -> insight -> evidence -> recommendation -> close
-
Embed local images. If the user provides local image paths, encode them as base64 before writing the HTML (see Image Handling below). This keeps the deck self-contained and portable.
-
Write the HTML file. Use the template below as the foundation. Customize only the slide content inside
.<body> -
Save the file. Write to the path the user specifies, or default to
. Tell the user the path so they can open it../presentation.html
Image Handling
The deck must be self-contained — local images must be embedded as base64 data URIs, not referenced by file path. A file path
src breaks as soon as the HTML is moved or shared.
Encoding local images
For every local image path the user provides, run this Python snippet via Bash to get the base64 data URI:
import base64, sys, mimetypes path = sys.argv[1] mime = mimetypes.guess_type(path)[0] or "image/jpeg" with open(path, "rb") as f: data = base64.b64encode(f.read()).decode() print(f"data:{mime};base64,{data}")
Then use the output as the
src value:
<img src="data:image/jpeg;base64,/9j/4AAQ..." alt="Description" />
Using /resize-images output
If the user ran
/resize-images before this skill, the resized-slides/ folder contains images already sized for the slide canvas:
— 1920×1080 (16:9) — use for full-bleed and image-grid slides*-slides-wide.jpg
— 1024×768 (4:3) — use only if the user asked for a 4:3 deck*-slides-standard.jpg
Prefer
slides-wide images. Embed them as base64 (see above) so the deck stays portable.
When no local images are provided
Use
src="" with a descriptive alt attribute as a placeholder. Note the placeholder in the output so the user knows which slides need images:
<img src="" alt="[Insert: project exterior view]" />
File size note
Base64-encoding large images increases HTML file size. If the user provides many high-res images, warn them: "Embedding N images will produce a large HTML file (~X MB). Consider running
/resize-images --slides first to reduce file size before embedding."
Design System
Layout Philosophy
- Left-aligned by default. Content is flush-left with generous left padding. Only statement slides center text.
- Massive whitespace. Content should breathe. Never fill the slide — leave at least 40% empty.
- Eyebrow top-left. Small bold monospace text in the top-left corner identifies the section.
- Brand mark bottom-right. A small "ALPA" wordmark sits fixed in the bottom-right corner.
- No decorative boxes or cards. Stats, lists, and content stand on their own — no background panels or rounded containers.
Slide Types (background classes on .slide
div)
.slide| Class | Background | Text | Use for |
|---|---|---|---|
| (none) | White (#ffffff) | Dark | Title, content, lists, tables — the default |
| Light grey (#f5f5f3) | Dark | Tables, stat comparisons, alternating rhythm |
| Dark (#1a1a1a) | White | Statement slides — bold centered declarations |
Components
Eyebrow — small bold label directly above the heading:
<div class="eyebrow">Eyebrow Text</div> <h2>The heading below</h2>
Always placed inside
.content, immediately before the <h2>.
Heading + Body — the most common slide: heading with paragraph below:
<div class="content"> <div class="eyebrow">Eyebrow Text</div> <h2>The heading states the insight</h2> <p>Supporting paragraph with context and detail. Keep it to 2-3 lines max.</p> </div>
Heading + List — bullet list below a heading:
<div class="content"> <h2>What we need to answer</h2> <ul class="body-list"> <li>First question or point</li> <li>Second question or point</li> <li>Third question or point</li> </ul> </div>
Heading + Stats — vertical stat list (not cards):
<div class="content"> <h2>Who do we build for?</h2> <p>Context paragraph explaining what the numbers mean.</p> <div class="stat-list"> <div class="stat-line">8,211 employees</div> <div class="stat-line">3,313 contingent workers</div> <div class="stat-line bold">11,524 total workforce</div> </div> </div>
Stat Row — large numbers in columns with labels (centered layout):
<div class="stat-row"> <div class="stat-col"> <div class="stat-title">Bay Area</div> <div class="stat-value">50%</div> <div class="stat-label">Share of workforce</div> </div> <div class="stat-col"> <div class="stat-title">Americas</div> <div class="stat-value">13%</div> <div class="stat-label">Share of workforce</div> </div> </div>
Stat Comparison — before/after with arrows and change indicators:
<div class="stat-row"> <div class="stat-col"> <div class="stat-title">Bay Area</div> <div class="stat-value muted">50%</div> <div class="stat-label">Share of workforce</div> <div class="stat-arrow">↓</div> <div class="stat-value">32%</div> <div class="stat-change negative">-26% ▼</div> </div> <div class="stat-col"> <div class="stat-title">Americas</div> <div class="stat-value muted">13%</div> <div class="stat-label">Share of workforce</div> <div class="stat-arrow">↓</div> <div class="stat-value">26%</div> <div class="stat-change positive">+115% ▲</div> </div> </div>
Heading + Stat Row — eyebrow + heading with columnar stats below. Same vertical rhythm as timeline slides. Use
.slide.centered:
<div class="slide centered"> <div class="content"> <div class="eyebrow">Section</div> <h2>Perfil del comprador</h2> <div class="stat-row"> <div class="stat-col"> <div class="stat-title">Label</div> <div class="stat-value">50%</div> <div class="stat-label">Description text</div> </div> <div class="stat-col"> <div class="stat-title">Label</div> <div class="stat-value">30%</div> <div class="stat-label">Description text</div> </div> </div> </div> <div class="brand-mark">ALPA</div> </div>
The
.slide.centered .content h2 rule tightens the heading's bottom margin so the heading sits close to the stat-row, matching the timeline layout.
Statement — bold centered text on white or dark:
<!-- White statement --> <div class="slide"> <div class="statement">We talk about flexibility but design for predictability.</div> </div> <!-- Dark statement --> <div class="slide dark"> <div class="statement">People don't connect to policies. They connect to places, to their work, and to each other.</div> </div>
Data Table — clean table with dotted borders:
<div class="content"> <h2>Bay Area: Workforce & Footprint Shifts ('20 - '25)</h2> <table class="data-table"> <thead><tr><th>Cities</th><th>Workforce Today</th><th>Change</th><th>Ratio</th></tr></thead> <tbody> <tr><td>San Francisco</td><td>2,330</td><td class="negative">-26% ▼</td><td>1 : 108</td></tr> <tr class="total-row"><td></td><td><strong>2,330</strong></td><td class="negative">-26% ▼</td><td><strong>1 : 108</strong></td></tr> </tbody> </table> </div>
Insight List — numbered items with bold lead:
<div class="content"> <h2>Key findings</h2> <ul class="insight-list"> <li><span class="num">01</span><span><span class="emphasis">Bold lead</span> — supporting detail after the dash</span></li> </ul> </div>
Bar Chart — horizontal bars with labels and values:
<div class="content"> <h2>Distribution</h2> <div class="bar-chart"> <div class="bar-row"> <span class="bar-label">Label</span> <div class="bar-track"><div class="bar-fill accent" style="width:73%"></div></div> <span class="bar-value">73%</span> </div> </div> </div>
Timeline — phased progression:
<div class="timeline"> <div class="timeline-item active"> <div class="timeline-dot"></div> <div class="timeline-label">Phase 1</div> <div class="timeline-title">Title</div> <div class="timeline-desc">Description</div> </div> </div>
Two Column — side by side content areas:
<div class="two-col"> <div><!-- left content --></div> <div><!-- right content --></div> </div>
Comparison — side by side with arrow:
<div class="comparison"> <div class="comparison-side"> <div class="comparison-label">Before</div> <div class="comparison-content">Description</div> </div> <div class="comparison-arrow">→</div> <div class="comparison-side highlight"> <div class="comparison-label">After</div> <div class="comparison-content">Description</div> </div> </div>
Callout — inline annotation:
<div class="callout">Key takeaway or footnote.</div>
Image — Full Bleed — single image filling the entire slide:
<div class="slide image-slide"> <img src="image-url.jpg" alt="Description" /> </div>
Image — Full Bleed + Title — full-bleed image with overlaid title (like a cover or statement). Use
.image-title-slide:
<div class="slide image-title-slide"> <img src="image-url.jpg" alt="Description" /> <div class="image-title-overlay"> <h1>Title Goes Here</h1> <p class="subtitle">Optional subtitle</p> </div> <div class="brand-mark">ALPA</div> </div>
Image — Split 2 — two images side by side with white border:
<div class="slide image-grid cols-2"> <img src="image1.jpg" alt="" /> <img src="image2.jpg" alt="" /> </div>
Image — Split 3 — three images in a row:
<div class="slide image-grid cols-3"> <img src="image1.jpg" alt="" /> <img src="image2.jpg" alt="" /> <img src="image3.jpg" alt="" /> </div>
Image — Split 4 — two rows of two:
<div class="slide image-grid cols-2 rows-2"> <img src="image1.jpg" alt="" /> <img src="image2.jpg" alt="" /> <img src="image3.jpg" alt="" /> <img src="image4.jpg" alt="" /> </div>
Image — Split 6 — two rows of three:
<div class="slide image-grid cols-3 rows-2"> <img src="image1.jpg" alt="" /> <img src="image2.jpg" alt="" /> <img src="image3.jpg" alt="" /> <img src="image4.jpg" alt="" /> <img src="image5.jpg" alt="" /> <img src="image6.jpg" alt="" /> </div>
Composition Rules
- Every content slide (not statements) should have a
top-lefteyebrow - Title slide: full-bleed image with
— h1 + subtitle over gradient overlay. Falls back to white text-only title if no image is available..image-title-slide - Content slides: white (default), left-aligned —
+eyebrow
with heading + body/list/stats.content - Statement slides: centered text, no eyebrow — white bg for regular statements,
for dramatic onesdark - Stat slides: white or grey, centered stat-row or stat-comparison layout
- Table slides: white or grey, left-aligned heading + data-table
- Dark slides: use sparingly — at most 1-2 per deck for maximum emphasis
- Closing slide: white, left-aligned or centered — bold statement or summary
- Use
for bold inline text<span class="emphasis"> - Never put more than one major component per slide (one table OR one stat-row OR one list)
- Alternate slide backgrounds for visual rhythm — never use the same type 3x in a row
- Centered content: Use
(class on the slide div) for slides with a heading + grid, timeline, stat-row, or comparison below. These read better centered. Left-align is for heading + body text, lists, tables, and insight lists..slide.centered - Leave generous whitespace — content should occupy at most 60% of the slide
Writing Style
- Headlines: short, declarative, opinionated. State the insight, not the topic.
- Good: "We have 18 huddle rooms. At peak, 29 groups need one."
- Bad: "Huddle Room Analysis"
- Subtitles and descriptions: lightweight, factual, no jargon
- Stats: pick the most dramatic number, give it context with the label
- Tables: 4-6 rows max. Use colored indicators for changes (red for negative, green for positive).
- Lists: lead with the bold action/finding, follow with the detail after an em dash
HTML Template
Use this exact CSS and JS. Only modify the slide
<div> elements inside <body>.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{TITLE}}</title> <style> :root { --black: #1a1a1a; --grey-700: #484848; --grey-500: #6b6b6b; --grey-300: #b0b0b0; --grey-200: #d4d4d4; --grey-100: #e8e8e6; --grey-50: #f5f5f3; --white: #ffffff; --accent: #E8B517; --negative: #D92B2B; --positive: #2563EB; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background: var(--black); overflow: hidden; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } /* --- Slide base --- */ .slide { width: 100vw; height: 100vh; display: none; flex-direction: column; justify-content: flex-start; align-items: flex-start; padding: clamp(48px, 6vw, 96px) clamp(60px, 8vw, 140px); background: var(--white); color: var(--black); position: relative; } .slide.active { display: flex; } .slide.dark { background: var(--black); color: var(--white); justify-content: center; align-items: center; } .slide.centered { justify-content: center; align-items: center; } .slide.grey { background: var(--grey-50); } /* --- Eyebrow (top-left) --- */ .eyebrow { font-size: clamp(9px, 0.8vw, 11px); font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--grey-500); margin-bottom: clamp(16px, 2vw, 28px); margin-left: 4px; } .slide.dark .eyebrow { color: var(--grey-300); } /* --- Brand mark (bottom-right) --- */ .brand-mark { position: absolute; bottom: clamp(28px, 3vw, 48px); right: clamp(36px, 4vw, 64px); font-size: clamp(11px, 1vw, 14px); font-weight: 700; letter-spacing: 0.15em; color: var(--grey-300); text-transform: uppercase; } .slide.dark .brand-mark { color: var(--grey-500); } /* --- Page number (bottom-right, auto-generated by JS) --- */ .page-number { position: absolute; top: clamp(32px, 4vw, 56px); right: clamp(36px, 4vw, 64px); font-size: clamp(11px, 1vw, 14px); font-weight: 400; color: var(--grey-300); } .slide.dark .page-number { color: var(--grey-500); } /* --- Typography --- */ h1 { font-size: clamp(40px, 6vw, 88px); font-weight: 700; letter-spacing: -0.04em; line-height: 1.0; max-width: 900px; margin-bottom: clamp(24px, 3vw, 48px); } h2 { font-size: clamp(24px, 3.2vw, 52px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.1; max-width: 900px; margin-bottom: clamp(24px, 3vw, 48px); } .subtitle { font-size: clamp(14px, 1.6vw, 24px); font-weight: 400; line-height: 1.4; max-width: 700px; color: var(--grey-500); margin-bottom: clamp(12px, 1.5vw, 24px); } p { font-size: clamp(13px, 1.3vw, 18px); font-weight: 400; letter-spacing: -0.01em; line-height: 1.7; max-width: 800px; color: var(--grey-700); } .slide.dark p { color: var(--grey-300); } /* --- Content wrapper (left-aligned) --- */ .content { display: flex; flex-direction: column; align-items: flex-start; justify-content: center; flex: 1; width: 100%; max-width: 1100px; } .slide.centered .content { align-items: center; text-align: center; } .slide.centered .content h2 { margin-bottom: clamp(16px, 2vw, 32px); } .content .stat-row { margin: 0; } /* --- Statement (centered, for statement slides) --- */ .statement { font-size: clamp(28px, 4vw, 60px); font-weight: 700; letter-spacing: -0.03em; line-height: 1.15; text-align: center; max-width: 900px; margin: auto; } /* --- Body list (bullet points) --- */ .body-list { list-style: disc; padding-left: 24px; max-width: 800px; } .body-list li { font-size: clamp(14px, 1.4vw, 20px); font-weight: 400; line-height: 1.6; color: var(--grey-700); padding: 6px 0; } .body-list li::marker { color: var(--black); } /* --- Stat list (vertical, no cards) --- */ .stat-list { margin-top: 16px; } .stat-line { font-size: clamp(14px, 1.4vw, 20px); font-weight: 400; line-height: 1.8; color: var(--grey-700); } .stat-line.bold { font-weight: 700; color: var(--black); } /* --- Stat row (large numbers in columns) --- */ .stat-row { display: flex; gap: clamp(32px, 5vw, 80px); justify-content: center; align-items: flex-start; width: 100%; margin: auto; flex-wrap: wrap; text-align: center; } .stat-col { flex: 1; min-width: 160px; max-width: 280px; } .stat-title { font-size: clamp(13px, 1.3vw, 18px); font-weight: 400; color: var(--grey-700); margin-bottom: 12px; } .stat-value { font-size: clamp(40px, 5.5vw, 80px); font-weight: 700; letter-spacing: -0.04em; line-height: 1.0; margin-bottom: 8px; } .stat-value.muted { color: var(--grey-300); } .stat-label { font-size: clamp(11px, 1vw, 14px); font-weight: 400; color: var(--grey-500); margin-bottom: 8px; } .stat-arrow { font-size: clamp(16px, 1.6vw, 22px); color: var(--grey-300); margin: 12px 0; } .stat-change { font-size: clamp(11px, 1vw, 14px); font-weight: 700; margin-top: 4px; } .stat-change.negative { color: var(--negative); } .stat-change.positive { color: var(--positive); } /* --- Data table --- */ .data-table { width: 100%; max-width: 1000px; border-collapse: collapse; margin-top: 16px; text-align: left; } .data-table th { font-size: clamp(9px, 0.8vw, 12px); font-weight: 700; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.06em; padding: 14px 16px; border-top: 1px dotted var(--grey-200); border-bottom: 1px dotted var(--grey-200); background: var(--grey-50); text-align: center; } .data-table th:first-child { text-align: left; } .data-table td { font-size: clamp(12px, 1.2vw, 16px); font-weight: 400; color: var(--grey-700); padding: 14px 16px; border-bottom: 1px dotted var(--grey-200); text-align: center; } .data-table td:first-child { text-align: left; color: var(--black); font-weight: 400; } .data-table .negative { color: var(--negative); font-weight: 400; } .data-table .positive { color: var(--positive); font-weight: 400; } .data-table .total-row td { font-weight: 700; color: var(--black); } /* --- Insight list --- */ .insight-list { list-style: none; text-align: left; width: 100%; max-width: 800px; } .insight-list li { display: flex; align-items: flex-start; gap: 20px; padding: 18px 0; border-bottom: 1px solid var(--grey-100); font-size: clamp(13px, 1.3vw, 18px); font-weight: 400; line-height: 1.6; color: var(--grey-700); } .insight-list .num { font-weight: 700; color: var(--black); min-width: 32px; } .emphasis { font-weight: 700; color: var(--black); } .slide.dark .emphasis { color: var(--white); } /* --- Bar chart --- */ .bar-chart { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 500px; } .bar-row { display: flex; align-items: center; gap: 12px; } .bar-label { font-size: clamp(11px, 1vw, 14px); font-weight: 400; color: var(--grey-500); min-width: 100px; text-align: right; } .bar-track { flex: 1; height: 28px; background: var(--grey-100); overflow: hidden; } .bar-fill { height: 100%; background: var(--grey-300); transition: width 0.6s ease; } .bar-fill.accent { background: var(--black); } .bar-value { font-size: clamp(11px, 1vw, 14px); font-weight: 700; color: var(--grey-500); min-width: 44px; } /* --- Comparison --- */ .comparison { display: flex; align-items: stretch; gap: 2px; width: 100%; max-width: 850px; } .comparison-side { flex: 1; background: var(--grey-50); padding: clamp(28px, 3vw, 44px); text-align: center; } .comparison-side.highlight { background: var(--black); color: var(--white); } .comparison-side.highlight p { color: var(--grey-300); } .comparison-label { font-size: clamp(9px, 0.8vw, 11px); font-weight: 700; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.15em; margin-bottom: 20px; } .comparison-content { font-size: clamp(13px, 1.3vw, 18px); font-weight: 400; line-height: 1.6; } .comparison-arrow { display: flex; align-items: center; font-size: clamp(13px, 1.3vw, 18px); color: var(--grey-300); padding: 0 8px; background: var(--white); } /* --- Timeline --- */ .timeline { display: flex; align-items: flex-start; gap: 0; width: 100%; max-width: 900px; position: relative; margin-top: 20px; } .timeline::before { content: ''; position: absolute; top: 6px; left: 12px; right: 12px; height: 2px; background: var(--grey-200); z-index: 0; } .timeline-item { flex: 1; text-align: center; position: relative; z-index: 1; padding: 0 12px; } .timeline-dot { width: 14px; height: 14px; background: var(--grey-200); margin: 0 auto 20px; } .timeline-item.active .timeline-dot { background: var(--black); } .timeline-label { font-size: clamp(9px, 0.8vw, 11px); font-weight: 700; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.12em; margin-bottom: 8px; } .timeline-title { font-size: clamp(13px, 1.3vw, 18px); font-weight: 700; letter-spacing: -0.01em; line-height: 1.3; margin-bottom: 10px; } .timeline-desc { font-size: clamp(11px, 1vw, 14px); font-weight: 400; line-height: 1.6; color: var(--grey-500); } /* --- Two column --- */ .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 3vw, 48px); width: 100%; max-width: 900px; text-align: left; } /* --- Callout --- */ .callout { display: inline-block; width: fit-content; background: var(--grey-50); padding: 18px 28px; margin-top: 24px; font-size: clamp(11px, 1vw, 14px); font-weight: 400; color: var(--grey-700); } /* --- Image: full bleed --- */ .slide.image-slide { padding: 0; } .slide.image-slide > img { width: 100%; height: 100%; object-fit: cover; display: block; } /* --- Image: full bleed + title overlay --- */ .slide.image-title-slide { padding: 0; position: relative; } .slide.image-title-slide > img { width: 100%; height: 100%; object-fit: cover; display: block; } .image-title-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: flex-end; align-items: flex-start; padding: clamp(48px, 6vw, 96px) clamp(60px, 8vw, 140px); background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.2) 40%, transparent 70%); } .image-title-overlay h1 { color: var(--white); } .image-title-overlay .subtitle { color: var(--grey-300); } .slide.image-title-slide .brand-mark { color: rgba(255,255,255,0.5); } /* --- Image: grids --- */ .slide.image-grid { padding: 0; display: none; } .slide.image-grid.active { display: grid; } .slide.image-grid img { width: 100%; height: 100%; object-fit: cover; display: block; } .slide.image-grid.cols-2 { grid-template-columns: 1fr 1fr; gap: 4px; background: var(--white); } .slide.image-grid.cols-3 { grid-template-columns: 1fr 1fr 1fr; gap: 4px; background: var(--white); } .slide.image-grid.rows-2 { grid-template-rows: 1fr 1fr; } /* --- Navigation --- */ .nav { position: fixed; bottom: 28px; left: 50%; transform: translateX(-50%); display: flex; gap: 4px; z-index: 100; } .nav-btn { width: 40px; height: 40px; border: none; background: var(--black); color: var(--white); font-size: clamp(13px, 1.3vw, 18px); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: opacity 0.15s ease; opacity: 0.3; } .nav-btn:hover { opacity: 1; } .progress { position: fixed; top: 0; left: 0; height: 3px; background: var(--accent); transition: width 0.3s ease; z-index: 100; } </style> </head> <body> <!-- SLIDES GO HERE --> <!-- SLIDE STRUCTURE EXAMPLES: Title slide (image cover — default): <div class="slide image-title-slide active"> <img src="cover-image.jpg" alt="Cover" /> <div class="image-title-overlay"> <h1>Title Goes<br/>Here</h1> <p class="subtitle">Subtitle — Month Year</p> </div> <div class="brand-mark">ALPA</div> </div> Title slide (text only — fallback): <div class="slide active"> <div class="content"> <h1>Title Goes<br/>Here</h1> <p class="subtitle">Subtitle — Month Year</p> <p>Prepared by Name</p> </div> <div class="brand-mark">ALPA</div> </div> Content slide: <div class="slide"> <div class="content"> <div class="eyebrow">Eyebrow Text</div> <h2>Heading states the insight</h2> <p>Supporting text goes here.</p> </div> <div class="brand-mark">ALPA</div> </div> Statement slide (white): <div class="slide centered"> <div class="statement">Bold centered statement text.</div> <div class="brand-mark">ALPA</div> </div> Statement slide (dark): <div class="slide dark"> <div class="statement">Bold centered statement text on dark.</div> <div class="brand-mark">ALPA</div> </div> Centered content slide (stats, timelines, grids): <div class="slide centered"> <div class="content"> <div class="eyebrow">Section</div> <h2>Heading</h2> <!-- stat-row, timeline, grid, or comparison here --> </div> <div class="brand-mark">ALPA</div> </div> Table slide: <div class="slide grey"> <div class="content"> <div class="eyebrow">Eyebrow Text</div> <h2>Table heading</h2> <table class="data-table">...</table> </div> <div class="brand-mark">ALPA</div> </div> --> <nav class="nav"> <button class="nav-btn" onclick="prevSlide()">←</button> <button class="nav-btn" onclick="nextSlide()">→</button> </nav> <div class="progress" id="progress"></div> <script> const slides = document.querySelectorAll('.slide'); let current = 0; function showSlide(n) { slides[current].classList.remove('active'); current = (n + slides.length) % slides.length; slides[current].classList.add('active'); document.getElementById('progress').style.width = ((current + 1) / slides.length * 100) + '%'; } function nextSlide() { showSlide(current + 1); } function prevSlide() { showSlide(current - 1); } document.addEventListener('keydown', (e) => { if (e.key === 'ArrowRight' || e.key === ' ') { e.preventDefault(); nextSlide(); } if (e.key === 'ArrowLeft') { e.preventDefault(); prevSlide(); } }); let touchStartX = 0; document.addEventListener('touchstart', (e) => { touchStartX = e.changedTouches[0].screenX; }); document.addEventListener('touchend', (e) => { const diff = e.changedTouches[0].screenX - touchStartX; if (Math.abs(diff) > 50) { diff < 0 ? nextSlide() : prevSlide(); } }); document.getElementById('progress').style.width = (1 / slides.length * 100) + '%'; // Auto-inject page numbers (skip first and last slide) slides.forEach((slide, i) => { if (i > 0 && i < slides.length - 1) { const num = document.createElement('div'); num.className = 'page-number'; num.textContent = String(i).padStart(2, '0'); slide.appendChild(num); } }); </script> </body> </html>
Accent Color
The default accent is
--accent: #E8B517 (warm yellow — used only on the progress bar). The design is primarily monochrome — black, white, and greys. Change indicators use --negative: #D92B2B (red) and --positive: #2563EB (blue) for data.
If the presentation is for a different brand or context, change
--accent. Common alternatives:
- Blue:
#2563EB - Teal:
#0D7377 - Purple:
#6B21A8 - Orange:
#C2410C
Ask the user if they want a specific accent color. If the topic suggests a brand, try to match.
Slide Structure Rules
- First slide: Always
— useactive
with a relevant cover image, h1 + subtitle over gradient. If no image is available, fall back to white text-only title (h1 +.image-title-slide
+ credit)..subtitle - Second slide: Context or framing question — what we need to answer, what this is about.
- Middle slides: Alternate between white and grey backgrounds. Use statement slides (white or dark) to break rhythm and emphasize key points. Build the argument.
- Stat slides: Use
to center the stat-row on the page. No eyebrow needed.<div class="slide centered"> - Statement slides: Center the
div. No eyebrow. Use dark bg sparingly (1-2 per deck)..statement - Penultimate slide: The ask / recommendations / next steps
- Last slide: White — closing statement or summary, left-aligned or centered.
Output
Write the complete HTML file using the Write tool. The first slide must have class
active. Every slide must be a direct child <div class="slide ..."> inside body, before the <nav>. Add <div class="brand-mark">ALPA</div> to every slide.