@opendirectory.dev/skills 0.1.59 → 0.1.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendirectory.dev/skills",
3
- "version": "0.1.59",
3
+ "version": "0.1.61",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "bin": {
package/registry.json CHANGED
@@ -126,6 +126,14 @@
126
126
  "version": "1.0.0",
127
127
  "path": "skills/graphic-case-study"
128
128
  },
129
+ {
130
+ "name": "graphic-chart",
131
+ "description": "Generates data visualization charts (bar, line, area, pie, doughnut, scatter, radar, treemap) as PNG using Apache ECharts v6.",
132
+ "tags": [],
133
+ "author": "OpenDirectory",
134
+ "version": "2.0.0",
135
+ "path": "skills/graphic-chart"
136
+ },
129
137
  {
130
138
  "name": "graphic-ebook",
131
139
  "description": "Creates professionally designed B2B SaaS e-books in HTML + CSS, exported as print-ready PDF.",
@@ -454,6 +462,16 @@
454
462
  "version": "0.0.1",
455
463
  "path": "skills/vc-finder"
456
464
  },
465
+ {
466
+ "name": "vid-motion-graphics",
467
+ "description": "Generates motion graphics videos (MP4) from a content brief.",
468
+ "tags": [
469
+ "Copywriting"
470
+ ],
471
+ "author": "OpenDirectory",
472
+ "version": "1.0.0",
473
+ "path": "skills/vid-motion-graphics"
474
+ },
457
475
  {
458
476
  "name": "where-your-customer-lives",
459
477
  "description": "Given a product utility and ICP, researches the internet to find the specific channels.",
@@ -0,0 +1,104 @@
1
+ # graphic-chart
2
+
3
+ Generate publication-quality data visualization charts as PNG using Chart.js v4. 8 chart types, 5 style presets, annotation highlights.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx "@opendirectory.dev/skills" install graphic-chart --target claude
9
+ ```
10
+
11
+ ### Manual Install (2 steps)
12
+
13
+ 1. Copy the URL of this skill folder, paste it at [download-directory.github.io](https://download-directory.github.io/), download the zip.
14
+ 2. Open Claude desktop app → sidebar → **Customize** → **Skills** → **+** → **Upload a skill** → drop the extracted folder.
15
+
16
+ ---
17
+
18
+ ## What it does
19
+
20
+ - Takes chart type + data (JSON or CSV) as input
21
+ - Generates a self-contained HTML file with Chart.js v4
22
+ - Screenshots via headless Chromium at 2× deviceScaleFactor (retina quality)
23
+ - Outputs a crisp PNG ready for decks, reports, social, or email
24
+ - Supports annotation highlights on a specific data point
25
+ - No Python, no API key, no external service
26
+
27
+ ---
28
+
29
+ ## Example
30
+
31
+ > "Create a line chart. Title: 'From $12k to $95k ARR in 12 Months'. Data: [12, 18, 22, 25, 31, 38, 44, 52, 61, 68, 78, 95] (Jan–Dec 2024, in thousands). Highlight December in gold. Source: Internal CRM. Style: electric-burst. Dimensions: 1080x1080."
32
+
33
+ Output: `chart.png` — dark canvas, electric yellow December highlight with callout, growth title.
34
+
35
+ ---
36
+
37
+ ## Supported Chart Types
38
+
39
+ | Type | Best for |
40
+ |---|---|
41
+ | bar | Comparing values across categories |
42
+ | line | Trends over time |
43
+ | area | Cumulative trends, volume over time |
44
+ | pie | Part-to-whole relationships |
45
+ | doughnut | Part-to-whole with center hole |
46
+ | scatter | Correlations between two variables |
47
+ | radar | Multi-dimensional comparisons |
48
+ | treemap | Hierarchical data, proportional sizes |
49
+
50
+ ---
51
+
52
+ ## Supported Styles
53
+
54
+ | Style | Best for |
55
+ |---|---|
56
+ | clean-slate | Enterprise B2B, investor decks, any professional audience |
57
+ | midnight-editorial | Editorial, premium brand, thought leadership |
58
+ | matt-gray | Board materials, consultancy reports, sophisticated neutral |
59
+ | electric-burst | Growth metrics, startup content, bold data stories |
60
+ | brutalist | Design-forward, stark comparisons, confrontational data |
61
+
62
+ ---
63
+
64
+ ## Parameters
65
+
66
+ | Parameter | Required | Default | Description |
67
+ |---|---|---|---|
68
+ | chart_type | Yes | — | bar / line / area / pie / doughnut / scatter / radar / treemap |
69
+ | data | Yes | — | JSON array or CSV |
70
+ | title | No | — | States the insight (≤10 words) |
71
+ | subtitle | No | — | 1-sentence context line |
72
+ | style | No | clean-slate | Visual style preset |
73
+ | dimensions | No | 1080x1080 | WxH in pixels |
74
+ | x_label | No | — | X-axis label |
75
+ | y_label | No | — | Y-axis label |
76
+ | source | No | — | Data source for footer attribution |
77
+ | highlight | No | — | Data label/value to annotate (e.g. "Q4", "Dec") |
78
+
79
+ ---
80
+
81
+ ## Output
82
+
83
+ | File | What it is |
84
+ |---|---|
85
+ | `chart/[slug]/chart.html` | Self-contained HTML (open in browser to preview) |
86
+ | `chart/[slug]/chart.png` | PNG at 2× retina quality |
87
+
88
+ Default output: `1080×1080` viewport → `2160×2160` PNG (@2× deviceScaleFactor).
89
+
90
+ ---
91
+
92
+ ## Dependencies
93
+
94
+ **Node.js** — required. Install from [nodejs.org](https://nodejs.org) or `brew install node`.
95
+
96
+ Bundled inside this skill:
97
+ - `scripts/export-chart.sh` — orchestrator script
98
+ - `scripts/screenshot-chart.mjs` — Playwright capture script
99
+
100
+ Auto-installed on first run via npm:
101
+ - `playwright` — headless Chromium for screenshot
102
+ - Chromium browser binary (~200MB, downloaded once and cached)
103
+
104
+ No API keys required.
@@ -0,0 +1,318 @@
1
+ ---
2
+ name: graphic-chart
3
+ description: Generates 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", "pie chart", "data visualization", "chart this data", "plot", "graph", or "visualize these numbers".
4
+ compatibility: [claude-code, gemini-cli, github-copilot]
5
+ author: OpenDirectory
6
+ version: 2.0.0
7
+ ---
8
+
9
+ # graphic-chart
10
+
11
+ Generates data visualization charts as PNG. Renders HTML with Apache ECharts v6 in headless Chromium via Playwright → screenshots at 2× retina quality.
12
+
13
+ CDN: `https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.min.js`
14
+
15
+ ---
16
+
17
+ ## Critical Rules (read before every generation)
18
+
19
+ 1. **`area` type → `type: 'line'` + `areaStyle: {}`** — ECharts has no `type: 'area'`.
20
+ 2. **`doughnut` → `type: 'pie'` + `radius: ['40%', '70%']`** — ECharts has no `type: 'doughnut'`.
21
+ 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.
22
+ 4. **`xAxis.type: 'category'` must be explicit** — ECharts does not infer it from the data. Forgetting this produces a blank chart.
23
+ 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`.
24
+ 6. **Data labels are fully built-in** — use `label: { show: true }` on any series. No plugin needed.
25
+ 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.
26
+ 8. **ECharts init uses a `<div>` container, not `<canvas>`** — `echarts.init(document.getElementById('chart'))`. The container div needs explicit dimensions.
27
+ 9. **`animation: false` in option** — disables animation for instant render. Still register `finished` + `rendered` events before setOption for the readiness signal.
28
+ 10. **Never dump HTML in chat.** Save to file, show summary only.
29
+ 11. **Title states the insight, not the subject.** "Revenue grew 3× in 12 months" not "Monthly Revenue".
30
+ 12. **Pie/doughnut: use body `padding: 64px 80px` and `.chart-container { max-height: 860px }`** — prevents edge-to-edge fill when no title.
31
+
32
+ ---
33
+
34
+ ## Step 1: Intake
35
+
36
+ **Required:** `chart_type`, `data`
37
+
38
+ **Optional parameters and defaults:**
39
+
40
+ | Parameter | Default | Description |
41
+ |---|---|---|
42
+ | chart_type | — | bar / line / area / pie / doughnut / scatter / radar / treemap |
43
+ | data | — | JSON array or CSV — required |
44
+ | title | — | States the insight, ≤10 words |
45
+ | subtitle | — | 1-sentence context line |
46
+ | style | clean-slate | clean-slate / midnight-editorial / matt-gray / electric-burst / brutalist |
47
+ | dimensions | 1080x1080 | WxH pixels (output PNG = 2× via deviceScaleFactor) |
48
+ | x_label | — | X-axis label text |
49
+ | y_label | — | Y-axis label text |
50
+ | source | — | Data source shown in footer |
51
+ | highlight | — | Data label to highlight (e.g. "Q4", "Dec", index 3) |
52
+
53
+ **If `chart_type` or `data` is missing, ask exactly:**
54
+
55
+ > "To create the chart, I need:
56
+ > 1. **Chart type** — bar / line / area / pie / doughnut / scatter / radar / treemap
57
+ > 2. **Data** — provide as JSON array or CSV (e.g. `[12, 18, 22, 25, 31]` with labels `['Q1','Q2','Q3','Q4','Q5']`)
58
+ >
59
+ > Optional: title, style (default: clean-slate), dimensions (default: 1080×1080), highlight a specific data point"
60
+
61
+ If both present → skip to Step 2.
62
+
63
+ ---
64
+
65
+ ## Step 2: Internal Architecture (never shown to user)
66
+
67
+ **1. Normalize chart type:**
68
+ - `area` → `line` + `areaStyle: {}` on series
69
+ - `doughnut` → `pie` + `radius: ['40%', '70%']` on series
70
+ - `horizontal bar` → `bar` + swap xAxis/yAxis (category axis on y)
71
+ - All others: use as-is
72
+
73
+ **2. Read `references/chart-library.md`** — load full config spec for this chart type.
74
+
75
+ **3. Read `references/style-presets.md`** — load CSS tokens + data palette for chosen style.
76
+
77
+ **4. Commit to design direction:**
78
+
79
+ | Decision | Derive from |
80
+ |---|---|
81
+ | Tone | Professional / editorial / bold / technical — match the data's audience |
82
+ | Data story | Single insight this chart proves (becomes the title) |
83
+ | Highlight strategy | Which data point needs visual emphasis and why? |
84
+ | Background | Light (clean-slate, matt-gray) or dark (midnight-editorial, electric-burst, brutalist) |
85
+
86
+ **5. Parse data:**
87
+ - Simple array `[12, 18, 22]` → series.data, labels provided separately
88
+ - Object array `[{x: 'Jan', y: 12}]` → xAxis.data from x keys, series.data from y values
89
+ - CSV: parse header row as xAxis.data, value row as series.data
90
+ - Multi-series: multiple `series` entries each with `type`, `name`, `data`
91
+ - Scatter: `series.data: [[x1,y1], [x2,y2], ...]` format
92
+
93
+ **6. Parse dimensions:** `"1080x1080"` → W=1080, H=1080. Body = WxH. Output PNG = 2W × 2H.
94
+
95
+ ---
96
+
97
+ ## Step 3: HTML Generation
98
+
99
+ Read ALL before generating:
100
+ - `references/chart-library.md` for this chart type's full ECharts config spec
101
+ - `references/style-presets.md` for the chosen style's CSS tokens + palette
102
+
103
+ **Required HTML structure:**
104
+
105
+ ```html
106
+ <!DOCTYPE html>
107
+ <html lang="en">
108
+ <head>
109
+ <meta charset="UTF-8">
110
+ [font CDN link from style preset]
111
+ <style>
112
+ :root {
113
+ [all CSS tokens from style preset]
114
+ }
115
+
116
+ *, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
117
+ html, body {
118
+ width: [W]px; height: [H]px;
119
+ overflow: hidden;
120
+ background: var(--bg);
121
+ font-family: var(--font-body);
122
+ }
123
+ body {
124
+ display: flex;
125
+ flex-direction: column;
126
+ padding: 40px 48px 32px; /* pie/doughnut: use 64px 80px */
127
+ }
128
+
129
+ /* ECharts container must have explicit size */
130
+ .chart-container {
131
+ flex: 1;
132
+ min-height: 0;
133
+ /* pie/doughnut only: max-height: 860px; */
134
+ }
135
+
136
+ .chart-header { margin-bottom: 24px; }
137
+ .chart-title {
138
+ font-family: var(--font-display);
139
+ font-size: clamp(1.1rem, 2.5vw, 1.6rem);
140
+ font-weight: 700;
141
+ color: var(--text);
142
+ line-height: 1.2;
143
+ }
144
+ .chart-subtitle {
145
+ font-family: var(--font-body);
146
+ font-size: clamp(0.75rem, 1.2vw, 0.9rem);
147
+ color: var(--text-muted);
148
+ margin-top: 6px;
149
+ line-height: 1.5;
150
+ }
151
+ .chart-footer {
152
+ margin-top: 14px;
153
+ font-family: var(--font-body);
154
+ font-size: 10px;
155
+ color: var(--text-muted);
156
+ opacity: 0.65;
157
+ }
158
+ </style>
159
+ </head>
160
+ <body>
161
+
162
+ [if title or subtitle: <div class="chart-header"><div class="chart-title">...</div>...</div>]
163
+
164
+ <div id="chart" class="chart-container"></div>
165
+
166
+ [if source: <div class="chart-footer">Source: [source]</div>]
167
+
168
+ <script src="https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/echarts.min.js"></script>
169
+
170
+ <script>
171
+ window.__chartReady = false;
172
+
173
+ document.fonts.ready.then(() => {
174
+ const container = document.getElementById('chart');
175
+ const chart = echarts.init(container, null, { renderer: 'canvas' });
176
+
177
+ // CRITICAL: register events BEFORE setOption — ECharts bug #14101/#17500
178
+ // 'finished' may silently not fire if registered after setOption with animation:false
179
+ chart.on('finished', () => {
180
+ window.__chartReady = true;
181
+ });
182
+ // Belt-and-suspenders fallback via 'rendered'
183
+ chart.on('rendered', () => {
184
+ clearTimeout(window.__renderDebounce);
185
+ window.__renderDebounce = setTimeout(() => { window.__chartReady = true; }, 100);
186
+ });
187
+
188
+ const palette = [palette from style preset];
189
+
190
+ const option = {
191
+ animation: false, // instant render for screenshot
192
+
193
+ backgroundColor: 'transparent', // body CSS handles bg color
194
+
195
+ textStyle: {
196
+ fontFamily: '[--font-body value]',
197
+ color: '[--text-muted value]',
198
+ },
199
+
200
+ [title config if title param provided],
201
+ [legend config per chart type],
202
+ [grid config per chart type],
203
+ [xAxis config per chart type],
204
+ [yAxis config per chart type],
205
+
206
+ series: [{
207
+ [full series config from chart-library.md for this type]
208
+ [palette colors applied per chart type]
209
+ [if highlight: per-item itemStyle on the highlighted data point]
210
+ }]
211
+ };
212
+
213
+ chart.setOption(option); // setOption ALWAYS comes after event registration
214
+ });
215
+ </script>
216
+ </body>
217
+ </html>
218
+ ```
219
+
220
+ **Design quality rules:**
221
+ - Title font: `fontWeight: 'bold'`, `fontSize: 20–24` — no thin titles
222
+ - Grid lines: low opacity (0.06–0.10) — subordinate to data
223
+ - Bars: `barMaxWidth: 60`, rounded via `itemStyle.borderRadius: [4,4,0,0]`
224
+ - Lines: `smooth: true` for natural curves, `symbolSize: 8` for points
225
+ - Pie/doughnut: `label.formatter: '{b}\n{d}%'` for built-in on-slice labels
226
+ - Dark presets: grid `rgba(255,255,255,0.07)`, axis line/tick color `rgba(255,255,255,0.15)`
227
+ - Tooltip: `show: false` — static PNG, no hover interaction
228
+ - When no title provided: skip `.chart-header`, omit title from ECharts option
229
+
230
+ ---
231
+
232
+ ## Step 4: Self-QA (fix every failure before Step 5)
233
+
234
+ **Structure:**
235
+ - [ ] Container is a `<div>`, not `<canvas>`
236
+ - [ ] `window.__chartReady = false` declared before `document.fonts.ready`
237
+ - [ ] `chart.on('finished', ...)` registered BEFORE `chart.setOption()`
238
+ - [ ] `chart.on('rendered', ...)` debounce fallback registered BEFORE `chart.setOption()`
239
+ - [ ] `animation: false` in option object
240
+ - [ ] `chart.setOption(option)` is the LAST call in the init block
241
+
242
+ **Type-specific:**
243
+ - [ ] Area: `type: 'line'` + `areaStyle: {}` — no `type: 'area'`
244
+ - [ ] Doughnut: `type: 'pie'` + `radius: ['40%', '70%']` — no `type: 'doughnut'`
245
+ - [ ] Bar: `xAxis.type: 'category'` explicitly set
246
+ - [ ] Category data in `xAxis.data` (not `data.labels`)
247
+ - [ ] Pie/doughnut: body `padding: 64px 80px` + `.chart-container { max-height: 860px }`
248
+ - [ ] Highlight: per-item `{ value: N, itemStyle: { color } }` in data array
249
+
250
+ **Design:**
251
+ - [ ] All palette colors from `references/style-presets.md`
252
+ - [ ] Title states insight (not just subject)
253
+ - [ ] `tooltip: { show: false }` or omitted (no hover on static PNG)
254
+ - [ ] Dark preset: grid/axis colors use `rgba(255,255,255,...)`
255
+ - [ ] Source in footer if `source` param provided
256
+ - [ ] Data labels visible (built-in `label: { show: true }` on series)
257
+
258
+ ---
259
+
260
+ ## Step 5: Export
261
+
262
+ Determine slug from title or chart type + data context (kebab-case, ≤30 chars):
263
+ ```bash
264
+ mkdir -p chart/[slug]
265
+ ```
266
+
267
+ Save HTML: `chart/[slug]/chart.html`
268
+
269
+ Quick browser check:
270
+ ```bash
271
+ open chart/[slug]/chart.html
272
+ ```
273
+
274
+ Run export (replace `[skill-root]` with actual path to this skill's directory):
275
+ ```bash
276
+ bash [skill-root]/scripts/export-chart.sh \
277
+ chart/[slug]/chart.html \
278
+ chart/[slug]/chart.png \
279
+ --width [W] \
280
+ --height [H]
281
+ ```
282
+
283
+ The script installs Playwright on first run (~200MB Chromium download), then captures the chart at `deviceScaleFactor: 2`.
284
+
285
+ ---
286
+
287
+ ## Step 6: Output Summary
288
+
289
+ ```
290
+ ## Chart: [title]
291
+ Date: [YYYY-MM-DD] | Type: [chart_type] | Style: [style]
292
+ Dimensions: [W×H]px → PNG: [2W×2H]px @2× retina
293
+
294
+ Files
295
+ Source: chart/[slug]/chart.html
296
+ Output: chart/[slug]/chart.png
297
+ Size: [X] KB
298
+
299
+ Checklist
300
+ - [ ] Title states the insight clearly
301
+ - [ ] Data labels legible at display size
302
+ - [ ] Highlight visible on correct data point
303
+ - [ ] Source attribution present in footer
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Prompt Tips (show when user asks for guidance)
309
+
310
+ > "Provide structured data — JSON or CSV, not prose descriptions."
311
+ >
312
+ > "Name the chart type explicitly. 'bar chart comparing Q1–Q4' not 'a chart showing quarters'."
313
+ >
314
+ > "Specify the data story. 'highlight Q4 which outperformed all others' gives the annotation context."
315
+ >
316
+ > ✅ Good: "Create a line chart. Title: 'From $12k to $95k ARR in 12 Months'. Data: [12, 18, 22, 25, 31, 38, 44, 52, 61, 68, 78, 95] (Jan–Dec 2024). Highlight December. Source: Internal CRM. Style: electric-burst."
317
+ >
318
+ > ❌ Bad: "make a chart about our company growth"
@@ -0,0 +1,30 @@
1
+ {
2
+ "skill_name": "graphic-chart",
3
+ "evals": [
4
+ {
5
+ "id": 1,
6
+ "prompt": "Create a line chart. Title: 'From $12k to $95k ARR in 12 Months'. Data: [12, 18, 22, 25, 31, 38, 44, 52, 61, 68, 78, 95] (Jan–Dec 2024, in thousands). Highlight December in gold. Source: Internal CRM. Style: terminal. Dimensions: 1080x1080.",
7
+ "expected_output": "type: 'line', animation: {duration: 0, onComplete: () => window.__chartReady = true}, chartjs-plugin-annotation CDN loaded after Chart.js (UMD auto-registers — no Chart.register call), annotation box on 'Dec' label with callout showing '95', electric-burst-style dark tokens applied (terminal mapped to electric-burst or midnight-editorial), title states growth story not just description, source shown in footer, no CSS on canvas element, deviceScaleFactor: 2 in export script → 2160×2160 output PNG."
8
+ },
9
+ {
10
+ "id": 2,
11
+ "prompt": "Create a bar chart. Title: 'Q4 Outperformed Every Quarter'. Data: Q1=420, Q2=510, Q3=480, Q4=780. Highlight Q4. Style: electric-burst.",
12
+ "expected_output": "type: 'bar', borderRadius: 4 on dataset (non-negotiable), borderSkipped: false, annotation box xMin:'Q4' xMax:'Q4' with label callout, annotation CDN script loaded after Chart.js (UMD auto-registers — no Chart.register call), electric-burst tokens (Space Grotesk display, DM Sans body, #09090B bg, #FACC15 accent), window.__chartReady set in animation.onComplete, no animation: false, no CSS on canvas."
13
+ },
14
+ {
15
+ "id": 3,
16
+ "prompt": "Create an area chart. Revenue by month: 5, 8, 12, 10, 15, 22, 28, 25, 32, 38, 45, 52. Style: clean-slate.",
17
+ "expected_output": "type: 'line' (NOT 'area'), fill: 'origin' on dataset, backgroundColor rgba at 0.15 opacity, NO annotation plugin loaded (no highlight param), clean-slate tokens (Plus Jakarta Sans, white bg, #3B82F6 accent), animation: {duration: 0, onComplete: ...} present, maintainAspectRatio: false, position: relative on container."
18
+ },
19
+ {
20
+ "id": 4,
21
+ "prompt": "Create a pie chart. Market share: Product A 45%, Product B 28%, Product C 17%, Other 10%. Style: midnight-editorial.",
22
+ "expected_output": "type: 'pie', backgroundColor is palette array (not single color), legend position: 'right', NO chartjs-plugin-annotation script loaded (pie not supported), midnight-editorial tokens (Instrument Serif display, Inter body, #111111 bg, #D8F90A accent), 4 segments (under 7 max), hoverOffset: 6, no CSS on canvas."
23
+ },
24
+ {
25
+ "id": 5,
26
+ "prompt": "make a chart",
27
+ "expected_output": "chart_type AND data both missing. Does NOT read any reference files. Does NOT generate HTML. Asks exactly for both: chart type (bar/line/area/pie/doughnut/scatter/radar/treemap) and data (JSON or CSV). Waits for user response."
28
+ }
29
+ ]
30
+ }