skills/presentation-creator/SKILL.md
Create data-driven presentation slides using React, Vite, and Recharts with Sentry branding. Use when asked to "create a presentation", "build slides", "make a deck", "create a data presentation", "build a Sentry presentation". Scaffolds a complete slide-based app with charts, animations, and single-file HTML output.
npx skillsauth add getsentry/skills presentation-creatorInstall 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 interactive, data-driven presentation slides using React + Vite + Recharts, styled with the Sentry design system and built as a single distributable HTML file.
Ask the user:
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.
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.
Create the project structure:
<project-name>/
├── index.html
├── package.json
├── vite.config.js
└── src/
├── main.jsx
├── App.jsx
├── App.css
└── Charts.jsx
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200&display=swap" rel="stylesheet" />
<title>TITLE</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
{
"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" }
}
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteSingleFile } from 'vite-plugin-singlefile'
export default defineConfig({ plugins: [react(), viteSingleFile()] })
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './App.css'
ReactDOM.createRoot(document.getElementById('root')).render(<App />)
Read references/design-system.md for the complete Sentry color palette, typography, CSS variables, layout utilities, and animation system.
Define slides as an array of functions returning JSX:
const SLIDES = [
() => ( /* Slide 0: Title */ ),
() => ( /* Slide 1: Context */ ),
// ...
];
Each slide function returns a <div className="slide-content"> with:
<h2> heading.anim, .d1, .d2, .d3 for staggered fade-inDo 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.
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.
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 && <div className="glyph-watermark"><SentryGlyph size={50} /><span className="watermark-title">TITLE</span></div>}
<div className="progress" style={{ width: `${((cur + 1) / SLIDES.length) * 100}%` }} />
{SLIDES.map((S, i) => (
<div key={i} className={`slide ${i === cur ? 'active' : ''}`}>
<div className={`slide-content${i === cur ? ' anim' : ''}`}>
<S />
</div>
</div>
))}
<Nav cur={cur} total={SLIDES.length} go={go} setCur={setCur} />
</>
);
}
IMPORTANT: Only create charts for slides backed by real, concrete data from the source content. If a slide's content is qualitative (strategies, learnings, process descriptions, opinions), use text-based layouts instead (cards, tables, bullet lists, columns). Never invent numbers, fabricate percentages, or generate synthetic data to populate a chart. If you are unsure whether data is real or inferred, do NOT create a chart.
If NO slides require charts, skip this step entirely — do not create Charts.jsx or import Recharts.
When real data IS available, read references/chart-patterns.md for Recharts component patterns including axis configuration, color constants, chart types, and data generation techniques.
Put all chart components in Charts.jsx. Key patterns:
ResponsiveContainer with explicit height.chart-wrap div with max-width 920pxuseMemo for data generationCAT[]) for distinguishing data series and groups. Only use semantic colors (SEM_GREEN, SEM_RED, SEM_AMBER) when the color itself carries meaning (good/bad, success/failure, warning).ComposedChart with stacked Area/Line, BarChart, custom SVG diagramsApply the complete CSS from the design system reference. Key elements:
--purple, --dark, --muted). Semantic CSS variables (--semantic-green, --semantic-red, --semantic-amber) only where color conveys meaning. Categorical palette (CAT[]) for all other data visualization.fadeUp keyframe with staggered delays.cols flex rows, .cards grid, .chart-wrap containers.tag-purple, .tag-red, .tag-green, .tag-amber for slide labelsreferences/sentry-logo.svg (full wordmark) or references/sentry-glyph.svg (glyph only). Do NOT hardcode an approximation — always use the exact SVG paths from these files.Logo (from references/sentry-logo.svg or references/sentry-glyph.svg) + h1 + subtitle + author/date info.
Tag + heading + 2-column card grid with icon headers.
Tag + heading + side-by-side charts or before/after comparison table.
Tag + heading + full-width chart + annotation bullets below.
Tag + heading + 3-column layout with category headers and bullet lists.
After initial scaffolding:
npm install && npm run dev to start the dev servernpm run build produces a single HTML file in dist/A working React + Vite project that:
Charts.jsx and the Recharts dependency entirely if no slides have real datatools
Analyze a repository to generate recommended Claude Code settings.json permissions. Use when setting up a new project, auditing existing settings, or determining which read-only bash commands to allow. Detects tech stack, build tools, and monorepo structure.
development
Triage new issues in the Sentry `javascript` project by archiving non-actionable noise. Use when asked to "triage issues", "triage the javascript project", "archive non-actionable issues", "triage new frontend issues", or "clean up the sentry/javascript queue". Operates only on the sentry/javascript project, only archives (never resolves), and always archives with `untilEscalating`.
documentation
Append a GitHub issue link and its Linear ticket to the current PR's description. Use when asked to "link issue to pr", "fill in issue and linear in pr", "add issue refs to pr", or when given a GitHub issue URL and asked to attach it to the current PR. Resolves the Linear ticket automatically from the issue's linear-linkback comment.
testing
Iterate on a PR until actionable CI passes and high/medium review feedback is addressed. Use for PR CI failures, review feedback, or green-check loops; do not wait for human approval, draft status, or merge gates.