Dembrandt 0.39 is out. The run now shows its evidence, and it reaches the pages behind a sign-in. The primary colour explains how it was picked, a saved sign-in can be reused in CI, and rendered values can be checked against your own token file.
Dembrandt 0.39 is out. The run now shows its evidence, and it reaches the pages behind a sign-in. The primary colour explains how it was picked, a saved sign-in can be reused in CI, and rendered values can be checked against your own token file.
Slide text
v0.39.0
The run shows its evidence, and it reaches the pages behind a sign-in.
Additive: output contract 1.18.0 to 1.19.0
colors.semanticEvidence--login--tokens
The primary colour now carries its evidence. When Dembrandt elects one, it records the rule, the reason, the custom properties that declare it, and the runners-up. When it refuses, that's recorded too, with the candidates that lost. The terminal, the HTML report and DESIGN.md all say which.
Slide text
colors.semanticEvidence.primary
Evidence
The primary colour now says how it was decided
elected · rule, reason, declaring tokens, runners-up
Primary (#1D3A8A): Elected: an element class names it primary (--brand).
refused · the candidates that lost
Primary: not elected, 2 chromatic logo colours of equal weight, none painted as a surface. Candidates: #00b6ff, #ff7237.
DESIGN.md lines from the release's tests · terminal and HTML report say the same
The run also keeps the raw measurement under the palette. The occurrences list has one row per colour per paint, so fill, text or border. Each row counts the elements, sums the area a fill covers, and names the custom property that declares it. And the CSS variables map is now complete, with alias tokens and dark-mode values keeping their names.
Slide text
v0.39.0
Evidence
Every colour, on every paint, with the area it fills
colors.cssVariables is complete: alias tokens and dark-mode values keep their names, each with its scope.
colors.occurrences[]
hex"#111111"
paints"fill" or text, border
count3
area50 fills only
cssVar"--ink"
one row per colour per paint,
summed across a crawl
A crawl now tags every merged value with how many pages carry it. On every page, it's site-wide. On one page, it's page-local. Anything in between is a section. The crawl gets a coverage score out of a hundred, with the page-local outliers listed. Each family of values counts equally, so a long colour list can't drown out a few radii.
Slide text
pageCount · scope · coverage
Evidence
A crawl now scores how consistently a site uses its values
page 1page 2page 3page 4sitesectionpage
72/100 consistentacross 4 pages
page-local: colors #ff0000
Pages behind a sign-in are now in reach. Run once with the login flag, sign in through the browser that opens, and press Enter to save the session to a file. Later runs and CI reuse it with the cookie file flag. A lapsed session gets a warning, basic auth works too, and one switch keeps a failed load from opening a browser.
Slide text
v0.39.0
Reach
Sign in once, then reuse the session in later runs and CI
--no-headed-fallback no visible browser on a failed load
A drift gate compares a site with its own past. The token check asks which rendered values aren't tokens at all. Point the tokens flag at a W3C design tokens file, and every rendered colour, radius and font size is matched to its nearest token. Too many misses and the run exits 1, with a Markdown report and CI annotations to show where.
Slide text
v0.39.0
Against a token file
Check every rendered colour, radius and font size against your tokens
ΔE2000 ≤ 2.3from the nearest token counts as that colour
exit 1more off-token values than --max-off-token
github | azure--annotations print off-token values in the CI log
Drift also picks up a tech category. A framework or icon set that's added, removed, or bumped a major version raises the score. Each run records its browser context, so drift warns when two snapshots were measured differently. And the MCP server now ships to the MCP Registry with every release.
Slide text
v0.39.0
Also
Drift now compares the frameworks and icon sets a site is built with
A tech drift category
Added, removed, or a major version: the score rises. Minor and patch: listed only.
Both snapshots 1.18.0 or later, same CLI version
meta.context
Drift warns when two snapshots were measured under different browser contexts.
MCP Registry
io.github.dembrandt/dembrandt, published each release.
Plus formatter fixes and Playwright 1.63.0
The output contract moves from 1.18 to 1.19, and the change is additive. A colour seen fewer than three times now reads supporting instead of accent, so a 0.38 drift baseline may score a small move on those colours, once. On 175 test sites, 158 matched a same-day 0.38 run exactly, and primary accuracy rose by one site.
Slide text
output contract 1.18.0 to 1.19.0, additive
Upgrading
One palette role reads differently, and the rest is additive
role: "accent"nowrole: "supporting"
For a colour seen under three times. Drift weighs the two roles differently, so a 0.38.0 baseline may score a small move on such colours once.
158 of 175
corpus sites identical to a same-day 0.38.0 control
3
primaries moved: two bot walls, one site that moves between control days
106 vs 105
primaries correct of 141 labelled sites, 0.39.0 vs 0.38.0
To upgrade, run the latest package from npm, or pin the GitHub Action to v0.39.0. If CI gates on drift against a 0.38 baseline, it may flag that one-time move, and the approve flag accepts the new run. The run shows its evidence, and it reaches the pages behind a sign-in.
Slide text
v0.39.0
CLI
$ npx -y dembrandt@latest <url>
GitHub Action
uses: dembrandt/dembrandt@v0.39.0
Drift gate on a 0.38.0 baseline? It may score a one-time move on rarely seen colours. --approve accepts the current run as the new baseline.