skills/frontend-slides/SKILL.md
Create stunning, animation-rich HTML presentations locked to your brand identity. Use when the user wants to build a branded presentation, convert a PPT/PPTX to web, or create slides for a talk/pitch. On first use, a brand wizard walks you through defining your visual identity — every presentation after that is automatically on-brand.
npx skillsauth add motleyai/agent-skills frontend-slidesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Create zero-dependency, animation-rich HTML presentations locked to your brand identity.
You tend to converge toward generic, "on distribution" outputs. In frontend design, this creates what users call the "AI slop" aesthetic. Avoid this: make creative, distinctive frontends that surprise and delight — within the brand's visual identity.
Focus on:
Avoid generic AI-generated aesthetics:
These invariants apply to EVERY slide in EVERY presentation:
.slide must have height: 100vh; height: 100dvh; overflow: hidden;clamp(min, preferred, max) — never fixed px/remmax-height constraintsmax-height: min(50vh, 400px)prefers-reduced-motion support-clamp(), -min(), -max() are silently ignored) — use calc(-1 * clamp(...)) insteadWhen generating, read viewport-base.css and include its full contents in every presentation.
| Slide Type | Maximum Content | | ------------- | --------------------------------------------------------- | | Title slide | 1 heading + 1 subtitle + optional tagline | | Content slide | 1 heading + 4-6 bullet points OR 1 heading + 2 paragraphs | | Feature grid | 1 heading + 6 cards maximum (2x3 or 3x2) | | Code slide | 1 heading + 8-10 lines of code | | Quote slide | 1 quote (max 3 lines) + attribution | | Image slide | 1 heading + 1 image (max 60vh height) |
Content exceeds limits? Split into multiple slides. Never cram, never scroll.
First: check if BRAND_CONFIG.md exists and is filled in (not just the empty template with <!-- ... --> placeholders).
Then determine what the user wants:
When enhancing existing presentations, viewport fitting is the biggest risk:
max-height: min(50vh, 400px). If slide already has max content, split into two slides.slide has overflow: hidden, new elements use clamp(), images have viewport-relative max-height, content fits at 1280x720When adding images to existing slides: Move image to new slide or reduce other content first. Never add images without checking if existing content already fills the viewport.
Ask ALL questions in a single AskUserQuestion call so the user fills everything out at once:
Question 1 — Purpose (header: "Purpose"): What is this presentation for? Options: Pitch deck / Teaching-Tutorial / Conference talk / Internal presentation
Question 2 — Length (header: "Length"): Approximately how many slides? Options: Short 5-10 / Medium 10-20 / Long 20+
Question 3 — Content (header: "Content"): Do you have content ready? Options: All content ready / Rough notes / Topic only
Question 4 — Inline Editing (header: "Editing"): Do you need to edit text directly in the browser after generation? Options:
Remember the user's editing choice — it determines whether edit-related code is included in Phase 3.
If user has content, ask them to share it.
If user selected "No images" -> skip to Phase 3.
If user provides an image folder:
This phase runs once — when BRAND_CONFIG.md does not exist or is empty/unfilled. It creates the brand configuration that locks every future presentation to the user's visual identity.
Ask how they want to define their brand (header: "Brand Setup"). The recommended path is "From an existing presentation" — most companies already have a deck template that codifies their visual identity (colors, fonts, logo, layout patterns) far more completely than any website does. Make this the first option and label it (Recommended).
Why presentation-first: A deck template includes pre-resolved decisions (logo placement, slide layouts, color hierarchy, font weights for hero vs body) that a website does not. Websites optimize for scrolling and conversion; decks optimize for the same medium we're generating. Use this as the default unless the user specifically asks for one of the other paths.
If "From an existing presentation" (recommended path):
python scripts/extract-pptx.py to extract content, then read the theme XML directly to get the full color scheme, font scheme, and embedded images.89504e470d0a1a0a). Headless Chromium fails silently on corrupted images during PDF export — even if interactive Chrome appears to render them. If <img>.naturalWidth === 0 after load, the encoding is corrupt; re-encode from the source file.filter: brightness(0) invert(1) to render it white on dark backgrounds — no need for a separate white asset.If "From a website":
This path uses dembrandt — a tool that extracts a website's full design system (colors, typography, logo, borders, components) into design tokens in seconds.
Ask the user for the URL.
Prefer the dembrandt MCP server if it's connected (tools named get_brand_identity, get_color_palette, get_typography, get_design_tokens, get_component_styles, get_surfaces, get_spacing). Call get_brand_identity first for the high-level summary, then get_color_palette and get_typography for the specifics.
If the MCP server is not connected, tell the user once: "I can extract richer brand data if you connect the dembrandt MCP server. To enable it, run: claude mcp add --transport stdio dembrandt -- npx -y dembrandt-mcp — but I'll proceed with the CLI now."
CLI fallback: Run npx -y dembrandt <url> --json-only via Bash and parse the resulting JSON. If the site is JavaScript-heavy or behind Cloudflare, retry with --slow or --browser=firefox.
From the extracted tokens, populate:
Watch for web-vs-deck font mismatches. A company's website often uses a commercial display font (e.g. "Factor A" via Adobe Fonts) that isn't on Google Fonts. If the user also has a deck template, ask whether they want the website's font (which may need a paid license) or the deck's font (which is usually already a Google Font). Suggest the closest free Google Fonts equivalent if needed.
Present what was extracted and ask the user to confirm or adjust each piece via AskUserQuestion.
If "From brand guidelines":
If "From scratch":
Ask these questions in a single AskUserQuestion call:
Based on the brand mood and feeling, propose 2-3 font pairings (display + body). Use fonts from Google Fonts or Fontshare — never system fonts. Show the font names, weights, and a brief description of why they fit.
Ask the user to pick one, or suggest their own.
Based on everything gathered, propose 3 signature visual elements that will make the brand's slides distinctive. These are CSS-only patterns — no illustrations, no stock images. Examples:
Present the 3 proposals and let the user pick, modify, or request alternatives.
Generate a single title slide as an HTML file (.claude-design/brand-preview.html) that demonstrates the full brand identity: logo, colors, fonts, signature elements, and animations. Open it for the user.
Ask (header: "Brand Preview"): "Does this look right for your brand?" Options: Looks great / Adjust colors / Adjust fonts / Adjust layout / Start over
Iterate until the user approves.
Once approved, write the final brand configuration to BRAND_CONFIG.md with all values filled in:
Delete .claude-design/brand-preview.html after saving.
Tell the user: "Your brand is saved. Every presentation from now on will use this identity. To change it later, just ask me to update the brand config."
Generate the full presentation using content from Phase 1 and brand identity from BRAND_CONFIG.md.
Before generating, read these files:
Key requirements:
<style> block/* === SECTION NAME === */ comment blockWhen converting PowerPoint files:
python scripts/extract-pptx.py <input.pptx> <output_dir> (install python-pptx if needed: pip install python-pptx).claude-design/ if it existsopen [filename].html to launch in browser:root CSS variables for colors, font link for typography, .reveal class for animationsAfter delivery, ask the user: "Would you like to share this presentation? I can deploy it to a live URL (works on any device including phones) or export it as a PDF."
Options:
If the user declines, stop here. If they choose one or both, proceed below.
This deploys the presentation to Vercel — a free hosting platform. The link works on any device (phones, tablets, laptops) and stays live until the user takes it down.
If the user has never deployed before, guide them step by step:
Check if Vercel CLI is installed — Run npx vercel --version. If not found, install Node.js first (brew install node on macOS, or download from https://nodejs.org).
Check if user is logged in — Run npx vercel whoami.
vercel login and follow the prompts (it opens a browser window to authorize)vercel whoamiDeploy — Run the deploy script:
bash scripts/deploy.sh <path-to-presentation>
The script accepts either a folder (with index.html) or a single HTML file.
Share the URL — Tell the user:
Deployment gotchas:
src="..." in the HTML and bundles them. But if the presentation references files via CSS background-image or unusual paths, those may be missed. Before deploying, verify: open the deployed URL and check that all images load. If any are broken, the safest fix is to put the HTML and all its assets into a single folder and deploy the folder instead of a standalone HTML file.my-deck/index.html + my-deck/logo.png), deploy the folder directly: bash scripts/deploy.sh ./my-deck/. This is more reliable than deploying a single HTML file because the entire folder contents are uploaded as-is.Two export methods are available. Use the vector PDF method first — it's faster, produces dramatically smaller files (~130KB vs ~20MB), preserves selectable text, and renders instantly in macOS Preview. Fall back to the screenshot method only if you encounter rendering issues with specific visual effects.
Note: Animations and interactivity are not preserved in either method — the PDF is a static snapshot. This is normal and expected; mention it to the user so they're not surprised.
Uses Chromium's native PDF renderer with font patching. Produces small, fast, text-selectable PDFs.
npx -p playwright node scripts/export-pdf.js <path-to-html> [output.pdf]
What happens behind the scenes:
Prerequisites:
npx playwright install chromium — browser enginepip3 install fonttools — font patching (only needed if Fontshare fonts are detected)brew install qpdf — PDF linearization (optional but recommended)Typical result: 17-slide deck = ~130KB, instant page flips in Preview, selectable text.
Captures each slide as a PNG screenshot and combines them into a PDF. Use this if Method 1 has rendering issues with specific visual effects (e.g., canvas animations, complex SVGs).
bash scripts/export-pdf.sh <path-to-html> [output.pdf]
Tradeoffs vs Method 1:
--compact flag for smaller files: bash scripts/export-pdf.sh <path> --compactFontshare ships font files with broken metadata. The PostScript name, family name, and full name fields in Fontshare's TTF files are literally set to the string "false". This is not a Chromium bug — it's in the font binary itself. When Chromium embeds these fonts in a PDF, macOS Preview cannot cache or identify them, causing:
The vector PDF script (Method 1) fixes this automatically by downloading the TTF files, patching the name tables with Python fonttools, and injecting the corrected fonts as base64 during generation.
If you're choosing fonts for a new presentation and PDF export is likely needed, prefer Google Fonts. All Google Fonts have correct PostScript metadata and embed cleanly in PDFs without patching.
⚠ Other PDF export gotchas:
class="slide". Both export scripts find slides by querying .slide elements.::before pseudo-elements with hsla() radial gradients create PDF transparency groups. The vector PDF script strips these automatically. The solid --bg-primary background looks clean without them.qpdf --linearize reorganizes the PDF for progressive page loading. Without it, Preview may show white flashes between pages.| File | Purpose | When to Read | | -------------------------------------------------- | --------------------------------------------------------------- | -------------------------------- | | BRAND_CONFIG.md | Brand identity: colors, fonts, logo, signature elements, layouts | Phase 0 (always) + Phase 3 | | viewport-base.css | Mandatory responsive CSS — copy into every presentation | Phase 3 (generation) | | html-template.md | HTML structure, JS features, code quality standards | Phase 3 (generation) | | animation-patterns.md | CSS/JS animation snippets and effect-to-feeling guide | Phase 3 (generation) | | scripts/extract-pptx.py | Python script for PPT content extraction | Phase 4 (conversion) | | scripts/deploy.sh | Deploy slides to Vercel for instant sharing | Phase 6 (sharing) | | scripts/export-pdf.js | Vector PDF export with font patching (recommended) | Phase 6 (PDF export) | | scripts/export-pdf.sh | Screenshot-based PDF export (fallback) | Phase 6 (PDF export) |
development
Create branded HTML presentations using structured slide specs. Outputs JSON DeckSpec instead of raw HTML — the server handles all rendering, styling, and viewport fitting.
data-ai
Create or modify text blocks using update_text_block. Covers template syntax with variable references, LLM generation, and constrained outputs.
data-ai
Create or modify table blocks using update_table_block. Covers template syntax, target_shape constraints, and table generation patterns.
data-ai
Create or modify numerical query blocks within text or table blocks using update_query_block. Queries provide data values referenced as {query_name} in parent templates.