Skip to content

onsen-ai/chart-skill

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“Š Chart Skill

Turn YAML into beautiful, publication-grade chart images. No design skills required.

A Claude Code skill that generates SVG charts from simple YAML specs using Vega-Lite under the hood. Write data, get charts.

✨ What it does

graph LR
    A["πŸ“ YAML Spec"] --> B["βš™οΈ Chart Skill"]
    B --> C["🎨 Themed SVG"]
    C --> D["πŸ“„ Your Document"]
Loading

πŸ“‹ Prerequisites

  • Node.js 18+ β€” check with node --version
  • npm β€” comes with Node.js

That's it. No native compilers, system libraries, or other tools needed.

πŸš€ Quick Start

1. Install the skill

npx skills add onsen-ai/chart-skill

2. Install dependencies

cd <skill-directory> && npm install --production

Installs vega, vega-lite, and js-yaml (~50MB, one-time only).

3. (Optional) Configure defaults

node scripts/setup.mjs

Pick your default theme, output directory, and variant. This is optional β€” the skill works immediately with sensible defaults (onsen theme, desktop size, light variant).

4. Render

# From a file
node scripts/render.mjs --spec chart.yaml --output chart.svg

# Inline YAML
node scripts/render.mjs --yaml 'mark: bar
data:
  values:
    - x: A
      y: 28
    - x: B
      y: 55
encoding:
  x: { field: x, type: nominal }
  y: { field: y, type: quantitative }' --output chart.svg

That's it. πŸŽ‰


πŸ“ˆ Chart Gallery

All charts below were generated by this skill from the YAML specs in examples/.

Bar Chart (Vertical)

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Quarterly Revenue
mark: bar
data:
  values:
    - quarter: Q1
      revenue: 120000
    - quarter: Q2
      revenue: 185000
    - quarter: Q3
      revenue: 210000
    - quarter: Q4
      revenue: 245000
encoding:
  x: { field: quarter, type: nominal, title: null }
  y: { field: revenue, type: quantitative, title: "Revenue ($)" }

Bar Chart (Horizontal)

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Feature Adoption
mark: bar
data:
  values:
    - feature: Search
      users: 84
    - feature: Dashboards
      users: 72
    - feature: Export
      users: 58
    - feature: Alerts
      users: 45
    - feature: API
      users: 31
encoding:
  y: { field: feature, type: nominal, title: null, sort: "-x" }
  x: { field: users, type: quantitative, title: "Active Users (%)" }

Stacked Bar Chart

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Revenue by Region
mark: bar
data:
  values:
    - quarter: Q1
      region: EMEA
      revenue: 48000
    # ... (add color encoding for stacking)
encoding:
  x: { field: quarter, type: ordinal, title: null }
  y: { field: revenue, type: quantitative, title: "Revenue ($)" }
  color: { field: region, type: nominal, title: Region }

Line Chart

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Monthly Active Users
mark: line
data:
  values:
    - month: Jan
      users: 1200
    - month: Feb
      users: 1800
    # ...
encoding:
  x: { field: month, type: ordinal, title: null }
  y: { field: users, type: quantitative, title: Users }

Multi-Series Line Chart

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Traffic by Channel
mark: line
data:
  values:
    - month: Jan
      channel: Organic
      visits: 12000
    # ...
encoding:
  x: { field: month, type: ordinal, title: null }
  y: { field: visits, type: quantitative, title: Visits }
  color: { field: channel, type: nominal, title: Channel }

Area Chart

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Cumulative Sign-ups
mark: area
data:
  values:
    - month: Jan
      total: 500
    - month: Feb
      total: 1200
    # ...
encoding:
  x: { field: month, type: ordinal, title: null }
  y: { field: total, type: quantitative, title: Total Users }

Scatter Plot

πŸ”΅ Onsen LightπŸŒ™ Onsen Dark
πŸ“ YAML spec
title: Session Length vs Satisfaction
mark: point
data:
  values:
    - duration: 2
      score: 2.1
    - duration: 5
      score: 3.5
    # ...
