Zum Inhalt springen
chartlet
MITDokumentation
Rust-CLI · Astro-Integration · Open Source

JSON rein,
fertiges SVG raus

chartlet übersetzt eine kleine JSON-Spezifikation beim Build in ein fertiges Diagramm. Im Browser läuft davon nichts: kein Chart-JavaScript, keine Hydration, kein Layout-Shift.

0 KB
Chart-JavaScript im Browser
SVG · HTML
Ausgabeformate
byte-gleich
bei gleicher Spezifikation
Terminal
$ cargo install chartlet --version 0.1.0-alpha.3
$ chartlet render monthly-revenue.json -o chart.svg
$ chartlet render broken.json -o chart.svg
chartlet: series_length_mismatch at /series/0/values: expected 2 values, one per category; use null for a missing value
$ echo $?
1
3,2 KB SVG für drei KategorienFehler → Exit 1
Stand: September 2026 · v0.1.0-alpha.3
3
Diagrammtypen: bar, line, time
100
Kategorien je Diagramm, Obergrenze
4
Serien beziehungsweise Layer
MIT
Lizenz
01 — Überblick

Ein Diagramm ist ein Build-Artefakt, kein Laufzeit-Feature.

Wer auf einer statischen Seite ein Diagramm zeigt, lädt heute meist eine Chart-Bibliothek in den Browser – für Daten, die sich seit dem Build nicht geändert haben. chartlet verschiebt diesen Schritt nach vorn: Die Spezifikation wird beim Build zu SVG oder HTML, das Ergebnis ist eine Datei wie jede andere.

Dokumentation →
  1. 01Deterministisch — dieselbe Spezifikation ergibt dieselben Bytes, prüfbar im Diff und cachebar wie jedes Build-Artefakt
  2. 02Barrierefrei angelegt — jedes Diagramm trägt Titel und Beschreibung, die HTML-Ausgabe zusätzlich die vollständigen Daten als Tabelle
  3. 03Ehrlich bei Problemen — ungültige Eingaben werden mit Code, JSON-Pointer und Lösungshinweis abgelehnt
  4. 04Zwei Wege hinein — Rust-CLI und Crate, dazu eine Astro-Integration, die zur Build-Zeit rendert
02 — Eingabe und Ausgabe

Eine Spezifikation, zwei Ausgabeprofile.

