Skip to main content

Technical-drawing SVG dashboards for GitHub repositories and profiles.

Project description

Cartouche

๐Ÿ‡ฌ๐Ÿ‡ง English (you are here) ยท ๐Ÿ‡ซ๐Ÿ‡ท Franรงais

CI Last commit License: MIT Python Version Visitors

Technical-drawing SVG dashboards for GitHub repositories and profiles. Pure SVG primitives, sixteen themes (incl. watermarked variants), two languages, embeddable in any README via <picture>.

PyPI name: cartouche-svg (the bare cartouche slot belongs to an unrelated, abandoned Sphinx extension from 2013). Always pip install cartouche-svg.

Cartouche dashboard for the cartouche repo โ€” refreshed every 6 hours by GitHub Actions

[!TIP] The dashboard at the top of this README pulls real data and refreshes every 6 hours. A โ˜… on the repo means you'll show up as a tick on its own star-history curve before tonight. It's the most self-referential growth hack we could come up with. Yes, we already starred it ourselves โ€” the experiment lacks a control group.

drafting-light blueprint-light vellum-davinci-light botanical-floral-light blossom-kawai-light

Light theme sampler โ€” click any thumbnail for its section in THEMES.md, where every variant lives at full size in light + dark.

Cartouche takes a GitHub repo (or a whole profile) and renders it as a technical-drawing SVG: grid, double-line frame, annotated star history, health radar, key metrics, and a cartouche โ€” the architectural title block โ€” in the bottom-right corner. Sixteen themes (light + dark, plus watermarked variants for Vellum + Davinci, Botanical + Floral, Blossom + Kawai), two built-in languages (English + French) with extensible custom packs via JSON, all served through the <picture> tag for both color modes.

Contents

Why

Existing solutions (star-history.com, GitHub Charts, etc.) serve images through GitHub's Camo proxy, which means aggressive caching, occasional refresh failures, and zero control over the rendering. Cartouche makes the opposite tradeoff: generate the SVG locally via a GitHub Action, commit it to your repo, and serve it as a versioned file โ€” so it refreshes on the cron cadence you set, is readable by anyone, and is fully styleable to taste.

What gets displayed

Repo dashboard

  • FIG. 01 โ€” Star history with peak annotations and endpoint marker
  • FIG. 02 โ€” 6-axis radar: stars, forks, commits, code, tests, docs
  • FIG. 03 โ€” Cards: stargazers, forks, issues, commits/30d + language breakdown bar

Profile dashboard

  • FIG. 01 โ€” Cumulative stars across all the account's public repos
  • FIG. 02 โ€” Top 5 repos by stars, with language and commits/30d (long names are truncated with โ€ฆ to keep them off the bars)
  • FIG. 03 โ€” 6-axis profile radar: reach, activity, breadth, depth, polyglot, engagement
  • FIG. 04 โ€” 53-week trailing contribution heatmap (via GraphQL โ€” requires a token)
  • FIG. 05 โ€” Indicators: total stars, total forks, commits/12 months, account age

Both dashboards carry a small Proudly Clauded by @<handle> watermark just below the frame, in the bottom-right corner. The handle is pulled from the data, so anyone running the lib gets their own credit line automatically. To remove or rephrase it, override the proudly_clauded template via --lang-file.

Installation

pip install cartouche-svg

Zero runtime dependencies โ€” Cartouche uses only the standard library (urllib for API calls, json, datetime, math, importlib.resources).

CLI usage

# Repo dashboard (English by default)
cartouche repo Sandjab/Athanor --theme blueprint-light --out dashboard.svg

# Same dashboard in French
cartouche repo Sandjab/Athanor --theme blueprint-light --lang fr --out dashboard.svg

# Profile dashboard
cartouche profile Sandjab --theme drafting-dark --out profile.svg

# List available themes and languages
cartouche themes
cartouche langs

# Test layouts without hitting the API (canned data)
cartouche repo Sandjab/Athanor --mock --theme vellum-light

# Override individual labels with your own JSON pack
cartouche repo Sandjab/Athanor --lang fr --lang-file ./my-overrides.json

# Replace auto-detected callouts on the star line with your own events
cartouche repo Sandjab/Athanor --annotations-file ./events.json

Token resolution: --token > $GITHUB_TOKEN > $GH_TOKEN > anonymous (60 req/h, rarely enough for a profile).

Internationalization

English by default. Switch to French with --lang fr.

Built-in packs

cartouche langs   # โ†’ en, fr

Adding a language

Drop a <code>.json file into src/cartouche/lang/, mirroring the schema of en.json (keys: labels, templates, months_short, months_long). The test_lang_has_all_required_keys test will tell you which keys are mandatory. Once dropped and the wheel rebuilt, --lang <code> works out of the box.

