$npx -y skills add Varnan-Tech/opendirectory --skill graphic-chartGenerates data visualization charts (bar, line, area, pie, doughnut, scatter, radar, treemap) as PNG using Apache ECharts v6. 1080×1080px default, 5 style presets, highlight annotations. Trigger when user says "create a chart", "visualize data", "make a bar chart", "line graph",
| 1 | # graphic-chart |
| 2 | |
| 3 | Generates data visualization charts as PNG. Renders HTML with Apache ECharts v6 in headless Chromium via Playwright → screenshots at 2× retina quality. |
| 4 | |
| 5 | CDN: `https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.min.js` |
| 6 | |
| 7 | --- |
| 8 | |
| 9 | ## Critical Rules (read before every generation) |
| 10 | |
| 11 | 1. **`area` type → `type: 'line'` + `areaStyle: {}`** — ECharts has no `type: 'area'`. |
| 12 | 2. **`doughnut` → `type: 'pie'` + `radius: ['40%', '70%']`** — ECharts has no `type: 'doughnut'`. |
| 13 | 3. **Readiness signal: register `chart.on('finished', fn)` BEFORE `chart.setOption()`** — ECharts bug #14101/#17500: if listener is registered after setOption, it silently never fires. Always register both `finished` and `rendered` events before setOption. |
| 14 | 4. **`xAxis.type: 'category'` must be explicit** — ECharts does not infer it from the data. Forgetting this produces a blank chart. |
| 15 | 5. **Category labels go in `xAxis.data`**, not in a `data.labels` array. ECharts structure is flat: `{ xAxis, yAxis, series, grid, title, legend }` — not nested under `data` or `options`. |
| 16 | 6. **Data labels are fully built-in** — use `label: { show: true }` on any series. No plugin needed. |
| 17 | 7. **Highlight a specific bar/point via per-item `itemStyle`** — put `{ value: N, itemStyle: { color: '#...' } }` directly in the `data` array. Do NOT use Chart.js-style `backgroundColor` arrays. |
| 18 | 8. **ECharts init uses a `<div>` container, not `<canvas>`** — `echarts.init(document.getElementById('chart'))`. The container div needs explicit dimensions. |
| 19 | 9. **`animation: false` in option** — disables animation for instant render. Still register `finished` + `rendered` events before setOption for the readiness signal. |
| 20 | 10. **Never dump HTML in chat.** Save to file, show summary only. |
| 21 | 11. **Title states the insight, not the subject.** "Revenue grew 3× in 12 months" not "Monthly Revenue". |
| 22 | 12. **Pie/doughnut: use body `padding: 64px 80px` and `.chart-container { max-height: 860px }`** — prevents edge-to-edge fill when no title. |
| 23 | |
| 24 | --- |
| 25 | |
| 26 | ## Step 1: Intake |
| 27 | |
| 28 | **Required:** `chart_type`, `data` |
| 29 | |
| 30 | **Optional parameters and defaults:** |
| 31 | |
| 32 | | Parameter | Default | Description | |
| 33 | |---|---|---| |
| 34 | | chart_type | — | bar / line / area / pie / doughnut / scatter / radar / treemap | |
| 35 | | data | — | JSON array or CSV — required | |
| 36 | | title | — | States the insight, ≤10 words | |
| 37 | | subtitle | — | 1-sentence context line | |
| 38 | | style | clean-slate | clean-slate / midnight-editorial / matt-gray / electric-burst / brutalist | |
| 39 | | dimensions | 1080x1080 | WxH pixels (output PNG = 2× via deviceScaleFactor) | |
| 40 | | x_label | — | X-axis label text | |
| 41 | | y_label | — | Y-axis label text | |
| 42 | | source | — | Data source shown in footer | |
| 43 | | highlight | — | Data label to highlight (e.g. "Q4", "Dec", index 3) | |
| 44 | |
| 45 | **If `chart_type` or `data` is missing, ask exactly:** |
| 46 | |
| 47 | > "To create the chart, I need: |
| 48 | > 1. **Chart type** — bar / line / area / pie / doughnut / scatter / radar / treemap |
| 49 | > 2. **Data** — provide as JSON array or CSV (e.g. `[12, 18, 22, 25, 31]` with labels `['Q1','Q2','Q3','Q4','Q5']`) |
| 50 | > |
| 51 | > Optional: title, style (default: clean-slate), dimensions (default: 1080×1080), highlight a specific data point" |
| 52 | |
| 53 | If both present → skip to Step 2. |
| 54 | |
| 55 | --- |
| 56 | |
| 57 | ## Step 2: Internal Architecture (never shown to user) |
| 58 | |
| 59 | **1. Normalize chart type:** |
| 60 | - `area` → `line` + `areaStyle: {}` on series |
| 61 | - `doughnut` → `pie` + `radius: ['40%', '70%']` on series |
| 62 | - `horizontal bar` → `bar` + swap xAxis/yAxis (category axis on y) |
| 63 | - All others: use as-is |
| 64 | |
| 65 | **2. Read `references/chart-library.md`** — load full config spec for this chart type. |
| 66 | |
| 67 | **3. Read `references/style-presets.md`** — load CSS tokens + data palette for chosen style. |
| 68 | |
| 69 | **4. Commit to design direction:** |
| 70 | |
| 71 | | Decision | Derive from | |
| 72 | |---|---| |
| 73 | | Tone | Professional / editorial / bold / technical — match the data's audience | |
| 74 | | Data story | Single insight this chart proves (becomes the title) | |
| 75 | | Highlight strategy | Which data point needs visual emphasis and why? | |
| 76 | | Background | Light (clean-slate, matt-gray) or dark (midnight-editorial, electric-burst, brutalist) | |
| 77 | |
| 78 | **5. Parse data:** |
| 79 | - Simple array `[12, 18, 22]` → series.data, labels provided separately |
| 80 | - Object array `[{x: 'Jan', y: 12}]` → xAxis.data from x keys, series.data from y values |
| 81 | - CSV: parse header row as xAxis.data, value row as series.data |
| 82 | - Multi-series: multiple `series` entries each with `type`, `name`, `data` |
| 83 | - Scatter: `series.data: [[x1,y1], [x2,y2], ...]` format |
| 84 | |
| 85 | **6. Parse dimensions:** `"1080x1080"` → W=1080, H=1080. Body |