@rokkit/cli 1.6.0 → 1.8.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.
@@ -39,7 +39,8 @@ the vocabulary — cite it, don't restate it.
39
39
  Colours/patterns/symbols come from `createChartPreset()` shared via `<ChartProvider>` (nest to
40
40
  scope a subtree); named presets (`default`/`accessible`/`print`, or `helpers.presets`) go through
41
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`
42
+ (`@rokkit/core` `categoricalPalette` / `patterns/patterns.js` `PATTERNS` /
43
+ `lib/brewing/marks/points.js`
43
44
  `SYMBOL_NAMES`+`SYMBOL_TYPES`) then naming it in a preset — never inlining scattered raw colours.
44
45
  - **Colour follows the theme.** Preset shades resolve per light/dark mode; a chart should reskin
45
46
  from the preset/skin, not from hardcoded per-mark hex. Token-literal fills are fine when
@@ -47,6 +48,12 @@ the vocabulary — cite it, don't restate it.
47
48
  - **Accessibility is not free.** Colour-only encoding fails for print/colourblind — patterns
48
49
  (`pattern` channel) dual-code series. Interactive charts need `keyboard`/`onselect` and the
49
50
  `role`/`aria-label` the geoms provide.
51
+ - **Plane annotations go first, and the theory fixes the frame.** `Region`, `Hull` and `Contour`
52
+ describe the metric plane, and SVG paints in document order — placed after `Plot.Point` they
53
+ paint over it. A `Region` never moves the scales, so a plane defined by theory (Martin's
54
+ `[0,1]×[0,1]`) needs `xDomain`/`yDomain` on `PlotChart`, or a zone shrinks to wherever the rows
55
+ fall. `Rule slope` is ignored on a band axis. Thresholds on skewed metrics belong at a high
56
+ percentile of the data (p95), not a guessed constant.
50
57
  - **Evidence beats assertion.** You do not say "it themes" — you build and snapshot and paste what
51
58
  you saw.
52
59
 
@@ -66,6 +73,9 @@ the vocabulary — cite it, don't restate it.
66
73
  8. Is there a colour-independent encoding (pattern) where accessibility/print matters, and are
67
74
  interactive charts keyboard/aria-enabled?
68
75
  9. Does the chart hold up in light AND dark mode (no invisible marks, no overflow)?
76
+ 10. Are `Region` / `Hull` / `Contour` placed before the marks they sit behind, and is the domain
77
+ fixed where a region — not the data — defines the frame? Do many overlapping hulls default to
78
+ off rather than stacking into mud?
69
79
 
70
80
  ## Procedure
71
81
 
@@ -79,9 +89,11 @@ results than blind grep. Fall back to Grep/Glob only if a tool errors or returns
79
89
  `orientation`, `alpha`, and preset config.
80
90
  3. Grep the app's `.svelte` for the smells: `<Plot ` (stale root), `<GeomBar`/`<GeomLine` used as a
81
91
  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
92
+ raw `#[0-9a-fA-F]{3,8}`/`oklch(`/`rgb(` inside chart props, and a `Plot.Region`/`Plot.Hull`/
93
+ `Plot.Contour` that follows a `Plot.Point` in the same chart. Map each hit to the correct
83
94
  channel/preset fix.
84
- 4. If a new palette/pattern/symbol was added, verify it's in the right registry (`palette.json` /
95
+ 4. If a new palette/pattern/symbol was added, verify it's in the right registry
96
+ (`categoricalPalette` /
85
97
  `PATTERNS` / `SYMBOL_*`) with the right shape, and referenced by name in a preset. Run
86
98
  `rokkit doctor` if available and fold in its advisories.
87
99
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rokkit/cli",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Command line utilities for icon bundling and conversion.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "@mdi/svg": "^7.4.47",
31
- "@rokkit/unocss": "1.6.0",
31
+ "@rokkit/unocss": "1.8.0",
32
32
  "sade": "^1.8.1",
33
33
  "@iconify/tools": "^5.0.14",
34
34
  "@iconify/types": "^2.0.0",
@@ -1,6 +1,6 @@
1
1
  ---
