Skip to content

Releases: Chris0Jeky/CommitAtlas

CommitAtlas v0.3.0 — the cards, redrawn

Choose a tag to compare

@Chris0Jeky Chris0Jeky released this 24 Aug 17:00
4ec77d7

The eight SVG cards are redesigned on the Fieldline chassis, and the two defects that made their colour untrustworthy are fixed. Every existing theme= URL still resolves; no route, size, or function signature moved.

Hue is no longer used as a scale

The reported symptom was that the density squares used colours that didn't clearly mean anything. Checking it found something worse.

Levels 2, 3 and 4 were drawn in accent, positive and warningthe exact three colours the contribution mix printed one panel to the right. A square's colour therefore named a category it did not mean: an orange cell read as a commit rather than a medium day.

Underneath that sat the real fault. Hue carries no order. Nothing about orange → green → yellow says "more", and in greyscale the shipped ramp actually inverted between levels 3 and 4 — so the scale failed outright for anyone reading it without colour. The same mapping was in the activity card, where nobody had noticed it.

Every theme now uses one hue at four steps, plus a neutral socket for a day with nothing observed. densityFill is the single place a level becomes a colour, and it resolves a non-finite level to the socket rather than indexing past the end of the ramp — an unreadable signal must never paint as the busiest day. Tests assert monotonic luminance, a ≥1.25× separation at every step so the scale survives greyscale, and that no step collides with the mix ink or a status colour.

The direction follows the ground: on a dark card more activity is brighter, on a light card it is darker. The socket stays neutral either way, because a pale tint of the activity colour reads as a little activity and a day with none had none.

The contribution mix moves to one ink with bar length as the only variable, which is what stops the two panels handing the reader contradictory colour vocabularies.

Cards ship as a dark/light pair

Each card carries its own opaque background, so a dark card on a light GitHub profile really is a dark slab — the Studio's LIGHT preview canvas was accurate, not misleading. But the generated Markdown pinned one theme, so whichever the user picked was wrong for every reader on the other colour scheme.

Each card now ships as a <picture> block keyed on prefers-color-scheme, so a README serves the reader's own scheme from a single snippet. The <img> fallback names the theme the user actually chose, so a renderer without <picture> support still shows their selection.

Theme Scheme Ground Partner
ember dark #121310 paper
aurora dark #09131f paper
midnight dark #05070d paper
paper light #dfe4c9 ember

paper is Limestone rather than white, so the light card still reads as a card on a white page.

The chassis vocabulary, at card scale

Corner-cut plates, section numerals, mono chrome labels, square swatches that match the density cells, and dashed empty sockets for an unconfigured probe — the same language the web surface uses, so a reader who learns it once recognises it everywhere.

The cards use a system font stack, deliberately. They render as SVG inside an <img> on GitHub, where no webfont can load and an embedded @font-face would spend the whole 30 KiB budget before any data was drawn. The design has to survive font substitution on whatever machine renders it.

Two faults found by looking, not by testing

  • The font stacks first shipped with double quotes around multi-word families. Inside a double-quoted XML attribute that closed font-family=" early and produced malformed SVG. assertWellFormedXml failed five suites at once — exactly what that assertion exists for.
  • The hazard strip was, at real size, the loudest element on the card while carrying no information. It works on a 1440px web fascia as one element among many; repeated down a README at 720px it dominated the data. It is edge texture now, at 4px and 18% rather than 6px and 42%.

Neither would have been caught by a test written in advance.

Also in this release

Keyboard QA and the 1440×900 screenshot pair are closed, both carried as NOT verified since v0.1.0. The keyboard pass could not be done by observing keypresses — the available controller does not produce native focus traversal — so the properties that make traversal correct were measured against production instead: no positive tabindex anywhere, every reachable control named, and zero non-native widgets, which is what guarantees Enter and Space work. Details in docs/PROJECT_STATE.md.

Verification

npm run check green at the released commit: 301 tests across nine suites, plus TypeScript, ESLint, four package builds, and Action bundle parity. All eight cards were rendered as <img> on both GitHub grounds — which is how they are actually consumed — in dark and light.

npm publication is still not claimed. The packages are built and pack-verified but are not on the registry.

