import { type PageRegion, type Recipe } from '@variance-authority/core/format'; import { type BrowserEngine } from './engines.js'; import { type AssembleOptions, type Renderer } from '@variance-authority/raster'; /** * A local renderer: one browser, one page per viewport, N documents. * * Persistent for the reason measured in journal 0007 — a browser launch and first * navigation dominate the work they enclose by roughly two orders of magnitude * (205 ms cold against 7.5 ms warm), so a renderer that launches per image spends * the entire saving this project exists to produce before it paints anything. * * `setContent` rather than `goto`: the document is the input, and there is no * server, no build, and no application to navigate to. That is also what makes * this renderer able to serve documents acquired from jsdom, which has no browser * to navigate at all. */ /** * The engines this renderer can be. Defaults to `chromium`. * * ## Why cross-browser is a field here and a plan tier everywhere else * * The category prices coverage by multiplication — Percy states it as "two pages * rendered across two browsers and three widths would result in twelve * screenshots", and Chromatic bills `tests × builds × browsers × modes`. That * arithmetic is a property of pipelines where a browser produces the *whole* * observation, so observing in a second engine means running everything again. * * Here a `RenderDocument` is acquired once, by one collector, and rasterization * is the only phase that is engine-bound. So a second engine costs one more * paint of a document that already exists — not a second run. The multiplication * is against the tier that is ~65 ms rather than against the tier that decides. * * ## Why this needs no new comparison rule * * The engine is already in {@link RenderIdentity}, which already keys the store * and already names the cause of a cross-machine change. A WebKit baseline * therefore lands in its own directory, and a Chromium run that finds it is * compared with it and names both engines as the cause — by the machinery that * was there for two laptops, unchanged. * Nothing about cross-engine support required a cross-engine concept. * * **What is not claimed.** The tricks in the stabilization recipe are written * against Chromium's behaviour and have never been asked to hold another engine * still, and text rasterization is pinnable on Chromium alone — see * {@link CHROMIUM_RASTER_ARGS}. `engines.chromium.test.ts` exercises the engines * `DECLARED_ENGINES` names, so the identity claim is verified rather than assumed. */ export type { BrowserEngine }; /** * Chromium settings that make rasterization independent of host defaults and of * what the page painted before. * * The two text flags: **no other engine accepts them**, so Firefox and WebKit * paint text the way the host does; WebKit's one lever is the page's * `-webkit-font-smoothing`, which changes the subject rather than the conditions * it is shot under. Dormant on macOS — no subpixel antialiasing since 10.14, * every flag a no-op — and load-bearing wherever fontconfig is live: 6,662 * chromatic pixels in the standard image, zero with the flags. A raster belongs * to a host. See the README. * * `--disable-partial-raster`: with partial raster, an edit repaints only the * damaged part of a tile and keeps the rest, and the repainted pixels come out a * colour level off a whole-tile paint. A page that mounts subject after subject * then shoots one subject two ways, by whether something else was painted over * it first. Without partial raster every tile is painted whole, at no cost: 240 * mounts and shots on one page took 23.9 ms each with the flag and 24.0 ms * without it, on an M4 Max. */ export declare const CHROMIUM_RASTER_ARGS: readonly ['--disable-lcd-text', '--font-render-hinting=none', '--disable-partial-raster']; /** Each page opens in {@link PageRegion}'s timezone and language: `UTC` and `en-US` by default. */ export interface PlaywrightRendererOptions extends PageRegion { readonly headless?: boolean; /** * Browser launch arguments that may affect pixels. * * Chromium defaults to {@link CHROMIUM_RASTER_ARGS}; other engines default to * none. The exact ordered list is folded into `RenderIdentity`. */ readonly launchArgs?: readonly string[]; /** Which engine paints. Defaults to `chromium`. See {@link BrowserEngine}. */ readonly browser?: BrowserEngine; /** * Fonts this machine is asserted to have, as `family/weight/style/hash`. * * Asserted, not detected: a page can ask whether a family resolves, and cannot * read the bytes behind it. This is the caller's declaration of what the * machine is, and it goes straight into the identity digest — which is the * mechanism by which a change against a durable baseline written on a machine * with a different font stack names the font stack as its cause. */ readonly fonts?: readonly string[]; readonly assemble?: AssembleOptions; /** Waits for web fonts and images before shooting. Defaults to `true`. */ readonly waitForFonts?: boolean; /** * Which tricks hold the page still. Defaults to the raster recipe. * * A list rather than a set of switches, so a project can drop one, replace one * with a different mechanism, or add its own without editing this package. * Every shipped trick is applied from outside the subject, so nothing in the * product is shaped by it. The recipe is folded into the renderer's identity: * a baseline made under one recipe and a run made under another are compared, * and what changed names this option as its cause rather than anybody's code. */ readonly stabilization?: Recipe; /** * How many documents may be painted at once. Defaults to 1. * * Above 1 this renderer leases a *separate page* per render instead of sharing * one per viewport, because `setContent` replaces a page's whole document — * two concurrent renders into one page would paint each other's subject, which * is the failure the harness has always warned about, arriving from the other * direction. * * Pages, not browsers. A page costs a few MB against a browser's process, and * the isolation a *render* needs is a document of its own: nothing here shares * state between renders, since each one `setContent`s a complete document. * That is exactly the property collection does **not** have (ADR-0009), which * is why the collector stays serial while this does not. * * Worth having because the raster tier is where a run's time is: ~65 ms to * paint against ~7.5 ms to collect. */ readonly concurrency?: number; } export declare function createPlaywrightRenderer(options?: PlaywrightRendererOptions): Promise; //# sourceMappingURL=renderer.d.ts.map