monthly-revenue.jsonSpezifikation
{
  "schemaVersion": 1,
  "type": "bar",
  "title": "Monthly revenue",
  "description": "Revenue increased in February and remained above January in March.",
  "source": "Example data",
  "categoryAxis": { "title": "Month" },
  "valueAxis": { "title": "Revenue in thousands", "format": "number" },
  "data": [
    { "label": "January", "value": 120 },
    { "label": "February", "value": 180 },
    { "label": "March", "value": 150 }
  ]
}
chart.svgSVG · Auszug
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="450" viewBox="0 0 800 450"
  role="img" class="chartlet-root"
  aria-labelledby="chartlet-e92f7ad68bc8a2d6-title chartlet-e92f7ad68bc8a2d6-description">
  <title id="chartlet-e92f7ad68bc8a2d6-title">Monthly revenue</title>
  <desc id="chartlet-e92f7ad68bc8a2d6-description">Revenue increased in February
    and remained above January in March.</desc>
  <style>.chartlet-root{--chartlet-text:#172033;--chartlet-muted:#344054;
    --chartlet-grid:#d9dee8;--chartlet-accent:#2563eb;--chartlet-background:#fff; …}</style>
  …
</svg>
chart.htmlHTML · Auszug
<figure class="chartlet-figure">
  <figcaption>Monthly revenue</figcaption>
  <svg …>…</svg>
  <p class="chartlet-source">Source: Example data</p>
  <details class="chartlet-data">
    <summary>Show chart data</summary>
    <table>
      <caption>Data for Monthly revenue</caption>
      <thead><tr><th scope="col">Category</th><th scope="col">Value</th></tr></thead>
      <tbody>
        <tr><th scope="row">January</th><td>120</td></tr>
        <tr><th scope="row">February</th><td>180</td></tr>
        <tr><th scope="row">March</th><td>150</td></tr>
      </tbody>
    </table>
  </details>
</figure>
03 — Diagrammtypen

Balken, Linien, Zeitreihen – und sonst nichts.

Balken, vertikal

"type": "bar" mit data: eine Liste aus label und value. Der Standardfall, 800 × 450 Pixel, wenn nichts anderes angegeben ist.

Balken, horizontal

"orientation": "horizontal" – auch mit negativen Werten; die Nulllinie wird dann eigens gezeichnet.

Gruppierte Balken

categories und series statt data, bis zu vier Serien. Die Legende entsteht automatisch, die Datentabelle bekommt eine Spalte je Serie.

Linien mit Lücken

"type": "line" mit null für eine Beobachtung, die es nicht gibt. chartlet lässt eine sichtbare Lücke, statt eine Linie darüber zu ziehen; die Tabelle zeigt „Missing“.

Zeitreihen

"type": "time" mit panes und layers zeichnet auf einer Kalenderachse. Zeitstempel als Unix-Sekunden oder ISO 8601, Zeitzone als fester UTC-Versatz, UTC als Vorgabe.

Grenzen im Vertrag

Bis zu 100 Kategorien und vier Serien; eine Zeit-Pane trägt vier Layer mit je 2000 Beobachtungen. Labels müssen eindeutig sein. Was darüber liegt, wird abgelehnt statt still gekürzt.

04 — Interaktion

Bedienelemente ohne eine Zeile Chart-JavaScript.

Serienfilter

Ein gruppiertes Diagramm bekommt eine Checkbox je Serie. Abwählen blendet Balken und Wertlabels per CSS :has() aus; die Achse skaliert nicht neu. Browser ohne :has() zeigen schlicht alle Serien.

Zoom-Stufen

Zwei bis vier zoomSteps erzeugen vorberechnete Ausschnitte desselben Diagramms, umschaltbar über Radio-Buttons. Jede Stufe kostet ein eigenes SVG in der Datei.

Tooltips

Jeder Balken und jeder Punkt trägt ein natives <title>. Als Alternative für assistive Technik gelten aber die Beschreibung und die Datentabelle, nicht diese Hover-Hinweise.

05 — Einstieg

Installieren, Spezifikation schreiben, rendern.

  1. 1Installieren

    CLI von crates.io holen

    Rust 1.88 oder neuer. Solange chartlet im Alpha-Stand ist, gehört die Version ausdrücklich dazu.

    cargo install chartlet --version 0.1.0-alpha.3
  2. 2Rendern

    Spezifikation übersetzen

    Ohne --format entsteht ein eigenständiges SVG, mit --format html eine <figure> samt Quelle und Datentabelle. - liest von der Standardeingabe.

    chartlet render spec.json --format html -o chart.html
  3. 3Astro

    Beim Seitenbau rendern

    @casoon/chartlet ruft im Alpha-Stand die CLI auf – beide werden gebraucht, und chartlet muss im PATH liegen oder über CHARTLET_BIN erreichbar sein.

    --- import Chart from '@casoon/chartlet/astro'; import revenue from '../data/monthly-revenue.json'; --- <Chart id="monthly-revenue" spec={revenue} />
  4. 4CI

    Warnungen zu Fehlern machen

    --strict lässt den Lauf bei jeder Warnung scheitern – etwa wenn ein Label gekürzt oder ein Wertlabel weggelassen werden musste.

    chartlet render spec.json --strict -o chart.svg
06 — Barrierefreiheit

Was im Diagramm steckt – und was noch offen ist.

chartlet ist auf Barrierefreiheit hin gebaut, aber noch nicht mit Screenreadern geprüft. Die folgenden Punkte sind im Quelltext umgesetzt; die Prüfung mit VoiceOver und NVDA steht aus.

  1. 01

    Ein Bild mit Namen und Beschreibung

    Das SVG trägt role="img" und verweist über aria-labelledby auf <title> und <desc>. Fehlt eine eigene description, erzeugt chartlet sie aus den Daten – etwa: „Bar chart with 4 categories and 2 series (Budget, Actual). Highest: 160 (Budget in April). Lowest: 120 (Budget in January). 1 value is missing.“

  2. 02

    Die Daten als echte Tabelle

    Die HTML-Ausgabe enthält immer ein <table> mit caption, th scope="col" und th scope="row" – auch die Werte, deren sichtbares Label keinen Platz hatte. Standardmäßig steckt es in einem nativen <details>; --table visible zeigt es dauerhaft.

  3. 03

    Farben mit Kontrast

    Die Serienfarben bleiben bei den verbreiteten Formen der Farbfehlsichtigkeit unterscheidbar und halten mindestens 4,5:1 gegen Weiß; im dunklen Thema erreicht die schwächste Serienfarbe 7,65:1. Die Legende führt die Serien in der Reihenfolge der Balken.

  4. 04

    Kein stilles Weglassen

    Gekürzte Labels und ausgelassene Wertlabels erzeugen Warnungen (text_truncated, value_labels_omitted). Der vollständige Text bleibt in der Spezifikation und in der Datentabelle.

07 — Support-Matrix

Geprüft, entworfen, geplant.

KontextStatusAnmerkung
Eigenständiges SVGVerifiziertByte-gleich auf macOS und Linux, durch Golden-File-Tests abgedeckt
HTML-Figure mit DatentabelleVerifiziertDie Tabelle ist immer vorhanden, standardmäßig in einem `<details>`
Astro-KomponenteVerifiziertRendert zur Build-Zeit und liefert kein Chart-JavaScript aus
Chromium (Chrome, Edge)Verifiziertaxe-Scan in der CI und manuelle Prüfung während der Entwicklung
`<img src="chart.svg">`EntworfenTitel und Beschreibung bleiben; Figure und Datentabelle entfallen
Serienfilter und Zoom-StufenEntworfenIm HTML-Profil vorhanden; breitere Browser-Prüfung steht aus
Firefox und SafariGeplantStandard-SVG wird erwartet, der Accessibility-Baum ist ungetestet
VoiceOver, NVDA, JAWSGeplantNoch nicht getestet
Markdown, PDF und Druck, E-MailGeplantNoch nicht bewertet
WASM-Build und native Node-BindingsNicht unterstütztNach dem MVP geplant; die Alpha ruft die CLI auf

Die vollständige Matrix mit Themes und Zeitreihen steht in der Dokumentation.

Entwicklungsstand · Stand: September 2026

Umgesetzt

Balken, Linien, Zeitreihen

Balkendiagramme einzeln und gruppiert, vertikal und horizontal, kategoriale Liniendiagramme und Zeitreihen auf einer Kalenderachse. Dazu die HTML-Ausgabe mit Datentabelle, Serienfilter und Zoom-Stufen, das JSON-Schema als Vertrag und Golden-File-Tests für die Ausgabe.

In Arbeit

Frühe Alpha, Version 0.1.0-alpha.3

Das erste Release liegt seit dem 11. September 2026 auf crates.io, das npm-Paket unter derselben Version. Die Spezifikation kann sich vor dem ersten stabilen Release noch ändern – schemaVersion ist dafür von Anfang an Pflichtfeld.

Geplant

Marks, Screenreader-Prüfung, Bindings

Die Mark-Typen area, ohlc, band und annotation werden derzeit mit mark_not_implemented abgelehnt, mehrere Panes mit too_many_panes. Offen sind außerdem die Prüfung mit VoiceOver und NVDA, Forced-Colors-Unterstützung sowie ein WASM-Build und native Node-Bindings anstelle des CLI-Aufrufs.

08 — Ausgabe

Drei Beispiele, direkt aus dem Repo.

Balkendiagramm Monatsumsatz, erzeugt von chartlet
examples/monthly-revenue.svg — unveränderte Ausgabe von chartlet.
Diagramm Budget gegen Ist-Kosten, erzeugt von chartlet
examples/budget-vs-actual.svg — unveränderte Ausgabe von chartlet.
Diagramm Umsatz nach Kanal, erzeugt von chartlet
examples/revenue-by-channel.svg — unveränderte Ausgabe von chartlet.

Die Dateien stammen aus examples/ im Repo, erzeugt mit chartlet 0.1.0-alpha.3. Jede trägt Titel und Beschreibung im SVG.

09 — Grenzen

Wann chartlet das falsche Werkzeug ist.

chartlet veröffentlicht ein fertiges Diagramm. Es ist kein Werkzeug, um Daten zu erkunden.

Interaktive Analyse

Stufenloses Zoomen, Pannen, Cross-Filtering, Live-Updates oder einzeln per Tastatur ansteuerbare Datenpunkte gibt es nicht.

Daten, die sich zur Laufzeit ändern

Gerendert wird beim Build. Wer Werte zeigt, die sich im Minutentakt bewegen, braucht etwas anderes.

Andere Diagrammarten

Karten, Netzwerke, 3D und alles jenseits von Balken, Linien und Zeitreihen sind nicht vorgesehen.

Zwei Installationen

Das npm-Paket ruft im Alpha-Stand die Rust-CLI auf. Auf einem Build-Server müssen also beide vorhanden sein.

Noch nicht mit Screenreadern geprüft

Die Ausgabe ist auf Barrierefreiheit hin entworfen, aber die Prüfung mit VoiceOver, NVDA und JAWS steht aus. Bis dahin gilt sie als geplant, nicht als nachgewiesen.

10 — FAQ

Häufige Fragen.

Was heißt „deterministisch“ konkret?

Dieselbe Spezifikation ergibt dieselben Bytes. Die Golden-File-Tests des Repositories prüfen das für macOS und Linux. Praktisch heißt das: Ein Diagramm lässt sich reviewen, diffen und cachen wie jedes andere Build-Artefakt.

Wie meldet chartlet einen Fehler in der Spezifikation?

Mit einem Code, der Stelle als JSON-Pointer und einem Hinweis zur Behebung, zum Beispiel: chartlet: series_length_mismatch at /series/0/values: expected 2 values, one per category; use null for a missing value. Der Prozess endet dann mit Exit-Code 1.

Was ist der Unterschied zwischen einem Fehler und einer Warnung?

Ein Fehler stoppt das Rendern. Eine Warnung geht nach stderr, das Diagramm entsteht trotzdem. Es gibt vier Warnungscodes: text_truncated, value_labels_omitted, dense_chart und color_not_supported. Mit --strict wird jede Warnung zum Fehler.

Brauche ich Rust, um chartlet in einem Astro-Projekt zu nutzen?

Im Alpha-Stand ja. Das npm-Paket @casoon/chartlet ruft die Rust-CLI auf, also müssen beide installiert sein und chartlet im PATH liegen oder über CHARTLET_BIN erreichbar sein. Native Node-Bindings sind geplant, aber noch nicht vorhanden.

Wie sieht das Diagramm im Dark Mode aus?

Mit "theme": "dark" setzt chartlet dieselben CSS-Custom-Properties auf eine dunkle Palette und zeichnet einen eigenen Hintergrund. Die schwächste Serienfarbe erreicht dabei 7,65:1 Kontrast gegen #0e131c. Ein Umschalten zur Laufzeit gibt es nicht – das Thema gehört zur Spezifikation.

Kann ich dasselbe Diagramm zweimal auf einer Seite einbinden?

Ja, aber mit --id-prefix. Die IDs für Titel und Beschreibung werden aus der Spezifikation abgeleitet; ohne eigenen Präfix stünden sie zweimal identisch im Dokument.

Diagramme, die vor dem Browser fertig sind.

chartlet ist MIT-lizenziert und liegt vollständig auf GitHub – mit JSON-Schema, Beispielsammlung und einer Galerie, in der jede Spezifikation neben ihrer Ausgabe steht.