一键导入
data-reports
Data visualization report scripts. NOT for general ETL or scraping (use data).
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Data visualization report scripts. NOT for general ETL or scraping (use data).
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Development wisdom and workflow rules. NOT for project-specific conventions (those live in CLAUDE.md, edit via wisdom).
The `BUGS.md` open-issues queue — entry format, lifecycle, pruning to diary. NOT for the record-don't-fix policy (that's CLAUDE.md Bug Triage Protocol), NOT for resolved-bug history (use /diary), NOT for feature backlog (use TODO.md/specs).
Terminal demo GIF + MP4 recordings for READMEs and social (asciinema + agg + ffmpeg). NOT for general Makefile targets (use software) or GUI screenshots (use visual).
Go development. NOT for non-Go code (use rs, py, ts, tsx, or sh).
Humanize text: strip AI-isms and add real voice. NOT for drafting new copy (use writing).
Python development. NOT for shell scripting (use sh) or non-Python code.
| name | data-reports |
| description | Data visualization report scripts. NOT for general ETL or scraping (use data). |
| when_to_use | Vega-Lite charts, report generator, chart script, multi-panel PNG, structured data visualization, Bun report script, data presentation script |
Reference example: scripts/report-chart.ts (validator-bonds).
bun runtime, vega-lite (spec), vega (render), sharp (SVG→PNG), yaml (input).compile(spec).spec → vega.parse → new vega.View(parsed, {renderer:'none'}) → await view.toSVG() → sharp(Buffer.from(svg)).png().toFile(out).Bun.spawn + await proc.exited — NEVER Bun.spawnSync.[report.yml] [out.png] with defaults (out = report with .png). -h/--help writes usage to stderr, then process.exit(2).load() — read YAML, map to typed row objects, derive computed fields there (e.g. actualFeeBps = feeAdj * maxFeeBps / feeMax). NEVER compute in the spec.loadConfigTarget() — read sibling config (e.g. settlement-config.yaml) for reference lines; return null if missing so the chart still renders without the target line.async function main() — all chart math, spec construction, render.title.text = what + range (e.g. '… Simulation · Epochs 885–985').title.subtitle = the run SETUP so the chart is self-describing: input tag + key config bounds (e.g. 'r200-x1600 · min fee 200 bps · max fee 1600 bps'). Derive the tag from the input filename basename (<tag>.yml → <tag>; suppress the bare default report). Style with subtitleFontSize: 11, subtitleColor: '#666'.Panels stacked in vconcat; hconcat for side-by-side pairs.
height: 20, invisible mark, legend.orient: 'top') — separates legend from the panel above.hconcat of two half-width panels (e.g. 460 each).height: 1, type:'text' mark) — config params + source file.[brackets] in axis and panel titles: 'Fee Payable [SOL]', 'fee [%]', 'APY [%]'. ALWAYS name the quantity before the unit — '[SOL]' alone is not enough; write 'Fee Payable [SOL]' or 'Stake [SOL]'.Math.ceil(max * 1.1 / 100) * 100; SOL → Math.ceil(max * 1.1 / 10) * 10.range(lo, hi) → scale: { domain: epochDomain }, so missing slots stay visible instead of collapsing.mkLabel(s) helper → s > 1 ? \...% ${s} === 0...` : 'datum.label'. Full-width panel (960px): mkLabel(Math.ceil(n/40)). Half-width panels (460px): double the stride → xEncSmall = { ...xEnc, axis: { ...xEnc.axis, labelExpr: mkLabel(stride*2) } }`.offset: all lower panels 4 (tight); dedicated legend row (owns its row) uses 0.'adjusted', 'at max fee', 'at min fee', 'max-fee cap'. Acronyms only: keep uppercase (e.g. 'SSR baseline').resolve: { scale: { color: 'independent' } } on the top level AND on any hconcat panel with its own color encoding.Date.now() (which mislabels historical reports): a boundary period holding fewer epochs than its neighbour is partial → cnt(0) < cnt(1) and cnt(last) < cnt(last-1). Factor fillOpacity/strokeWidth/strokeDash conditionals into a hollowBar object, spread into the bar layer's encoding. Incomplete = fillOpacity:0, strokeWidth:1.5, strokeDash:[4,2].rule mark at { datum: target } for the line itself.text mark pinned to an edge, NEVER centered: left edge → x: { value: 0 }, align: 'left', dx: 4; right edge → x: { value: width }, align: 'right'.rule mark plus a rotated text label.Define as top-of-file constants:
C_ACTUAL = '#4682b4' (blue — actual/observed)C_REF = '#708090' (gray — reference line)C_CAP = '#2e8b57' (green — cap/ceiling)C_MINFEE = '#9370db' (purple — floor/min)C_COST = '#b22222' (red — cost/risk/shortfall)(unit) in labels — ALWAYS [unit] (so [SOL], not (SOL)). NEVER use bare [unit] as an axis title — always prepend the quantity name.align + x: { value }.Bun.spawnSync — ALWAYS Bun.spawn + await .exited.load().