Releases: ganapativs/microcharts
Release list
@microcharts/react@0.8.0
Minor Changes
-
#50
7e25243Thanks
@ganapativs! - Robustness, consistency and legibility pass across all 106 charts.
Most of this is invisible if your charts already looked right; the parts that aren't are listed under "behaviour
changes" below.Fixed: charts that could hang, crash or vanish. These were all reachable from ordinary props, and each now has a
regression test.TapeGaugenever finished rendering whenvaluewas large enough (about 1e16 and up) that its tick step fell below
one ULP — the tick loop stopped advancing and spun until the tab died. Ticks are now counted, not accumulated, and
capped.TraceFoldhung forever on aparentgraph containing a cycle (a span parented to itself, or any two-span loop).
The critical-path walk now tracks what it has visited.- Marks silently disappeared whenever a scale's domain span was infinite — including finite data whose arithmetic
overflows, such as aWaterfallrunning total past 1e308. An infinite span yields a slope of exactly0, which
passed the old finite check and then producedNaNcoordinates.scaleLinearnow validates the span itself. PictogramRow'stotal,Progress'ssegments,Thermometer'sticksandFoldedDayBand'sbinsallocated
one node per unit with no ceiling, so a raw count passed by mistake could exhaust memory. All four now saturate.- Charts derived bounds with
Math.max(...array), which throwsRangeErrorpast roughly 125k elements. Every such
site now uses a stack-safe fold, so a long series renders instead of crashing. CyclePlotthrew onperiod={NaN}(an empty input field yields exactly that),HeartbeatBlipdivided by a zero or
non-finitewindowand could put "in the last NaN minutes" into its accessible name, andActivityGridaccepted an
unvalidateddomainand paintedfill-opacity="NaN".
Fixed: accessibility and inline seating.
- Labels sitting on a solid mark (
HeatCell's upper steps,TimeInRangezones,EventTimelinespans) were rendering
in body ink instead of on-fill ink — dark-on-dark on the strongest cells. The stylesheet always won over thefill
attribute these charts were setting, so the intended colour never applied. - A decorative interactive chart (
summary={false}orlive={false}) lost its inline baseline seat, which also
detached its readout chip and hit box from the mark by up to a seat's height. The live region — which carries the
seat — now stays mounted and is silenced by emptying it. - Visible readout chips and idle labels on
MicroDonut,GradeProfile,GardenGrid,QuantileDotsand
EventTimelinecomposed English inline instead of going through thestringscontract, so they stayed English in a
localized app.
Behaviour changes worth knowing.
- Interactive charts now claim only the horizontal touch gesture (
touch-action: pan-y pinch-zoom) rather than all
gestures, so a chart no longer traps the page scroll under a finger; a scroll that takes over now clears the
highlight. HeatCellandHeatStripbuild their step colour by mixing the accent into the band rather than ramping opacity,
so the steps stay distinct on dark surfaces. The fill moved to the stylesheet, which restores the high-contrast
(forced-colors) mapping that an inline fill was overriding.DotPlot,DumbbellandSlopescale their label type and row-name budget with the chart's size instead of using
a fixed 6-unit font and 6-character cap, so figure-scale charts read properly.Slopesteps its type down until the
labels fit rather than dropping them.
Added.
stringson the staticSparkline,SparkBarandMusicStaff. Their generated accessible name was English-only
with no override short of writing the wholesummaryyourself.labelAtonStackedArea, so endpoint share labels can track a scrubbed column.
Breaking (pre-1.0), types only.
SummaryStringsgainedquantileDotsChip,quantileDotsOddsand
timelineFallback. If you supply your own strings object forQuantileDotsorEventTimeline, add those three
templates; every other consumer is unaffected.
@microcharts/react@0.7.0
Minor Changes
-
#46
5310b1dThanks
@ganapativs! - Breaking (pre-1.0 API freeze): prop-name consistency pass. Same
prop name must mean the same thing across the catalog. Collisions found in the pre-1.0 audit are renamed; behaviour is
unchanged — pass the new name, get identical output.Chart Old New Why MusicStaffrangemoderangeis the peer-band recipe onBenchmarkStripPercentileTracebandsshowBandsbandsis qualitative thresholds onBulletFoldedDayBandbandspercentiles⇑; avoided levels(alreadyDepthWedge/GradedBand)Waterfallstartopenstartcollided with PolarClock / ActivityGrid; avoidedfrom(Delta)PolarClockstartorigin⇑ ActivityGridstartanchor⇑ OrbitStatusalertthresholdDecision cutoffs spell thresholdelsewhereCyclePlottrend: "line" | "none"trend?: booleanMatches MicroScatterAlso in this release: chart polish (label defaults, annotation hosts, motion safety); interactive scrub/HOP
re-render wins (picker SVG cache, Sparkline memo overlays, EnsembleGhosts DOM hop); size sync tolerates over-budget
size-limit --json; marketing band ~2–7 kB interactive · ~1–4 kB static.Non-breaking:
MicroDatum.formatted+readouton interactive pickers (hide in-chart chip, render the chart's
own display string elsewhere); empty-stateseaton 11 charts;LiveRegionon dice-pips / tally-marks / hourglass;
data-mc-inkon Slope + forced-colors fordata-mc-status; Delta / Bullet / ActivityGrid / TokenConfidence English
viastrings-*; coreclamp/lastFinitereuse; docs registry + MDX synced (catalog.json / llms surfaces
regenerate); gallery collections + comparison/SEO doc pages; CI splitscore/dom/browserprojects.Examples microsites migrate after publish — not in this release.
@microcharts/react@0.6.0
Minor Changes
-
#42
86dcf8eThanks
@ganapativs! - Breaking (pre-1.0 API freeze): remove props that were declared but
never read. Each of these was accepted by the type signature and documented, but had no effect on rendering,
geometry, or the accessible summary — passing one did nothing. They are gone rather than fixed where the chart had no
number and no announcement to apply them to.Removed outright:
DualSparkline—compareLabel. Never reached the summary or any announcement; the compare series is described
positionally.DualWindowMeter—damping. Documented as "ballistics for the live entry", but the interactive entry never read
it; its motion comes from the shared entrance engine.
Narrowed to the interactive entry only (still available on
…/interactive, removed from the static default export,
where they did nothing):PercentileTrace—unit. Names the reading in the hover/focus announcement; the static entry announces
percentiles, not individual readings.CalendarStrip,EventRaster,MicroScatter,TokenConfidence—locale(andformaton the latter three).
These statics render lane names, marks and text, never a formatted number; only the readout does.
Wired up instead of removed:
ConfusionGrid—format/localenow reach the accuracy gutter label, which previously hard-coded
Math.round(v * 100) + "%". Percent formatting goes through the shared cachedmakeFormatter, so the one number
this chart renders is locale-aware and honors a customformat. Default output is unchanged. The right-hand gutter
is measured from the produced string, so a locale that widens the label still fits inside the viewBox.
-
#42
86dcf8eThanks
@ganapativs! - One interaction contract across the catalog. 103 of 106 charts now
share a single picker kernel, so a consumer's handler reads the same on a Sparkline, an ActivityGrid or a MicroDonut.This is a pre-1.0 minor with breaking changes — permitted under semver for a
0.xpackage, but read the Breaking
section below before upgrading.Picker charts (84 multi-unit entries) gain four props on their
…/interactiveentry:onActive(datum | null)— the hovered / keyboard-focused unit changedonSelect(datum | null)— a unit was activated by click, tap,EnterorSpaceselectedIndex/defaultSelectedIndex— controlled and uncontrolled selection
The payload is one shape everywhere:
MicroDatum = { index, value, label? }.indexidentifies the navigable unit
(documented per chart — a data index where the chart is 1:1 withdata, otherwise a unit position).valueis that
unit's primary encoded number, which may be derived — a segment's share, a run's duration, a signed gap, a bin's
count — and isnullwhere the unit encodes nothing.Behavior, everywhere: pointer scrub sets the active unit; click or tap selects and pins it (surviving blur);
Enter/Spaceselect;Escapeclears; re-selecting the same unit clears it; arrows rove on both axes;
Home/Endjump to the ends. On touch, a tap pins and a drag scrubs. Still one listener on the wrapper and pure math
— never a listener per data point.Scalar charts (19 single-unit entries) take the lean half:
onSelectonly, with{ index: 0, value, label? }.
There is nothing to rove between and no pinned state, so they don't pretend otherwise.Deliberately excluded, and documented as such:
MinimapStripis a viewport-window slider and keeps its
onWindowChange([lo, hi])range payload;TokenConfidencemoves real focus to per-token spans so a screen reader
reads the text in flow;WindBarbships no interactive entry at all.Breaking
- Removed
onPointFocus(Sparkline, SparkBar, and Waveform's two-argument(index, fraction)form) and
onRunFocus(StreakSpark). UseonActive, which reports{ index, value, label? }. Waveform'sfractionhas
no equivalent — the datum reports the bucket index and its peak. PictogramRow's interactivestringsprop now takesPictogramStrings, which adds apictogramUnittemplate
so roving announces each unit (it previously announced nothing — an accessibility gap). A customScalarStrings
object needs that one template added. The static entry is unchanged.- Charts whose interactive entry hand-rolled geometry that disagreed with their static now mirror the static exactly.
This corrects rendered output where the two had drifted — most visiblyEventRaster(its interactive entry rendered
43% shorter than its static) andHypnogram(default size and row-label gutter). Overlays, focus rings and
hit-tests now land on the marks. - Six charts that silently ignored
ArrowUp/ArrowDownnow accept them as prev/next, matching the rest of the
catalog.
Fixed
- Nine interactive entries dropped consumer
children, silently discarding annotations (<Threshold>,<Marker>,
…). TreeRings' pinned mark had its stroke width overridden by the stylesheet.SproutRowignoredsummary={false};CometTrailmis-indexed its readout when the series contained non-finite
values;ControlStriphad an index/value misalignment on gappy data;BalanceBeamignored
width/height/shape.Honeycombannounced bare numerals to screen readers; it now uses a properhoneycombCelltemplate.CyclePlot's within-slot drill-down (↑/↓over the observations in the focused slot) is restored.
-
#42
86dcf8eThanks
@ganapativs! - Interactive charts now forwardclassNameandstyleto their
wrapper and size the inner SVG from one sharedFILLconstant, so the SVG always fills the interactive<span>—
hover math, crosshairs, and focus rings stay locked to the cursor instead of drifting when the chart is scaled by a
consumer. Passingstylemerges (it no longer clobbers the wrapper'sdisplay/position/line-height), and
classNamecomposes with the chart's own class. No change at rest — static output is byte-identical.Formatters are also hardened against IEEE float noise:
makeFormattersnaps its input to 12 significant digits before
handing it toIntlor a customformatfunction, so internally-derived values (value - target→
-3.5999999999999943) render clean without touching real precision. -
#42
86dcf8eThanks
@ganapativs! - Prop-name grammar freeze. Non-negotiable
#4 says the same prop name means the same thing on every chart —
an API audit before 1.0 found several names carrying two meanings across the catalog. Each is now spelled one way.This is a pre-1.0 minor with breaking renames — permitted under semver for a
0.xpackage. Every rename below is
mechanical: pass the new name, get identical output. No rendering, geometry, or accessibility behaviour changed.Chart Old New Why ABStripslabelsseriesLabelslabelsis a boolean show/hide toggle on 11 other chartsShiftHistogramlabelsseriesLabels⇑ SpreadBandlabelsseriesLabels⇑ WaterfalltotaltotalBartotalis a number denominator on 5 other chartsChangePointmaxmaxItemsmaxis a scale denominator onProgress(mirrors<progress>)DataDiffmaxmaxItems⇑ ParetoStripmaxmaxItems⇑ CalibrationStripvariantmode13 charts already spelled this modeHypnogramvariantmode⇑ MinimapStripvariantmode⇑ Ohlcvariantmode⇑ StackedAreavariantmode⇑ Waveformvariantmode⇑ WindBarbvariantmode⇑ DataDiffsortordersort/orderwere two names for one conceptMiniBarsortorder⇑ ...
@microcharts/react@0.5.0
Minor Changes
- #40
427c25aThanks
@ganapativs! -defineTheme()gains astrokeWidthtoken — pin the base data
stroke weight (--mc-stroke-width) alongside the other geometry/type tokens. A number is stringified as-is (not
twinned into the dark variant). Additive and identity at its default.
Patch Changes
- #40
427c25aThanks
@ganapativs! - Floor charts now seat their baseline flush with the box bottom so they
align on the text baseline when rendered inline: SparkBar (bar mode), StackedArea, DepthWedge, and GradeProfile. These
marks are flat fill edges (crispEdges rects / stroke-free, dot-free areas), so filling to the box bottom bleeds
nothing; the top pad is untouched. SparkBar win-loss keeps its symmetric mid-line inset. No API change.
@microcharts/react@0.4.0
Minor Changes
-
#38
0796194Thanks @ganapativs! - Pre-launch quality pass — expanded annotation hosting, correctness fixes, and internal
consolidation. All changes are backward-compatible at their defaults; existing charts render
identically.Annotations on 17 value-series charts (was 2).
Threshold,TargetZone,Marker, and
Callout(from@microcharts/react/annotations) can now be passed as children to Sparkline,
SparkBar, MiniBar, CyclePlot, CitySkyline, ChangePoint, DualSparkline, SpreadBand, ForecastCone,
ControlStrip, QueueDepth, BurnChart, Waterfall, PercentileTrace, RetentionCurve, WinProbWorm, and
ErrorBudget. Every host resolves annotation coordinates through the same shared path, so label
sizing and containment are identical across charts.Correctness fixes:
weekGridno longer crashes on aNaNweek count or hangs onInfinity— non-finite inputs
clamp to a single row.divergingStackno longer emitsNaNsegments whenneutralIndexis out of range — an
out-of-range index is treated as "no neutral".stepOpacityno longer divides by zero atsteps === 1(wasInfinity).- The interactive MinimapStrip slider always has an accessible name, even when
summary={false}
and notitleis given (falls back to the localized viewport sentence). - Consumer-supplied annotation labels are now truncated to fit the chart's box, closing the one
text path that could paint outside the viewBox. - The trend-percentage in generated summaries now routes through the locale formatter, so
non-ASCII-digit locales no longer mix numeral systems in one sentence.
Summary strings (i18n):
- TokenConfidence's empty-state string moved from the shared
noDatakey to its ownnoTokens
key onSummaryStrings, so it is no longer silently overridden by other charts'noData. If
you supply customstringsto TokenConfidence, renamenoData→noTokens. Rendered output is
unchanged ("No tokens."). compass8is now canonically lowercase across WindBarb and StationGlyph (WindBarb capitalizes
its sentence-initial octant in its own template), fixing lowercase sentence starts when both
charts' strings were merged. Standalone output is unchanged.heartbeatWindownow reports clean multiples of an hour as hours ("2 hours") instead of minutes
("120 minutes").
Internally, duplicated label-sizing, live-region, gutter, and summary-resolution logic was
consolidated into shared helpers, and several unused internal exports were removed. No public
export, prop, or chart was added or removed. -
#38
0796194Thanks @ganapativs! - Deepen the theming surface — all additive, backward-compatible, and identity at
their defaults (no visual change to existing charts):defineTheme()— a new opt-in@microcharts/react/themesubpath (zero
runtime deps, ~2 kB gzip, tree-shaken when unused). Give it one brand accent
and it derives a harmonized, colour-blind-safe categorical palette and
hand-tuned-style dark twins in-house in OKLCH — never moving the
positive/negative hues off their CVD-safe split. Extend a preset, pin any
token, pass an explicit palette, orextend()a variant; returns
vars/style/css(selector)(with aprefers-color-scheme: darkblock).- New tokens —
--mc-font-numeric(a dedicated face for figures, tracks
--mc-fontby default),--mc-label-weight, and--mc-density(one scalar
that scales stroke weight, label size, and small-multiple gap together for
compact vs comfortable layouts; the plot box is untouched). colorsprop — per-instance series colours on the categorical charts
(SegmentedBar,StackedArea,PartitionStrip,Hypnogram,MicroDonut),
overriding--mc-cat-*just there.printandeinkpresets — output-context token bundles for paper and
grayscale e-paper, answeringdata-mc-theme/data-mc-presetlike the rest.
The
MicrochartCommonPropsshared-grammar type is now enforced as a single
source of truth: a guard test holds every chart's shared props to its canonical
types.
Patch Changes
-
#38
0796194Thanks @ganapativs! - Ship a minifiedstyles.css.@microcharts/react/styles.css(and the
per-chartstyles/*.cssescape-hatch files) now resolve to minified copies in
dist/— the shared stylesheet drops from ~8.7 kB to ~2.8 kB gzip. The
minifier only strips comments and whitespace (no rule merging), so@layer
membership and cascade order are unchanged. The repo-rootstyles.cssstays the
unminified source of truth; no API or visual changes. -
#38
0796194Thanks @ganapativs! - Improve npm and search discoverability: expandkeywords, add afundinglink
(GitHub Sponsors), and a structuredauthor(name/email/url). Metadata only — no
API, runtime, or visual changes.
@microcharts/react@0.3.0
Minor Changes
-
#23
c5854a0Thanks @ganapativs! - Deepen the theming surface — all additive, backward-compatible, and identity at
their defaults (no visual change to existing charts):defineTheme()— a new opt-in@microcharts/react/themesubpath (zero
runtime deps, ~2 kB gzip, tree-shaken when unused). Give it one brand accent
and it derives a harmonized, colour-blind-safe categorical palette and
hand-tuned-style dark twins in-house in OKLCH — never moving the
positive/negative hues off their CVD-safe split. Extend a preset, pin any
token, pass an explicit palette, orextend()a variant; returns
vars/style/css(selector)(with aprefers-color-scheme: darkblock).- New tokens —
--mc-font-numeric(a dedicated face for figures, tracks
--mc-fontby default),--mc-label-weight, and--mc-density(one scalar
that scales stroke weight, label size, and small-multiple gap together for
compact vs comfortable layouts; the plot box is untouched). colorsprop — per-instance series colours on the categorical charts
(SegmentedBar,StackedArea,PartitionStrip,Hypnogram,MicroDonut),
overriding--mc-cat-*just there.printandeinkpresets — output-context token bundles for paper and
grayscale e-paper, answeringdata-mc-theme/data-mc-presetlike the rest.
The
MicrochartCommonPropsshared-grammar type is now enforced as a single
source of truth: a guard test holds every chart's shared props to its canonical
types.
Patch Changes
-
#23
c5854a0Thanks @ganapativs! - Ship a minifiedstyles.css.@microcharts/react/styles.css(and the
per-chartstyles/*.cssescape-hatch files) now resolve to minified copies in
dist/— the shared stylesheet drops from ~8.7 kB to ~2.8 kB gzip. The
minifier only strips comments and whitespace (no rule merging), so@layer
membership and cascade order are unchanged. The repo-rootstyles.cssstays the
unminified source of truth; no API or visual changes. -
#23
c5854a0Thanks @ganapativs! - Improve npm and search discoverability: expandkeywords, add afundinglink
(GitHub Sponsors), and a structuredauthor(name/email/url). Metadata only — no
API, runtime, or visual changes.
@microcharts/react@0.2.1
Patch Changes
- 3955472: Fix subpath resolution on StackBlitz and some CDNs. Every export now includes a
defaultcondition alongsideimport, so imports like
@microcharts/react/sparkline/interactiveresolve on loose resolvers that don't
request theimportcondition (they previously failed with "file does not
exist"). Also ship a minified dist — smaller install, and correct bytes for
consumers that import the ESM directly (Deno, CDNs). No API changes.
@microcharts/react@0.2.0
Minor Changes
- ef2df66: Ship the full catalog: 106 stable chart types (34 core, 26 decision, 23 expressive, 23
frontier), each with a static React Server Component entry and an/interactivetwin, an
auto-generated accessible summary, opt-in mount animation via@microcharts/react/motion, and
a CI-gated size budget. Zero runtime dependencies; one sharedstyles.css. First public release
usable end to end.
@microcharts/react@0.1.0
Minor Changes
-
69eb408: Batch 1 wave 1 — four scalar glyph charts, each with a static RSC-safe entry and an
interactive/interactiveentry:TrendArrow(./trend-arrow) — direction glyph (arrow/triangle/chevron),flatBand
noise floor,showValuegutter,positivepolarity.StatusDot(./status-dot) — five paired shape+color states (ok/warn/error/off/busy),
pulsehalo, extensiblestatesvocabulary.HeatCell(./heat-cell) — one calibrated color step (shared 5-step ramp), shared
shapecell vocabulary, optional centered value label.Progress(./progress) — zero-anchored bar + direct percent label,segments
stepped mode, honest >100% clamp (label carries the truth), burn-down wording.
Also:
ENlocale dictionary is now composed from per-shape modules (EN_SERIES+
EN_SCALAR) so each chart bundles only its own summary templates; newScalarStrings
keysscalarDir,flatChange,status,level,progress,remaining,stepsDone. -
16a3914: Batch 1 wave 2 — five tick/cell strip charts, each with static +
/interactiveentries:RugStrip(./rug-strip) — raw observations as ticks, density via opacity tiers,
highlightfor "you are here", never downsamples.MiniBar(./mini-bar) — zero-anchored categorical bars, honest data order,sort,
highlight, signed data withpositivepolarity.PictogramRow(./pictogram-row) — countable units (●●●○○), true fractional units as
circular segments (no clipPath ids),renderPointescape hatch.Seismogram(./seismogram) — event density/intensity ticks,barcodemode,
spike-preserving max-per-bucket downsampling, summaries always from raw values.HeatStrip(./heat-strip) — 1×N calibrated intensity cells sharing ActivityGrid's
vocabulary; empty ≠ zero; density-adaptive gaps.
Kernel fix:
scaleLinearnow treats denormal-span domains as degenerate (the slope
overflowed to ±Infinity and0 × Infinitypoisoned coordinates with NaN). New summary
template modules:EN_CATEGORY,EN_DIST,EN_SLOTS(slot-empty announcements — also
fixes the latent "No data.." double period in ActivityGrid's null-cell announcement). -
7bb9ee1: Batch 1 wave 3 — five categorical/relationship charts, each with static +
/interactive
entries:DotPlot(./dot-plot) — named values on one scale;stemflips to a zero-anchored
magnitude read; deterministic label drop-out and coincident-dot de-overlap.Dumbbell(./dumbbell) — hollow→filled before/after per row;positivevalence for
changes (documented: drop it for ranges).PairedBars(./paired-bars) — actual vs reference on ONE zero-anchored domain;
grouped or overlay-ghost modes; ref muted by opacity AND width.Slope(./slope) — two aligned columns, one y-domain; neutral untilpositive;
greedy endpoint-label dedup; dashed "incomplete" stubs for missing ends.MicroScatter(./micro-scatter) — 2-D position + Pearson r in the summary (claim and
evidence travel together); linear-only least-squarestrend;focalpoint.
New summary template modules:
EN_PAIRED(fromTo/pairs/slopes…),EN_SCATTER
(count + relationship tiers). Pluralization fixes incategories/pairstemplates. -
0c92adc: Batch 1 wave 4 — the annotations layer + seven part-to-whole/staged charts:
@microcharts/react/annotations—<Threshold>,<TargetZone>,<Marker celebrate?>,
<Callout>as declarative children; hosts pay only a tiny walker (mark renderers ship
with this entry). Sparkline/SparkBar retrofitted as hosts.SegmentedBar(./segmented-bar) — composition with a labeled Other rollup +
largest-remainder percents.HistogramStrip(./histogram-strip) — ≤ 12 uniform bins from raw observations;
valuehighlight.MicroBox(./micro-box) — five-number box; min-max or tukey whiskers; refuses fake
boxes (< 5 raw values → dots; non-monotonic stats → refused).ProgressRing(./progress-ring) — fixed 12-o'clock arc, butt caps,sweep
countdown mode; threshold-crossing announcements.MicroDonut(./micro-donut) — ≤ 4 wedges + Other;decorativeornament mode.Funnel(./funnel) — stepped columns + retained-share slats; rate-of-first mode;
inversion notes.LikertStrip(./likert-strip) — diverging valence bar; split/omit neutral (never
silently dropped); ends/net labels.
New
EN_COMPOSITIONstring module + distribution templates (binAt, distribution,
fiveNum, boxStat). Sparkline budget 3.65/4.65 kB pending sign-off (annotations walker). -
15b0a12: Batch 1 wave 5 — six composed-series charts:
Waterfall(./waterfall) — signed deltas bridging into a total; zero-anchored total
bar on by default;positive="down"for cost bridges.BumpStrip(./bump-strip) — rank trajectory on an inverted ordinal scale (#1 on
top); change dots; "#5" → "#1" end labels; null = unranked gap.DualSparkline(./dual-sparkline) — series vs benchmark on ONE shared domain;
dashed/thinner/neutral reference; coincident-endpoint dedup.curve="step"renders
as linear (documented — keeps the entry inside the 3 kB hard cap).StackedArea(./stacked-area) — share-normalized stack, ≤ 3 series;
variant="ridge"skin;order="asc".Ohlc(./ohlc) — candle/bars price action, ≤ 20 periods rendered (never averaged);
valence + geometry encode direction.Horizon(./horizon) — 2–3 fold horizon band; mirror/offset modes; authored
baseline; summaries read the unfolded values.
EN_COMPOSEDsplit into per-chart string modules (EN_FLOW/EN_VS/EN_STACK/
EN_OHLC) so no chart pays for another family's templates. Horizondomainprop is
now actually wired to the geometry (was silently ignored). -
cf601c5: Batch 1 wave 6 — the two date-structured charts, completing the core-29:
CalendarStrip(./calendar-strip) — the last few weeks day by day on a real
weeks × 7 UTC calendar grid; value days step the shared intensity ramp, zero days
show the track, no-record days render as outlines (empty ≠ zero), future days are
blank. 2-D keyboard nav announces real calendar days.EventTimeline(./event-timeline) — spans + point-event diamonds on one linear
time axis; window clipping is flat-cut honest; coverage merges intervals (overlaps
never double-count); authorednowtick.
New core: cached
makeDateFormatter(UTC-forced for calendar charts) +EN_CALENDAR/
EN_TIMELINEstring modules.core/calendarsplit intocalendar(day parsing) and
calendar-grid(week-grid/year math) so ActivityGrid stops carrying grid math it never
calls. Fixed:normalizeSharescould emit a negative share when the float remainder
landed on a denormal-tiny entry (property-test counterexample) — remainder now folds
into the largest share. -
425f933: Batch 2 wave 1 — five decision micrographs, each with a static RSC-safe entry and an
interactive/interactiveentry:CoverageStrip(./coverage-strip) — presence/absence on a time strip;null(no
measurement) is hollow,0(a measured zero) is filled, so absence never masquerades
as zero.expectedmakes trailing missingness count;mode="intensity"shades measured
cells;label="percent".BenchmarkStrip(./benchmark-strip) — a focal dot against the peers' empirical
quantile bands; the stated percentile uses a mid-rank rule; small samples fall back to
min–max.range,median,label,positive.PercentileLadder(./percentile-ladder) — p50/p90/p99 as graduated ticks on a
zero-anchored track;scale="log"renders an in-chartlogtag (never silent);
ps,label,dots.GradedBand(./graded-band) — nested central intervals graded by opacity, never a bar
from zero;levels(1–3),valuedot,softEdge,label="median".IconArray(./icon-array) — one rate made countable in a fixed N-unit grid with the
denominator visible; no partial-unit fills (sub-unit rates are flagged);of(10/20/100),
label,shape,positive.
Also: new per-family summary-string modules
EN_COVERAGE,EN_QUANTILE,EN_FREQ(each
chart bundles only its own templates) and the correspondingSummaryStringskeys. -
425f933: Batch 2 wave 2 —
BurnChart(./burn-chart), static +/interactiveentries:BurnChart— a dashed plan line (full length to the deadline), the solid
actual line to today, a today tick, and a dotted projection whose slope
is a linear fit over the lastmax(2, ⌈today/3⌉)actual points — provisional by
construction, never a smoothed or optimistic curve.label="gap"states the
signed schedule landing vs the deadline (e.g.+2 d), colored by valence with
the sign in text.mode="down" | "up",projection={false}for retrospectives.
A flattened recent burn never reaches zero: no landing, and the summary says
"not finishing at the current pace" outright.
New
EN_BURNsummary module (burn,burnNoPlan,burnLanding,burnFlatlined,
burnAt,burnAtProjected,burnRemain/burnDone). -
425f933: Batch 2 wave 2 —
ControlStrip(./control-strip), static +/interactiveentries:ControlStrip— a Shewhart individuals control chart: the band is center ± 3σ̂
where σ̂ = mean moving range ÷ 1.128 (the individuals estimator, stated —
sample SD is not used, it inflates limits under drift). In-control points are bare
vertices; only out-of-control points are marked (ringed, negative).limits="sigma" | "percentile"(empirical p0.135/p99.865 for skew),baselinefor a golden-period
center,rules="we"for the enumerated Western Electric subset (WE-1/2/4, no rule
fires silently),dots="all"for sparse series. Fewer than 10 points → dashed band- "limits provisional"; ze...