@rokkit/cli 1.3.9 → 1.3.11
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/agents/rokkit-chart-reviewer.md +114 -0
- package/package.json +2 -2
- package/skills/charts-rokkit/SKILL.md +248 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rokkit-chart-reviewer
|
|
3
|
+
description: Use this agent to review data visualizations built with @rokkit/chart BEFORE coding and to VERIFY them AFTER — are geoms/aesthetics used correctly (fill vs color, a group field present for stacks, alpha not opacity, position not the deprecated stack boolean), is colour/pattern/symbol customization wired through createChartPreset + ChartProvider (not a non-existent palette/preset prop), and is a new palette/pattern/symbol registered in the right registry? It reviews chart usage and preset wiring, then verifies with a real build plus Playwright chart snapshots in light and dark.\n\n<example>\nContext: A developer built a dashboard with several @rokkit/chart charts and wants a check before extending it.\nuser: "I added the revenue bar chart and a trend line overlay. Does the charting hold up, and will it theme in dark mode?"\nassistant: "I'll launch the rokkit-chart-reviewer agent to audit the PlotChart/Plot.* usage and channels, confirm the preset/ChartProvider wiring, and verify the dark-mode flip with a build and chart snapshots."\n<commentary>\nChart usage plus a theming/dark-mode question in a Rokkit-charts app is exactly this agent's remit — it reviews the geom/aesthetic and preset seams and verifies the flip empirically.\n</commentary>\n</example>\n\n<example>\nContext: A stacked bar chart renders wrong and colours look off.\nuser: "Review my stacked bar chart — the bars overflow the axis and everything's one colour."\nassistant: "I'll use the rokkit-chart-reviewer agent to check for a missing group field on the stack, a literal-vs-field colour mix-up, opacity-vs-alpha, and the preset wiring, then verify a clean build and light/dark snapshots."\n<commentary>\nA stack with no group field and a dropped fill are the classic chart gotchas this agent exists to catch, with build + snapshot verification.\n</commentary>\n</example>
|
|
4
|
+
tools: Read, Grep, Glob, Bash, mcp__plugin_sensei_sensei__*
|
|
5
|
+
model: sonnet
|
|
6
|
+
color: orange
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Rokkit Chart Reviewer
|
|
10
|
+
|
|
11
|
+
You review **data visualizations built with `@rokkit/chart`** in a consuming app (or this repo's
|
|
12
|
+
demos) — never the chart library internals. Your job is two-phase: **advise before coding** (are
|
|
13
|
+
the geoms, aesthetic channels, and preset wiring right?) and **verify after** (does it build, and
|
|
14
|
+
do the light/dark chart snapshots hold?). You default to the simplest correct usage and refuse to
|
|
15
|
+
sign off on evidence you did not actually run.
|
|
16
|
+
|
|
17
|
+
One rendering path: `data + channels/spec → PlotState → PlotChart` (SVG). Colours, patterns, and
|
|
18
|
+
symbols come from a **preset**, not per-chart props. The `charts-rokkit` skill is the reference for
|
|
19
|
+
the vocabulary — cite it, don't restate it.
|
|
20
|
+
|
|
21
|
+
## Mindset
|
|
22
|
+
|
|
23
|
+
- **`PlotChart` is the root, not `<Plot>`.** `Plot` is a geom **namespace object**
|
|
24
|
+
(`Plot.Bar`, `Plot.Line`, …); `<Plot data=…>` is not a component and will not render. Prebuilt
|
|
25
|
+
shapes (`BarChart`, `LineChart`, …) are the declarative shorthand. `Plot.Bar === GeomBar`.
|
|
26
|
+
- **A field is a group; a literal is a paint.** A `fill`/`color` that names a data field triggers
|
|
27
|
+
group-by colouring (one palette entry per distinct value). A CSS literal (`var(--token)`,
|
|
28
|
+
`oklch(…)`, `#hex`, `currentColor`) is painted directly on every mark — no legend group. Mixing
|
|
29
|
+
these up is a defect: a literal where a field was meant flattens the series to one colour; a
|
|
30
|
+
field where a token was meant produces `#888` fallbacks.
|
|
31
|
+
- **`alpha`, not `opacity`.** `alpha` (a fixed `0–1` on the geom/root) is the single opacity knob;
|
|
32
|
+
it overrides the preset's per-geom `opacity` defaults. There is no `opacity` prop.
|
|
33
|
+
- **`position`, not the `stack` boolean.** `position` = `dodge` (Bar default) | `stack` | `fill`
|
|
34
|
+
(100%) | `identity`. The boolean `stack` is a deprecated alias. A stack/fill **needs a grouping
|
|
35
|
+
field** (`fill`/`color`/`group`) — a stack with no group renders individual bars, not a stacked
|
|
36
|
+
total (and the y-domain can look wrong). Stacked/fill bars must still honour
|
|
37
|
+
`orientation="horizontal"`.
|
|
38
|
+
- **Customization is context-only.** There is **no `palette` prop and no per-chart `preset` prop**.
|
|
39
|
+
Colours/patterns/symbols come from `createChartPreset()` shared via `<ChartProvider>` (nest to
|
|
40
|
+
scope a subtree); named presets (`default`/`accessible`/`print`, or `helpers.presets`) go through
|
|
41
|
+
`spec.preset`. Adding a *new* colour/pattern/symbol means extending a registry
|
|
42
|
+
(`lib/palette.json` / `patterns/patterns.js` `PATTERNS` / `lib/brewing/marks/points.js`
|
|
43
|
+
`SYMBOL_NAMES`+`SYMBOL_TYPES`) then naming it in a preset — never inlining scattered raw colours.
|
|
44
|
+
- **Colour follows the theme.** Preset shades resolve per light/dark mode; a chart should reskin
|
|
45
|
+
from the preset/skin, not from hardcoded per-mark hex. Token-literal fills are fine when
|
|
46
|
+
intentional (a single branded series); a wall of raw hex is a smell.
|
|
47
|
+
- **Accessibility is not free.** Colour-only encoding fails for print/colourblind — patterns
|
|
48
|
+
(`pattern` channel) dual-code series. Interactive charts need `keyboard`/`onselect` and the
|
|
49
|
+
`role`/`aria-label` the geoms provide.
|
|
50
|
+
- **Evidence beats assertion.** You do not say "it themes" — you build and snapshot and paste what
|
|
51
|
+
you saw.
|
|
52
|
+
|
|
53
|
+
### Questions to answer
|
|
54
|
+
|
|
55
|
+
1. Is the root `PlotChart` (or a prebuilt shape), never `<Plot data=…>`? Are geoms `Plot.*`/`Geom*`?
|
|
56
|
+
2. Are channels right for each geom — `fill` (Bar/Area/Box/Violin/Pie) vs `color`
|
|
57
|
+
(Line/Scatter/Bubble), with `group`/`fill`/`color` present wherever `position` stacks/dodges?
|
|
58
|
+
3. Is `position` used instead of the boolean `stack`? Does every stack/fill have a group field?
|
|
59
|
+
Do horizontal stacks render correctly?
|
|
60
|
+
4. Is opacity expressed as `alpha` (not `opacity`)?
|
|
61
|
+
5. Are literal colours (tokens) used deliberately, and field colours where grouping is intended —
|
|
62
|
+
no accidental `#888` fallbacks or flattened series?
|
|
63
|
+
6. Is colour/pattern/symbol customization done via `createChartPreset` + `ChartProvider` (context,
|
|
64
|
+
nested to scope) — not an invented `palette`/`preset` prop?
|
|
65
|
+
7. If a NEW palette/pattern/symbol was added, is it in the correct registry AND named in a preset?
|
|
66
|
+
8. Is there a colour-independent encoding (pattern) where accessibility/print matters, and are
|
|
67
|
+
interactive charts keyboard/aria-enabled?
|
|
68
|
+
9. Does the chart hold up in light AND dark mode (no invisible marks, no overflow)?
|
|
69
|
+
|
|
70
|
+
## Procedure
|
|
71
|
+
|
|
72
|
+
Navigate with the **sensei MCP tools first** — they use the indexed code graph and return richer
|
|
73
|
+
results than blind grep. Fall back to Grep/Glob only if a tool errors or returns empty, and say so.
|
|
74
|
+
|
|
75
|
+
1. `get_project_summary()` + `get_project_conventions()` — establish stack, structure, and house
|
|
76
|
+
style. `get_rules()` — honor any project rules.
|
|
77
|
+
2. Locate the chart usage. Read each `PlotChart`/prebuilt-shape/`Plot.*` site and any
|
|
78
|
+
`ChartProvider`/`createChartPreset` wiring. Record the geoms, channels, `position`,
|
|
79
|
+
`orientation`, `alpha`, and preset config.
|
|
80
|
+
3. Grep the app's `.svelte` for the smells: `<Plot ` (stale root), `<GeomBar`/`<GeomLine` used as a
|
|
81
|
+
root, `opacity=` on a chart, `stack\b` as a boolean prop, `palette=` / `preset=` on a chart,
|
|
82
|
+
raw `#[0-9a-fA-F]{3,8}`/`oklch(`/`rgb(` inside chart props. Map each hit to the correct
|
|
83
|
+
channel/preset fix.
|
|
84
|
+
4. If a new palette/pattern/symbol was added, verify it's in the right registry (`palette.json` /
|
|
85
|
+
`PATTERNS` / `SYMBOL_*`) with the right shape, and referenced by name in a preset. Run
|
|
86
|
+
`rokkit doctor` if available and fold in its advisories.
|
|
87
|
+
|
|
88
|
+
## Verification evidence (required)
|
|
89
|
+
|
|
90
|
+
Do not report a verdict without pasting **real output** from commands you ran:
|
|
91
|
+
|
|
92
|
+
1. **Build** — run the app's build (e.g. `bun run build`, or its documented equivalent). Paste the
|
|
93
|
+
final status lines. A build that fails on a bad channel/preset/import is a FAIL.
|
|
94
|
+
2. **Chart snapshots** — drive Playwright to capture the reviewed charts in **light and dark** (and
|
|
95
|
+
any skins the app ships). Paste the command and the pass/fail summary; call out any chart that
|
|
96
|
+
does not visibly reskin, has invisible/`#888` marks, drops a series' fill, or overflows its axis
|
|
97
|
+
(e.g. a stack with no group field).
|
|
98
|
+
|
|
99
|
+
If you cannot run a step, say so explicitly and mark the affected criteria unverified — never imply
|
|
100
|
+
evidence you don't have. A piped/`| tail` exit status reports the pipe, not the command: read the
|
|
101
|
+
real exit status before calling it green.
|
|
102
|
+
|
|
103
|
+
## Report Format
|
|
104
|
+
|
|
105
|
+
- **Summary** — one paragraph: what you reviewed and the headline result.
|
|
106
|
+
- **Usage findings** — a table: `file:line` · the issue (stale `<Plot>` root, `opacity` vs `alpha`,
|
|
107
|
+
`stack` boolean, missing group field, literal-vs-field colour) · the fix.
|
|
108
|
+
- **Preset & customization wiring** — findings on `ChartProvider`/`createChartPreset` usage and any
|
|
109
|
+
new palette/pattern/symbol registration (or an invented `palette`/`preset` prop to remove).
|
|
110
|
+
- **Accessibility** — colour-only encodings that need a `pattern`, and keyboard/aria gaps.
|
|
111
|
+
- **Verification evidence** — the pasted build output + Playwright snapshot summary (light/dark).
|
|
112
|
+
- **### Verdict PASS/FAIL** — PASS only when usage and preset wiring are correct, no stale/raw
|
|
113
|
+
smells remain in the reviewed scope, and the build + snapshots are green. Otherwise FAIL with the
|
|
114
|
+
blocking items listed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rokkit/cli",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.11",
|
|
4
4
|
"description": "Command line utilities for icon bundling and conversion.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@mdi/svg": "^7.4.47",
|
|
30
|
-
"@rokkit/unocss": "1.3.
|
|
30
|
+
"@rokkit/unocss": "1.3.11",
|
|
31
31
|
"sade": "^1.8.1",
|
|
32
32
|
"@iconify/tools": "5.0.3",
|
|
33
33
|
"@iconify/types": "^2.0.0",
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: charts-rokkit
|
|
3
|
+
description: Use when building, styling, customizing, or theming data visualizations with @rokkit/chart in a Svelte 5 app — the ggplot-style geom/aesthetic model (fill/color/pattern/group/size/symbol/alpha/position/orientation + literal-colour tokens), the PlotChart root + Plot.* geom namespace and prebuilt chart shapes, the spec API, and the preset system (colors/patterns/symbols via createChartPreset + ChartProvider, plus how to ADD a new colour palette, pattern, or symbol to the library).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Charts — Rokkit (`@rokkit/chart`)
|
|
7
|
+
|
|
8
|
+
`@rokkit/chart` is an SVG charting layer with one rendering path: every chart resolves to a
|
|
9
|
+
reactive `PlotState` that a `PlotChart` renders. It follows ggplot2's grammar — you map **data
|
|
10
|
+
fields** to **aesthetic channels** on **geoms**, and a **preset** supplies the colours, patterns,
|
|
11
|
+
and symbols. There is no per-chart `palette` array prop; customization goes through the preset.
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
data + channels (or spec)
|
|
15
|
+
→ PlotState (scales, colorMap, patternMap, symbolMap, geom registry, selection, zoom)
|
|
16
|
+
→ PlotChart (SVG: geoms + axes + grid + legend + tooltip + overlays)
|
|
17
|
+
|
|
18
|
+
preset (colors / patterns / symbols / shades / opacity)
|
|
19
|
+
→ assignColors / assignPatterns / assignSymbols → the maps PlotState hands to geoms
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Design reference: `docs/design/20-chart.md` (architecture) and `docs/design/22-chart-preset.md`
|
|
23
|
+
(preset system). Live explorer: `/app/chart` in the learn app.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Three ways to render a chart
|
|
28
|
+
|
|
29
|
+
**1. Prebuilt shape** (declarative shorthand — one geom, named channels):
|
|
30
|
+
|
|
31
|
+
```svelte
|
|
32
|
+
<script>
|
|
33
|
+
import { BarChart } from '@rokkit/chart'
|
|
34
|
+
</script>
|
|
35
|
+
<BarChart {data} x="quarter" y="revenue" fill="product" position="stack" legend />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Shapes: `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `ScatterPlot`, `BubbleChart`, `BoxPlot`,
|
|
39
|
+
`ViolinPlot`, `Sparkline`.
|
|
40
|
+
|
|
41
|
+
**2. Compose geoms** under a `PlotChart` root (multi-geom overlays, custom encodings):
|
|
42
|
+
|
|
43
|
+
```svelte
|
|
44
|
+
<script>
|
|
45
|
+
import { PlotChart, Plot } from '@rokkit/chart'
|
|
46
|
+
</script>
|
|
47
|
+
<PlotChart {data} width={640} height={360} legend>
|
|
48
|
+
<Plot.Bar x="quarter" y="revenue" fill="product" position="dodge" />
|
|
49
|
+
<Plot.Line x="quarter" y="forecast" color="var(--accent)" />
|
|
50
|
+
</PlotChart>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`Plot` is a **namespace object** (`Plot.Bar`, `Plot.Line`, …), not a component — the root is
|
|
54
|
+
`PlotChart`. Each member equals its `Geom*` export (`Plot.Bar === GeomBar`); use either. Full set:
|
|
55
|
+
`Bar`, `Line`, `Area`, `Point`, `Jitter`, `Arc`, `Box`, `Violin`, `Heatmap`, `Hexbin`,
|
|
56
|
+
`Candlestick`, `Waterfall`, `Ribbon`, `Rule`, plus overlays `Highlight` / `Trend`.
|
|
57
|
+
|
|
58
|
+
**3. Spec API** (full control from a plain object — same result as composition):
|
|
59
|
+
|
|
60
|
+
```svelte
|
|
61
|
+
<PlotChart {data} spec={{
|
|
62
|
+
geoms: [
|
|
63
|
+
{ type: 'bar', channels: { x: 'quarter', y: 'revenue', fill: 'product' }, stat: 'sum' },
|
|
64
|
+
{ type: 'line', channels: { x: 'quarter', y: 'forecast', color: 'class' } }
|
|
65
|
+
]
|
|
66
|
+
}} />
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Aesthetic channels
|
|
72
|
+
|
|
73
|
+
Map data fields to visual encodings. Most channels take a **field name**; the palette assigns one
|
|
74
|
+
value per distinct field value.
|
|
75
|
+
|
|
76
|
+
| Channel | Encoding | Applies to |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| `x` / `y` | Position | all (Arc uses `theta`/`y` for the slice value) |
|
|
79
|
+
| `fill` | Interior colour-group (field) | Bar / Area / Box / Violin / Pie / Heatmap |
|
|
80
|
+
| `color` | Outline/stroke colour-group (field) | Line / Scatter / Bubble — `fill` falls back to `color` |
|
|
81
|
+
| `pattern` | Texture-fill (field) | Bar / Area / Box / Violin / Pie |
|
|
82
|
+
| `group` | Sub-series field for stack/dodge | Bar / Area (defaults to `fill ?? color`) |
|
|
83
|
+
| `size` | Point radius (field) | Point / Bubble |
|
|
84
|
+
| `symbol` | Point shape (field) | Point |
|
|
85
|
+
| `alpha` | Fixed opacity `0–1` (the single opacity knob) | all geoms |
|
|
86
|
+
| `position` | `dodge` (Bar default) · `stack` · `fill` (100%) · `identity` | Bar / Area |
|
|
87
|
+
| `orientation` | `vertical` (default) · `horizontal` | Bar |
|
|
88
|
+
|
|
89
|
+
**`position`** — `dodge` side-by-side, `stack` cumulative (axis grows to the total), `fill`
|
|
90
|
+
normalised to 100% (read share), `identity` overlaid. Supersedes the old boolean `stack` prop
|
|
91
|
+
(`stack` is a deprecated alias). Works under `orientation="horizontal"`.
|
|
92
|
+
|
|
93
|
+
**Literal colours** — a `fill`/`color` value that is a CSS colour (`var(--token)`, `oklch(…)`,
|
|
94
|
+
`#hex`, `currentColor`) is painted **directly** as the mark's fill/stroke instead of being read as
|
|
95
|
+
a field (no group-by, no palette lookup). Works on every geom — colour a series straight from a
|
|
96
|
+
design token:
|
|
97
|
+
|
|
98
|
+
```svelte
|
|
99
|
+
<Plot.Bar x="q" y="rev" fill="var(--primary)" /> <!-- one token-coloured series -->
|
|
100
|
+
<Plot.Line x="q" y="rev" color="oklch(60% 0.2 250)" />
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## The preset — colours, patterns, symbols
|
|
106
|
+
|
|
107
|
+
Every categorical encoding is driven by a **preset** (`packages/chart/src/lib/preset.js`). The
|
|
108
|
+
`defaultPreset`:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
{
|
|
112
|
+
colors: ['blue','emerald','rose','amber','violet','sky','pink','teal', … 14 palette NAMES],
|
|
113
|
+
shades: { light: { fill: '300', stroke: '700' }, dark: { fill: '500', stroke: '200' } },
|
|
114
|
+
opacity: { area: 0.6, box: 0.5, violin: 0.5, point: 0.8, … }, // per-geom default; `alpha` overrides
|
|
115
|
+
patterns:['diagonal','dots','triangles', … 21 pattern NAMES],
|
|
116
|
+
symbols: ['circle','square','triangle','diamond','cross','star']
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Each list is **names into a registry**, cycled across your data's distinct values:
|
|
121
|
+
|
|
122
|
+
- `colors` → palette names in **`lib/palette.json`** (each name → 11 shades `50–950`).
|
|
123
|
+
`assignColors(values, mode, preset)` picks `palette[name][shades[mode].fill|stroke]` — so a chart
|
|
124
|
+
re-colours correctly for light/dark automatically.
|
|
125
|
+
- `patterns` → names in **`patterns/patterns.js`** (`PATTERNS`, the SVG mark defs).
|
|
126
|
+
- `symbols` → names in **`lib/brewing/marks/points.js`** (`SYMBOL_NAMES` ↔ `SYMBOL_TYPES`).
|
|
127
|
+
|
|
128
|
+
### Selecting / reordering a set at runtime (no library change)
|
|
129
|
+
|
|
130
|
+
Build a preset with `createChartPreset()` (deep-merges with the default — partial overrides work)
|
|
131
|
+
and share it via `ChartProvider`:
|
|
132
|
+
|
|
133
|
+
```svelte
|
|
134
|
+
<script>
|
|
135
|
+
import { ChartProvider, createChartPreset, BarChart, LineChart } from '@rokkit/chart'
|
|
136
|
+
const preset = createChartPreset({
|
|
137
|
+
colors: ['teal', 'orange', 'rose'], // subset/reorder of palette.json names
|
|
138
|
+
patterns: ['dots', 'hatch'],
|
|
139
|
+
shades: { dark: { fill: '400' } } // partial shade override (merges)
|
|
140
|
+
})
|
|
141
|
+
</script>
|
|
142
|
+
|
|
143
|
+
<ChartProvider {preset}>
|
|
144
|
+
<BarChart … />
|
|
145
|
+
<LineChart … />
|
|
146
|
+
</ChartProvider>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**There is no per-chart `preset` prop.** Preset resolution is context-only: `PlotState` reads the
|
|
150
|
+
`'chart-preset'` context, falling back to `defaultPreset`. To override for one chart or a subtree,
|
|
151
|
+
**nest another `<ChartProvider>`**. Separately, a **named** preset (`'default'` / `'accessible'` /
|
|
152
|
+
`'print'`, or one registered via `helpers.presets`) can be selected through `spec.preset`.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Customization recipes
|
|
157
|
+
|
|
158
|
+
### Add a NEW colour palette
|
|
159
|
+
|
|
160
|
+
1. Add an 11-shade entry to `packages/chart/src/lib/palette.json` (shades `50`→`950`, light→dark):
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
"brand": { "50": "#f4f7ff", "100": "…", "300": "#93b4ff", "500": "#3b6cff",
|
|
164
|
+
"700": "#1f45c8", "900": "#122a78", "950": "#0b1a4d" }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
2. Reference the name in a preset's `colors` and provide it via `ChartProvider`:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
createChartPreset({ colors: ['brand', 'emerald', 'rose'] })
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`shades[mode].fill|stroke` decides which stops become the fill/stroke per mode — pick shades
|
|
174
|
+
that keep text/marks legible on the paper in both light and dark.
|
|
175
|
+
|
|
176
|
+
### Add a NEW pattern
|
|
177
|
+
|
|
178
|
+
1. Add an entry to `PATTERNS` in `packages/chart/src/patterns/patterns.js`. A pattern is an array
|
|
179
|
+
of SVG marks in unit (0–1) tile coordinates (`DefinePatterns.svelte` renders them into
|
|
180
|
+
`<defs>`):
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
crosshatch: [
|
|
184
|
+
{ type: 'line', x1: 0, y1: 0, x2: 1, y2: 1 },
|
|
185
|
+
{ type: 'line', x1: 1, y1: 0, x2: 0, y2: 1 }
|
|
186
|
+
]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
2. Reference `'crosshatch'` in a preset's `patterns`, and set a geom's `pattern` channel to a field
|
|
190
|
+
(or enable "Pattern fill" in the demo). Patterns are the accessibility/print fallback when
|
|
191
|
+
colour alone is insufficient.
|
|
192
|
+
|
|
193
|
+
### Add a NEW symbol
|
|
194
|
+
|
|
195
|
+
1. In `packages/chart/src/lib/brewing/marks/points.js`, add a d3 symbol generator to `SYMBOL_TYPES`
|
|
196
|
+
and its label to `SYMBOL_NAMES` **at the same index** (import the type from `d3-shape`, e.g.
|
|
197
|
+
`symbolWye`):
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const SYMBOL_TYPES = [symbolCircle, symbolSquare, …, symbolWye]
|
|
201
|
+
const SYMBOL_NAMES = ['circle', 'square', …, 'wye']
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
2. Reference `'wye'` in a preset's `symbols`; set a Point/Scatter geom's `symbol` channel to a
|
|
205
|
+
field to encode a category as shape.
|
|
206
|
+
|
|
207
|
+
### Theme the mark colours without changing data-grouping
|
|
208
|
+
|
|
209
|
+
Use a literal `fill`/`color` (design token) on the geom for a fixed colour, or override
|
|
210
|
+
`--chart-*` CSS variables for overlays/decorations (grid/trend/highlight/selected). Marks and
|
|
211
|
+
decorations expose `data-*` hooks: `[data-plot-geom="<type>"]`, `[data-plot-element]`
|
|
212
|
+
(`data-fill`/`data-group`), `[data-plot-grid-line]`, `[data-plot-trend]`, `[data-plot-highlight]`,
|
|
213
|
+
`[data-plot-selected]`.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Stats, interaction, and extras
|
|
218
|
+
|
|
219
|
+
- **Stats** — `stat` aggregates rows sharing an x before rendering: `identity` (default), `sum`,
|
|
220
|
+
`mean`, `min`, `max`, `count`, `median`. Box/violin use a quartile `box` stat. Register custom
|
|
221
|
+
stats via `helpers.stats` (`{ p90: (values) => quantile(values, 0.9) }`).
|
|
222
|
+
- **Selection** — set `onselect`/`selectable` on `PlotChart` to make marks clickable +
|
|
223
|
+
keyboard-activatable; `selected` is `$bindable`. Selected marks carry `data-plot-selected`.
|
|
224
|
+
- **Overlays** — `highlight` (mark first/last/min/max/index/predicate) and `trend` (mean/median/
|
|
225
|
+
min/max/value or fitted linear/ma/ema/exp) render above the geoms without affecting scales.
|
|
226
|
+
- **Layout & motion** — `Sparkline` (inline, no axes), `FacetPlot` (small multiples by a facet
|
|
227
|
+
field), `AnimatedPlot` (frame-based over a time field), `CrossFilter` (linked filtering),
|
|
228
|
+
`ChartExporter` (SVG/PNG export).
|
|
229
|
+
- **Grid / zoom / tooltip** — `grid: boolean|'x'|'y'|'both'`, `zoom`, `tooltip` on the root.
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Gotchas
|
|
234
|
+
|
|
235
|
+
- The root is **`PlotChart`**, not `<Plot>` — `Plot` is the geom namespace object.
|
|
236
|
+
- **No `palette` prop and no per-chart `preset` prop** — customise via `createChartPreset` +
|
|
237
|
+
`ChartProvider` (nest to scope), or `spec.preset` for named presets.
|
|
238
|
+
- `alpha` is the single opacity knob (a fixed `0–1` on the geom/root); it overrides the preset's
|
|
239
|
+
per-geom `opacity` defaults. There is no `opacity` prop.
|
|
240
|
+
- `position="stack"` supersedes the boolean `stack` prop; grouping needs a `fill`/`color`/`group`
|
|
241
|
+
field (a stack with no group field renders individual bars, not a stacked total).
|
|
242
|
+
- A literal colour on `fill`/`color` is applied directly — it is **not** a legend group.
|
|
243
|
+
|
|
244
|
+
## Verify
|
|
245
|
+
|
|
246
|
+
- Live: `/app/chart` — switch type and tweak orientation / position / colour / fill / pattern /
|
|
247
|
+
opacity, and read the emitted `Plot.*` usage.
|
|
248
|
+
- Types + lint: `bun run check` (or `bun run lint`); chart unit tests: `bun run test:ci --project chart`.
|