v0.39.0

1 hour ago

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.

Ask about this presentation

Chapters

  1. 0:00Dembrandt 0.39
  2. 0:17The primary colour explains itself
  3. 0:37Every colour, per paint
  4. 0:59A crawl scores site-wide agreement
  5. 1:21Sign in once, reuse the session
  6. 1:42Rendered values against a token file
  7. 2:05Drift, context and the MCP Registry
  8. 2:26What reads differently
  9. 2:52Upgrade to 0.39.0
Show transcript
  1. 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
    Dembrandt 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
  2. 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
    Dembrandt 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
  3. 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
    Dembrandt 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
    count 3
    area 50 fills only
    cssVar "--ink"
    one row per colour per paint, summed across a crawl
  4. 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
    Dembrandt pageCount · scope · coverage

    Evidence

    A crawl now scores how consistently a site uses its values

    page 1 page 2 page 3 page 4 site section page
    72/100 consistent across 4 pages
    page-local: colors #ff0000
  5. 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
    Dembrandt v0.39.0

    Reach

    Sign in once, then reuse the session in later runs and CI

    On your workstation
    $ dembrandt <url> \ --login \ --save-storage-state session.json
    In later runs and CI
    $ dembrandt <url> \ --cookie-file session.json
    meta.sessionWarnings
    a lapsed or rejected session
    --basic-auth user:pass
    HTTP Basic for the browser
    --no-headed-fallback
    no visible browser on a failed load
  6. 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
    Dembrandt v0.39.0

    Against a token file

    Check every rendered colour, radius and font size against your tokens

    $ dembrandt https://test.example.com /search /orders \ --cookie-file session.json \ --tokens tokens/light.json --tokens tokens/dark.json \ --max-off-token 10 --tokens-report docs/drift/rendered.md
    Δ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
  7. 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
    Dembrandt 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
  8. 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
    Dembrandt output contract 1.18.0 to 1.19.0, additive

    Upgrading

    One palette role reads differently, and the rest is additive

    role: "accent" now role: "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
  9. 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
    Dembrandt 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.

    github.com/dembrandt/dembrandt/releases/tag/v0.39.0

What happened in AI today, in your inbox

One short email each evening. Read it and you’re caught up.

Built in New York with ❤️