The design contract is in docs/DESIGN_CHASSIS.md.

CommitAtlas v0.2.0 — the shared chassis

Choose a tag to compare

@Chris0Jeky Chris0Jeky released this 24 Aug 15:34
5fea6e6

The web surface is rebuilt on the shared chassis from the design_handoff_shared_chassis bundle. No SVG card, route, response contract, or workspace package changed — the four packages stay at 0.1.0 because none of their public APIs moved.

The landing page is now the product measuring itself

Every number in the instrument fascia, the six-state health rack, and the new evidence drawer comes out of one landingSnapshot() call — the same fetchPortfolioSnapshot the SVG routes use, in demo mode. Nothing on the page is typed in, and none of it costs a GitHub request, so the front page cannot be taken down by a rate limit and cannot drift away from what the routes actually render.

Four instrument bays, each with its reading printed as text beside it: a 28-day momentum plotter, the rhythm gauge, a full 365-day density calendar, and a portfolio reticle.

Four chassis themes

Fieldline (default), Observatory, Midline, and Limestone. Brightness and chrome are the only things a theme changes — the 42px survey grid, the temperature scale, the corner cuts, and every measurement are shared. The theme persists in localStorage and applies before first paint; it is deliberately not a cookie, so the served HTML stays identical for every visitor and therefore cacheable. The SVG card theme= parameter is a separate setting and is untouched.

Building the light theme surfaced a real problem: every colour in the temperature scale measures between 1.1:1 and 2.1:1 against Limestone — unreadable as text and under the 3:1 floor even for a graphical mark. The chassis already solves this once for chrome (signal lime becomes olive), so ink roles apply that same rule to the rest of the palette. lib/chassis.test.ts now measures every role against every theme's own ground and plate, at 4.5:1 where it prints small text and 3:1 where it only strokes or fills.

An evidence layer

Every dotted number opens one shared drawer carrying that reading's tier, basis, formula, and caveat. Three rungs — observed, derived, hypothesis — and a tier is not a fixed property of a metric:

  • The activity mix is observed with exact categorised counts, and a hypothesis when the only source is GitHub's annual public-profile percentages, because those describe a year the requested window does not cover.
  • The star total is derived normally and a hypothesis when the repository list came back truncated, where it is a lower bound rather than a total.
  • The rhythm score is derived. The rhythm level — "steady", "strong" — is a hypothesis, because CommitAtlas chose the thresholds and nothing in GitHub's data draws them.

The drawer is a native <dialog> opened with showModal(), so the browser supplies the focus trap, the backdrop, and Escape.

A six-bay health rack

Each of the six CI states carries four independent channels — a printed word, a glyph, a lamp shape, and a trace pattern — so the rack reads with the colours deleted. The two states that mean nothing was observed carry no colour at all, and the three unknowns lead.

The hero's fourth instrument is the honest one. Both declared demo projects have no named workflow, so both lamps are empty sockets and the tile reads 0/2 CI PASSING · 0 ATTENTION · 2 UNCONFIGURED — shown dark, never green. Configuring a workflow would have lit two lamps green; the front page is where that shortcut most needed refusing.

Motion

M1–M9 implemented, and the reduced-motion path is a complete page rather than a degraded one. Every keyframe declares only a start state, so the inline value is the final state. Verified by reading computed styles with animations disabled: the plotter rests at stroke-dashoffset: 0, the needle at its settled 39.6°, the density columns at their own opacities, and the acquisition gauge at its −90° rest stop with the plate still reading NO SIGNAL.

One correction that did not survive checking

The README, ARCHITECTURE.md, and the design handoff all described the Languages surface as a repository-language byte share. It has never been one: toLanguagesCard is fed by the profile snapshot, whose share is repositories / total. The labels are corrected rather than the code, because byte share needs a per-repository /languages call and that rate-limit cost belongs to its own slice. The dated 2026-08-20 QA record still says "byte-share" and is deliberately left alone — it records what was observed then.

Verification

npm run check green at the released commit: TypeScript, ESLint, deploy tooling 5, core 20, chassis 51, GitHub/API 93, Studio 49, SVG 30, static 14, Action 2, packaging 3, rendered product/API 47, plus four package builds and Action bundle parity.

