Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Generates dark-themed, accessible data visualization components using Chart.js or Recharts. Produces glass morphism styled charts that match the user's design system with proper accessibility, responsive sizing, and performance optimization. Triggered when the user asks to create a chart, visualize data, add a graph, or build a dashboard component.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 79% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 22% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 90% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 16% | 0% |
Dark-themed, accessible data visualization generator.
Activate this skill when the user:
| Scenario | Library | Reason | |----------|---------|--------| | Standalone chart, no React | Chart.js | Lightweight, canvas-based | | React/Next.js project | Recharts | Native React components, composable | | Complex interactive dashboards | Recharts | Better state management integration | | Static image export needed | Chart.js | Canvas toDataURL() support |
All charts must follow these design tokens to match the user's dark theme:
jsconst chartTheme = { background: '#18181B', // zinc-900 surface: 'rgba(255,255,255,0.05)', // glass bg border: 'rgba(255,255,255,0.10)', // glass border gridLines: 'rgba(255,255,255,0.06)', labelText: '#D4D4D8', // zinc-300 valueText: '#F4F4F5', // zinc-100 tooltip: { bg: 'rgba(24,24,27,0.90)', border: 'rgba(255,255,255,0.10)', blur: '16px', }, };
Use these for data series — ordered by visual priority:
| Index | Name | Hex | Use case | |-------|------|-----|----------| | 0 | Blue | #3B82F6 | Primary metric | | 1 | Purple | #8B5CF6 | Secondary metric | | 2 | Emerald | #10B981 | Positive/growth | | 3 | Amber | #F59E0B | Warning/attention | | 4 | Rose | #F43F5E | Negative/decline | | 5 | Cyan | #06B6D4 | Tertiary metric |
Wrap every chart in a glass container:
jsx<div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6"> <h3 className="text-zinc-100 text-lg font-semibold mb-4">{title}</h3> <div className="min-h-[300px]" role="img" aria-label={ariaLabel}> {/* Chart component */} </div> </div>
Best for: trends over time, continuous data.
linearGradient from accent to transparent)type="monotone" (Recharts) or tension: 0.4 (Chart.js)Best for: comparisons between categories.
radius={[4, 4, 0, 0]}Best for: volume/magnitude over time.
Best for: part-to-whole relationships (max 6 segments).
Best for: correlation between two variables.
Best for: multi-dimensional comparison (3-8 axes).
Every chart must include:
jsx <div role="img" aria-label="Monthly revenue trend showing 23% growth from January to June 2025">
css @media (prefers-reduced-motion: reduce) { .chart-container * { animation: none !important; transition: none !important; } }
jsx <table className="sr-only"> <caption>Monthly revenue data</caption> {/* Full data in tabular form */} </table>
zinc-900).responsive: true / width="100%")min-h-[300px] on the wrapper to prevent CLS@media print)Charts are heavy — always lazy load:
jsximport dynamic from 'next/dynamic'; const RevenueChart = dynamic(() => import('@/components/charts/RevenueChart'), { loading: () => ( <div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6 min-h-[300px] animate-pulse" /> ), ssr: false, });
ssr: false — canvas/SVG charts need the DOMjsxconst CustomTooltip = ({ active, payload, label }) => { if (!active || !payload) return null; return ( <div className="backdrop-blur-xl bg-zinc-900/90 border border-white/10 rounded-lg px-3 py-2 shadow-xl"> <p className="text-zinc-400 text-xs mb-1">{label}</p> {payload.map((entry, i) => ( <p key={i} className="text-zinc-100 text-sm font-medium"> <span style={{ color: entry.color }}>●</span> {entry.name}: {entry.value} </p> ))} </div> ); };
Other measured skills in the registry, with their headline benchmark lift.