
> ski-jump-web@0.5.0 verify
> npm run check && npm test && npm run build


> ski-jump-web@0.5.0 check
> node tools/check.mjs

Checked 10 package manifests, publication files and all JavaScript syntax.

> ski-jump-web@0.5.0 pretest
> node tools/link.mjs


> ski-jump-web@0.5.0 test
> node --test tests/*.test.mjs

✔ classic menu letterboxes 320x200 without altering the logical grid (2.422603ms)
✔ classic menu letterboxes 640x400 without altering the logical grid (0.201165ms)
✔ classic menu letterboxes 1280x800 without altering the logical grid (0.213594ms)
✔ classic menu letterboxes 800x600 without altering the logical grid (0.193517ms)
✔ classic menu letterboxes 390x844 without altering the logical grid (0.227688ms)
✔ classic menu letterboxes 844x390 without altering the logical grid (2.072978ms)
✔ classic menu letterboxes 1920x1080 without altering the logical grid (0.19464ms)
✔ classic menu letterboxes 240x180 without altering the logical grid (0.172157ms)
✔ invalid classic viewport width 0 is rejected (0.688507ms)
✔ invalid classic viewport height 0 is rejected (0.34714ms)
✔ invalid classic viewport width -1 is rejected (0.120776ms)
✔ invalid classic viewport height -1 is rejected (0.114511ms)
✔ invalid classic viewport width NaN is rejected (0.171538ms)
✔ invalid classic viewport height NaN is rejected (0.108557ms)
✔ invalid classic viewport width Infinity is rejected (0.100427ms)
✔ invalid classic viewport height Infinity is rejected (0.104557ms)
✔ invalid classic viewport width -Infinity is rejected (0.137084ms)
✔ invalid classic viewport height -Infinity is rejected (0.104607ms)
✔ fitted mode remains aspect-preserving and explicitly fractional (0.155056ms)
✔ measured menu constants are immutable (0.136834ms)
✔ menu ArrowUp 0 -> 15 (0.218716ms)
✔ menu ArrowDown 15 -> 0 (0.091436ms)
✔ menu ArrowDown -1 -> 0 (0.074546ms)
✔ menu ArrowUp -1 -> 15 (0.078085ms)
✔ menu Home 3 -> 0 (0.083177ms)
✔ menu End 2 -> 15 (0.090263ms)
✔ menu PageDown 0 -> 8 (0.094784ms)
✔ menu PageDown 14 -> 15 (0.085222ms)
✔ menu PageUp 15 -> 7 (0.090043ms)
✔ menu PageUp 2 -> 0 (0.089151ms)
✔ horizontal navigation selects an adjacent grid item, not the next vertical row (0.222566ms)
✔ empty menus are inert (0.15245ms)
✔ DOM-less import is safe, invalid skin roots fail explicitly (0.458153ms)
✔ authored backdrop is stable for the same seed and independent of game state (76.778673ms)
✔ backdrop seed changes authored vegetation/grain, not logical dimensions (65.065938ms)
✔ classic logo is drawn using the package bitmap pipeline at its native size (0.59683ms)
✔ seeded RNG and shuffle are deterministic without mutating input (3.609627ms)
✔ math guards and color fallback (0.353746ms)
✔ fixed clock is presentation-rate independent (0.456158ms)
✔ fixed clock bounds tab-resume catch-up (0.317571ms)
✔ event listeners unsubscribe (0.392588ms)
✔ 32 verified hill roster entries, endpoints and IDs (0.476616ms)
✔ Finland K105: finite smooth geometry and complete landed CPU jump (14.030037ms)
✔ Switzerland K170: finite smooth geometry and complete landed CPU jump (8.290434ms)
✔ Czech Rep. K135: finite smooth geometry and complete landed CPU jump (2.135385ms)
✔ Belarus K220: finite smooth geometry and complete landed CPU jump (3.70385ms)
✔ Austria K70: finite smooth geometry and complete landed CPU jump (1.892271ms)
✔ USA K130: finite smooth geometry and complete landed CPU jump (2.445196ms)
✔ Latvia K165: finite smooth geometry and complete landed CPU jump (1.34187ms)
✔ Poland K80: finite smooth geometry and complete landed CPU jump (1.29132ms)
✔ Japan K210: finite smooth geometry and complete landed CPU jump (3.040784ms)
✔ Belgium K95: finite smooth geometry and complete landed CPU jump (1.267875ms)
✔ Iceland K190: finite smooth geometry and complete landed CPU jump (4.665262ms)
✔ England K50: finite smooth geometry and complete landed CPU jump (0.894032ms)
✔ Germany K120: finite smooth geometry and complete landed CPU jump (2.531935ms)
✔ Estonia K155: finite smooth geometry and complete landed CPU jump (2.471209ms)
✔ Norway K90: finite smooth geometry and complete landed CPU jump (1.129498ms)
✔ Australia K240: finite smooth geometry and complete landed CPU jump (5.302868ms)
✔ Ireland K125: finite smooth geometry and complete landed CPU jump (1.632527ms)
✔ Ukraine K60: finite smooth geometry and complete landed CPU jump (0.879518ms)
✔ Hungary K180: finite smooth geometry and complete landed CPU jump (0.745381ms)
✔ Sweden K140: finite smooth geometry and complete landed CPU jump (1.130909ms)
✔ Italy K230: finite smooth geometry and complete landed CPU jump (1.801978ms)
✔ Denmark K75: finite smooth geometry and complete landed CPU jump (0.713325ms)
✔ Slovakia K110: finite smooth geometry and complete landed CPU jump (0.871519ms)
✔ Canada K185: finite smooth geometry and complete landed CPU jump (1.549661ms)
✔ Lithuania K145: finite smooth geometry and complete landed CPU jump (1.082187ms)
✔ Kazakhstan K85: finite smooth geometry and complete landed CPU jump (0.811978ms)
✔ China K205: finite smooth geometry and complete landed CPU jump (0.968858ms)
✔ France K160: finite smooth geometry and complete landed CPU jump (1.015429ms)
✔ Holland K100: finite smooth geometry and complete landed CPU jump (3.224508ms)
✔ Russia K200: finite smooth geometry and complete landed CPU jump (0.93105ms)
✔ Korea K150: finite smooth geometry and complete landed CPU jump (0.987403ms)
✔ Slovenia K250: finite smooth geometry and complete landed CPU jump (2.048149ms)
✔ wind is absolute-time deterministic and fixed-wind mode is constant (0.199001ms)
✔ same inputs and seed produce identical results (6.547238ms)
✔ unprepared landing crashes (3.840453ms)
✔ command state guards and non-finite input rejection (1.043575ms)
✔ takeoff near the lip is much stronger than early takeoff (0.311255ms)
✔ parallel command upgrades existing telemark but cannot downgrade (0.215419ms)
✔ distance scoring and dropped judge marks (0.291308ms)
✔ all seeds and extreme winds terminate without non-finite state (23.493455ms)
✔ replay roundtrip, seeking, end-frame phase and pause (7.832354ms)
✔ replay frame sampling at 60 Hz remains bounded and monotonic (3.415138ms)
✔ replay import rejects unsupported format, unsorted frames and non-finite values (2.568698ms)
✔ replay import strips unsafe player HTML and unknown top-level data (0.9484ms)
✔ 16 human players and 64 total are supported; names and colors sanitized (1.158787ms)
✔ rank ties share positions and use stable deterministic ordering (10.556901ms)
✔ individual top-30 cutoff, reversed final order and event points (2.56908ms)
✔ ties at the cutoff all advance (0.521271ms)
✔ cup save resumes exactly, including partial round and next hill (0.842019ms)
✔ four-jumper teams, eight-team final, four groups and two rounds (2.008024ms)
✔ full 32-hill cup progresses to finish without a stranded turn (177.709064ms)
✔ result for another hill is rejected (0.359289ms)
✔ settings validate enums and clamp numeric ranges (0.339993ms)
✔ records reject falls and keep assisted records separate (3.671314ms)
✔ storage quota exceptions preserve in-memory play (0.412565ms)
✔ save and replay library export/import and cleanup (6.933862ms)
✔ replay library handles a damaged index and keeps at most 20 entries (23.693877ms)
✔ geometry batches contain finite vertex positions and RGB colors (134.967517ms)
✔ tour presets preserve their explicit sequence, not hill roster order (5.649404ms)
✔ tour duplicate, movement and removal work by event index (0.38529ms)
✔ tour operations never mutate the source preset (0.290206ms)
✔ tour supports 64 repeated venues and rejects a 65th (0.814946ms)
✔ tour rejects unknown hills, malformed files, and invalid indices (0.471454ms)
✔ tour shuffle is deterministic, preserves multiplicity, and remains serializable (0.43188ms)
✔ start list exposes bib, state and previous round without mutating a cup (1.627355ms)
✔ team start list separates the four jumping groups (0.980326ms)
✔ target estimate clears the leader after the assumed style points (13.292745ms)
✔ team details expose all four athletes and both round scores (1.001747ms)
✔ a repeated 64-event tour progresses, saves, and resumes through every event (23.715318ms)
✔ cup restoration rejects duplicate queue entries and an exhausted running queue (0.485838ms)
✔ reserved prototype property player IDs are rejected (0.251144ms)
✔ CSV exports all event results and cup standings with escaped fields (1.123855ms)
✔ replay frame step -1 follows actual recorded timestamps (3.133804ms)
✔ replay frame step 1 follows actual recorded timestamps (1.846662ms)
✔ replay multiframe stepping and boundary clamps (0.983183ms)
✔ replay markers point to recorded flight and landing transitions (0.861295ms)
✔ reverse non-looping replay pauses exactly at the beginning (3.482217ms)
✔ forward non-looping replay pauses exactly at its final frame (0.444911ms)
✔ flight-only loop wraps correctly forwards and backwards (0.49088ms)
✔ invalid loop ranges, deltas and playback rates do not produce NaN state (0.614942ms)
✔ record board keeps one best per name, excludes falls, and sorts top ten (2.032191ms)
✔ leaderboards migrate the old overall record on the first additional jump (0.306464ms)
✔ assisted personal bests and leaderboard snapshots remain isolated (0.475053ms)
✔ named saved tours preserve repeats and bounded library size (1.448282ms)
✔ replay label editing leaves the recorded player and frames unchanged (5.022376ms)
✔ backup roundtrip retains named tours and personal record boards (3.618188ms)
✔ invalid tour or leaderboard import cannot partially replace existing data (0.595346ms)
✔ releasing mouse buttons never starts, takes off or changes a landing (0.362176ms)
✔ classic takeoff requires a rising two-button chord (0.186601ms)
✔ classic mouse emits independent foot presses; simulation resolves their timing (0.132483ms)
✔ middle mouse button and movement with no buttons never issue jump commands (0.127581ms)
✔ backup rejects malformed cup before replacing settings and records (0.454755ms)
✔ importing a backup without a cup removes an unrelated saved cup (0.427219ms)
✔ audio volume never becomes nonfinite and a disposed mixer stays disposed (2.343668ms)
✔ documented start-window and blink thresholds are 15 and 10 seconds (3.653512ms)
✔ original-profile gate expires precisely on step 1800 and emits one zero-score disqualification (9.10015ms)
✔ gate wind evolves before start but legacy gate semantics remain unchanged (7.534861ms)
✔ reset restores original start signal and clears timed foot state (2.214642ms)
✔ manual scoring coefficient and K-point base for small hills (0.396356ms)
✔ manual scoring coefficient and K-point base for large hills (0.200674ms)
✔ manual scoring coefficient and K-point base for flying hills (0.815576ms)
✔ legacy distance coefficients remain available without changing old saved results (0.220421ms)
✔ simultaneous feet in left-first order prepare parallel landing (0.585774ms)
✔ sequential feet in left-first order prepare telemark with timing-based width (0.709887ms)
✔ simultaneous feet in right-first order prepare parallel landing (0.339652ms)
✔ sequential feet in right-first order prepare telemark with timing-based width (1.304492ms)
✔ longer interval makes a wider telemark and repeated same-foot press cannot complete it (3.948728ms)
✔ authored simultaneous tolerance is inclusive and distinct from a sequential telemark (0.401409ms)
✔ an incomplete one-foot landing falls rather than silently converting to telemark (0.410029ms)
✔ excessively wide telemark can fall; accessibility commands complete both feet (0.553808ms)
✔ DSJ 2.10 profile completes Finland K105 with finite scores (5.561689ms)
✔ DSJ 2.10 profile completes Switzerland K170 with finite scores (4.942036ms)
✔ DSJ 2.10 profile completes Czech Rep. K135 with finite scores (3.646803ms)
✔ DSJ 2.10 profile completes Belarus K220 with finite scores (1.600812ms)
✔ DSJ 2.10 profile completes Austria K70 with finite scores (1.157695ms)
✔ DSJ 2.10 profile completes USA K130 with finite scores (2.228886ms)
✔ DSJ 2.10 profile completes Latvia K165 with finite scores (1.225355ms)
✔ DSJ 2.10 profile completes Poland K80 with finite scores (1.133809ms)
✔ DSJ 2.10 profile completes Japan K210 with finite scores (1.399356ms)
✔ DSJ 2.10 profile completes Belgium K95 with finite scores (2.733726ms)
✔ DSJ 2.10 profile completes Iceland K190 with finite scores (1.328929ms)
✔ DSJ 2.10 profile completes England K50 with finite scores (0.940863ms)
✔ DSJ 2.10 profile completes Germany K120 with finite scores (3.86861ms)
✔ DSJ 2.10 profile completes Estonia K155 with finite scores (4.610603ms)
✔ DSJ 2.10 profile completes Norway K90 with finite scores (0.80416ms)
✔ DSJ 2.10 profile completes Australia K240 with finite scores (4.208162ms)
✔ DSJ 2.10 profile completes Ireland K125 with finite scores (0.7618ms)
✔ DSJ 2.10 profile completes Ukraine K60 with finite scores (0.710949ms)
✔ DSJ 2.10 profile completes Hungary K180 with finite scores (1.118613ms)
✔ DSJ 2.10 profile completes Sweden K140 with finite scores (0.991403ms)
✔ DSJ 2.10 profile completes Italy K230 with finite scores (1.26964ms)
✔ DSJ 2.10 profile completes Denmark K75 with finite scores (1.088652ms)
✔ DSJ 2.10 profile completes Slovakia K110 with finite scores (0.643049ms)
✔ DSJ 2.10 profile completes Canada K185 with finite scores (0.836807ms)
✔ DSJ 2.10 profile completes Lithuania K145 with finite scores (2.166021ms)
✔ DSJ 2.10 profile completes Kazakhstan K85 with finite scores (0.621218ms)
✔ DSJ 2.10 profile completes China K205 with finite scores (0.908767ms)
✔ DSJ 2.10 profile completes France K160 with finite scores (0.841669ms)
✔ DSJ 2.10 profile completes Holland K100 with finite scores (0.594434ms)
✔ DSJ 2.10 profile completes Russia K200 with finite scores (0.864914ms)
✔ DSJ 2.10 profile completes Korea K150 with finite scores (1.152723ms)
✔ DSJ 2.10 profile completes Slovenia K250 with finite scores (0.968568ms)
✔ documented team cup awards 200,160,120,100 rather than individual points (9.647653ms)
✔ cup serialization snapshots rules; pre-0.3 saves restore as legacy and reject unknown profiles (0.777948ms)
✔ timed-out cup jump advances exactly once and carries zero points (1.414902ms)
✔ fresh installations use original profile; previous settings preserve legacy mode (1.495563ms)
✔ records, leaderboards and ghosts are isolated by rules and reject disqualification (1.93847ms)
✔ version-2 replay round-trips stance and gate time; old version-1 replays still play (16.347098ms)
✔ disqualification replays retain the entire gate clock and terminal status (6.248605ms)
✔ classic HUD has 13-pixel status band and measured wind/judge positions, without guide overlays (1.744502ms)
✔ scoped record reset preserves every other profile, assisted board and replay library (0.684567ms)
✔ legacy telemark retains its visual split stance (0.137184ms)
✔ replay wind arrow interpolates the shortest arc and gate clock is continuous (0.230435ms)
✔ fin: closed inrun underside and terminal faces in every camera (183.785663ms)
✔ sui: closed inrun underside and terminal faces in every camera (117.224568ms)
✔ cze: closed inrun underside and terminal faces in every camera (69.905014ms)
✔ blr: closed inrun underside and terminal faces in every camera (101.490949ms)
✔ aut: closed inrun underside and terminal faces in every camera (53.441342ms)
✔ usa: closed inrun underside and terminal faces in every camera (62.55696ms)
✔ lat: closed inrun underside and terminal faces in every camera (48.484848ms)
✔ pol: closed inrun underside and terminal faces in every camera (40.73753ms)
✔ jpn: closed inrun underside and terminal faces in every camera (43.925194ms)
✔ bel: closed inrun underside and terminal faces in every camera (34.459954ms)
✔ isl: closed inrun underside and terminal faces in every camera (54.33523ms)
✔ eng: closed inrun underside and terminal faces in every camera (35.537055ms)
✔ ger: closed inrun underside and terminal faces in every camera (33.604192ms)
✔ est: closed inrun underside and terminal faces in every camera (37.221044ms)
✔ nor: closed inrun underside and terminal faces in every camera (33.467348ms)
✔ aus: closed inrun underside and terminal faces in every camera (58.274693ms)
✔ irl: closed inrun underside and terminal faces in every camera (39.1341ms)
✔ ukr: closed inrun underside and terminal faces in every camera (31.797314ms)
✔ hun: closed inrun underside and terminal faces in every camera (39.597781ms)
✔ swe: closed inrun underside and terminal faces in every camera (38.659037ms)
✔ ita: closed inrun underside and terminal faces in every camera (42.15769ms)
✔ den: closed inrun underside and terminal faces in every camera (39.849606ms)
✔ svk: closed inrun underside and terminal faces in every camera (33.669369ms)
✔ can: closed inrun underside and terminal faces in every camera (40.460651ms)
✔ ltu: closed inrun underside and terminal faces in every camera (45.383992ms)
✔ kaz: closed inrun underside and terminal faces in every camera (41.654249ms)
✔ chn: closed inrun underside and terminal faces in every camera (44.113079ms)
✔ fra: closed inrun underside and terminal faces in every camera (42.798135ms)
✔ ned: closed inrun underside and terminal faces in every camera (32.105ms)
✔ rus: closed inrun underside and terminal faces in every camera (42.53018ms)
✔ kor: closed inrun underside and terminal faces in every camera (36.247981ms)
✔ slo: closed inrun underside and terminal faces in every camera (54.122433ms)
✔ fin: full classic scene and explicit original-fidelity provenance (298.796228ms)
✔ sui: full classic scene and explicit original-fidelity provenance (180.506341ms)
✔ cze: full classic scene and explicit original-fidelity provenance (107.657522ms)
✔ blr: full classic scene and explicit original-fidelity provenance (109.995974ms)
✔ aut: full classic scene and explicit original-fidelity provenance (82.617443ms)
✔ usa: full classic scene and explicit original-fidelity provenance (92.779037ms)
✔ lat: full classic scene and explicit original-fidelity provenance (113.383924ms)
✔ pol: full classic scene and explicit original-fidelity provenance (81.895072ms)
✔ jpn: full classic scene and explicit original-fidelity provenance (104.633825ms)
✔ bel: full classic scene and explicit original-fidelity provenance (88.900059ms)
✔ isl: full classic scene and explicit original-fidelity provenance (99.876032ms)
✔ eng: full classic scene and explicit original-fidelity provenance (85.859811ms)
✔ ger: full classic scene and explicit original-fidelity provenance (93.100719ms)
✔ est: full classic scene and explicit original-fidelity provenance (92.765566ms)
✔ nor: full classic scene and explicit original-fidelity provenance (79.904222ms)
✔ aus: full classic scene and explicit original-fidelity provenance (107.37565ms)
✔ irl: full classic scene and explicit original-fidelity provenance (82.606765ms)
✔ ukr: full classic scene and explicit original-fidelity provenance (72.716553ms)
✔ hun: full classic scene and explicit original-fidelity provenance (94.630121ms)
✔ swe: full classic scene and explicit original-fidelity provenance (101.944923ms)
✔ ita: full classic scene and explicit original-fidelity provenance (102.310577ms)
✔ den: full classic scene and explicit original-fidelity provenance (72.907166ms)
✔ svk: full classic scene and explicit original-fidelity provenance (87.541898ms)
✔ can: full classic scene and explicit original-fidelity provenance (92.185358ms)
✔ ltu: full classic scene and explicit original-fidelity provenance (92.180653ms)
✔ kaz: full classic scene and explicit original-fidelity provenance (72.651031ms)
✔ chn: full classic scene and explicit original-fidelity provenance (101.909581ms)
✔ fra: full classic scene and explicit original-fidelity provenance (86.927085ms)
✔ ned: full classic scene and explicit original-fidelity provenance (77.728498ms)
✔ rus: full classic scene and explicit original-fidelity provenance (106.254512ms)
✔ kor: full classic scene and explicit original-fidelity provenance (86.594747ms)
✔ slo: full classic scene and explicit original-fidelity provenance (98.714713ms)
✔ 32 explicit render descriptors correspond one-to-one with playable roster (0.552867ms)
✔ classic surface decorations never change physics profile (48.000715ms)
✔ record guide affects only its scene section (72.969037ms)
✔ projected articulated shadows contact the same landing profile (0.475334ms)
✔ ordered dither is a complete periodic 4x4 threshold matrix (0.385847ms)
✔ snow depends on sample time, not rendering history or frame rate (1.398409ms)
✔ WGSL and GLSL emit the same shading and snow algorithm (0.19867ms)
✔ software depth, not submission order, selects opaque nearest triangles (2.38929ms)
✔ software rasterization is winding-independent without cracks at shared edges (0.999928ms)
✔ software size-preserving renders reuse depth, projection and pixel storage (0.835382ms)
ℹ tests 269
ℹ suites 0
ℹ pass 269
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 4005.821283

> ski-jump-web@0.5.0 build
> node tools/build.mjs

Built dist/ and SkiJumpWeb.html (307.1 KiB, no runtime dependencies).