Three fresh-context reviews ran against the branch — an adversarial correctness pass, an accessibility pass, and a verification pass scoped to the fixes. None found a CRITICAL. What they did find is recorded in docs/PROJECT_STATE.md, including two findings triaged as non-blocking and left deliberately.

The 390-wide layout was measured in a same-origin frame: scrollWidth === clientWidth, no element past the viewport. All four themes were inspected on the running surface.

npm publication is still not claimed. The packages are built and pack-verified but are not on the registry.

The design contract is recorded in docs/DESIGN_CHASSIS.md.

CommitAtlas v0.1.0 — Your GitHub work, mapped clearly

Choose a tag to compare

@Chris0Jeky Chris0Jeky released this 24 Aug 11:50
ee24f80

Your GitHub work, mapped clearly.

The first tagged release of CommitAtlas: eight embeddable SVG cards, a project-health dashboard, a credential-free static generator, and a bundled GitHub Action — deployed and continuously verified on Cloudflare Workers.

Live now: https://commit-atlas.commit-atlas.workers.dev · Studio


The rule this project is built around

An unknown, missing, or stale signal is never displayed as healthy or passing.

Most GitHub card projects render whatever comes back and paint the gaps green. CommitAtlas doesn't.

CI freshness has a 72-hour window, and a run older than that reports stale rather than passing. A repository whose workflow cannot be read reports unavailable, not "0 failures". A rate limit, an upstream outage, and a genuine 404 are three distinct answers, never collapsed into one. The rhythm score says on its own face that it is a personal consistency measure and not a GitHub rank. The languages card reports byte share and refuses to imply proficiency. The breakdown card labels its own scope whenever it falls back to calendar-year profile percentages.

That rule is enforced by tests, not by discipline — including against the project's own authors. Two examples from this release: a negative project count was being clamped to a confident-looking 0 attention in the healthy style, and the machine-readable licence metadata briefly claimed MIT on a GPL-3.0-only project. Both were caught by review and are now pinned by tests.

What's in it

Eight cards

Card What it shows
Atlas A full year in one 860×380 SVG: heatmap, density, streaks, collaboration mix, 12-bucket momentum, rhythm, languages, project health
Profile Repositories, followers, following, stars, contribution total
Streak Current and longest streak inside the displayed window, active days, last activity
Breakdown Window-scoped categorized counts when exact; otherwise calendar-year percentages, labelled as not window-scoped
Rhythm Personal consistency from density, streak, and momentum — not a rank
Activity Bounded daily contribution graph with its exact date window
Languages Repository-language byte share, never guessed proficiency
Projects Up to six curated projects with declared lifecycle, named-workflow CI, release, and freshness

Four themes (aurora, midnight, paper, ember), wide and compact layouts, and motion=none|subtle. subtle ships a prefers-reduced-motion override; none emits no keyframes at all. The paper light theme exists because README embeds land on light GitHub profiles.

