apps.header.allAppsCount
test-card
apps.detail.types.app from Stoatworks Labs' Repository
apps.detail.sections.overview
Readme
View on GitHubTest Card
AI-assisted project. This codebase was created with Claude Code (Anthropic), directed and reviewed by a human author. The RP 219 pattern is asserted against a reference measured from ffmpeg's
smptehdbarsat four resolutions rather than transcribed from prose descriptions of the standard, and its fifteen colours are computed through Rec. 709 and land exactly on those measured values — which is itself the proof the measurement is sound. The importers are tested against real files: Arena 7.27.0's own advanced-output XML, and exports produced by Blend Calc's and Pixel Peeker's own test suites. The ZIP writer is checked against the published CRC-32 vector and its archives unpacked with the systemunzip; 88 tests in all, and the whole path has been driven end to end in a browser. No image it produces has been played out to a real projector, LED processor or display and measured. The patterns are correct as pixels; what a screen does with them is not something this can tell you.
Generate test patterns for every physical output in a show, from the file that already describes the outputs.
Import a Resolume advanced output, a Pixel Peeker wall or a Blend Calc projector array, and get one PNG per physical output at that output's exact raster — or a single composition-sized image that proves the output map is what you think it is. Everything runs in the browser; nothing is uploaded.
Patterns
| Pattern | What it is for |
|---|---|
| SMPTE RP 219 | Standard bars, +I/+Q, luma ramp and pluge. Geometry and colours measured from a real generator — see docs/rp219.md |
| 75% bars | Eight equal full-height bars. Survives being squeezed onto a narrow LED strip where RP 219's four rows would be unreadable |
| Grid | Your own pitch or division count, heavy lines every N, cell labels, diagonals, centre target |
| Alignment | 1px edge border, corner markers with pixel counts, safe areas, centre target and circles, 1px checker patches |
| LED tiles | One cell per cabinet. Either a uniform tile size you state, or the real cabinet map imported from Pixel Peeker — including irregular walls, chain order and per-port colouring |
| Solid field | Flat colour at a chosen level, for dead pixels and uniformity |
| Greyscale | Continuous ramp or stepped wedge, optionally split into R, G, B and neutral |
| Pixel check | 1px checkerboard and line bursts. If it renders as flat grey on the real output, something in the chain is scaling |
Every pattern can carry a burn-in — output name, resolution, pattern, plus your own text — and can draw the imported slice or port outlines on top.
Two ways to render
- One PNG per output — each file at that output's native raster. One output
downloads as a bare PNG; several download as a ZIP with a
manifest.txtrecording which file is which output, the level range used, and any raster the app had to infer. - Single composition canvas — one image at composition size with every output's region drawn and labelled. Play it through Resolume and each physical output should light up showing its own name. That is the fastest proof the advanced output map matches what you think it does, and it needs no way of getting a file to each output individually.
Level range
SMPTE bars are defined in Y′CbCr; a PNG is RGB, and a PNG cannot say which convention it was written in. So the app asks, and records the answer in the manifest.
- Full 0–255 (default) — media server, GPU output, HDMI/DP set to full range. The −2% pluge patch clips to black and cannot be judged.
- Legal 16–235 — studio swing, for an SDI chain. Sub-black and super-white survive, so the pluge is meaningful. Looks washed out on a full-range display, correctly.
Imports
See docs/importers.md for what each file does and does not know. In short:
- Resolume — one output per
<Screen>. The raster is read from the output device when it records one, and otherwise inferred from slice bounds, which can come out too small. Inferred rasters are badged in the UI and called out in the manifest; correct them by hand. - Pixel Peeker — use
Export → JSON, notSave project. The project file stores cabinets as library references in millimetres and cannot be resolved to pixels here, so it is refused with a message naming the right export. - Blend Calc — needs the projector resolution (not in the file) and, for designs using a fit mode, the solved overlap (also not in the file — Blend Calc computes it and never writes it back). Both are asked for. Its Resolume XML export needs neither and is the better file to bring.
You can also just add outputs by hand.
Development
npm install
npm run dev
npm test
See CLAUDE.md for the full command list and AGENTS.md for the invariants and the traps.
Verification
- RP 219 — geometry and colour asserted against a reference measured from
ffmpeg's
smptehdbarsat four resolutions, committed astest/fixtures/rp219-ffmpeg.jsonand reproducible withscripts/extract-rp219-reference.py. - Importers — tested against real files: Arena 7.27.0's own
AdvancedOutput.xmland a saved Advanced Output preset, plus exports generated by runningblend-calc's andpixel-peeker's own test suites. No hand-written fixtures — a fixture invented to match the parser proves only that the parser matches itself. - ZIP writer — CRC-32 checked against the published test vector, archives
verified with the system
unzipand with Python'szipfile. - End to end — driven in a browser: a real Blend Calc export imported, six 1920x1200 PNGs rendered, packed, and the resulting ZIP unpacked and its PNG headers checked. Bar colours and pluge values sampled off the canvas and confirmed against the standard.
This project is built on other people's work — see ATTRIBUTIONS.md.
Licence
MIT. Not a distributable product — this repo exists to feed the deployed web app, so it has no releases and no installers.
apps.marketingCta.appInstallTitle
apps.marketingCta.appInstallDescription
apps.detail.sections.categories
apps.detail.sections.related
apps.detail.related.exploreCategories
apps.detail.related.exploreAllapps.detail.sections.links
apps.detail.sections.details
ghcr.io/stoatworks-labs/test-card:latestapps.detail.sections.runtime
- apps.detail.details.webui
http://[IP]:[PORT:80]/- apps.detail.details.network
bridge- apps.detail.details.shell
sh- apps.detail.details.privileged
- false
apps.detail.sections.configuration
Host port for the web interface.
- apps.detail.config.target
- 80
- apps.detail.config.default
- 8522
- apps.detail.config.value
- 8522