--- id: getsentry/skills/presentation-creator version: "5e352201" license: Apache-2.0 install: manual updated: 2026-07-27 --- # presentation-creator — Presentation Creator scaffolds a complete slide-based React application with Recharts data visualization, keyboard navigation, and Sentry design system styling. It outputs a single distributable HTML file and enforces real data validation—charts are only generated when source content contains concrete quantitative data, never fabricated numbers. Publisher: getsentry · Stars: 891 · Updated: 2026-07-27 Install (manual): `git clone https://github.com/getsentry/skills` ## SKILL.md # Sentry Presentation Builder Create interactive, data-driven presentation slides using React + Vite + Recharts, styled with the Sentry design system and built as a single distributable HTML file. ## Step 1: Gather Requirements Ask the user: 1. What is the presentation topic? 2. How many slides (typically 5-8)? 3. What data/charts are needed? (time series, comparisons, diagrams, zone charts) 4. What is the narrative arc? (problem → solution, before → after, technical deep-dive) ### Data Assessment (CRITICAL) Before designing any slides, assess whether the source content contains **real quantitative data** (numbers, percentages, measurements, time series, costs, metrics). Only create Recharts visualizations for slides where real data exists. Do NOT fabricate, estimate, or invent data to fill charts. - **Has real data** → use a Recharts chart (bar, area, line, etc.) - **Has no data** → use text-based layouts: cards, tables, bullet columns, diagrams, or quote blocks. Do NOT create a chart with made-up numbers. If the source content is purely qualitative (narrative, opinions, strategy, process descriptions), the presentation should use zero charts. Recharts and `Charts.jsx` should only be included in the project if at least one slide has real data to visualize. ## Step 2: Scaffold the Project Create the project structure: ``` / ├── index.html ├── package.json ├── vite.config.js └── src/ ├── main.jsx ├── App.jsx ├── App.css └── Charts.jsx ``` ### index.html ```html TITLE
``` ### package.json ```json { "name": "PROJECT_NAME", "private": true, "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "react": "^18.3.1", "react-dom": "^18.3.1", "recharts": "^2.15.3" }, "devDependencies": { "@vitejs/plugin-react": "^4.3.4", "vite": "^6.0.0", "vite-plugin-singlefile": "^2.3.0" } } ``` ### vite.config.js ```javascript import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import { viteSingleFile } from 'vite-plugin-singlefile' export default defineConfig({ plugins: [react(), viteSingleFile()] }) ``` ### main.jsx ```jsx import React from 'react' import ReactDOM from 'react-dom/client' import App from './App' import './App.css' ReactDOM.createRoot(document.getElementById('root')).render() ``` ## Step 3: Build the Slide System Read `references/design-system.md` for the complete Sentry color palette, typography, CSS variables, layout utilities, and animation system. ### App.jsx Structure Define slides as an array of functions returning JSX: ```jsx const SLIDES = [ () => ( /* Slide 0: Title */ ), () => ( /* Slide 1: Context */ ), // ... ]; ``` Each slide function returns a `
` with: 1. An `

` heading 2. Optional subtitle paragraph 3. Main content (charts, cards, diagrams, tables) 4. Animation classes: `.anim`, `.d1`, `.d2`, `.d3` for staggered fade-in Do NOT add category tag pills/badges above headings (e.g., "BACKGROUND", "EXPERIMENTS"). They look generic and add no value. Let the heading speak for itself. ### Navigation Implement keyboard navigation (ArrowRight/Space = next, ArrowLeft = prev) and a bottom nav overlay with prev/next buttons, dot indicators, and slide number. The nav has **no border or background** — it floats transparently. A small low-contrast Sentry glyph watermark sits fixed in the top-left corner of every slide. ```jsx function App() { const [cur, setCur] = useState(0); const go = useCallback((d) => setCur(c => Math.max(0, Math.min(SLIDES.length - 1, c + d))), []); useEffect(() => { const h = (e) => { if (e.target.tagName === 'INPUT') return; if (e.key === 'ArrowRight' || e.key === ' ') { e.preventDefault(); go(1); } if (e.key === 'ArrowLeft') { e.preventDefault(); go(-1); } }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [go]); return ( <> {cur > 0 &&
TITLE
}
{SLIDES.map((S, i) => (
))}