Three ways to use it

  • Hosted API/api/v1/cards/*.svg. No credentials needed for any documented surface.
  • Static generator — reads the logged-out public profile, renders every selected card from one snapshot, and writes a SHA-256 manifest. The config is one-owner and public-only by design: it rejects unknown fields, credentials, absolute/traversing/symlinked paths, untracked config, duplicate cards, and invalid workflow identities.
  • GitHub Action — repository-root action.yml, Node 24, bundled. It only generates files. It never commits, never pushes, never uploads, and never receives GITHUB_TOKEN.

The Studio

Configure, preview, and copy the exact README Markdown. Project Docs / Install / Download / Release / Source / CI links live in the accessible HTML dashboard rather than in the SVG, because a README-embedded SVG is one linked image and cannot reliably carry independent links.

Deployment

CommitAtlas is a Cloudflare Worker with static assets and needs no credentials to serve every documented surface, so the free Workers plan is enough.

npx wrangler login
npm run deploy

npm run deploy builds, publishes, reads the deployed origin out of Wrangler's own output, and runs seventeen deterministic probes against it. The origin is never hard-coded: a workers.dev hostname is account-specific, and a hard-coded one would have a fork's verification probe someone else's healthy site and report success for a deployment that never happened.

Push-to-deploy from GitHub Actions is wired and proven end to end — CI green on main, then build, deploy, verify. Without deployment secrets configured the workflow reports unconfigured and skips cleanly rather than failing, so a fork gets a clean skip and not a red workflow.

Deploying a fork? Set SITE_ORIGIN in wrangler.jsonc to your own origin. It is the canonical URL your deployment advertises — in rel=canonical, the sitemap, and the JSON-LD — and leaving it unset makes your site tell crawlers the canonical copy lives somewhere else. See docs/DEPLOYMENT.md.

Security and privacy posture

  • Credential-free by default. Public GitHub data only. No token is required for anything documented here.
  • Outbound data hosts stay GitHub-owned. Rendering never fetches a link it displays.
  • All user text is schema-bounded and XML-escaped at the package boundary, not at the route.
  • Generated SVGs contain no script, no foreignObject, no event handlers, and no external references.
  • Invalid, duplicate, and traversal queries are rejected as bounded 400 JSON with no-store.
  • The deploy workflow refuses to run on a fork's workflow_run, checking head_repository.full_name rather than the spoofable head_branch. This is reviewed, not demonstrated — no fork has opened a pull request, so the guard has never been exercised by a real fork event.

Known limitations

Named rather than hidden. Every one is a tracked issue:

  • #62 — a genuine non-rate-limit 403 (a blocked repository, an organisation restriction) is still reported as github_rate_limited. Wrong label, correct direction: it reports unavailable, never healthy.
  • #58 — bar geometry can overflow at absurd intermediate magnitudes. Measured clean at 3.7e306 and broken at 3.8e306; unreachable from any GitHub response, reachable by a direct library caller.
  • #54npm run check can abort on Windows from a deeply nested checkout path. Environmental, not a product defect.
  • Safari and older Windows want a raster favicon; only an SVG icon ships. No .ico is faked from it.
  • npm publication is not claimed. The packages are built and pack-verified but are not on the registry, and nothing here will say otherwise until a registry lookup succeeds.

Requirements

Node.js 22.13 or newer. Licensed GPL-3.0-only.


235 commits, merge history intact — nothing squashed. Every card, metric, renderer, and GitHub response shape ships with a fixture and a focused test.

What's Changed

  • ci: add locked quality and dependency gates by @Chris0Jeky in #3
  • chore(deps): bump actions/checkout from 4 to 7 by @dependabot[bot] in #4
  • fix: restore the declared GPL-3.0-only license by @Chris0Jeky in #12
  • docs: add contributor and security guidance by @Chris0Jeky in #11
  • feat(core): add truthful GitHub metric contracts by @Chris0Jeky in #1
  • fix(core): bound streaks to the as-of date by @Chris0Jeky in #22
  • fix(core): reject future CI observations by @Chris0Jeky in #23
  • feat(svg): add accessible card renderers by @Chris0Jeky in #2
  • fix(core): require non-empty contribution calendars by @Chris0Jeky in #24
  • docs(state): save implementation checkpoint by @Chris0Jeky in #26
  • fix(release): close core package blockers by @Chris0Jeky in #27
  • feat(data): add versioned GitHub signal API by @Chris0Jeky in #25
  • fix(svg): ship bounded accessible renderer contracts by @Chris0Jeky in #39
  • fix(core): harden manifest identity contracts by @Chris0Jeky in #43
  • feat(api): ship versioned SVG card routes by @Chris0Jeky in #44
  • feat(studio): ship interactive portfolio dashboard by @Chris0Jeky in #47
  • fix(tests): stop pinned CI fixtures from decaying into stale by @Chris0Jeky in #51
  • chore(deps): bump actions/setup-node from 4 to 7 by @dependabot[bot] in #5
  • build(deps-dev): bump the development-dependencies group across 1 directory with 8 updates by @dependabot[bot] in #6
  • fix(svg): bound caller prose on the breakdown and rhythm cards by @Chris0Jeky in #56
  • feat(deploy): publish CommitAtlas on Cloudflare Workers by @Chris0Jeky in #52
  • hardening(static): tighten generated project catalog boundaries by @Chris0Jeky in #53
  • hardening(api): stable not-found contract and reviewed response-contract gaps by @Chris0Jeky in #57
  • fix(studio): confirm live card evidence per preview run by...
Read more