Stoatworks Labs

Test Card

A pattern per output, at the output's own raster

In developmentRuns in a browser tab

The fastest way to find out the output map is wrong.

Import the file that already describes the outputs (a Resolume advanced output, a Pixel Peeker wall, a Blend Calc array) and get a test pattern for every physical output, each at that output's own raster.

Everything is rendered in the page and downloaded from it, and no file of yours is uploaded. The importers are upfront about what each format doesn't carry, and anything the app had to infer is badged in the UI and written into the manifest rather than quietly assumed.

Test Card — A pattern per output, at the output's own raster
SMPTE RP 219 at 1920 × 1080 with the output name and resolution burnt in. The preview says it's scaled and that the exported PNG is the exact one, because the app won't let a resampled preview pass for the file.

What it makes

01

Eight patterns for measuring

SMPTE RP 219, 75% bars, a grid on your own pitch, alignment marks, LED tiles, solid fields, greyscale ramps and a 1px pixel check. Every pattern, these and all the ones below, can carry a burn-in (output name, resolution, pattern, your own text) and can draw the imported slice or port outlines on top.

02

RP 219 measured, not transcribed

The point of it

Published descriptions of RP 219 disagree with each other and mostly leave out the code values, so the geometry and colours were measured off a real generator instead. Two traps there each produce plausible, wrong output: decoding HD to rgb24 applies a BT.601 matrix, which turns 75% yellow into 189,202,7 instead of 191,191,0, and default chroma upsampling smears the band edges. Anything built by sampling that inherits the error.

03

One file per output, or one for all of them

A PNG per output at its native raster: one downloads on its own, several come as a ZIP with a manifest recording which file is which output, the level range, and any raster the app had to infer. Or a single composition-sized canvas with each output's region drawn and labelled, so when you play it out every screen should show its own name.

04

It asks which range you mean

Bars are defined in Y′CbCr, a PNG is RGB, and a PNG can't record which convention it was written in, so the app asks and puts the answer in the manifest. Full 0–255 for a media server or GPU output, legal 16–235 for an SDI chain, where sub-black survives and the pluge is actually judgeable.

05

A classic card, a levels check and AV sync

A test card in the old broadcast tradition: grey grid, castellated edges, colour bars, gratings down to 1px and a big circle with the output's name at its foot, and a stoat where the famous ones had a photograph (or your own picture, or your own words). A levels check that says whether the chain is full range end to end and, if it isn't, which end has it wrong, with the verdicts printed on the card. And AV sync: a flash and a one-frame beep once a second, with boxes numbered −6 to +6 lighting a frame apart, so filming it with sound tells you how many frames late the audio is. The MP4 carries the sound, each beep within a quarter of a millisecond of its flash.

06

Nine for while the client walks in

Rulers along the edges, worked out from the pixel pitch and never more than half a pitch out. A life-size bunch of bananas for scale, once or on every tile, with the wall's size in bananas. Seven dinosaurs at life size, cut off by the wall's edges where they don't fit. A dancing pixel-art hamster on every LED tile, as a nod to a certain 1998 web page. A sea, a scrolling Cretaceous, a volcano with a comet on the way, a wall broken fifteen different ways (labelled, if you're training someone), and any picture of your own, which stays in your browser.

07

Three for Halloween, eleven for doing nothing

For the one week a year the wall is expected to be festive: a jack-o'-lantern on every LED tile, a night wood scrolling past in five layers with witches crossing the moon, and a haunted house with the dead walking its graveyard. And for the hours a wall spends waiting for something to happen, the Windows 95 and 98 screensavers, Mystify to 3D Pipes, ported from Idler, my Resolume generator of the same eleven, and drawn through its own shaders. Those need WebGL2.

08

Loops that go round without a seam

Everything that moves (the scenes, the hamsters, Halloween, the screensavers, AV sync, a broken wall over any of them) exports as H.264 MP4, encoded in the tab, one per output or one for the composition. Everything in the loop does a whole number of cycles, so the last frame leads straight back into the first, and the colour goes through Rec. 709 into limited-range 4:2:0, labelled as such. Read back with ffmpeg, 75% bars come out within one code value of the standard. A raster bigger than the browser will encode comes out as a set of tiles, each its own seamless loop, with a manifest saying where each goes.