Overriding without recompiling

To tweak a few strings ad-hoc without publishing a new pack, write a JSON overlay and pass it via --lang-file:

{
  "labels": {
    "fig_radar_health": "FIG. 02 โ€” VITAL SIGNS",
    "drawn_by": "BY"
  },
  "templates": {
    "n_years": "{n} years"
  }
}
cartouche repo Sandjab/Athanor --lang en --lang-file my-overrides.json --out dashboard.svg

The overlay is deep-merged on top of the base pack: only the keys you specify are replaced, everything else stays intact.

Language pack schema

{
  "code": "xx",
  "name": "My language",
  "labels": {
    "drawn_by": "...",
    "fig_radar_health": "...",
    "card_stargazers": "...",
    ...
  },
  "templates": {
    "fig_star_history": "FIG. 01 โ€” STAR HISTORY ยท {start} โ†’ {end}",
    "first_star_top": "// FIRST STAR โ€” {date}",
    ...
  },
  "months_short": ["JAN", "FEB", ...],
  "months_long":  ["Jan", "Feb", ...]
}

See src/cartouche/lang/en.json for the full key list.

Themes

Sixteen themes in eight families, each with a light and a dark counterpart. The first five families are clean palettes; the last three are watermarked variants that ghost a bundled PNG (Da Vinci plate, floral motif, kawaii character) behind the data layer at low opacity. See THEMES.md for side-by-side previews of every variant.

Family Light Dark
Drafting drafting-light drafting-dark
Blueprint blueprint-light blueprint-dark
Vellum vellum-light vellum-dark
Botanical botanical-light botanical-dark
Blossom blossom-light blossom-dark
Vellum + Davinci vellum-davinci-light vellum-davinci-dark
Botanical + Floral botanical-floral-light botanical-floral-dark
Blossom + Kawai blossom-kawai-light blossom-kawai-dark
  • Drafting โ€” pure grayscale. White paper, black ink โ€” no hue at all, series and accent separated by lightness only.
  • Blueprint โ€” cyanotype lineage. Pale faded blue or a deep nighttime Prussian blue dive.
  • Vellum โ€” cream parchment / sepia. Dark variant: aged leather and gold. For those who want a Beaux-Arts feel rather than engineering.
  • Botanical โ€” 19th-century herbarium plate. Sage-and-fern ink on ivory, deep forest at night with candle-pollen accents.
  • Blossom โ€” sakura kawaii. Powder-rose on pearl-grey ivory, deep aubergine boudoir at night, neon-soft pink data with mint accents.
  • Vellum + Davinci โ€” Vellum palette + Da Vinci plate watermark. Reads as the surface of an old codex with the master draftsman's notebook bleeding through.
  • Botanical + Floral โ€” Botanical palette + floral motif watermark. The herbarium feel pushed further into a wallpapered field of flowers.
  • Blossom + Kawai โ€” Blossom palette + kawaii character watermark. Sakura stationery, soft mascot ghosted under the cartouche grid.

Custom annotations

By default the repo dashboard auto-detects two callouts on the star history: the first star and the largest single-step spike. Pass --annotations-file path/to/events.json to replace them with your own list of events:

[
  {"date": "2025-12-15", "label_top": "// HACKER NEWS", "label_bottom": "// front page"},
  {"date": "2026-04-01", "label_top": "// SHIPPED v1", "label_bottom": "// public release"},
  {"date": "2026-04-15", "count": 100, "label_top": "// MILESTONE", "label_bottom": "// 100 stars"}
]
  • date (required, ISO YYYY-MM-DD) is where the callout anchors on the star-history axis.
  • label_top / label_bottom (required) are the two text lines drawn next to the leader line. Convention is // PREFIX for the top line and a more descriptive bottom line, but anything goes.
  • count (optional) is the cumulative star count to anchor on the curve. If omitted, Cartouche derives it from the closest star_history entry on or before that date.

Custom annotations replace the auto-detected pair โ€” copy the auto- detected ones into your file if you want to keep them. Only available on the repo dashboard (the profile star line does not have annotations).

Embedding in a README

Serve the right variant based on the visitor's prefers-color-scheme:

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/dashboard-dark.svg">
  <img src="assets/dashboard-light.svg" alt="Cartouche dashboard">
</picture>

Important: use a relative path (assets/...), not an absolute URL. GitHub rewrites external images through its Camo proxy, which breaks the <picture> light/dark mechanism; relative paths are served as-is.

Auto-update via GitHub Actions

