Home/Design checks

Design checks

Does the PR look like the design? Talooner renders the changed UI, compares it with your design file, and turns the result into facts your rules gate on.

coming soon

Review and tests tell you whether a change works. Design checks tell you whether it looks like the design — on every PR that touches UI, without a designer opening the preview.

Design tools

Tool
Figmafirst — components, nodes and design tokens through the Figma API
Penpotnext — the open-source design tool, self-hostable next to Talooner
Sketchplanned
Framerplanned

Want another one first? Tell us.

How it works

When a PR touches UI, Talooner can go past "does it work" to "does it look like the design". The design_check executor reads the referenced Figma nodes (reference image

It folds the result into design.* facts:

FactMeaning
design.figma_matchevery changed component matched its Figma source
design.pixel_driftworst-case visual difference, 0–1
design.token_mismatchesdesign tokens that didn't match (color/primary, spacing/md, …)
design.undocumented_countrendered components with no Figma source
design.undocumented_componentswhich ones
design.match_confidencecalibrated confidence in the verdict

The generated design scenario is a Jest + Playwright visual test:

// talooner-generated · design scenario: "PriceCard vs Figma node 1284:57"
import { test, expect } from '@jest/globals';
import { chromium } from 'playwright';
import { fetchFigmaNode, diffAgainstFigma, componentsOnPage } from '@talooner/figma-qa';

const DEPLOY = process.env.PREVIEW_URL;

test('PriceCard renders within 1% of its Figma component', async () => {
  const ref = await fetchFigmaNode('1284:57');            // reference image + tokens
  const browser = await chromium.launch();
  const page = await browser.newPage();
  await page.goto(`${DEPLOY}/components/price-card`);

  const shot = await page.locator('[data-component="price-card"]').screenshot();
  const { pixelDrift, tokenMismatches } = diffAgainstFigma(shot, ref);

  expect(pixelDrift).toBeLessThan(0.01);
  expect(tokenMismatches).toEqual([]);                    // colors/spacing/type match tokens
  await browser.close();
});

test('every rendered component maps to a Figma component', async () => {
  const rendered   = await componentsOnPage(`${DEPLOY}/pricing`);       // [data-component] nodes
  const documented = await fetchFigmaNode('page:pricing').then(n => n.componentNames);
  const orphans    = rendered.filter(c => !documented.includes(c));
  expect(orphans).toEqual([]);   // UI with no Figma source is a finding, not a pass
});

And the rule that catches the not-in-Figma case:

rule "Flag UI that isn't in Figma" {
  for records where type == "pr"
    and is "pr.touches_design"
    and attr "design.undocumented_count" > 0
  do require "review.design"
  do comment "pr" "These rendered components have no Figma source: {attr.design.undocumented_components}. Add them to the design file, or remove them"
  reason "undocumented UI"
  priority MEDIUM
}

Pair it with the drift and confidence rules on the Rules page and a UI change is gated three ways: it must match Figma, contain nothing that isn't in Figma, and — when the check is unsure — go to a human.

Want this guarding your repos?

Start a free demo