A chart ismeant for people to read, and for you to execute. This skill turns "looking good" into a process with checks: correctness is guaranteed by construction, not by taste. There is only one core habit:
Color is computable, so compute it. Never judge by eye whether a palette is color-blind safe — run
scripts/validate_palette.js。
Positioning: method layer + parameter layer
- Method layer(this SKILL + references): choose form → choose pipeline → color by function → validate → mark specifications → render self-check. The method is independent of the medium.
- Parameter layer(
references/palette.md): a unified palette instance derived from the Feishu color system — categorical 8 colors (light/dark), sequential blue ramp, diverging pairs, status four colors, neutral chrome colors, all validated on Feishu light and dark backgrounds. The four rendering pipelines share this one set of parameters and no longer maintain their own color schemes.
Process — execute in order, color is always decided last
- Choose form. What is the data's task — compare magnitudes, distinguish series, show polarity, or is there just one number?
The task determines the form, and sometimes the answer is not a chart at all (a big number/metric row is more honest). →
references/choosing-a-form.md - Choose pipeline. See the routing table below. Form + medium together determine which pipeline to use.
- Color by function. categorical (identity) / ordinal (ordered tiers) / sequential (magnitude) /
diverging (polarity) / status (state), one rule per function, and color values are always taken from
references/palette.md,do not invent color values, do not cyclically generate a 9th color。 - Validate the palette — run the script, do not eyeball it(
scripts/relative to this skill's root directory):
Use in order as-isnode scripts/validate_palette.js "#3370ff,#d99904,..." --mode light node scripts/validate_palette.js "..." --mode dark --surface "#1f1f1f"palette.mdno need to rerun when finalizing color values(the finalized conclusions are already written in that file); only needed when changing color values, changing the background, or using an all-pairs scenario. FAIL must be fixed before continuing; WARN (color-blind ΔE 8–12 floor zone, contrast below 3:1 relief zone) is only legitimate when secondary encoding is fully in place (direct labels / whitespace gaps / table view). For scatter/bubble/map add--pairs all— this scenariodoes not use all 8 colors, usepalette.md's all-pairs safe subset (4 colors); for a single-color ramp add--ordinal。 - Apply mark specifications and self-check. Thin marks (bar ≤ 24px, line 2px), leave a 2px background gap between adjacent fills,
grids use hairline solid lines, text always uses the text color (series identity is carried by the color block beside it; do not apply series colors to text).
When done, check item by item against
references/anti-patterns.md; any hit is an error; finally render it and look at it with your own eyes (use scripts/verify.sh to screenshot htmlbox, svg-export for board, and actually send a preview for card).
Pipeline routing
| Requirement characteristics | Pipeline | Skill |
|---|---|---|
| Needs to "move": interactive tooltips, animations, real-time refresh, 3D, complex dashboards | HTML widgets (ECharts, etc.) | feishu-cli-htmlbox |
| Charts appear inmessage/notification cardsinside | Card chart component (VChart) | feishu-cli-card |
| Charts arepart of the document, batch-imported with Markdown, static is enough | Mermaid → board | feishu-cli-import |
| A standaloneboard: free-form visual/architecture diagrams/infographics, nodes editable | SVG → native nodes, etc., 5 paths | feishu-cli-board |
| Only one or two numbers + status | Don't draw a chart: card big numbers/fields, document Callout | feishu-cli-card / feishu-cli-import |
Each pipeline has a different degree of controllability, and the depth of spec implementation also differs: htmlbox (full control: palette + marks + interaction + automatic in-browser validation) > board SVG (palette + marks + layout; no tooltip fallback after rendering, direct labels must be more thorough than default) > card VChart (color array + form selection) > import Mermaid (classDef coloring + form selection).
Non-negotiable rules (apply to all four pipelines)
The complete acceptance checklist is based on
references/anti-patterns.md, this section is a quick overview of the most frequent rules among them; if there is any discrepancy between the two, anti-patterns.md is authoritative.
- Single axis. Never draw dual Y-axis charts (two dimensions → split into two charts, small multiples, or unify by indexing to a common base period).
- categorical colors are taken in a fixed order, never cycled. The 9th series is not a new color, it is folded into "other", split into small multiples, or compound encoding (hue × shape). Scatter/bubble/map (any two colors may be adjacent) use the all-pairs safe subset (≤4 series), and anything beyond that also goes to folding/small multiples.
- Colors follow the entity, not the ranking. After filtering out one series, the remaining series are not recolored.
- sequential = single hue light→dark; diverging = two opposing cool/warm colors + neutral gray midpoint. Never use a rainbow ramp; the diverging midpoint never carries a hue.
- The four status colors are reserved colors(good/warning/serious/critical), not to be used as "the 4th series"; when they appear they must be paired with an icon + text, and must not convey meaning by color alone.
- Text wears text color. Values, labels, and legend text use neutral ink, not series colors; identity is carried by the color swatch/short line next to the text.
- ≥ 2 series must have a legend(a single series does not need a legend box, the title already explains it); direct labels only label endpoints/extremes/the protagonist series, never label every point with a number。
File index
| File | What question does it answer |
|---|---|
references/palette.md |
Unified palette instance — the single source of truth for all color values (human-readable version), including how each pipeline uses them |
references/choosing-a-form.md |
Which chart form to choose? Or should you not draw a chart at all? |
references/anti-patterns.md |
Acceptance checklist — check item by item before shipping, any hit is an error |
scripts/validate_palette.js |
Runnable validator (Node CLI + browser data-palette dual mode; its functions can be required and reused) |
scripts/palette.json |
Machine-readable version of the palette (including deprecated color list), when changing colors update together with palette.md |
scripts/check_docs.js |
Documentation consistency check: Scan all skill documents for deprecated color remnants + palette.md completeness |