Two ready-to-use workflows live in examples/workflows/:

  • repo-dashboard.yml โ€” drop into .github/workflows/ of the repo whose dashboard you want. Regenerates and commits every 6 hours.
  • profile-dashboard.yml โ€” drop into your profile repo (<handle>/<handle>). Twice a day.

Both use secrets.GITHUB_TOKEN (already available in any Action) and work with no further configuration. To serve a French dashboard, add --lang fr to the cartouche commands in the workflow.

Python API

from cartouche import lang
from cartouche.render import repo
from cartouche.themes import get_theme

# Load a language pack (with optional overlay)
fr = lang.load("fr", overlay_path="my-overrides.json")  # overlay optional

# Load data (mock or via fetch.repo_data())
from cartouche.mock import mock_repo
data = mock_repo("Sandjab", "Athanor", lang=fr)

# Render the SVG
svg = repo.render(data, theme=get_theme("vellum-light"), lang=fr)

Architecture

src/cartouche/
โ”œโ”€โ”€ themes.py            # 16-theme registry (dict-of-dicts)
โ”œโ”€โ”€ lang/
โ”‚   โ”œโ”€โ”€ __init__.py      # load(), list_builtin(), t(), tmpl()
โ”‚   โ”œโ”€โ”€ en.json          # default language
โ”‚   โ””โ”€โ”€ fr.json          # French
โ”œโ”€โ”€ fetch.py             # GitHub REST + GraphQL wrappers, stdlib only
โ”œโ”€โ”€ mock.py              # canned fixtures for development without API
โ”œโ”€โ”€ cli.py               # argparse entry point
โ””โ”€โ”€ render/
    โ”œโ”€โ”€ primitives.py    # frame, grid, cartouche, axes, radar, text
    โ”œโ”€โ”€ repo.py          # repo dashboard composer
    โ””โ”€โ”€ profile.py       # profile dashboard composer

The render engine is token-agnostic (colors come from themes) and literal-free (strings come from lang). Adding a seventh theme = ~12 lines in THEMES. Adding a language = drop a JSON in lang/. See CLAUDE.md for the architectural invariants in detail.

Known limitations

  • The profile dashboard hits /repos/.../stargazers for each public repo; the first run on a viral account can still take a minute, but subsequent runs are near-instant thanks to a 24h disk cache ($XDG_CACHE_HOME/cartouche/). Pass --no-cache to skip it, --cache-ttl 0 to force a one-shot refresh, or --cache-dir PATH to relocate. True incremental refresh (only fetch stars added since last run) isn't implemented yet โ€” when the cache is stale, the timeline is refetched in full.
  • Forks are excluded from profile aggregates (filtered out). The dashboard for an individual fork still works normally.
  • Web fonts are not embedded โ€” GitHub strips them when rendering SVGs in READMEs. The fallback is a system monospace stack.
  • The two auto-detected annotations (first โ˜…, biggest spike) replace each other if you pass --annotations-file; there's no way to augment the auto-detected pair without listing them manually in your overlay.

Development

git clone https://github.com/Sandjab/cartouche
cd cartouche
pip install -e ".[dev]"
pytest                                                 # 128 tests, ~0.3s
python -m cartouche repo Sandjab/Athanor --mock        # smoke test without API
python -m cartouche profile Sandjab --mock --lang fr   # FR variant

For Claude Code CLI: see CLAUDE.md for architecture, invariants, and common tasks.

License

MIT โ€” see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cartouche_svg-0.2.2.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cartouche_svg-0.2.2-py3-none-any.whl (1.8 MB view details)

Uploaded Python 3

File details

Details for the file cartouche_svg-0.2.2.tar.gz.

File metadata

  • Download URL: cartouche_svg-0.2.2.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for cartouche_svg-0.2.2.tar.gz
Algorithm Hash digest
SHA256 effc94a57aaa0c91ed292e55448f6d3763853bda0626207581bdb860ba74d952
MD5 10294f70eeacda1cc688cf5bec353447
BLAKE2b-256 ab0932299071e66f8c451498f974aced07dbe250338d4be6371175a38caae3d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for cartouche_svg-0.2.2.tar.gz:

Publisher: release.yml on Sandjab/cartouche

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cartouche_svg-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: cartouche_svg-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for cartouche_svg-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a351d6a0901549baeadd3615a3c64d75719bb10a05e87d1c3e540ada865d1a26
MD5 8e815334bbe57ccdba9871398b53b10c
BLAKE2b-256 668e1045ad236c25adfe68383035977d24e58c5c67ca1939e0f2d555b517e55e

See more details on using hashes here.

Provenance

The following attestation bundles were made for cartouche_svg-0.2.2-py3-none-any.whl:

Publisher: release.yml on Sandjab/cartouche

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page