---
name: 0xjitsu/chart-builder
source: https://app.decimal.ai/s/0xjitsu-chart-builder@1/SKILL.md
source_sha256: ca3e028483ef
---

# Chart Builder Skill

Dark-themed, accessible data visualization generator.

## When to Trigger

Activate this skill when the user:
- Asks to create a chart, graph, or data visualization
- Wants to visualize data from an API, database, or static dataset
- Requests a dashboard component with charts
- Needs to display metrics, trends, or comparisons visually

## Stack Selection

| 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 |

## Design System

All charts must follow these design tokens to match the user's dark theme:

### Colors

```js
const 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',
  },
};
```

### Accent Palette

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 |

### Glass Morphism Container

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>
```

## Chart Types

### Line Chart
Best for: trends over time, continuous data.
- Use gradient fill below the line (`linearGradient` from accent to transparent)
- Smooth curves: `type="monotone"` (Recharts) or `tension: 0.4` (Chart.js)
- Show data points on hover only (reduce visual clutter)

### Bar Chart
Best for: comparisons between categories.
- Rounded top corners: `radius={[4, 4, 0, 0]}`
- Max bar width: 48px (prevent oversized bars on few data points)
- Add value labels above bars for small datasets (under 8 items)

### Area Chart
Best for: volume/magnitude over time.
- Stack multiple areas for composition views
- Use decreasing opacity for stacked layers (0.6, 0.4, 0.2)
- Gradient fill from accent color to transparent

### Pie / Donut Chart
Best for: part-to-whole relationships (max 6 segments).
- Donut preferred over pie (inner radius 60%)
- Active segment: slight outward offset on hover
- Center label: total value or primary metric
- Legend positioned below on mobile, right on desktop

### Scatter Chart
Best for: correlation between two variables.
- Variable dot size for third dimension (bubble chart)
- Add quadrant lines if meaningful thresholds exist
- Tooltip shows both axis values plus label

### Radar Chart
Best for: multi-dimensional comparison (3-8 axes).
- Filled area with low opacity (0.2)
- Grid lines match the dark theme
- Limit to 2-3 overlapping datasets for readability

## Accessibility Requirements

Every chart must include:

1. **ARIA attributes:**
   ```jsx
   <div role="img" aria-label="Monthly revenue trend showing 23% growth from January to June 2025">
   ```

2. **Reduced motion:**
   ```css
   @media (prefers-reduced-motion: reduce) {
     .chart-container * {
       animation: none !important;
       transition: none !important;
     }
   }
   ```

3. **Color independence:** Never rely on color alone to convey meaning. Add:
   - Pattern fills or dash styles for line differentiation
   - Direct labels or legends with text descriptions
   - Shape variation for scatter plots

4. **Screen reader fallback:** Include a hidden data table:
   ```jsx
   <table className="sr-only">
     <caption>Monthly revenue data</caption>
     {/* Full data in tabular form */}
   </table>
   ```

5. **Contrast:** All text on the chart must meet WCAG AA (4.5:1 ratio against `zinc-900`).

## Responsive Behavior

- Charts fill their container width (`responsive: true` / `width="100%"`)
- Set `min-h-[300px]` on the wrapper to prevent CLS
- On mobile (< 640px): move legends below the chart, reduce font sizes
- On print: switch to light theme with black text (via `@media print`)

## Performance

Charts are heavy — always lazy load:

```jsx
import 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,
});
```

- Never put chart components in the LCP critical path
- Use `ssr: false` — canvas/SVG charts need the DOM
- Skeleton matches the glass container dimensions exactly

## Tooltip Styling

```jsx
const 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>
  );
};
```