encoding:
  x: { field: duration, type: quantitative, title: "Session Length (min)" }
  y: { field: score, type: quantitative, title: "Satisfaction Score" }

🎨 Theme Gallery

9 built-in themes β€” the same 6-segment stacked bar chart rendered in each, showing the full colour palette:

Light Mode

πŸ”΅ Onsen
βšͺ Neutral
πŸ”΄ Bain
πŸ”· McKinsey
🟒 BCG
🌿 Holland & Barrett
πŸ“° Economist
πŸ“„ FT
🟩 Deloitte

Dark Mode

πŸ”΅ Onsen
βšͺ Neutral
πŸ”΄ Bain
πŸ”· McKinsey
🟒 BCG
🌿 Holland & Barrett
πŸ“° Economist
πŸ“„ FT
🟩 Deloitte

Theme Reference

Theme Flag Primary Style Best for
Onsen --theme onsen πŸ”΅ #4d93e5 Warm, friendly blue Product dashboards, blog posts
Neutral --theme neutral βšͺ #374151 Clean grayscale Academic papers, formal reports
Bain --theme bain πŸ”΄ #CC0000 Bold red + greys Strategy consulting decks
McKinsey --theme mckinsey πŸ”· #1c3cdf Deep blue Executive presentations
BCG --theme bcg 🟒 #29BA74 Fresh green Sustainability, growth reports
Holland & Barrett --theme holland-barrett 🌿 #005335 H&B deep green + lime Health, wellness, retail
Economist --theme economist πŸ“° #E3120B Red + teal Data journalism, editorials
FT --theme ft πŸ“„ #0D7680 Teal on salmon Financial reporting
Deloitte --theme deloitte 🟩 #86BC25 Lime green + blue Audit, advisory decks

Custom themes? Drop a JSON file in ~/.chart-skill/themes/ β€” see themes/onsen.json for the format.


πŸ“± Responsive Sizing

The same chart at desktop vs mobile sizes:

πŸ–₯️ Desktop (728px)πŸ“± Mobile (600px)

Mobile variants automatically:

  • Use larger font sizes (22px vs 16px) to stay readable when scaled
  • Hide Y-axis titles to save space
  • Skip overlapping X-axis labels

🎯 Design System

The chart styling is opinionated β€” every default was chosen deliberately to produce clean, readable charts without manual tweaking. Here's what we do and why.

Typography

Element Size (desktop) Size (mobile) Weight Color
Chart title 16px 22px 500 (medium) text
Axis labels 16px 22px normal textLight
Axis titles 16px 22px 500 (medium) text
Value labels 14px 20px 500 (medium) text

All font sizes match the surrounding article body text on desktop. Mobile sizes are ~38% larger to compensate for SVG downscaling on smaller screens.

Axes

Element Style Why
Y-axis ticks Max 5, scale.nice aligned Top tick always sits at the axis end
X-axis ticks Hidden Cleaner look β€” labels are sufficient
X-axis label padding 8px from axis, 12px to title Breathing room without wasted space
Gridlines Solid, divider color Subtle but present β€” dashed lines feel busy
Domain lines text color, rendered on top of marks Strong contrast, visible even behind tall bars
Label overlap parity strategy Skips every other label on mobile when they'd collide
Chart title Top-left, 10px offset Left-aligned for natural reading flow

Marks

Mark Style Why
Bar Square corners, 1.5px background-colored stroke Flat, modern look. The stroke creates subtle visual separation between segments without harsh borders
Line 2px stroke with hollow dots (white fill, colored 2px border) Dots mark individual data points without dominating the line. Hollow style avoids visual heaviness
Area 30% opacity fill with solid border line Fill shows volume, border line shows the trend clearly
Point (scatter) Solid filled circles, 120 size Larger dots for better visibility; solid fill since there's no line to compete with

Color Hierarchy

Token Role Contrast
text Titles, axis domain lines Highest β€” near black/white
textLight Labels, legend text Secondary β€” readable but recedes
divider Gridlines Subtle β€” visible but doesn't compete
bgGray Bar stroke, line dot fill Matches container background
primaryColor All marks (bars, lines, dots) Brand accent color

