Slide sage
Show your presentations with charts, diagrams, and code highlighting. Works with most AI coding tools (Claude Code, Codex, Cursor, AMP).
npx -y skills add rhnfzl/slide-sage --skill slide-sageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Create or enhance a data-rich, single-file HTML slide deck or pitch deck. Use when the user asks for a new presentation, to convert a PowerPoint (.pptx) or PDF into an HTML deck, or to improve an existing HTML presentation. Not for native PowerPoint editing or high-fidelity PPTX export.
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
28.7 KB, as published. Nobody here has run it
Slide Sage
Create data-rich, interactive HTML presentations as a single HTML runtime with charts, diagrams, and code highlighting.
Core Principles
- Data-First - Charts, diagrams, and metrics are first-class citizens, not afterthoughts
- Single HTML Runtime - Keep presentation HTML, CSS, and JavaScript in one file. Use an
assets/directory only for many or large images. Load pinned libraries from a CDN by default. When offline delivery is requested, runscripts/inline-vendor.pyafter generation and keep the bundled notices with the output. - Viewport Fitting (NON-NEGOTIABLE) - Every slide fits exactly within 100vh. No scrolling. Content overflows? Split into multiple slides
- Adaptive Intelligence - When given raw data, act as narrative director. When given a clear outline, act as layout executor
- Colorblind Safe - All data visualization uses accessible color palettes by default
- Utility-First CSS (NON-NEGOTIABLE) - Define CSS classes in
<style>before referencing them in HTML. Never use inlinestyle="..."for properties that repeat across 2+ elements. Readreferences/css-class-inventory.mdfor all available classes
Anti-slop design doctrine
Every visual choice must clarify a claim, comparison, hierarchy, or state. Do not use generic dashboard gradients, floating glass cards, repeated glowing borders, or an accent color as decoration. Do not default to Inter or the Catppuccin values #1e1e2e, #cdd6f4, and #89b4fa. Commit to one named preset, use its tokens for the interface, use the Tier 1 palette for data, and give each slide one intentional focal point. Limit a slide to one orchestrated reveal sequence. A literal hex belongs only in the selected preset, Tier 1 palette, or an intentional visual asset.
Charts represent supplied facts. Never silently invent numbers, percentages, sources, or time periods.
Phase 0: Detect Mode
Determine what the user wants:
- Mode A: New Presentation - Create from scratch. Go to Phase 1
- Mode B: PPT/PDF Conversion - User provides a .pptx or .pdf file. Extract content with
scripts/extract-pptx.pyorscripts/extract-pdf.py, then treat extracted JSON as input for Mode A - Mode C: Enhancement - User references an existing HTML file. Read it first, understand its style and structure, then add/modify slides while preserving consistency
Mode C Rules
When enhancing existing presentations:
- Read the existing HTML file completely before making changes
- Match the existing style preset, fonts, colors, and animation level
- Check content density before adding - respect slide type limits
- If modifications cause overflow, split into additional slides automatically
- Preserve all existing speaker notes and keyboard navigation
Phase 1: Gap-driven intake
Infer audience and style from a detailed prompt and state the choice in one line. Ask only when the prompt is genuinely thin. Never block in one-shot, subagent, or CI runs: choose sensible defaults and state them in one line. Offer a visual preview only when style is unspecified and a browser is available.
When an interactive response would materially change the deck, ask one focused question. The visual preview is optional and must not delay generation.
Genuine gaps
| Gap | Focused question |
|---|---|
| No data provided but the topic requires factual chart data | "Do you have the numbers and their source?" |
| Scope is too ambiguous to choose a useful slide count | "Roughly how many slides? (5 for a quick update, 15+ for a deep dive)" |
| The prompt does not say who reads the slide | "Will you present this live, send it to be read on its own, or both?" |
| The prompt does not say how much prose belongs beside the visuals | "Diagram-led, balanced, or text-rich?" |
Never ask about: animation level (detect from audience), library choices (auto-select), file format (auto-detect), presenter mode (included automatically whenever the deck has speaker notes, see Reader and density), or brand information when a named preset is sufficient.
Reader and density
These two answers decide more about whether a deck lands than the preset does, and neither is inferable from the audience. A leadership deck can be diagram-led or text-rich. The same deck can be presented or forwarded. Treat both as genuine gaps unless the prompt states them, because a prompt almost never does.
Reader decides WHERE the context lives:
| Answer | Slide face | Speaker notes |
|---|---|---|
present | Stays clean. The room reads the slide, the presenter reads the notes. | Carry the recall material. Presenter mode ships. |
send | Must carry the context. Nobody is there to explain it. | Fold onto the slide instead. A note nobody opens is a note nobody reads. |
both (default) | Readable standalone. | Carry the extra depth. Presenter mode ships. |
Density decides HOW MUCH prose sits beside the visual:
| Answer | Shape of a content slide |
|---|---|
diagram-led | Diagram or example is the slide. At most 3 short lines, and only for what the diagram cannot say. |
balanced (default) | One plain-language lead sentence, the diagram, then 4 to 6 points. |
text-rich | Full sentences. The reason, the tradeoff, and the caveat all sit on the slide face. |
Ask both in one turn when both are missing. State the inferred answers in one line when the prompt gives them.
The failure this prevents. Terse and dense are both wrong when guessed, and guessing tends to overcorrect: a deck stripped to diagrams starves the presenter of anything to recall from, and a deck padded to explain everything walls off the room it is shown to. "Too much text" on a previous deck does NOT mean diagram-led on the next one; it means the reader and density were never separated. Ask instead of swinging.
Never let the presenter's half be invisible. If the recall material only exists in a place the presenter cannot see while presenting, it does not exist. Speaker notes without presenter mode are exactly that failure.
Large decks
For a presentation with more than 15 slides, share a brief outline only when it resolves a genuine scope gap in an interactive run. Otherwise choose a sensible structure, state it in one line, and continue.
Phase 2: Content Analysis
Analyze the user's content to determine what's needed.
Detect Content Types
Scan the user's message for:
| Signal | Content Type | Action |
|---|---|---|
| Numbers, metrics, KPIs, percentages | Data/Charts | Read references/viz-integration.md |
| "Architecture", "flow", "system design", "pipeline" | Diagrams | Read references/diagram-patterns.md (CSS/HTML preferred, SVG templates, inline SVG) |
| Code snippets, "API", "endpoint", function names | Code slides | Read references/code-highlighting.md |
| Comparative language ("vs", "compared to", "before/after") | Comparison slides | Use comparison templates |
| JSON/CSV data pasted or file referenced | Data parsing | Parse inline or read file |
| .pptx file path | PPT conversion | Run scripts/extract-pptx.py |
| .pdf file path | PDF conversion | Run scripts/extract-pdf.py |
| Images referenced | Image processing | Use scripts/process-images.py if needed |
| Architecture with specific tech (DB, cloud, auth, security) | Icons | Read references/icon-library.md |
Library Selection (Silent)
Based on content types, decide which CDN libraries to include. Do NOT ask the user - just select:
| Need | Library | CDN |
|---|---|---|
| Bar, line, pie, scatter, radar charts | Chart.js 4.4 | cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js |
| Heatmap, sankey, treemap | ECharts 6.1 | cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js |
| Custom statistical charts | D3.js v7 | cdn.jsdelivr.net/npm/[email protected]/dist/d3.min.js |
| Network/dependency graph | Cytoscape.js | cdn.jsdelivr.net/npm/[email protected]/dist/cytoscape.min.js |
| Calendar/activity heatmap | Frappe Charts | cdn.jsdelivr.net/npm/[email protected]/dist/frappe-charts.min.umd.js |
| Code syntax highlighting | Prism.js | cdn.jsdelivr.net/npm/[email protected]/prism.min.js |
| Number animations | CountUp.js | cdn.jsdelivr.net/npm/[email protected]/dist/countUp.umd.min.js |
| Typing effects (title slides) | Typed.js | cdn.jsdelivr.net/npm/[email protected]/dist/typed.umd.js |
| Hand-drawn diagram accents | Rough.js | cdn.jsdelivr.net/npm/[email protected]/bundled/rough.min.js |
| Generative backgrounds | q5.js | cdn.jsdelivr.net/npm/[email protected]/q5.js |
| Icons for diagrams/content | Lucide (inline) | Inline SVG paths from templates/icons/lucide-sprite.svg - no CDN needed |
Default: If the presentation has only text, include NO extra libraries. CSS animations suffice. Use CDN libraries by default. If the user explicitly needs offline delivery, create the deck first, run scripts/inline-vendor.py, and keep THIRD_PARTY_NOTICES.md with the offline copy. Do not call a deck offline if the converter reports an unsupported static remote asset.
Detect Animation Level
| Audience Signal | Level |
|---|---|
| "Technical", "engineers", "developers", "code review" | Minimal |
| "Business", "stakeholders", "team update" | Balanced |
| "Pitch", "investors", "conference", "keynote", "wow" | Dramatic |
| No signal | Balanced (default) |
Detect File Format
- Less than 3 small images → Single HTML file (images as data URIs)
- Many images or large images → HTML file + assets/ folder
Phase 3: Style Selection
Read references/style-guide.md for the full style system.
Three-Tier System
Tier 1: Data-Viz Palettes - Always applied. Colorblind-safe chart colors regardless of aesthetic choice.
Tier 2: Named Presets - Choose by the requested tone first, then use content type only as a tie-breaker. Read the compact index in references/style-guide.md and load the matching file from references/presets/.
Tier 3: Custom Theme - If user provides brand colors, generate a custom theme using the theme builder algorithm.
Style Application
- Set
data-themeanddata-modeon<html>from the chosen preset - Add the preset's matching font
<link>in<head>before the presentation<style>block. If CSS is the only option, place the preset's@importas the first stylesheet statement, beforeviewport-base.cssand all other rules. - Inline the selected preset CSS with its system-font fallback, then inline
viewport-base.cssso the base classes consume the preset tokens. - Use the Tier 1 palette for charts, independently of the preset accent
- Apply the preset's light or dark default unless the user overrides it
Phase 4: Generate Presentation
Step 1: Read Required References
Always read:
references/html-template.md- Base HTML structure, SlidePresentation classreferences/viewport-system.md- Responsive CSS rulesassets/viewport-base.css- Core CSS to inlinereferences/css-class-inventory.md- Available CSS classes and inline style rules
Conditionally read (based on Phase 2 analysis):
references/viz-integration.md- If charts/datareferences/diagram-patterns.md- If architecture/flow diagramsreferences/animation-guide.md- For animation patterns at detected levelreferences/code-highlighting.md- If code snippetsreferences/presenter-mode.md- Whenever the deck has speaker notes, which is every deck whose reader ispresentorboth. Not optional: notes the presenter cannot open during the talk are notes that do not exist. Skip only for asenddeck, where the notes are folded onto the slide instead.
Step 2: Plan Slide Structure
Before generating, plan the slide deck:
- Title slide - Presentation title, subtitle, date/author
- Agenda/Overview slide - If 8+ slides
- Content slides - One concept per slide, respect density limits:
- Title: 1 heading + 1 subtitle
- Content: 1 heading + 4-6 bullets OR 2 short paragraphs
- Chart: 1 heading + 1 chart (max 55vh height) + optional caption
- Code: 1 heading + 10-12 lines of code
- Diagram: 1 heading + 1 diagram (max 60vh)
- Comparison: 1 heading + 2 columns
- Quote: 1 quote (max 3 lines) + attribution
- Image: 1 heading + 1 image (max-height: min(50vh, 400px))
- Key takeaway / Summary slide - If 8+ slides
- Closing slide - Thank you, contact, or call to action
The numbers above are the balanced default. The density answer from Phase 1 scales the prose, never the viewport rule:
| Density | Content slide | Diagram and chart slides |
|---|---|---|
diagram-led | 1 heading + at most 3 short lines | The visual is the slide. Add a line only for what the visual cannot say. |
balanced | 1 heading + 1 lead sentence + 4-6 bullets | Visual + 2-3 supporting lines |
text-rich | 1 heading + 4-6 full sentences, carrying the reason and the caveat | Visual + the explanation that would otherwise be a speaker note |
Density changes how much goes on a slide. It never changes the 100vh rule. Content that does not fit still splits into another slide at every density.
Content exceeds limits? Split into multiple slides. Never cram, never scroll.
Step 3: Generate HTML
Structure the HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[Presentation Title]</title>
<link href="[Google Fonts URL]" rel="stylesheet">
<style>
/* viewport-base.css (inlined) */
/* Chosen style preset CSS variables */
/* Animation keyframes for detected level */
/* Code theme CSS (if code slides) */
/* Prism.js theme (if code slides) */
</style>
</head>
<body>
<div class="slides-container">
<div class="slide" id="slide-1">
<div class="slide-content">
<!-- Slide content -->
</div>
</div>
<!-- More slides -->
</div>
<script id="speaker-notes" type="application/json">[{"slide":1,"notes":"Speaker note text"}]</script>
<div class="progress-bar"><div class="progress-fill"></div></div>
<div class="slide-counter"></div>
<!-- CDN libraries (only those needed) -->
<script src="[Chart.js CDN if needed]"></script>
<script src="[Prism.js CDN if needed]"></script>
<script>
// SlidePresentation class (from html-template.md)
// Chart initializations
// Diagram template rendering
// Prism.highlightAll() - MUST call after DOM ready
</script>
</body>
</html>
Step 4: Chart Generation
When creating charts, follow these rules:
- Use Chart.js as default (covers 80% of chart needs)
- Place canvas in a responsive container:
max-height: min(55vh, 420px) - Apply colorblind-safe palette from Tier 1
- Match chart text colors to the presentation theme
- Set animation based on detected level (minimal →
animation: false) - Max 2 charts per slide in a side-by-side flexbox layout
- Include axis labels and a legend where appropriate
Step 5: Diagram Generation
Use a CSS-first approach for all diagrams.
Tier 0: CSS/HTML Diagrams (PREFERRED - use for 80% of diagrams)
Styled divs with flexbox/grid, borders, and accent colors. Full theme integration, perfect sizing, zero dependencies. Use the utility classes from viewport-base.css:
- Sequence flows →
.sequence-flow,.seq-participants,.seq-actor,.seq-step,.seq-arrow - Architecture stacks →
.arch-stack,.arch-row,.arch-row-group - Pyramids/hierarchies →
.pyramid,.pyramid-layer - Process flows →
.process-flow,.process-step,.process-arrow - Comparisons →
.card-accent,.card-top-accentwith CSS Grid
See references/diagram-patterns.md Tier 0 for complete HTML patterns.
Tier 1: SVG Templates - If the diagram matches a common pattern, use a pre-designed SVG template from templates/diagrams/. Available: microservices, data-pipeline, client-server, layered-arch, cicd-pipeline, hub-and-spoke, cloud-three-tier, kubernetes-cluster, event-driven-pubsub, ml-pipeline, c4-context, network-zones, api-gateway-auth, pyramid-roadmap, funnel, nested-scopes, tree-hierarchy. Write only the data object (~200-400 chars)
Tier 2: Inline SVG - Only for fully custom diagrams needing precise geometry (network topologies, custom shapes). Use viewBox + preserveAspectRatio + CSS variables for colors. Never use raw coordinate math for arrows - use CSS borders or SVG <marker> with clean polygon definitions.
For diagram style:
- Clean geometric (default) - Rounded corners, soft colors, professional
- Hand-drawn (user opts in) - Apply Rough.js to shapes for sketch-style
Step 5b: Icon Integration
When slides reference specific technologies or infrastructure components, enhance visual recognition with icons from the curated Lucide icon set.
When to use icons:
- Architecture diagrams mentioning specific tech (database, cloud, auth, server)
- Process steps or workflow slides where icons aid scanning
- KPI/metric cards where a category icon adds context
- Bullet lists with technical items (optional, don't overuse)
How to include:
- Read
references/icon-library.mdfor the full icon catalog and path data - Include the hidden sprite block from
templates/icons/lucide-sprite.svgat the top of<body>(before slides) - Reference icons via
<use href="#icon-name">inside inline SVG diagrams - Or use standalone
<svg class="icon">elements in HTML slide content
Icon sizing:
- In SVG diagrams:
width="20" height="20"for standard boxes,width="16" height="16"for small contexts - In HTML content: use the
.iconCSS class (1.2em, inherits text color)
Rules:
- Icons are always optional - never required. Templates work perfectly without them
- Only include the sprite block when at least one slide uses icons (don't add unused dependencies)
- Icons inherit
currentColor- they automatically match the presentation theme - Prefer icons that reinforce the component's function: database→database, auth→shield, API→plug, cloud→cloud
Step 6: Comparison Slides
When content involves comparisons (before/after, pros/cons, A vs B):
- Use split-view layout from
templates/comparison/split-view.html - Or feature matrix from
templates/comparison/feature-matrix.html - Color-code columns with accent and secondary accent colors
Step 7: Visual Polish (Applied by Default)
Apply visual depth only when it makes a claim easier to read. Keep one orchestrated reveal sequence per slide at most.
| Technique | Minimal | Balanced | Dramatic |
|---|---|---|---|
Card accent borders (.card-accent) | Yes | Yes | Yes |
Badge labels (.badge) | Yes | Yes | Yes |
Tight heading typography (.tight-heading) | Yes | Yes | Yes |
Background grid (.bg-grid) | No | Yes | Yes |
Staggered reveal animations (.reveal) | No | Yes | Yes |
Section labels (.section-label) | No | Yes | Yes |
Glow effects (.glow) | No | No | Yes |
Glow pulse (.glow-pulse) | No | No | Yes |
How to apply:
- Add
bg-gridonly when a technical or data-led tone benefits from it - Add
revealonly to one related sequence of elements on a slide - Add
card-accentorcard-top-accentonly where cards clarify grouping - Use
badgeclasses for labels, step numbers, and status indicators - Add
glowto one key accent element only for a dramatic deck - Use
tight-headingon main headings for tighter letter-spacing - Use
inline-codeclass for short code references in text (e.g.,FallbackModel(...))
See references/style-guide.md "Visual Depth Techniques" section for full details.
Step 8: Code Slide Quality
When generating code slides:
- Always specify the language class on
<code>elements:<code class="language-python"> - Call
Prism.highlightAll()in the initialization script after DOM ready - Max 10-12 lines per code block - if more, split across slides
- For inline code references (like
FallbackModel(...)in a paragraph), use<code class="inline-code">- do NOT create a separate code block - Style code containers with proper padding, border-radius, and a code-appropriate background
See references/code-highlighting.md for Prism.js initialization requirements.
Phase 5: Deliver
Pre-Delivery Validation (MANDATORY)
Before writing the final HTML file, perform these checks. This takes 30 seconds and prevents silent visual regressions.
Check 1: Class Integrity
Scan every class="..." attribute in the generated HTML. For each class name:
- Is it in
viewport-base.css? → OK - Is it in a comparison template you used? → OK
- Is it defined in this presentation's
<style>block? → OK - Is it a standard class from a CDN library (e.g., Prism.js)? → OK
- None of the above? → BUG. Define the class in
<style>or use the correct existing class name.
Common traps:
| Wrong (invented) | Fix |
|---|---|
section-label | Available in viewport-base.css - use directly |
metric-card | Define .metric-card in <style>, or use .kpi-card from KPI template |
slide-header | Use <h2> element (already styled by viewport-base.css) |
highlight | Define .highlight in <style> with specific styles |
content-box | Use .slide-content or .card |
Check 2: Inline Style Audit
Count style=" occurrences across all slides. Calculate per-slide average.
- Target: max ~3 inline styles per slide average
- If over threshold: Identify repeating patterns and extract to CSS classes
- Common offenders:
style="color: ...",style="font-size: ...",style="display: flex; gap: ..."
Check 3: Repeating Pattern Detection
Search for any inline style value that appears on 3+ elements. Extract to a class:
- Three
style="font-size: 0.85rem; color: rgba(255,255,255,0.6)"→.muted-textclass - Four
style="display: flex; gap: 1rem; align-items: center"→.flex-row .gap-mdor custom class - Multiple
style="background: rgba(255,255,255,0.05); border-radius: 8px; padding: 1rem"→.surface-cardclass
Check 4: Theme Variable Usage
Verify that custom CSS classes use theme variables, not hard-coded values:
- Colors:
var(--color-accent)not#3366cc - Spacing:
var(--spacing-md)not1.25rem - Fonts:
var(--font-mono)not'JetBrains Mono' - Radius:
var(--radius)not12px
This ensures the presentation respects the chosen theme and can be re-themed by changing :root variables.
Check 5: Run the static fallback
Run scripts/validate presentation.html. It checks class integrity, inline-style density, and theme-variable references without requiring browser automation. When a browser is available, also capture two or three representative slides and inspect console errors and overflow before delivery.
Check 6: The presenter can reach their own notes
If the deck has a speaker-notes block, presenter mode must be wired, or the notes are unreachable during the talk and the presenter is left recalling from memory. Confirm both: the notes block covers every slide, and pressing P opens them. A send deck has no notes to reach because its context is on the slide face instead. Never ship notes with no way to open them.
Output
- Write the HTML file to the user's specified path (or suggest a reasonable filename like
presentation.html) - Briefly mention:
- How to open: "Open in any browser"
- Keyboard shortcuts: "Use arrow keys to navigate, '?' for help"
- PDF export: "Run
scripts/export-pdf presentation.html; Browser Print > Save as PDF remains a fallback" - Presenter mode: "Press 'P' for presenter view with your speaker notes" whenever the deck ships notes. Say it plainly, because a presenter who does not know the notes are there gets no value from them.
- Note the tech stack used: "Built with [Chart.js, Prism.js] via CDN"
- State the reader and density the deck was built at, in one line ("Built diagram-led, for presenting live; press P for your notes"). It tells the user what to push back on if it reads wrong.
Do NOT
- Do NOT ask for approval before writing the file - just generate it
- Do NOT explain every design decision - the user wants a presentation, not a design document
- Do NOT include unused libraries - only CDN scripts that are actually referenced
Data Input Handling
Inline Data
If the user provides numbers in their message, extract and structure them:
- "Revenue went from $2.1M to $2.8M" → bar/line chart data
- Table of values → appropriate chart type
- Percentages → pie/doughnut or bar chart
JSON/CSV Data
If the user pastes or references structured data:
- Parse the structure
- Identify what maps to labels vs values
- Choose the best chart type for the data shape
- Generate the chart configuration
Data Description
If the user describes data without specific numbers:
- In an interactive run, ask for the numbers and their source before plotting a chart.
- In a one-shot, non-interactive, subagent, or CI run, continue with clearly-labeled
SAMPLE DATAonly. - Put a visible
SAMPLE DATAbadge on the chart slide and this speaker note:SAMPLE DATA, replace before sharing. - Never present sample values as factual evidence or cite an invented source.
Viewport Fitting - Critical Rules
These apply to EVERY slide in EVERY presentation:
.slidehasheight: 100vh; height: 100dvh; overflow: hidden;- ALL font sizes use
clamp(min, preferred, max)- never fixed px/rem - Images:
max-height: min(50vh, 400px); width: auto; object-fit: contain; - Charts: container
max-height: min(55vh, 420px) - Diagrams: container
max-height: min(60vh, 450px) - Code blocks:
max-height: min(55vh, 400px); overflow: hidden; - Include height breakpoints: @media (max-height: 700px), 600px, 500px
- Include
prefers-reduced-motionsupport - Include
@media printstyles that show every slide, hide navigation, and preserve backgrounds - Never negate CSS functions directly - use
calc(-1 * clamp(...))
If content doesn't fit → split into multiple slides. Never scroll.
Inline Style Rules - Critical
These rules prevent the #1 cause of post-generation cleanup.
When Inline Styles Are ACCEPTABLE
- One-off positioning: A single element needs
position: absolute; top: 15%; left: 60% - Animation delays:
style="--stagger-index: 3"orstyle="animation-delay: 0.3s" - Dynamic computed values: Chart container heights that depend on data count
- SVG presentation attributes:
fill,stroke,transforminside<svg>elements
When Inline Styles Are FORBIDDEN
- Font size, color, padding, margin, gap, display - Always use a class
- Any property on 2+ elements - If you write the same style twice, make it a class
- Background colors on cards/containers - Use a class with theme variable
- Typography styling (font-family, font-weight, text-transform, letter-spacing) - Always a class
The 3-Strike Rule
Before writing style="..." on an element, check:
- Does this property appear on any other element? → Make a class
- Is this a standard layout property (display, flex, grid, gap, padding, margin)? → Make a class
- Could this be expressed with a theme variable? → Make a class
If all three answers are "no", the inline style is acceptable.
Generation Workflow for Custom Slide Types
When creating a new slide type (metric cards, section headers, tech stack grids, etc.):
- Define the CSS class(es) in
<style>first - Use theme variables (
var(--color-accent),var(--spacing-md), etc.) - Apply the class in HTML
- If multiple visual variants needed, use modifier classes (
.card.highlight,.step.active)
Accessibility
- Colorblind-safe palettes for ALL data visualization (Tier 1 always active)
- Semantic HTML: proper heading hierarchy, alt text for images
- Keyboard navigation: full keyboard support, visible focus indicators
prefers-reduced-motion: disable all animations and transitions@media print: clean print output, one slide per page- Sufficient color contrast (WCAG AA minimum)
aria-labelon interactive elements (chart canvases, nav buttons)
Cross-Platform Notes
This skill works across AI coding tools. Some capabilities vary:
- WebFetch available (Claude Code, Gemini CLI): Can verify CDN URLs are current
- WebFetch unavailable (Codex CLI, Cursor): Use the pinned CDN URLs above - they are stable
- Subagents available (Claude Code): Can parallelize chart research and generation
- Subagents unavailable (most tools): Sequential generation works fine
- Bash available (all): Required for PPT conversion scripts and image processing
- File reading (all): Required for Mode C (enhancement) and reference file loading