09

Or straight to the displays

Live output skips the files: in Chrome or Edge it lists the displays plugged into this computer, gives each the output that's its size, and opens a window over each that goes full screen on a click, at 1:1 when the sizes match. The windows follow every change in the editor and keep going if the editor tab is reloaded.

What to check before a show

  1. 01

    A Resolume raster can be inferred, and inference can come out small

    One output per Screen. Where the file records an output device the raster is read from it. Where it doesn't, the raster is inferred from slice bounds and can land smaller than the real output. Inferred rasters are badged in the UI and named in the manifest, so correct them by hand before you render.

  2. 02

    Pixel Peeker needs its JSON export, not the project file

    Use Export → JSON. The project file stores cabinets as library references in millimetres, which can't be resolved to pixels here, so it's refused outright with a message naming the right export rather than being half-read.

  3. 03

    Blend Calc designs are missing two numbers by nature

    The projector resolution isn't in the file, and neither is the solved overlap, which Blend Calc works out and never writes back. Both are asked for. Its Resolume XML export needs neither and is the better file to bring.

  4. 04

    The preview is scaled; the PNG isn't

    The on-screen preview is resampled to fit, so 1px detail (the pixel check especially) is approximate there and says so. Judge those patterns from the exported file on the real output, which is the only place a 1:1 pixel test means anything.

  5. 05

    Life-size needs a pixel pitch

    A Pixel Peeker import brings the wall's pitch with it. For anything else, type it in under Edit on the output, as a pitch or as the image's width in metres (the easy way for a projector). Without one, the rulers, bananas and dinosaurs are drawn at a fallback and say pitch assumed across the bottom, because a life-size banana at the wrong pitch is still the wrong size, just more confidently.

  6. 06

    The MP4s have only been made in Chrome

    Encoding needs a browser with WebCodecs and an even width and height, and it tells you before it starts if it can't. Chrome on a Mac stops at 4096 × 2304 worth of picture in any shape, which is why bigger rasters come out as tiles, and I haven't yet played a set of tiles together in a media server. Safari and Firefox have WebCodecs too, but I haven't tried either.

  7. 07

    Resolume plays them right, once it gets going

    Arena 7.28.1 opens the loops at the right size, rate and length, gets the colour right, and goes round without dropping or repeating a frame. But an H.264 clip triggered from cold often plays for about half a second and then holds until its first wrap. That's Arena's H.264 playback, not the file: ffmpeg's own encodes do the same and DXV doesn't. For a show, convert the loop to DXV with Alley, or let it run once round before doors.

  8. 08

    Live output goes through colour management

    Browsers allow one new window per click and go full screen only from a click in the window, so it's a click per display unless the site may open pop-ups. What reaches the cable has passed through the browser's and the OS's colour management, which hasn't been measured, so for levels and exact bar values play the PNG or MP4 from the media server. It's been driven with pretend displays in Chrome, not yet with a real second one.

  9. 09

    The screensavers keep time with the loop, not with Windows

    The originals never come back to where they started, and a loop has to, so every speed in them is rounded to a whole number of cycles in the loop. A longer loop leaves more of the original speeds alone. 3D Pipes and 3D Maze grow, which no rounding fixes, so each loop is one run from the seed, starting again part-way through: the box clears, and the maze fades out and back in.

Run your own copy

Test Card is also published as a Docker image, ghcr.io/stoatworks-labs/test-card, serving the same files as the hosted copy. On a laptop or a box in the rack it keeps working when the venue's internet doesn't.

Docker

docker run -d --name test-card --restart unless-stopped -p 8522:80 ghcr.io/stoatworks-labs/test-card:latest

Then it's at http://localhost:8522/. The repo's docker-compose.yml does the same with docker compose up -d.

Unraid

Search Community Applications for test-card and install it. The template sets the port to 8522 for you.

Self-hosting the web tools, and which ones you can