vidimus

Showcase

Most tools show you a screenshot of a clean report on a hello-world page. This page is the opposite: it is built to be hard to audit. A WebGL scene, iframes from three hosts, video with captions, art-directed images in three formats and a table that does not exist until a script writes it. Eight site generators build it, from VitePress to mdBook to a client-rendered Angular app, and vidimus audits every one of them on every push to main. Then it runs again, live, in your browser, on the page you are reading.

Audit this page, live

No recording, no screenshot. Press the button and a pocket edition of vidimus runs inside this tab: nine of its checks, rewritten to read this page's DOM and the browser's Performance API as they are right now. It fetches every internal link on the page to see if it is broken, lists every host your browser has talked to, weighs every file it downloaded and looks for anything sticking out of the viewport.

$ vidimus --live
Waiting for you. Whatever it prints is what this page really has, theme and all.

Try to make it complain:

  • Scroll down to the OpenStreetMap iframe under Embeds and run it again. The map is lazy-loaded, so privacy fails as soon as the browser fetches it. The full audit reports the same iframe, and this site accepts it on purpose.
  • Play the zoo video, then run it again. privacy catches youtube-nocookie.com the moment the facade lets it in, and not a moment before.
  • Shrink the window to phone width and run it again: r12s measures the page at whatever size it is.
  • Open this page in another flavor and compare. Each theme brings its own markup, scripts and weight, and the live audit reads all of it.

The real vidimus does much more than this: it serves the build, drives headless Chromium over every page, and runs axe-core, html-validate, Lighthouse and pixel diffs across every page and viewport. The live audit is a taste of it, running where there is no server and no Node.js.

A three.js scene

Every page of these docs, coloured by section, with a line per link between two pages. Drag it to spin it. The graph is written as graph.glb when the docs are built.

The scene loads three.js from this site, bundled with the page's own script, not from a CDN. It reads its model from a .glb file, spins only while it is on screen, renders a single frame under prefers-reduced-motion: reduce, and leaves the static SVG poster in place when WebGL is not available. The whole block is one role="img" with a text alternative, and the script is an external module, so a strict CSP needs script-src 'self' and nothing else.

What vidimus reports here:

  • budget measures what the browser fetched, because render.include covers this page: the three.js bundle is the heaviest file.

    ✖ page 521 kB total > 300 kB budget
        144 kB /vidimus/showcase/showcase.js
        84 kB /assets/inter-roman-symbols.CQZtw9ew.woff2
        80 kB /assets/inter-italic-latin.Duvr4T3O.woff2
    

    That is with the page budget lowered to 300 kB to make it speak; the default is 2 MB.

  • shots freezes the scene: requestAnimationFrame stops after 30 frames of a virtual clock, so two runs capture the same frame.

    hugo_showcase@375x800.png  unchanged
    react_showcase@1280x800.png  0.01% changed -> diff/react_showcase@1280x800.png
    
  • lighthouse scores this page lower than the text pages, 76 to 97 on performance depending on the flavor, so it has its own threshold in docs/vidimus.config.ts: overrides: [{ match: 'showcase', thresholds: { performance: 0.75 } }].

  • csp, on the flavors with a strict meta CSP, finds nothing: the page's policy allows script-src 'self' and the script is a file.

Embeds

April 23, 2005: nineteen seconds of Jawed Karim in front of the elephants at the San Diego Zoo, the first video ever uploaded to YouTube. Here it sits behind a click-to-load facade: until you press play, the page shows a thumbnail served from this site and loads nothing from YouTube.

An OpenStreetMap iframe, loaded lazily with a sandbox and no facade, so it is exactly the kind of embed privacy exists to find:

View the map on openstreetmap.org.

A StackBlitz project, behind a facade too: it boots a whole development environment in the browser.

What vidimus reports here:

  • privacy sees no request to YouTube or StackBlitz: the facades load nothing until clicked. The map is reported, with the requests the iframe makes from inside:

    ✖ third-party embed from www.openstreetmap.org
        loaded in an <iframe> on page load
        https://www.openstreetmap.org/export/embed.html?bbox=11.2400%2C43.7630%2C11.2700%2C43.7800&layer=mapnik
        https://www.openstreetmap.org/assets/embed-8cbd447f….css
        https://www.openstreetmap.org/assets/embed-3c62483a….js
        on: /angular/showcase /astro/showcase/ /eleventy/showcase/ +5 more
        → Put the embed behind a click-to-load facade (a static preview that loads the iframe on click), or load it only after consent.
    

    It is accepted by an ignore rule scoped to this page, with a comment saying why.

  • csp checks the iframe against each page's frame-src; the Hugo, Eleventy, Zola, React and Angular policies list https://www.openstreetmap.org, so it passes, and the sandbox attribute keeps the third-party iframe warning away.

  • shots masks the map, a cross-origin iframe, as a black box, so tiles loading in a different order never count as a change.

  • a11y and html require the title on the iframe.

Video, images and a diagram

A self-hosted video with a poster and captions:

Vidimus is Latin for “we have seen”, so here is someone who has seen everything: a responsive image in AVIF, WebP and JPEG, each at two widths, and the browser picks one.

An inline SVG diagram of a run:

A vidimus run: the build is served, the audits read it, and their findings go to the reporters. build server audits findings

What vidimus reports here:

  • budget checks the image budget and legacy formats: every <picture> has AVIF and WebP sources, so the JPEG fallbacks are not reported, and every <img> has width and height.
  • shots captures the page at 375 and 1280 px wide, so the square crop of the tiger and the whole painting each have a baseline of their own.
  • shots also pauses the video on its first frame and loads its metadata, so the controls look the same in every run. It waits for lazy images, which it switches to eager loading.
  • The captions are a .vtt file, which the built-in server sends as text/vtt, as a host would.

A table filled by a script

The rows below are not in the HTML file: a script fetches them from results.json and adds them. They are a summary of the audit run over these docs, and so are these numbers:

pages audited
217
links followed
650
audits run
11
audits passed
11
Audit results for these docs
AuditStatusSummary
The results are filled in by JavaScript.

What vidimus reports here:

  • The table's rows exist only in the rendered DOM. render.include renders this page in every flavor, so html validates the rows and seo and assets read the page as a browser sees it. Without it they would read the empty <tbody> of the built file.
  • In the React and Angular flavors every page is like this table: the built file is an empty shell, and the page exists only after the app runs. See Client-rendered apps.

Edit this page on GitHub