@sema-agent/server 1.196.0 → 1.198.0
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/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -1
- package/dist/config.js.map +1 -1
- package/dist/http/server.js +1 -0
- package/dist/http/server.js.map +1 -1
- package/dist/main.js +24 -5
- package/dist/main.js.map +1 -1
- package/dist/plugins/remote-scratchpad.d.ts +8 -0
- package/dist/plugins/remote-scratchpad.d.ts.map +1 -0
- package/dist/plugins/remote-scratchpad.js +56 -0
- package/dist/plugins/remote-scratchpad.js.map +1 -0
- package/dist/task-cwd.d.ts +8 -0
- package/dist/task-cwd.d.ts.map +1 -1
- package/dist/task-cwd.js +14 -0
- package/dist/task-cwd.js.map +1 -1
- package/package.json +2 -1
- package/skills/code-review.md +28 -0
- package/skills/commit-push-pr.md +77 -0
- package/skills/dataviz/SKILL.md +112 -0
- package/skills/dataviz/references/anti-patterns.md +119 -0
- package/skills/dataviz/references/choosing-a-form.md +57 -0
- package/skills/dataviz/references/color-formula.md +113 -0
- package/skills/dataviz/references/components.md +39 -0
- package/skills/dataviz/references/interaction.md +60 -0
- package/skills/dataviz/references/marks-and-anatomy.md +97 -0
- package/skills/dataviz/references/palette.md +149 -0
- package/skills/dataviz/scripts/validate_palette.js +262 -0
- package/skills/find-skills.md +148 -0
- package/skills/init.md +28 -0
- package/skills/keybindings-help.md +294 -0
- package/skills/loop.md +50 -0
- package/skills/run-skill-generator.md +493 -0
- package/skills/run.md +148 -0
- package/skills/schedule.md +48 -0
- package/skills/security-review.md +181 -0
- package/skills/simplify.md +64 -0
- package/skills/update-config.md +93 -0
- package/skills/verify.md +334 -0
package/dist/task-cwd.js
CHANGED
|
@@ -11,6 +11,20 @@ export function isValidCwd(cwd) {
|
|
|
11
11
|
export function cwdHonored(config) {
|
|
12
12
|
return config.remoteExec?.provider === "host" && config.requirePrincipal !== true;
|
|
13
13
|
}
|
|
14
|
+
export function inProcessSingleUserLane(config) {
|
|
15
|
+
return config.remoteExec === undefined && config.requirePrincipal !== true;
|
|
16
|
+
}
|
|
17
|
+
export function satisfiedByProcessCwd(requested, realpath, cwd = process.cwd) {
|
|
18
|
+
try {
|
|
19
|
+
return realpath(requested) === realpath(cwd());
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function shellEnvMismatchCount(requested, procEnv) {
|
|
26
|
+
return Object.keys(requested).filter((k) => procEnv[k] !== requested[k]).length;
|
|
27
|
+
}
|
|
14
28
|
export const MAX_ADDITIONAL_DIRS = 64;
|
|
15
29
|
export function parseAdditionalDirectories(raw) {
|
|
16
30
|
if (!Array.isArray(raw))
|
package/dist/task-cwd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-cwd.js","sourceRoot":"","sources":["../src/task-cwd.ts"],"names":[],"mappings":"AAiBA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC;AAQnC,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,CAAC,MAAM,GAAG,CAAC;QACd,GAAG,CAAC,MAAM,IAAI,aAAa;QAC3B,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QACpB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CACnC,CAAC;AACJ,CAAC;AAMD,MAAM,UAAU,UAAU,CAAC,MAA0E;IACnG,OAAO,MAAM,CAAC,UAAU,EAAE,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;AACpF,CAAC;AAGD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAYtC,MAAM,UAAU,0BAA0B,CAAC,GAAY;IACrD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,MAAM,IAAI,mBAAmB;YAAE,MAAM;QAC7C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACpD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,CAAC;AAeD,MAAM,UAAU,sBAAsB,CACpC,UAA8B,EAC9B,GAA+C;IAE/C,OAAO,UAAU,IAAI,CAAC,GAAG,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAClF,CAAC"}
|
|
1
|
+
{"version":3,"file":"task-cwd.js","sourceRoot":"","sources":["../src/task-cwd.ts"],"names":[],"mappings":"AAiBA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC;AAQnC,MAAM,UAAU,UAAU,CAAC,GAAY;IACrC,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,CAAC,MAAM,GAAG,CAAC;QACd,GAAG,CAAC,MAAM,IAAI,aAAa;QAC3B,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;QACnB,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QACpB,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CACnC,CAAC;AACJ,CAAC;AAMD,MAAM,UAAU,UAAU,CAAC,MAA0E;IACnG,OAAO,MAAM,CAAC,UAAU,EAAE,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;AACpF,CAAC;AAWD,MAAM,UAAU,uBAAuB,CAAC,MAA0E;IAChH,OAAO,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,gBAAgB,KAAK,IAAI,CAAC;AAC7E,CAAC;AAKD,MAAM,UAAU,qBAAqB,CAAC,SAAiB,EAAE,QAA+B,EAAE,MAAoB,OAAO,CAAC,GAAG;IACvH,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,SAAS,CAAC,KAAK,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAKD,MAAM,UAAU,qBAAqB,CAAC,SAAiC,EAAE,OAA2C;IAClH,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAClF,CAAC;AAGD,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAYtC,MAAM,UAAU,0BAA0B,CAAC,GAAY;IACrD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QACxB,IAAI,GAAG,CAAC,MAAM,IAAI,mBAAmB;YAAE,MAAM;QAC7C,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QACpD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1C,CAAC;AAeD,MAAM,UAAU,sBAAsB,CACpC,UAA8B,EAC9B,GAA+C;IAE/C,OAAO,UAAU,IAAI,CAAC,GAAG,CAAC,SAAS,KAAK,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AAClF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.198.0",
|
|
4
4
|
"description": "Sema Server — the server/API implementation layer for Sema, wiring core, registry, model providers, and cloud agent execution. Built on @sema-agent/core.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"!dist/sema-server*",
|
|
18
18
|
"!dist/run-local-linux-x64",
|
|
19
19
|
"!dist/run-local-darwin-arm64",
|
|
20
|
+
"skills",
|
|
20
21
|
"deploy/sema-up"
|
|
21
22
|
],
|
|
22
23
|
"bin": {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: code-review-rubric
|
|
3
|
+
description: How to produce a prioritized, actionable code review (severity, path:line, concrete fixes).
|
|
4
|
+
scenarios: code-review
|
|
5
|
+
---
|
|
6
|
+
# Code review rubric
|
|
7
|
+
|
|
8
|
+
Produce a review that an engineer can act on immediately.
|
|
9
|
+
|
|
10
|
+
## Output shape
|
|
11
|
+
1. **Summary** — 2–3 lines: overall health + the single most important thing to fix.
|
|
12
|
+
2. **Findings**, grouped by severity:
|
|
13
|
+
- **Blocker** — correctness/security bug, data loss, or a crash path. Must fix before merge.
|
|
14
|
+
- **Major** — likely bug, missing error handling, race, leak, or a design problem.
|
|
15
|
+
- **Minor** — style, naming, small simplification, nit.
|
|
16
|
+
3. Each finding: `path:line — what's wrong — concrete fix`. Cite the actual code; reference real symbols.
|
|
17
|
+
|
|
18
|
+
## What to look for
|
|
19
|
+
- **Correctness**: edge cases, off-by-one, race conditions, resource leaks, missing/incorrect error paths, unhandled rejections.
|
|
20
|
+
- **Security**: authz/ownership checks, input validation, injection (SQL/command/path), secrets in code/logs, unsafe deserialization, SSRF.
|
|
21
|
+
- **Architecture**: module boundaries, coupling, data flow, error propagation, concurrency model, idempotency of side effects.
|
|
22
|
+
- **Performance**: hot paths, N+1 queries, unnecessary allocations/copies, blocking IO on the request path, missing caching/pooling.
|
|
23
|
+
- **Tests**: are the risky paths covered? Do tests assert behavior, not implementation?
|
|
24
|
+
|
|
25
|
+
## Discipline
|
|
26
|
+
- **Read before you judge.** Use `repo_tree` to map the repo, then `repo_read_file` for the files you assess. Never invent files, lines, or symbols.
|
|
27
|
+
- Prefer a few high-signal findings over an exhaustive list of nits.
|
|
28
|
+
- When delegating to specialist reviewers, give each a clear scope; merge their findings, de-duplicate, and resolve disagreements.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-push-pr
|
|
3
|
+
description: Commit the current changes, push the branch, and open (or update) a pull request — one clean commit, a short PR title, and a Summary / Test plan body.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Context
|
|
7
|
+
|
|
8
|
+
Gather the real state first — run these and read the output:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
whoami
|
|
12
|
+
git status
|
|
13
|
+
git diff HEAD
|
|
14
|
+
git branch --show-current
|
|
15
|
+
git log --oneline <base>..HEAD # commits that will ride in the PR
|
|
16
|
+
git diff <base>...HEAD # the FULL diff the PR will contain
|
|
17
|
+
gh pr view --json number 2>/dev/null || true # does a PR already exist?
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`<base>` is the default branch (usually `main` or `master`; check
|
|
21
|
+
`git remote show origin` if unsure).
|
|
22
|
+
|
|
23
|
+
## Git Safety Protocol
|
|
24
|
+
|
|
25
|
+
- NEVER update the git config
|
|
26
|
+
- NEVER run destructive/irreversible git commands (like push --force, hard reset, etc) unless the user explicitly requests them
|
|
27
|
+
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
|
|
28
|
+
- NEVER force push to main/master; warn the user if they request it
|
|
29
|
+
- Do not commit files that likely contain secrets (.env, credentials.json, etc)
|
|
30
|
+
- Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input which is not supported
|
|
31
|
+
|
|
32
|
+
## Your task
|
|
33
|
+
|
|
34
|
+
Analyze all changes that will be included in the pull request, making
|
|
35
|
+
sure to look at all relevant commits (NOT just the latest commit, but
|
|
36
|
+
ALL commits that will be included in the pull request from the
|
|
37
|
+
`git diff <base>...HEAD` output above).
|
|
38
|
+
|
|
39
|
+
Based on the above changes:
|
|
40
|
+
|
|
41
|
+
1. Create a new branch if you are currently on the default branch
|
|
42
|
+
(prefix the branch name with the username from `whoami`, e.g.
|
|
43
|
+
`username/feature-name`).
|
|
44
|
+
2. Create a single commit with an appropriate message:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git commit -m "$(cat <<'EOF'
|
|
48
|
+
Commit message here.
|
|
49
|
+
EOF
|
|
50
|
+
)"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
3. Push the branch to the repo's remote (usually `origin`; use the
|
|
54
|
+
remote this repo is actually configured with), with `-u` on first
|
|
55
|
+
push.
|
|
56
|
+
4. If a PR already exists for this branch (check the `gh pr view`
|
|
57
|
+
output above), update the PR title and body using `gh pr edit` to
|
|
58
|
+
reflect the current diff. Otherwise, create a pull request using
|
|
59
|
+
`gh pr create` with the multi-line body syntax shown below.
|
|
60
|
+
- IMPORTANT: Keep PR titles short (under 70 characters). Use the
|
|
61
|
+
body for details.
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
gh pr create --title "Short, descriptive title" --body "$(cat <<'EOF'
|
|
65
|
+
## Summary
|
|
66
|
+
- What changed and why, in a few bullets
|
|
67
|
+
|
|
68
|
+
## Test plan
|
|
69
|
+
- How this was verified (commands run, flows driven, or why not applicable)
|
|
70
|
+
EOF
|
|
71
|
+
)"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
You have the capability to call multiple tools in a single response.
|
|
75
|
+
You MUST do all of the above in a single message.
|
|
76
|
+
|
|
77
|
+
Return the PR URL when you're done, so the user can see it.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dataviz
|
|
3
|
+
description: Use this skill whenever you are about to create ANY chart, graph, plot, dashboard, or data visualization, in ANY output medium - an HTML or React artifact, inline SVG, plotting code in any library (matplotlib, plotly, d3, Recharts, ...), or an image/PNG you will render and share. Read it BEFORE writing the first line of chart code, choosing chart colors, building a stat tile / meter / KPI row, or laying out a dashboard. Produces visualizations that read as one system - elegant, accessible, consistent in light and dark - using a brand-neutral placeholder palette you swap for your own. Teaches a design-system-agnostic method: a form heuristic, a color formula with a runnable validator, mark specs, and interaction rules. A validated default palette is documented in `references/palette.md` - swap that file's values for your brand's. Triggers on: "chart", "graph", "plot", "data viz", "visualization", "dashboard", "analytics", "visualize data", "categorical colors", "sequential / diverging palette", "stat tile", "sparkline", "heatmap", "legend", "axis", "tooltip", "chart colors", "color by series".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Data Visualization
|
|
7
|
+
|
|
8
|
+
A chart is **read by people and executed by you**. This skill turns "make it look
|
|
9
|
+
good" into a procedure with checks, so the result is right by construction rather
|
|
10
|
+
than by taste.
|
|
11
|
+
|
|
12
|
+
**The method here is design-system-agnostic.** Nothing in the procedure, the form
|
|
13
|
+
heuristic, the six checks, or the mark specs is specific to one product. A design
|
|
14
|
+
system supplies a small set of *parameters* (its ramps, a categorical order, a
|
|
15
|
+
diverging pair, a status palette, a texture, its surfaces, its filter components);
|
|
16
|
+
the method consumes them unchanged. A **validated default palette** is the
|
|
17
|
+
reference instance, fully specified in `references/palette.md`. To target your
|
|
18
|
+
brand, read that file's structure and substitute its values — touch nothing else.
|
|
19
|
+
|
|
20
|
+
> The single most important habit: **the color part is computable, so compute it.**
|
|
21
|
+
> Never eyeball whether a palette is colorblind-safe — run `scripts/validate_palette.js`.
|
|
22
|
+
|
|
23
|
+
## The procedure — do these in order
|
|
24
|
+
|
|
25
|
+
Color comes LAST. Most bad charts pick colors first.
|
|
26
|
+
|
|
27
|
+
1. **Pick the form.** What is the data's job — magnitude, identity, polarity, a
|
|
28
|
+
single headline, change-over-time? The job picks the chart type, and sometimes
|
|
29
|
+
the answer is *not a chart* (a stat tile or hero number). → `references/choosing-a-form.md`
|
|
30
|
+
2. **Assign color by the job it does.** Categorical (identity), sequential
|
|
31
|
+
(magnitude), diverging (polarity), or status (state) — each has one rule.
|
|
32
|
+
Assign categorical hues in fixed order, never cycled. → `references/color-formula.md`
|
|
33
|
+
3. **VALIDATE the palette — run the script, don't reason about ΔE.**
|
|
34
|
+
`node scripts/validate_palette.js "<hex,hex,…>" --mode light` (relative to
|
|
35
|
+
this skill's base directory — or load it as `<script type="module">` in the
|
|
36
|
+
chart's own page, where it reads
|
|
37
|
+
`data-palette` off `<body>` and logs a `console.table` report). It returns
|
|
38
|
+
pass/fail on the lightness band, chroma floor, adjacent-pair CVD separation,
|
|
39
|
+
and contrast. Fix anything that FAILs before continuing. Re-run for
|
|
40
|
+
`--mode dark` with that mode's surface.
|
|
41
|
+
4. **Apply mark specs & spacers.** Thin marks, 4px rounded data-ends anchored to
|
|
42
|
+
the baseline, 2px lines, ≥8px markers, a 2px surface gap between fills (stacked
|
|
43
|
+
segments and adjacent bars alike) and a 2px surface ring on overlapping marks,
|
|
44
|
+
selective direct labels. → `references/marks-and-anatomy.md`
|
|
45
|
+
5. **Add the hover layer — by default.** An HTML/SVG chart *is* interactive; ship
|
|
46
|
+
a crosshair+tooltip on line/area and a per-mark hover tooltip on bar/dot/cell.
|
|
47
|
+
The only form that skips it is a bare stat tile with no plot. Hit targets bigger
|
|
48
|
+
than the mark; filters in one row above the charts. → `references/interaction.md`
|
|
49
|
+
6. **Final accessibility pass.** For ≥ 2 series a legend is always present and ≤ 4
|
|
50
|
+
are also direct-labeled (a single series needs no legend box — the title names
|
|
51
|
+
it), so identity is never color-alone; a table view exists; dark mode is **selected** — its own
|
|
52
|
+
steps from the same ramps, validated against the dark surface, not an automatic
|
|
53
|
+
flip; texture is available for the CVD/print/forced-colors case.
|
|
54
|
+
7. **Render it and look at it.** The validator checks color, not layout — open or
|
|
55
|
+
screenshot the output and eyeball it for label collisions, geometry, and overflow
|
|
56
|
+
before calling it done.
|
|
57
|
+
|
|
58
|
+
Then check the result against **`references/anti-patterns.md`** — it is the catalog
|
|
59
|
+
of what goes wrong. If your chart matches an entry, it's wrong.
|
|
60
|
+
|
|
61
|
+
## Non-negotiables (true in every design system)
|
|
62
|
+
|
|
63
|
+
- **Assign categorical hues in fixed order, never cycled.** A 9th series is never a
|
|
64
|
+
generated hue — it folds into "Other," small multiples, or composite encoding.
|
|
65
|
+
- **One axis.** Never a dual-axis chart (two y-scales). Two measures of different
|
|
66
|
+
scale → two charts, small multiples, or indexed to a common base. *(This is the
|
|
67
|
+
#1 chart mistake — see anti-patterns.)*
|
|
68
|
+
- **Color follows the entity, never its rank.** A filter that changes the series
|
|
69
|
+
count must not repaint the survivors.
|
|
70
|
+
- **Sequential = one hue, light→dark. Diverging = two hues + a neutral gray
|
|
71
|
+
midpoint.** Never a rainbow; never a hue at the diverging midpoint.
|
|
72
|
+
- **Run the validator before shipping any categorical palette.** CVD ≥ 12 is the
|
|
73
|
+
target; 8–12 is a floor that is legal ONLY with secondary encoding. A contrast WARN
|
|
74
|
+
obligates visible labels or a table view — it is not dismissable.
|
|
75
|
+
- **Thin marks; a legend always present for ≥ 2 series (none for one), with
|
|
76
|
+
selective direct labels (never a number on every point); recessive grid/axes.**
|
|
77
|
+
- **Text wears text tokens, never the series color** — values, labels, and legends
|
|
78
|
+
stay in primary/secondary/muted ink; a colored mark beside them carries identity.
|
|
79
|
+
- **Status colors are reserved** (good/warning/serious/critical) and never reused
|
|
80
|
+
for "series 4"; they ship with an icon + label, never color alone.
|
|
81
|
+
|
|
82
|
+
## Plugging in a design system
|
|
83
|
+
|
|
84
|
+
The method is invariant; only these parameters change per system. The reference
|
|
85
|
+
instance — every value filled in — is `references/palette.md`.
|
|
86
|
+
|
|
87
|
+
| Parameter | What the system provides |
|
|
88
|
+
|---|---|
|
|
89
|
+
| **Ramps** | the hue scales (named steps) the palette draws from |
|
|
90
|
+
| **Categorical theme** | the fixed hue order (a named theme); default + alternates |
|
|
91
|
+
| **Sequential hue** | the default single hue for magnitude |
|
|
92
|
+
| **Diverging pair** | two warm/cool poles + a neutral midpoint |
|
|
93
|
+
| **Status palette** | good / warning / serious / critical — steps distinct from categorical |
|
|
94
|
+
| **Texture fill** | one directional hand-drawn fill, used at 45° / 135° |
|
|
95
|
+
| **Surfaces** | light & dark chart-surface colors (the validator needs these) |
|
|
96
|
+
| **Filter controls** | date-range & dimension controls (behavioral spec in `interaction.md`) |
|
|
97
|
+
|
|
98
|
+
To onboard a new system: fill those rows, feed its ramps to the validator, and let
|
|
99
|
+
it snap each slot to the nearest passing step. Structure and rules stay as written.
|
|
100
|
+
|
|
101
|
+
## Reference files
|
|
102
|
+
|
|
103
|
+
| File | What it answers |
|
|
104
|
+
|------|-----------------|
|
|
105
|
+
| `references/choosing-a-form.md` | Which chart type / is it even a chart? |
|
|
106
|
+
| `references/color-formula.md` | The four jobs, the six checks, snap-to-passing |
|
|
107
|
+
| `references/marks-and-anatomy.md` | Mark specs, spacers, labels, figures, hero number |
|
|
108
|
+
| `references/interaction.md` | Tooltips & hover, filters & time ranges |
|
|
109
|
+
| `references/components.md` | The pieces a chart is made of — build each in plain HTML |
|
|
110
|
+
| `references/anti-patterns.md` | **What goes wrong — check every chart against this** |
|
|
111
|
+
| `references/palette.md` | **The reference palette instance** — every parameter, filled in; swap for your brand's |
|
|
112
|
+
| `scripts/validate_palette.js` | Runnable six-checks validator (run it; don't eyeball) |
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Anti-patterns — what goes wrong
|
|
2
|
+
|
|
3
|
+
Check every chart against this list. If your output matches an entry, it is wrong —
|
|
4
|
+
fix it before shipping. These are real failure modes, each caught in shipping
|
|
5
|
+
dashboards.
|
|
6
|
+
|
|
7
|
+
## Color & encoding
|
|
8
|
+
|
|
9
|
+
**❌ Dual-axis charts (two y-scales on one plot).**
|
|
10
|
+
Why it misleads: the alignment of the two scales is arbitrary, so the chart invents a
|
|
11
|
+
correlation that isn't in the data. Real example: an "Adoption" chart plotting Users
|
|
12
|
+
(0–30k) against Sessions (0–800k) — a reviewer flagged it as looking "hallucinated."
|
|
13
|
+
✅ Do instead: two charts, small multiples, or index both series to a common base
|
|
14
|
+
(=100 at t0) on **one** axis.
|
|
15
|
+
|
|
16
|
+
**❌ Recolor-on-filter.** Assigning colors by current rank, so filtering out a series
|
|
17
|
+
repaints the survivors.
|
|
18
|
+
Why: a reader who learned "Acme is blue" is now misled.
|
|
19
|
+
✅ Color follows the entity, not its row number. Survivors keep their hue.
|
|
20
|
+
|
|
21
|
+
**❌ Cycling / generating hues past 8.** A 9th categorical color, generated or reused.
|
|
22
|
+
Why: indistinguishable from an existing slot under CVD; breaks the order check.
|
|
23
|
+
✅ Fold the tail into "Other," facet into small multiples, or use composite encoding.
|
|
24
|
+
|
|
25
|
+
**❌ Eyeballing colorblind-safety.** "These look different enough."
|
|
26
|
+
✅ Run `scripts/validate_palette.js`. Adjacent ΔE ≥ 12, or 8–12 WITH secondary encoding.
|
|
27
|
+
|
|
28
|
+
**❌ A value-ramp on nominal categories.** Coloring each bar darker-where-bigger
|
|
29
|
+
when the categories have no natural order (products, teams, endpoints).
|
|
30
|
+
Why: it double-encodes bar length as hue, burns the only free channel on
|
|
31
|
+
information the chart already shows, and fails the categorical checks by design
|
|
32
|
+
(a ramp spans the lightness band and drops below the chroma floor).
|
|
33
|
+
✅ One series → one color (slot 1) for every bar. Ordered categories (funnel,
|
|
34
|
+
tiers, age bands) → the ordinal ramp, validated with `--ordinal`.
|
|
35
|
+
|
|
36
|
+
**❌ Rainbow / non-neighbor sequential.** A multi-hue ramp for magnitude.
|
|
37
|
+
✅ One hue, light→dark. (Analogous neighbors or semantic heat are the only multi-hue
|
|
38
|
+
sequential exceptions, always with a scale legend.)
|
|
39
|
+
|
|
40
|
+
**❌ A hue at the diverging midpoint, or two cool hues as the two poles.**
|
|
41
|
+
Why: the midpoint must read as "nothing"; poles must read as opposite. blue↔aqua
|
|
42
|
+
fails this (both cool); blue↔red or blue↔orange succeed (warm/cool).
|
|
43
|
+
✅ Two hues that read as opposite + a neutral gray midpoint.
|
|
44
|
+
|
|
45
|
+
**❌ Status color used for a non-status series** (or a series color used for status).
|
|
46
|
+
✅ Status tokens only when the color *means* good/bad; categorical when it's identity.
|
|
47
|
+
|
|
48
|
+
## Form
|
|
49
|
+
|
|
50
|
+
**❌ Eight categorical hues when the story is one number.** The most common way a
|
|
51
|
+
chart misses its point.
|
|
52
|
+
✅ Emphasis (highlight one, gray the rest), or a stat tile / hero number.
|
|
53
|
+
|
|
54
|
+
**❌ A one-bar bar chart, or a 2-slice pie.**
|
|
55
|
+
✅ A stat tile. The number is the chart.
|
|
56
|
+
|
|
57
|
+
**❌ A donut/pie for comparing close values.**
|
|
58
|
+
✅ A bar, or the numbers. Part-to-whole at a glance only, ≤ 6 segments.
|
|
59
|
+
|
|
60
|
+
**❌ More than ~7 color classes carrying meaning.**
|
|
61
|
+
✅ A table, or table + chart. Past ~7 bins, adjacent classes blur.
|
|
62
|
+
|
|
63
|
+
## Marks & chrome
|
|
64
|
+
|
|
65
|
+
**❌ Thick saturated blocks, heavy gridlines, no breathing room.** Reads loud, even
|
|
66
|
+
childish, at scale.
|
|
67
|
+
✅ Thin marks, hairline recessive grid/axes, generous padding. Saturated fills are
|
|
68
|
+
for small marks and accents, never large blocks.
|
|
69
|
+
|
|
70
|
+
**❌ Dashed gridlines or axis rules.** Dashing adds visual noise and reads as
|
|
71
|
+
"projection" or "threshold" when it's just a grid.
|
|
72
|
+
✅ Gridlines and axes are solid hairlines, one shade off the surface.
|
|
73
|
+
|
|
74
|
+
**❌ A number on every data point.** A value beside every dot or segment is chaos and goes unread.
|
|
75
|
+
✅ A legend is always present for ≥ 2 series; direct-label *selectively* (the endpoint, the extreme, the one series that matters) and let the axis + tooltip carry the rest.
|
|
76
|
+
|
|
77
|
+
**❌ A border drawn around marks to separate them.**
|
|
78
|
+
✅ A 2px surface gap between fills (stacked segments and adjacent bars alike) and a 2px surface ring (on overlapping markers).
|
|
79
|
+
|
|
80
|
+
**❌ A label clipped by, or overflowing, a too-small bar or stacked segment** —
|
|
81
|
+
including `overflow: hidden` cropping the first/last characters of an in-segment label.
|
|
82
|
+
✅ Only render a label inside a mark when it fits with padding; otherwise move it
|
|
83
|
+
outside the bar end, or drop it to the tooltip/legend (the value stays in the table view).
|
|
84
|
+
|
|
85
|
+
**❌ A chart container whose fixed height excludes the x-axis band** — the plot
|
|
86
|
+
fits, the axis labels don't, so the card gets a tiny nested vertical scroll.
|
|
87
|
+
✅ Size the container to include the axis labels (plot height + x-axis band),
|
|
88
|
+
or let the container grow with its content instead of fixing a height.
|
|
89
|
+
|
|
90
|
+
**❌ A display or serif face on the hero figure.** It reads as off-brand decoration.
|
|
91
|
+
✅ The hero figure uses the same sans as everything else.
|
|
92
|
+
|
|
93
|
+
**❌ `tabular-nums` on a large standalone number.** Equal-width digits make `121`
|
|
94
|
+
look loose at display sizes.
|
|
95
|
+
✅ Proportional figures on hero and stat-tile values; `tabular-nums` only where
|
|
96
|
+
numbers align vertically (table rows, axis ticks).
|
|
97
|
+
|
|
98
|
+
**❌ Texture on by default, or as decoration.** Dense angled fields are a vestibular
|
|
99
|
+
risk and read as noise on value scales.
|
|
100
|
+
✅ Texture is opt-in (a11y setting, print, forced-colors), 45°/135° only, ordered on
|
|
101
|
+
value scales.
|
|
102
|
+
|
|
103
|
+
## Interaction & accessibility
|
|
104
|
+
|
|
105
|
+
**❌ A tooltip as the only way to read a value.**
|
|
106
|
+
✅ Tooltips enhance, never gate — every value is also reachable via direct labels or
|
|
107
|
+
the table view; keyboard focus shows the same as hover.
|
|
108
|
+
|
|
109
|
+
**❌ Pinpoint hover targets — an 8px scatter dot you must land on dead-center.**
|
|
110
|
+
✅ The hit area includes the 2px gap and meets a ~24px minimum; dense scatter uses a nearest-point / Voronoi layer.
|
|
111
|
+
|
|
112
|
+
**❌ Per-chart filters, or filters inside a chart card.**
|
|
113
|
+
✅ One filter row above everything it scopes; all charts re-render against the same slice.
|
|
114
|
+
|
|
115
|
+
**❌ Skeleton flash on refetch.**
|
|
116
|
+
✅ Hold the previous render at reduced opacity — no layout jump.
|
|
117
|
+
|
|
118
|
+
**❌ No table view / color-only encoding on a continuous scale.**
|
|
119
|
+
✅ Every chart has a table-view twin (the WCAG-clean equivalent).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Choosing a form
|
|
2
|
+
|
|
3
|
+
Decide this **before** color. The data's job picks the form — and sometimes the
|
|
4
|
+
right form is not a chart.
|
|
5
|
+
|
|
6
|
+
## Is it even a chart?
|
|
7
|
+
|
|
8
|
+
| The data is… | Use | Not |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| A single current value (+ maybe a trend) | **Stat tile** (value + delta + sparkline) | A one-bar bar chart |
|
|
11
|
+
| A handful of headline numbers | **KPI row** of stat tiles | A grouped bar chart |
|
|
12
|
+
| The one number a dashboard leads with | **Hero figure** (≥48px, sans) | — |
|
|
13
|
+
| A single ratio against a limit | **Meter** (same-ramp track) | A pie of 2 slices |
|
|
14
|
+
| More than ~7 classes that all carry meaning | A **table** (or table + chart) | More colors |
|
|
15
|
+
|
|
16
|
+
If a chart *is* right, pick the type by the job:
|
|
17
|
+
|
|
18
|
+
## The job → the type
|
|
19
|
+
|
|
20
|
+
| Job (what the reader must do) | Default form | Color job |
|
|
21
|
+
|---|---|---|
|
|
22
|
+
| Compare magnitude, low → high | bar / column; **heatmap** for a grid | sequential (one hue) |
|
|
23
|
+
| Trend over time | line; area for a single series | sequential or 1 categorical |
|
|
24
|
+
| Tell distinct series apart | grouped/stacked bar, multi-line | **categorical** |
|
|
25
|
+
| One series is the point, rest are context | **emphasis** (highlight one, gray the rest) | 1 hue + gray |
|
|
26
|
+
| Above/below a baseline; Δ to target | diverging bar, or line vs baseline | diverging |
|
|
27
|
+
| Part-to-whole | **stacked bar** (go horizontal for many / long-named categories) | categorical |
|
|
28
|
+
| Ordered-scale share (Likert, sentiment, agree↔disagree) | **diverging stacked bar**, centered on neutral | diverging |
|
|
29
|
+
| Before → after per item | dumbbell | 1 hue, 2 shades |
|
|
30
|
+
|
|
31
|
+
## The rules behind the table
|
|
32
|
+
|
|
33
|
+
- **Sequential is the safe default.** One hue, more-is-darker. It stays legible and
|
|
34
|
+
consistent and is hard to misread. Reach for it unless the data's job is
|
|
35
|
+
specifically *identity* or *polarity*.
|
|
36
|
+
- **Categorical is for when the series ARE the subject** — and it has a real cost:
|
|
37
|
+
it can bury the one data point that actually matters. If the story is "this one
|
|
38
|
+
went up," that's **emphasis**, not categorical.
|
|
39
|
+
- **Emphasis** = the most underused form. One series in the accent hue, the rest in
|
|
40
|
+
the de-emphasis gray. Often the honest answer to "make this chart clearer."
|
|
41
|
+
- **Texture is an opt-in expression, not a default form.** It earns its place only
|
|
42
|
+
for accessibility (full CVD), print/export, and `forced-colors`. Never decorative.
|
|
43
|
+
→ see `marks-and-anatomy.md`.
|
|
44
|
+
|
|
45
|
+
## Series-count ladder (categorical)
|
|
46
|
+
|
|
47
|
+
| Series | Treatment |
|
|
48
|
+
|---|---|
|
|
49
|
+
| 1–3 | color alone is comfortable for everyone; direct-label |
|
|
50
|
+
| 4 | the CVD floor enters — direct labels become mandatory, not a courtesy |
|
|
51
|
+
| 5–6 | soft cap; legend or small multiples |
|
|
52
|
+
| 7–8 | token ceiling; past it, fold the tail into "Other," facet into small multiples, or use composite encoding (hue × shape) |
|
|
53
|
+
|
|
54
|
+
Never solve "too many series" by generating more hues. A generated 9th hue is
|
|
55
|
+
indistinguishable from an existing one under CVD and breaks every check.
|
|
56
|
+
|
|
57
|
+
---
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Color formula
|
|
2
|
+
|
|
3
|
+
Color is **not hand-picked**. Every chart color does exactly one of four jobs, and a
|
|
4
|
+
palette is legal only if it passes six checks. The checks are the product — they are
|
|
5
|
+
what makes a palette safe to change and what lets the same method run on any design
|
|
6
|
+
system's ramps.
|
|
7
|
+
|
|
8
|
+
## The four jobs
|
|
9
|
+
|
|
10
|
+
| Job | What it encodes | Structure |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| **Categorical** | identity (which series) | 8 hues, fixed order, assigned in sequence, never cycled |
|
|
13
|
+
| **Ordinal** | position in a sequence (funnel stage, tier, bucket) | one hue, monotone lightness steps; light end still ≥ 2:1 on surface |
|
|
14
|
+
| **Sequential** | magnitude (how much) | one hue, steps 100→700, light→dark; flips anchor in dark |
|
|
15
|
+
| **Diverging** | polarity (which side of a baseline) | two hues + a neutral gray midpoint; equal steps per arm |
|
|
16
|
+
| **Status** | state (good→critical) | a small fixed scale, reserved meaning, always icon+label |
|
|
17
|
+
|
|
18
|
+
**Categorical or ordinal?** If swapping the category order would change the
|
|
19
|
+
meaning — funnel stages, size tiers (S/M/L), age bands, cohort buckets — it is
|
|
20
|
+
**ordinal** and takes a one-hue ramp so the reader sees the order in the color.
|
|
21
|
+
If swapping would not — product names, teams, regions, endpoints — it is
|
|
22
|
+
**nominal categorical** and each bar takes the *same* slot-1 hue (one series,
|
|
23
|
+
so no legend box — the title names it), or slots 1..N when there are N separate
|
|
24
|
+
series. Never color nominal bars by their value: that spends the identity channel
|
|
25
|
+
re-encoding what bar length already shows.
|
|
26
|
+
|
|
27
|
+
## The six checks
|
|
28
|
+
|
|
29
|
+
Every categorical color — current or proposed — must pass all six.
|
|
30
|
+
|
|
31
|
+
1. **Fixed hue anchors.** Eight families in a fixed order. The order is the
|
|
32
|
+
CVD-safety mechanism; it never changes. *(structural — enforced, not measured)*
|
|
33
|
+
2. **Lightness band per mode.** OKLCH L ≈ 0.43–0.77 light; ≈ 0.48–0.67 dark. *(validator)*
|
|
34
|
+
3. **Chroma floor.** OKLCH C ≥ ~0.10 — below it a hue reads as gray and stops doing
|
|
35
|
+
identity work. *(validator)*
|
|
36
|
+
4. **CVD separation.** Machado-2009 ΔE ≥ 12 target / ≥ 8 floor (floor legal only with
|
|
37
|
+
secondary encoding), under protanopia & deuteranopia. *Adjacent* pairs for
|
|
38
|
+
stacks/bars/lines (only neighbors touch — assignment never skips); **all pairs for
|
|
39
|
+
scatter, bubble, choropleth, and small-multiples**, where any two marks can sit side
|
|
40
|
+
by side — pass `--pairs all` there or a real collapse stays hidden. *(validator)*
|
|
41
|
+
5. **Contrast vs surface.** ≥ 3:1 for marks; conditionally relaxed where values are
|
|
42
|
+
readable another way (visible labels or the table view). *(validator)*
|
|
43
|
+
6. **Documented palette only.** Every slot is a hex from the instance file
|
|
44
|
+
(`palette.md` or its equivalent) — no eyeballed values. *(structural; for a
|
|
45
|
+
customer's ramps, snap to nearest — below)*
|
|
46
|
+
|
|
47
|
+
## Run the checks — never eyeball them
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
node scripts/validate_palette.js \
|
|
51
|
+
"#2a78d6,#1baf7a,#eda100,#008300,#4a3aa7,#e34948,#e87ba4,#eb6834" --mode light
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
(`scripts/` is relative to this skill's base directory, shown at the top of the prompt.)
|
|
55
|
+
|
|
56
|
+
(or load it as `<script type="module">` in the chart's own page — it reads
|
|
57
|
+
`data-palette` off `<body>` and logs a `console.table` report)
|
|
58
|
+
|
|
59
|
+
Reports each computable check (2–5) with PASS / WARN / FAIL plus the worst CVD pair.
|
|
60
|
+
Exit 0 = no hard FAIL (WARN bands — floor-band CVD 8–12 and sub-3:1 contrast relief —
|
|
61
|
+
still exit 0 and require secondary encoding); exit 1 on any FAIL. Run once per mode
|
|
62
|
+
(`--mode dark --surface "#1a1a19"`), and add
|
|
63
|
+
`--pairs all` for scatter / bubble / map / small-multiples charts (where any two marks
|
|
64
|
+
can be neighbors — the default adjacent check would hide a collapse). For an
|
|
65
|
+
**ordinal** ramp pass `--ordinal` — it switches to the ramp checks (monotone L,
|
|
66
|
+
adjacent ΔL ≥ 0.06, light-end contrast ≥ 2.0:1, single hue) instead of the
|
|
67
|
+
categorical six.
|
|
68
|
+
A WARN on CVD (8–12 floor) is legal **only** if you also ship secondary encoding
|
|
69
|
+
(direct labels, gaps, or texture). A WARN on contrast is **not dismissable** — it
|
|
70
|
+
obligates a relief channel (visible direct labels or the table view); shipping the
|
|
71
|
+
sub-3:1 fill with neither is a fail.
|
|
72
|
+
|
|
73
|
+
**Scope — what the validator does and doesn't cover.** These six checks validate a
|
|
74
|
+
*categorical* palette (series identity). They do **not** judge a lone status/text
|
|
75
|
+
color or a sequential ramp. For a single status or text color, run a WCAG *text*-
|
|
76
|
+
contrast check (4.5:1 normal, 3:1 large) — `validate_palette.js` exports
|
|
77
|
+
`contrast(a, b)` for exactly this. For sequential/diverging, the check is lightness
|
|
78
|
+
monotonicity across the ramp, not adjacency CVD — running the categorical validator on
|
|
79
|
+
a sequential ramp **will FAIL by design** (it spans the band; steps sit close), which
|
|
80
|
+
is expected, not a real failure; don't "fix" a good ramp to satisfy it.
|
|
81
|
+
|
|
82
|
+
## Snap-to-passing (any design system)
|
|
83
|
+
|
|
84
|
+
Given a customer's ramps and a desired order:
|
|
85
|
+
1. For each slot, pick the step whose OKLCH L sits in the mode's band and C ≥ floor.
|
|
86
|
+
2. Run the validator. For any adjacent pair below ΔE 12, nudge one slot ± a step
|
|
87
|
+
(hold its hue, move its lightness) and re-run.
|
|
88
|
+
3. Repeat until the worst adjacent pair clears the floor. Function preserved, the
|
|
89
|
+
customer's hues kept.
|
|
90
|
+
|
|
91
|
+
## Themes
|
|
92
|
+
|
|
93
|
+
The slot **order** is a separable, named choice — a *theme* — on the same hues and
|
|
94
|
+
the same six checks. Each design system names a default order and any alternates;
|
|
95
|
+
swapping themes tunes the mood without touching the method. A surface adopts one
|
|
96
|
+
theme and freezes it; never mix themes within a dashboard. (See `palette.md`.)
|
|
97
|
+
|
|
98
|
+
**Deriving an order when a system has no theme yet:** don't guess. Enumerate candidate
|
|
99
|
+
orderings of the system's hues, run the validator on each, and pick the one that
|
|
100
|
+
maximizes the *minimum adjacent* CVD ΔE. (Seeding from a known-good order by hue-family
|
|
101
|
+
analogy, then optimizing, is fine — this is exactly how the default in
|
|
102
|
+
`palette.md` was derived.)
|
|
103
|
+
|
|
104
|
+
## Status is fixed
|
|
105
|
+
|
|
106
|
+
Status never follows the theme — it is a small fixed scale (good → warning → serious
|
|
107
|
+
→ critical) with reserved meaning, on steps deliberately distinct from the categorical
|
|
108
|
+
slots so a status color never impersonates a series, and always paired with an
|
|
109
|
+
icon + label (on a light surface warning and serious sit below 3:1 by design —
|
|
110
|
+
the pairing is the mitigation). (Exact steps in `palette.md`.) The collision rule: when a series *means* good/bad (error rate, pass/fail) it wears
|
|
111
|
+
status tokens; when it's just "series 4" it wears categorical — never both in one chart.
|
|
112
|
+
|
|
113
|
+
---
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Components — the pieces a chart is made of
|
|
2
|
+
|
|
3
|
+
A chart is built from these parts, assembled in plain HTML/SVG. Tier 0 is the
|
|
4
|
+
foundation everything mounts on; the System tier is what makes the method
|
|
5
|
+
portable (and is, itself, this skill).
|
|
6
|
+
|
|
7
|
+
## Tier 0 — Foundations
|
|
8
|
+
- **Color roles** — categorical (8 × light/dark), sequential ramps, diverging pairs,
|
|
9
|
+
status (4), de-emphasis / "Other", grayscale chart furniture (axis/grid/label/surface).
|
|
10
|
+
Defined as CSS custom properties at the top of the HTML — see `palette.md`.
|
|
11
|
+
- **Texture fill** — the directional fill + 45°/135° rotations.
|
|
12
|
+
- **Chart container** — a `<figure>` (or card `<div>`) that owns responsive
|
|
13
|
+
sizing, title/caption, and the **table-view toggle** (the accessibility twin
|
|
14
|
+
of every chart). **Any fixed height includes the x-axis band** (plot height
|
|
15
|
+
+ axis labels) so the card never gets a nested vertical scroll; prefer
|
|
16
|
+
letting the container grow with its content.
|
|
17
|
+
- **Legend** (toggle-to-isolate, texture-aware swatches) · **Tooltip** · **Axis** · **Data label**.
|
|
18
|
+
|
|
19
|
+
## Tier 1 — The charts people ask for
|
|
20
|
+
- **Bar chart** — grouped + stacked, thin-bar default, horizontal + vertical.
|
|
21
|
+
- **Line chart** — multi-series, soft-fill area variant, accessibility markers.
|
|
22
|
+
- **Stat tile** — value + delta + optional sparkline (the figure contract).
|
|
23
|
+
- **Meter / progress track** — same-ramp tracks.
|
|
24
|
+
|
|
25
|
+
## Tier 2 — Rounding out the kit
|
|
26
|
+
- **Area chart** (stacked, band-edge = line) · **Sparkline** · **Heatmap**
|
|
27
|
+
- **Scale legend** (sequential / diverging) · **Chart filters / time range** · **Empty state**
|
|
28
|
+
|
|
29
|
+
## System tier — becomes the skill
|
|
30
|
+
- **Six-checks validator** — `scripts/validate_palette.js` (palette validation).
|
|
31
|
+
- **Theming engine** — snap a customer's ramps to passing values (color-formula.md).
|
|
32
|
+
- **Chart-type heuristic** — pick the form (choosing-a-form.md).
|
|
33
|
+
- **Table-view generator** — the WCAG-clean equivalent of any chart.
|
|
34
|
+
|
|
35
|
+
Notes: part-to-whole rides on the stacked bar chart; donut stays deprioritized.
|
|
36
|
+
Small multiples is a layout pattern over these, not a separate piece. Scatter
|
|
37
|
+
joins Tier 2 if scatter-heavy surfaces land.
|
|
38
|
+
|
|
39
|
+
---
|