2
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).
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, plane annotations (Rule with slope/intercept, Region bands/polygons, Hull per group, density Contour) and the architecture-analysis recipes built from them (Martin's main sequence, hotspots, complexity × coverage, fan-in/fan-out, god modules), 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
4
  ---
5
5
 
6
6
  # Charts — Rokkit (`@rokkit/chart`)
@@ -12,7 +12,8 @@ and symbols. There is no per-chart `palette` array prop; customization goes thro
12
12
 
13
13
  ```text
14
14
  data + channels (or spec)
15
- → PlotState (scales, colorMap, patternMap, symbolMap, geom registry, selection, zoom)
15
+ → PlotState (a composition of job classes: config, geoms, frame, channels, orientation,
16
+ interaction, scales, aesthetics, axes — see docs/design/20-chart.md)
16
17
  → PlotChart (SVG: geoms + axes + grid + legend + tooltip + overlays)
17
18
 
18
19
  preset (colors / patterns / symbols / shades / opacity)
@@ -53,7 +54,8 @@ Shapes: `BarChart`, `LineChart`, `AreaChart`, `PieChart`, `ScatterPlot`, `Bubble
53
54
  `Plot` is a **namespace object** (`Plot.Bar`, `Plot.Line`, …), not a component — the root is
54
55
  `PlotChart`. Each member equals its `Geom*` export (`Plot.Bar === GeomBar`); use either. Full set:
55
56
  `Bar`, `Line`, `Area`, `Point`, `Jitter`, `Arc`, `Box`, `Violin`, `Heatmap`, `Hexbin`,
56
- `Candlestick`, `Waterfall`, `Ribbon`, `Rule`, plus overlays `Highlight` / `Trend`.
57
+ `Candlestick`, `Waterfall`, `Ribbon`, `Radar`, `Rule`, `Region`, `Hull`, `Contour`, plus overlays
58
+ `Highlight` / `Trend`.
57
59
 
58
60
  **3. Spec API** (full control from a plain object — same result as composition):
59
61
 
@@ -119,7 +121,8 @@ Every categorical encoding is driven by a **preset** (`packages/chart/src/lib/pr
119
121
 
120
122
  Each list is **names into a registry**, cycled across your data's distinct values:
121
123
 
122
- - `colors` → palette names in **`lib/palette.json`** (each name → 11 shades `50–950`).
124
+ - `colors` → palette names in **`@rokkit/core`'s `categoricalPalette`** (each name → 11 shades
125
+ `50–950`).
123
126
  `assignColors(values, mode, preset)` picks `palette[name][shades[mode].fill|stroke]` — so a chart
124
127
  re-colours correctly for light/dark automatically.
125
128
  - `patterns` → names in **`patterns/patterns.js`** (`PATTERNS`, the SVG mark defs).
@@ -134,7 +137,7 @@ and share it via `ChartProvider`:
134
137
  <script>
135
138
  import { ChartProvider, createChartPreset, BarChart, LineChart } from '@rokkit/chart'
136
139
  const preset = createChartPreset({
137
- colors: ['teal', 'orange', 'rose'], // subset/reorder of palette.json names
140
+ colors: ['teal', 'orange', 'rose'], // subset/reorder of categoricalPalette names
138
141
  patterns: ['dots', 'hatch'],
139
142
  shades: { dark: { fill: '400' } } // partial shade override (merges)
140
143
  })
@@ -157,7 +160,8 @@ and share it via `ChartProvider`:
157
160
 
158
161
  ### Add a NEW colour palette
159
162
 
160
- 1. Add an 11-shade entry to `packages/chart/src/lib/palette.json` (shades `50`→`950`, light→dark):
163
+ 1. Add an 11-shade entry to `packages/core/src/colors/categorical.json` (shades `50`→`950`,
164
+ light→dark). It lives in core because `@rokkit/chart` and `@rokkit/graph` both consume it:
161
165
 
162
166
  ```json
163
167
  "brand": { "50": "#f4f7ff", "100": "…", "300": "#93b4ff", "500": "#3b6cff",
@@ -230,6 +234,56 @@ decorations expose `data-*` hooks: `[data-plot-geom="<type>"]`, `[data-plot-elem
230
234
 
231
235
  ---
232
236
 
237
+ ## Annotating the plane — Rule, Region, Hull, Contour
238
+
239
+ These describe the metric PLANE, not a row. SVG paints in document order, so place them **before**
240
+ the marks they sit behind.
241
+
242
+ ```svelte
243
+ <PlotChart data={components} xDomain={[0, 1]} yDomain={[0, 1]} legend tooltip>
244
+ <Plot.Region name="pain" points={[[0, 0], [0.5, 0], [0, 0.5]]} label="Zone of pain" />
245
+ <Plot.Region name="uselessness" points={[[1, 1], [0.5, 1], [1, 0.5]]} label="Zone of uselessness" />
246
+ <Plot.Hull x="instability" y="abstractness" color="package" />
247
+ <Plot.Contour x="instability" y="abstractness" bandwidth={28} />
248
+ <Plot.Rule slope={-1} intercept={1} label="main sequence" />
249
+ <Plot.Point x="instability" y="abstractness" color="package" size="loc" />
250
+ </PlotChart>
251
+ ```
252
+
253
+ - **`Rule`** — `x` / `y` values, or `slope` + `intercept` (ggplot's abline), clipped to the visible
254
+ domain and labelled at its midpoint along the line. A slope is ignored on a band axis.
255
+ - **`Region`** — `x` / `y` as `[lo, hi]` (a `null` end runs to the axis edge: `[p95, null]`), or a
256
+ polygon `points`. Reads no data, never moves the scales, clipped to the plot. `name` →
257
+ `data-plot-region` for theming; `label` at the centroid or `labelAt`.
258
+ - **`Hull`** — one padded convex hull per value of `fill` / `color`; the group field joins the
259
+ shared palette. A one- or two-member group still draws (dot, capsule).
260
+ - **`Contour`** — kernel-density contours per group; `bandwidth` is in pixels; `filled` for bands.
261
+
262
+ **The frame comes from the theory, not the data.** A region never moves the scales, so fix the
263
+ domain on `PlotChart` (`xDomain` / `yDomain`) when the plane is defined — or a zone shrinks because
264
+ no row happens to fall in it.
265
+
266
+ ### Architecture analysis (recipes, not components)
267
+
268
+ The library ships no architecture vocabulary — the recipes are ordinary geoms over metric rows the
269
+ consumer computes (the learn site measures rokkit itself with
270
+ `apps/learn/scripts/build-architecture-metrics.mjs`):
271
+
272
+ | Recipe | x × y | Annotations |
273
+ |--------|-------|-------------|
274
+ | Main sequence (Robert Martin) | instability `Ce/(Ca+Ce)` × abstractness | zone polygons, `Rule slope={-1} intercept={1}`, `Hull` per package, `Contour` for the pile-up at A = 0 |
275
+ | Hotspots | complexity × churn | `Region x={[p95, null]} y={[p95, null]}` |
276
+ | Complexity × coverage | complexity × coverage | `Region` for complex-and-under-tested, `Rule y={0.8}` |
277
+ | Fan-in × fan-out | fan-out × fan-in | `Region` for hubs and for reaches-everywhere |
278
+ | God modules | complexity × fan-out | `Region` past p95 on both |
279
+
280
+ Martin's metrics are per COMPONENT (a package or top-level folder); per file, most points sit
281
+ exactly on (0,0) or (1,0). Take thresholds as percentiles of the codebase, and the 95th rather than
282
+ the 90th — these distributions are heavy-tailed. For dependency structure and hidden coupling, reach
283
+ for `@rokkit/graph`: `DependencyMatrix`, and edges flagged `overlay` (drawn, never shaping layout).
284
+
285
+ ---
286
+
233
287
  ## Gotchas
234
288
 
235
289
  - The root is **`PlotChart`**, not `<Plot>` — `Plot` is the geom namespace object.
@@ -240,6 +294,8 @@ decorations expose `data-*` hooks: `[data-plot-geom="<type>"]`, `[data-plot-elem
240
294
  - `position="stack"` supersedes the boolean `stack` prop; grouping needs a `fill`/`color`/`group`
241
295
  field (a stack with no group field renders individual bars, not a stacked total).
242
296
  - A literal colour on `fill`/`color` is applied directly — it is **not** a legend group.
297
+ - `Region`, `Hull` and `Contour` placed AFTER `Plot.Point` paint over the points. Put them first.
298
+ - A `Hull` over many overlapping groups stacks translucent fills into mud — offer it as a toggle.
243
299
 
244
300
  ## Verify
245
301