| load two result sets — or press DEMO | |||||||||||
The claim being tested, stated precisely: the selected per-element result summaries and series agree within the stated tolerances. That is deliberately narrower than "the same physics" — a certificate is only as strong as the metrics behind it, and this one now checks peak magnitude and integrated volume as required metrics, with whole-series NRMSE and peak timing as advisory metrics, all gated behind hard compatibility checks (exact flow units, identical time grids, complete engine runs, matching record sets, mass-conserving continuity). Left grid = every result record from engine A. Right grid = the same records from engine B. Green dots agree within tolerance, amber are near the line, red diverge, hollow gray exist on one side only. The dashed fan samples the worst disagreements — each ray flies from the model to a circled element so your eye lands exactly where the engines differ. The banner underneath is the certificate: counts, tolerances, worst offender, continuity from each .rpt, and three SHA-256 hashes per side with distinct meanings: RAW fingerprints the .out bytes (proves byte identity), RESULTS fingerprints only the stored results block (every timestamp and value, headers excluded), and SUMMARY fingerprints the canonical per-element peak/time/integral table at documented precision (6 significant digits, 4-decimal hours). A summary hash can theoretically collide across materially different series — that is why it is labeled SUMMARY and why the identity tiers are decided by the raw and results hashes, never the summary. Click the hash line to copy all six.
Layout borrowed with admiration from Mike Dupont's (@introsp3ctor) animated moonshine visualizer. Monstrous moonshine is the discovery that two unrelated mathematical worlds carry the same numbers: in 1978 John McKay noticed the modular j-function's coefficient 196884 equals 196883 + 1 — dimensions from the Monster group's character table. Conway and Norton conjectured the full correspondence; Borcherds proved it in 1992. An engine benchmark makes the same kind of claim — two independent computations, one shared truth — so the poster grammar transfers: record grids, sampled traces, a round-trip certificate, and one headline pair of numbers that ought to match.
| MOONSHINE VISUAL | THIS APP |
|---|---|
| irrep / character records grid | engine A per-element result records |
| moonshine q-series records grid | engine B per-element result records |
| radial fan of sampled chains | top-K elements by |Δ| (identity runs sample by magnitude instead) |
| three-shell globe | magnitude shells — bigger |Δ| lands on the outer shell |
| ✓ machine-checked round trip | counts + tolerances + max Δ + continuity + SHA-256 per table |
| dim ρ155 prime factorization | active element expanded: peaks, timing, inflow decomposition, sparkline overlay |
| 196883 ⇄ 196884 identity card | peak system outflow, engine A ⇄ engine B, Δ printed on the dashes |
| 24-second lossless loop | trace loop in-app + self-contained SMIL animated-SVG export |
Reads standard EPA SWMM5 binary .out files (magic 516114522), any build that writes that format —
including SWMM5+/SWMM6 builds that keep .out compatibility. The .rpt is optional and contributes continuity
errors, warnings, and the engine version line to the certificate. The .inp is optional and only labels the set.
The two DEMO buttons generate synthetic .out files in-browser (seeded, byte-identical every run) — they exercise the real
parser end-to-end but are not engine output; the poster says SYNTHETIC DEMO whenever they are loaded. The Δ table,
certificate, and hashes are computed from parsed values only — nothing is asserted that wasn't read from the files.
ΔPEAK% = 100 · |A − B| / max(|A|, |B|) on each element's peak; ΔVOL% is the same formula on the integrated series (∫ dt, unit·h); NRMSE% = 100 · RMSE(A,B) / max(peak A, peak B) over every reporting period — computed only when time grids match exactly. Required metrics (peak, volume) drive FAIL; advisory metrics (NRMSE, ΔtP against TOL ΔtP) can raise WARN but never FAIL. The fan and WORST line rank by the composite max(ΔPEAK, ΔVOL, NRMSE). Absolute floors are per quantity — ABS Q in flow units for flow-type records, ABS D in length units for depth/head — so one number no longer masquerades as both. OK: Δ% ≤ tolerance, or Δabs ≤ absolute floor (protects near-zero records from percent blowup). WARN: within 5× tolerance. FAIL: beyond it. ONLY-A / ONLY-B: the element exists in one table only — an automatic certificate failure because the record sets are not the same shape. Unit systems are read from each .out; a US ⇄ SI mismatch is flagged and fails the certificate rather than comparing unlike numbers.
The A/B slots take any two SWMM5-format .out files — nothing requires two engines. Load the same model
run twice with different options (LENGTHENING_STEP on/off, routing step, INERTIAL_DAMPING, surcharge method), a
calibration before/after, or a pre/post model-edit pair, and the fan ranks exactly which elements the change moved.
MODE changes vocabulary only (RUN A ⇄ RUN B vs SWMM5 ⇄ SWMM6), never the math. AUTO reads the output version code inside each .out and defaults to run mode when both codes match. A matching code
identifies a reported version and compatible output layout — not a unique executable fingerprint — so confirm the
builds via the .rpt version lines (shown in the certificate) or an executable hash when it matters. In run
mode a ✗ DIVERGENCE verdict is not a failure; it is the sensitivity finding, itemized worst-first.
The ΔtP column reports the peak-timing shift (B − A, hours) — the classic dynamic-wave phase drift that magnitude comparison misses. The divergent demo plants one on C5: its Δ% is noise-level OK while its peak is seeded 0.3 h late and reads +0.25 h in the table — the gap is report-step quantization (tPEAK snaps to the 300 s reporting grid), itself worth knowing when you compare timing. Sort the column and C5 surfaces instantly. Timing does not yet gate the status bands (roadmap), it is surfaced for the modeler's judgment. The continuity gate does judge: if either .rpt reports |routing continuity| > 5%, the certificate goes ✗ CONTINUITY SUSPECT regardless of element deltas — a run that doesn't conserve mass can't certify anything. No .rpt, no gate (load the reports). The NEAR-MISS demo fills the band the vocabulary defines but the other demos skip: every seeded delta lands inside the amber 5× warning band, zero failures — a ✓ verdict that still tells you where to look.
The verifier opens dark, always. DARK · LIGHT · AUTO in the header switches a complete second palette — poster, grids, fan, certificate, badge, and exports all repaint from one theme table, and AUTO follows your OS setting live. Theme changes nothing but colour: every number, verdict, and hash is computed identically in both, and the suite asserts it. Your choice persists and rides the share-URL (th=…).
Below 700 px the poster keeps a readable 760-unit width and pans horizontally; below 640 px the delta table drops to its essential columns — KIND, NAME, Δ%, ΔtP, STATUS — with every column always in the CSV. Fan endpoints carry an enlarged invisible tap target so a fingertip lands the trace a mouse pointer would.
Mode, tolerances, trace count, metric, and the loaded demo live in the URL hash — copy the address bar and the link reopens the same verdict (deployed builds; sandboxed previews may block hash writes). Click the SHA-256 line to copy both full hashes. BADGE exports the certificate alone as a small standalone SVG — a README-ready machine-checked stamp carrying verdict, counts, tolerance, worst offender, and both hash prefixes.
The GIF recorder loads html2canvas and gif.js from cdnjs; everything else in this file is self-contained. Inlining them would quadruple the file for an auxiliary feature, so instead the button self-checks: libraries missing → it disables and says so; gif.js alone missing → it relabels RECORD WEBM. The verifier itself never depends on the network.
Interpolated time-grid alignment (compare mismatched grids instead of withholding) · correlation/shape score joining NRMSE · deep .inp geometry diff (endpoints, inverts, sections, roughness — the fingerprint row currently proves textual identity only) · timing promoted from advisory to required with a quantization-aware tolerance · presentation mode · CSV ingest for engines that don't write .out · repo browser with sibling auto-fetch across a whole benchmark folder · optional in-browser SWMM WASM run so engine A can be generated from the .inp directly.