The bgGray token matches the chart container background, creating a "cut-out" effect for bar segment borders and line chart dot fills rather than a visible contrasting border.

Value Labels

Chart type Labels Position Format
Single-series bar Each bar's value Above (vertical) or right (horizontal), 6px gap Comma-separated (12,400)
Single-series line/area Each data point Above, 10px gap Comma-separated
Stacked bar Aggregate total only Above the full stack Comma-separated
Multi-series line None β€” Too cluttered with overlapping lines
Scatter None β€” Dots are the data

Legend

  • Position: bottom, horizontal β€” doesn't eat into the chart width
  • Symbols: 120px size for visibility
  • Direction: horizontal row layout
  • Background: transparent (no box)

Responsive Strategy

Aspect Desktop (728px) Mobile (600px)
Font sizes 16px 22px (~38% larger)
Y-axis title Shown Hidden (saves ~40px width)
Value labels Shown Shown
Label overlap All shown Parity (skip alternating)
SVG scaling ~1:1 on 728px container ~53% on 320px screen
Effective text ~16px ~12px (22 Γ— 0.53)

The mobile SVG is intentionally rendered wider than the screen, with proportionally larger text. When the browser scales it down to fit, the text ends up roughly the same apparent size as desktop.

SVG Post-processing

One non-obvious detail: Vega renders axis domain lines behind bar marks in the SVG. For stacked or tall bars, this means the axis disappears behind the bars. The renderer post-processes the SVG to duplicate axis domain lines and insert them after the mark groups, so they always paint on top.


πŸ”§ CLI Reference

node render.mjs [options]

Input (one required):
  --spec PATH       YAML spec file
  --yaml STRING     Inline YAML spec

Output:
  --output PATH     Output file path
  --output-dir DIR  Output directory
  --all-variants    Render all 4 combos (light/dark Γ— desktop/mobile)
  --quiet           Print only output paths to stdout

Styling:
  --theme NAME      onsen, neutral, or custom theme name
  --variant NAME    light or dark
  --size NAME       desktop (728px) or mobile (600px)
  --width N         Override width in pixels
  --height N        Override height in pixels

Info:
  --list-themes     Show available themes
  --help            Show help

πŸ€– Agent Integration

The render script prints the output file path to stdout β€” perfect for agent workflows:

graph TD
    A["πŸ€– Agent gets data"] --> B["πŸ“ Writes YAML spec"]
    B --> C["βš™οΈ Calls render.mjs"]
    C --> D["πŸ“‚ Gets file path from stdout"]
    D --> E["πŸ“„ Embeds ![](path) in markdown"]
Loading

🎁 What you get for free

No config needed β€” these are applied automatically:

  • βœ… Value labels on bars and data points (comma-formatted)
  • βœ… Stacked bar totals above each stack
  • βœ… Light/dark mode variants
  • βœ… Desktop/mobile responsive sizes
  • βœ… Axis formatting β€” 5 ticks, horizontal labels, clean gridlines
  • βœ… Legend β€” horizontal, bottom-positioned for multi-series
  • βœ… Number formatting β€” thousands separators

πŸ“ Project Structure

chart-skill/
β”œβ”€β”€ SKILL.md              # πŸ€– Skill definition (for AI agents)
β”œβ”€β”€ themes/
β”‚   β”œβ”€β”€ onsen.json        # πŸ”΅ Default theme
β”‚   └── neutral.json      # βšͺ Academic theme
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ *.yaml            # πŸ“ Example specs
β”‚   └── output/           # πŸ–ΌοΈ Generated SVGs
└── scripts/
    β”œβ”€β”€ render.mjs        # βš™οΈ CLI entry point
    β”œβ”€β”€ setup.mjs         # πŸ”§ Interactive setup wizard
    └── lib/
        β”œβ”€β”€ config.mjs    # Config management
        β”œβ”€β”€ themes.mjs    # Theme loading
        β”œβ”€β”€ defaults.mjs  # Vega-Lite defaults
        └── renderer.mjs  # SVG rendering engine

πŸ“„ License

MIT

About

Claude Code skill for generating publication-grade charts from YAML specs

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors