Return to Surf

Reference & validation

Three actual CSS maps. Independent movement implementation checked against public KSF telemetry and limited native CSS contact probes. Measured agreement does not establish universal native parity.

Updated 2 October 2026 · Map credits: Syncronyze and granis · Panzer · Arblarg
Movement reference & configuration

Download this document

# CSS / KSF movement reference

Updated 2 October 2026 after importing the actual CSS Boreas map and acquiring independent KSF telemetry. Target: **Counter-Strike: Source, KSF forward style, 66t**. The exact native executable build and live plugin manifest remain unknown. This document supersedes `REFERENCE-v1.md`.

Evidence labels: **Verified** means a primary source or independently recorded behavior; **Supported** means consistent with the tested CSS run and relevant implementation but not a complete live-server configuration dump; **Unresolved** remains a fidelity limit.

## Interval and branch

The simulation interval is **float32(0.015) = 0.014999999664723873 seconds**. Nominal “66 tick” means approximately 66.6667 Hz, not `1/66`. Valve declares `DEFAULT_TICK_INTERVAL = 0.015`. The public KSF Boreas replay viewer independently specifies 66.66666666666667 ticks/sec; its gravity/displacement steps support 15 ms. [Valve constants](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/public/const.h), [actual KSF replay](https://ksf.surf/replays/surf_boreas/replay_css_4060_0_712551_1763914843.rec).

The public SDK is shared Source code, not the shipped CSS movement binary. Its HL2/TF2 defaults are not automatically CSS facts. CSS-specific branches in RNGFix and CSS-derived Momentum code are supporting references; Momentum intentionally changes several jumping, ground-probe and ramp-recovery behaviors and is not an interchangeable controller. CS:GO/CS2 movement and hull dimensions were not substituted.

Coordinates remain Source units: X/Y horizontal, Z up; origin at the feet; yaw 0 along +X, 90 along +Y. Only the renderer converts coordinates.

## Profile

| Setting | Value / behavior | Evidence |
|---|---|---|
| Gravity | 800 | Supported by native KSF ballistic velocity and displacement steps. |
| Air acceleration | 150 | Verified in Boreas's compiled `logic_auto`; native air steps support the chosen formula. |
| Ground acceleration / friction / stopspeed | 5 / 4 / 75 | CSS-derived reference; independently matches 65 recorded ground/jump transitions. |
| Held command magnitude | ±400 per axis | Shared CSTRIKE input branch; diagonals crop to max wish speed. Native initial keydown may be fractional. |
| Maximum wish speed | 260 | CSS-derived normal surf profile, supported by ground and air telemetry; not a cap on momentum. |
| Air projection cap | 30 | CSS-specific RNGFix; acceleration term retains uncapped wish speed. |
| Velocity limit | ±5000 per component | 5000 verified in compiled Boreas; per-axis semantics from movement references. No total-vector clamp. |
| Standing hull | (-16,-16,0) to (16,16,62) | CSS-specific RNGFix branch. |
| Crouched hull | (-16,-16,0) to (16,16,45) | CSS-specific branch; ±8.5 airborne origin transition. |
| Standing / duck eye | 64 / 47 | CSS-derived view vectors; eyes intentionally exceed hull height. |
| Jump impulse | float32(sqrt(2×800×57)) = 301.9933776855469 | CSS-specific predictor and measured first crouch jump. |
| Jump order | Standing adds impulse after initial half gravity; ducking sets impulse. Jump adds its own half-gravity step. | CSS-specific predictor; native crouch-jump fixture. |
| Step / ground probe | 18 / 2 | Shared movement and CSS-specific predictor. |
| Ground classification | Normal Z ≥ .7; reject if upward velocity >140 | Source/CSS reference and boundary fixtures. |
| Duck speed / transition | .34 command scale; .4 s ground duck, .2 s unduck; immediate air hull transition | CSS-derived reference, telemetry supports tested transitions. Spam/reversal timing remains simplified. |
| Surface friction | Ordinary 1; unsupported slow rise .25; ground surface factor capped at 1 | Source categorization; native air fixtures confirm the .25 transition. Ramp PHY material metadata is retained; full CSS surface-property lookup remains unresolved. |

Primary mechanics: [Valve shared movement](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/shared/gamemovement.cpp), [CSS-specific RNGFix predictor](https://github.com/jason-e/rngfix/blob/9831d25e9f6747566a6adc72d75ae3fc671a656c/plugin/scripting/rngfix.sp), [CSS-derived mode constants](https://github.com/momentum-mod/game/blob/9da88b97769e0f2306623946ebbcb5d0f919a1f0/mp/src/game/shared/momentum/mom_system_gamemode.cpp), [input generation](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/client/in_main.cpp).

## Order and collision

Tick order: input cropping/ducking; StartGravity; jump; grounded friction; acceleration; swept movement/step handling; CategorizePosition; FinishGravity; grounded Z clearing. Four movement bumps consume remaining time; they do not create extra acceleration or gravity ticks. Multiple planes clip velocity and may constrain motion to a crease. StepMove compares lower and up-forward-down paths. No steering, ramp attraction or arbitrary speed preservation is used.

Collision uses the player's swept axis-aligned hull. The real BSP supplies compiled brush planes and bevels. VPHY files supply original convex ramp decompositions, converted from IVP metres and transformed by authored prop matrices. Displacements use the actual decoded triangles and flags. A stable-order BVH reduces candidate queries without changing narrowphase order.

BSP collision rejects sweeps that remain outside one plane. Its 1/32-unit contact margin backs up an actual crossing. VPhysics skin handling differs: shallow approaches within the margin are allowed, but a real convex exit inside the finite sweep must not be preceded by a padding-created corner intersection. Actual KSF seam/departure fixtures distinguish these cases. This is an independently implemented collision contract supported by measured behavior, not a copy of proprietary VPhysics. Remaining native precision/contact details are reported by the full comparison.

## KSF and map rules

**Current browser/ranked default (3 October 2026):** hold-jump auto-bhop with capped starting speed (`css-surf-capped-1`). Unrestricted starts remain an explicit unranked local option; the former open-start profile is retained for old replay playback. These settings are independently versioned in personal-best/replay keys and do not change gravity, air acceleration, ground friction or the surf clipping formula. Stamina and vanilla bunnyhop speed penalties are omitted as a surf-profile choice; a live KSF manifest is still unavailable.

The current ranked rule applies the existing end-tick start-exit XY clamp: 325 u/s if grounded, 350 if airborne. It preserves vertical velocity and XY direction and never increases sub-cap speed. Jumping in the start zone remains available. The complete exit tick is displaced before the clamp; a prespeed approach can therefore affect the fractional exit tick, rather than being capped continuously inside the zone. Subsequent surfing has no such horizontal cap.

**Evidence boundary:** the public Boreas telemetry verifies a falling-start 350 clamp despite an earlier crouch jump. A real-trigger one-step test against native frames124→125 gives zero position error and 0.0000432 u/s velocity error within predeclared .002/.002 tolerances. The [2013 KSF announcement](https://steamcommunity.com/groups/SurfTimerUpdates/announcements/detail/1513501526513859534) instead describes 325 for ordinary zones, 350 for falling-start zones, 270 after prehopping and a four-prehop limit. It does not say that every airborne player gets 350. Our grounded/airborne fallback across the three maps is a documented **Surfd ranked rule**, not established universal current KSF behavior. No blanket start-zone jump ban is claimed.

**Reference option:** manual jumping plus observed Boreas falling-start cap. This recording contains a prestart crouch jump, followed by an end-of-tick horizontal clamp to **350 u/s** on start exit. The older 2013 KSF announcement's 270 prehop / four-hop rules therefore cannot be generalized to this present Boreas case. Grounded 325 remains a historically supported fallback, not newly measured here. [KSF historical announcement](https://steamcommunity.com/groups/SurfTimerUpdates/announcements/detail/1513501526513859534), [KSF commands](https://ksf.surf/commands).

Boreas itself issues `sv_airaccelerate 150`, `sv_maxvelocity 5000` and `sv_enablebunnyhopping 1`. The last setting removes a vanilla restriction; it does not by itself mean global hold-jump automation. Actual KSF server overrides remain possible. See [import evidence](BOREAS-IMPORT-RESEARCH.md).

The map's original no-jump box uses `player_speedmod 0.9999`, suppresses jump, and scales **movement frametime** by .9999. The authoritative timer still advances by one 15 ms tick. Immediate exit restoration is implemented; the map's additional .03/.06-second repeated restores have no separate effect in this static trigger flow. Native recorded gravity steps independently show the tiny scale. [Valve speed modifier entity](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/server/player.cpp), [ProcessMovement](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/shared/gamemovement.cpp).

An evidenced **neutral uphill landing fix** is enabled: for a descending/slow-rising approach to a walkable nonflat incline, moving uphill, where clipping would not increase horizontal speed, movement ends at the first contact plus .1 Z, retains incoming XY, and categorizes ground. This matches native Boreas tick 2756 and the conditional RNGFix PreventCollision behavior. It never applies to steep surf faces. Other RNGFix/MomSurfFix corrections are not assumed installed or reproduced wholesale. [RNGFix primary implementation](https://github.com/jason-e/rngfix/blob/9831d25e9f6747566a6adc72d75ae3fc671a656c/plugin/scripting/rngfix.sp), [MomSurfFix](https://github.com/GAMMACASE/MomSurfFix/tree/2dda7ae7e2e1dc9da2a43fcaca642f6200d8401e).

## Additional classic-map profiles

Utopia NJV and Mesa Fixed retain the same 15 ms movement core, gravity and air acceleration. Their public KSF recordings support a **3500 u/s per-component** velocity cap; this is an inferred server profile, exported as an explicit map override, not an authored BSP command. Boreas retains its established 5000 profile. Source's limit is not a total-vector speed clamp.

Mesa's authored continuous push contributes base velocity during movement and the Source exit carry when the player leaves. This is a real map entity, not an arbitrary boost added to make a route work. Fifteen native recorded push transitions independently verify the implemented behavior; see [push reference](MAP-PUSH.md).

Stock installed CSS build 11003710 directly confirmed the 62/45-unit standing/crouched hulls and full 0-based trigger bounds. It also reproduced several reset contacts that KSF recordings pass through. The imported authored resets are retained; no unsupported hull shrink is applied. Exact KSF server/revision differences remain unresolved. See [native probe](NATIVE-CSS-PROBE.md), [map provenance](CLASSIC-MAPS.md), and [comparison results](VALIDATION.md).

## Mouse and camera

Mouse events update view immediately: `degrees = counts × .022 × sensitivity`, no frame-time factor or smoothing. Raw Pointer Lock is requested, with adjusted-input fallback. Pitch is ±89°. Device/browser raw counts need not equal native CSS counts on every system. Source FOV90 converts to vertical73.739795°, giving horizontal106.260205° at16:9. No banking or speed-driven FOV is added. Eye position follows the hull/duck state; default positional interpolation is off. Optional interpolation adds a tick of positional delay.

[Valve mouse path](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/client/in_mouse.cpp), [FOV conversion](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/client/view.cpp).

The browser samples held keyboard inputs at full400 immediately. Source's client-frame `KeyState` can generate fractional initial/released commands. The native replay lacks analog command magnitudes; its first forward press is reconstructed as200 from independent velocity evidence. This remains an explicit input-generation difference.

## Precision, validation and limits

State and selected intermediates use float32; JavaScript trigonometry, plane construction and some trace arithmetic remain double. The native replay contains positions/velocities/buttons/angles but no contact flags, hull-transition timers, build ID or plugin manifest. Full-course comparisons report their actual errors against predeclared tolerances rather than equating determinism with native parity. See [validation](VALIDATION.md) and [independent report](REVISION-VALIDATION.md).

Unresolved beyond the tested run: exact native build/plugins, some VPhysics/displacement edge ordering, tiny float/trace residuals, complete duck-spam behavior, native client prediction/step camera, fractional keyboard command generation, exact KSF timer internals, all map-entity dynamics, water/ladder movement and combat modifiers. No experienced human CSS playtest is claimed.

## Licences and provenance

The default course now uses the actual CSS BSP, not the earlier original map. Assets retain their authors' rights; no general redistribution licence was established. They were imported for this requested local game. The code is independently written from behavioral/file-format references. Valve's SDK licence is Source-specific; RNGFix and MomSurfFix are GPL; their implementations are not copied into this project. See [notices](../THIRD_PARTY_NOTICES.md), [Valve licence](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/LICENSE), [RNGFix licence](https://github.com/jason-e/rngfix/blob/9831d25e9f6747566a6adc72d75ae3fc671a656c/LICENSE).
Validation & remaining gaps

Download this document

# Classic Surf validation and remaining gaps

Updated 2 October 2026. Three original CSS maps are available: Boreas, Utopia NJV and Mesa Fixed. The previous single-map report is retained as `VALIDATION-v2.md`; Northline remains a regression fixture and a source for the authored laboratory ramps.

## Current release

The final automated suite passes **162/162 tests**, with no failures or skipped tests. All three shipped default-profile command witnesses complete their entire course with authored resets active and no assists:

| Map | Commands | Local run time | Ordered checkpoints | 30/60/144/240 FPS |
|---|---:|---:|---:|---|
| Boreas |2758|39.495360 s|2|Every tick identical|
| Utopia NJV |3867|53.349069 s|3|Every tick identical|
| Mesa Fixed |3653|52.635008 s|3|Every tick identical|

Each starts stationary at a legal point on its start deck and is verified through the complete `GameSession`. No intermediate position/velocity edits, scripted boosts, skipped resets or relaxed collision bounds are used. Mesa also has a separately completed 3598-command alternate. The shipped route's development and scope are documented in `MESA-ROUTE-WITNESS.md`; the full deterministic report is `fixtures/classic-playability-results.json`.

Final production Edge checks against `http://localhost:4173` passed **35 checks, zero failures**: Boreas controls/game flows 17/17; classic selection, lab, graphics and audio 9/9; replay-rule restoration 3/3; all three complete browser replays and restarts 6/6. There were no console errors or warnings. One renderer-only marker inspection is explicitly omitted from the production suite because it imports development modules; it already passed separately at 15 native approach-camera views. No gameplay check was skipped. Reports are `fixtures/browser-boreas-results.json`, `browser-classic-results.json`, `browser-replay-state-results.json`, and `browser-classic-replay-results.json`.

Every served replay hash matched its validated source. The actual browser reached every finish with exactly the expected final state, splits and elapsed time, and Watch never wrote a PB. Live raw mouse events initially exposed assumptions in the browser test, not a runtime defect: the final mouse oracle uses a passive event ledger aligned to actual simulation commands, keeping its original 1e-6-degree tolerance. WASD is evaluated relative to the received view angles; manual wheel-jump tests wait for a sampled release before the next press. The initial failed report is retained for investigation. These browser tests establish event behavior, not physical input-to-photon latency or all-case CSS parity.

Simulation remains fixed at float32 0.015 seconds. Boreas movement and its saved command trajectory are unchanged by the renderer work. Prop batching, conservative visibility culling and shared buffers reduce average Boreas draw calls from 221.3 to 70.8. At DPR 1, three comparison views have zero differing pixels; mean CPU submission fell from .497 to .264 ms. Balanced rendering caps the drawing buffer at DPR 1 without changing FOV, input, physics or timing. These are measured rendering costs, not a promised FPS multiplier. See `RENDER-PERFORMANCE.md`.

The practice facility has eight stationary, untimed stations. Its command witness traverses both surf faces and the transfer: 232 first-ramp contacts, 137 second-ramp contacts, peak speed 1735.13 u/s. Separate checks exercise jumping, stairs, crouch clearance and collision. It renders in roughly 11–18 draws. See `LABORATORY.md`.

Browser checks cover procedural wind's gesture gate, pause/suspend lifecycle, environment, persistent volume/mute, map switching and resource disposal. Green start and gold finish markings project onto landing floors without changing timer geometry. Placement was inspected at 15 native route-camera views. Independent review fixed demonstration-profile leakage and a stale-rAF timestamp race; the dedicated Edge regression passes 3/3 checks with no console errors. See `INDEPENDENT-REVIEW.md`.

`tests/classic-playability.test.ts` and `scripts/validate-classics.ts` require legal stationary starts, normal commands, every checkpoint, a finish, and no resets or assists. Every tick's state, contacts and timer is compared at 30/60/144/240 FPS with zero tolerance and first-divergence diagnostics. Missing fixtures fail. These tests establish playability and deterministic scheduling, not independent native parity.

## Utopia and Mesa independent evidence

Native public KSF recordings, source URLs and hashes are in `fixtures/{utopia,mesa}-ksf-telemetry.json`. The movement-only comparison keeps the existing .002-unit / .002-u/s tolerances. It deliberately excludes reset/timing events because these KSF recordings cross several authored reset edges. It is not the playable demonstration or an all-systems completion test.

| Map / comparison | Steps | Max position error | Max velocity error | First divergent tick |
|---|---:|---:|---:|---:|
| Utopia isolated |3868|.004854|.088105|731|
| Utopia continuous |3868|.088736|.132074|380|
| Mesa isolated |3395|33.549978|2236.146946|521|
| Mesa continuous |3395|12.878937|244.532538|234|

Mesa's large isolated outlier is retained: recorded states around 521–523 begin slightly inside a downloaded compiled playerclip surface, producing an all-solid stop in a subsequent local step. That origin is approximately .05 units beyond the BSP plane. Continuous traversal passes this area but has several contact-timing differences. These errors are not declared parity or hidden by loosening tolerances. Native contact flags are unavailable, preventing a direct contact-state comparison. `scripts/classic-movement-probe.ts` regenerates these reports.

The new recordings support a 3500 u/s per-component velocity limit, exported as an explicit map profile override; Boreas retains 5000. Mesa's authored push uses Source base velocity. Fifteen native entry/inside/exit steps pass the strict tolerances, with maximum .001138 units and .000223 u/s error; see `MAP-PUSH.md`.

An isolated real CSS server (build 11003710) measured standing Z 0–62 and crouched 0–45 hulls and reproduced the disputed resets at supplied native-recorded points. The browser therefore retains authored reset geometry and full hulls. The KSF server/revision difference remains unresolved. These short native contact probes do not prove whole-run parity. See `NATIVE-CSS-PROBE.md` and `CLASSIC-MAPS.md`.

The following Boreas measurements remain the previously established independent baseline; earlier release counts below describe that baseline.

## Boreas independent native evidence

The public KSF CSS forward-style run by .x (23 November 2025, published 39.495121 s) supplies 2,960 recorded frames, including 2,758 movement steps from stationary start through finish. Comparison uses original BSP/PHY/displacement geometry, buttons from frame i, view angles from i+1, a reconstructed half-strength first keyboard press, the observed 350 u/s start clamp, the map speed modifier and the evidenced incline fix. No native build/plugin dump or contact flags are available.

Predeclared comparison tolerances remain **.002 units position / .002u/s velocity**. They were not widened after seeing results.

| Comparison | Steps | Maximum position error | Maximum velocity error | First tick outside tolerance |
|---|---:|---:|---:|---:|
| Ground acceleration and first crouch jump, equivalent flat geometry |65|0|.00003146|None|
| Selected native ballistic air transitions |1672|.00048828|.00088027|None|
| All isolated native steps on actual map |2758|.00690534|.00374460|334|
| Continuous native command reconstruction on actual map |2758|.03162542|.00614367|199|

The isolated comparison resets to each recorded starting position/velocity; it verifies local movement, not whole-run drift. The continuous comparison begins once at the legal stationary start-deck position and then uses commands and explicit server/map rules only. Its final position error is .01162444 units. Twenty-seven isolated steps exceed the strict tolerance. Full per-tick errors are retained in `fixtures/boreas-reference-validation.json`; near agreement is not declared exact parity. Native grounded/contact-state differences cannot be measured from this recording.

Regression fixtures explicitly cover the native curved seams, two BSP ramp departures, the shallow skin contact, and the neutral uphill landing plus manual follow-through. They caught and helped correct false epsilon contacts and the distinction between compiled brushes and VPhysics hulls. The public replay and sources are documented in `REVISION-VALIDATION.md`.

## Playability and determinism

Both profiles finish the actual two-checkpoint course using normal view/button commands:

- Reference-style run: approximately 39.495235 s.
- Requested auto-bhop / open-start run: approximately 39.495360 s.

Both touch 103 distinct solids, cross CP1 at tick 1231, CP2 at 2303, and finish at 2758, with no reset or invalid record. The requested run's initial approach is fitted offline by changing seven view angles; it does not edit state or velocity. Playback contains only recorded commands and has no steering controller. Both fixtures start stationary at a legitimate location on the original start platform, matching the independent recording rather than the center teleport destination. They are explicit fixture initial states, not mid-run teleports.

All **116 automated regression tests pass**, with no skipped tests. `tests/boreas-playability.test.ts` compares every state, contact and timer event for the full requested course at 30/60/144/240 FPS. Physics and timing remain identical. Separate tests cover actual teleport-destination spawning, convex trigger unions, high-speed checkpoint crossing, practice/restart behavior, jump/wheel semantics, focus cleanup and record versioning. Regression passes do not override the explicitly reported native comparison residuals above.

## Geometry and visuals

Collision comprises 178 compiled BSP brush solids, 148 original PHY convex instances, and 129,728 displacement triangles. The importer honors player hull flags and includes the map's original nonrectangular reset unions. Independent raw-PHY transform checks and native deck height support scale/orientation. BVH candidate membership/order is checked against a separate linear oracle.

Visual import contains 1,783 visible BSP faces, 1,125 displacements, 26 model types and 1,587 original props, with original material coordinates, textures, lightmaps, vertex lighting and cubemaps. `fixtures/boreas-asset-validation.json` checks finite/index-valid assets and exact shared displacement decoding. This is internal geometry integrity, not CSS pixel parity. See `BOREAS-VISUALS.md` for unsupported material/effect details.

## Browser verification

The final production integration run passed **17/17 checks**, with zero skipped checks, console errors, warnings or failed requests. It used installed Edge 154 with real Pointer Lock, keyboard, mouse and wheel events against `http://localhost:4173`. The game-state seam is read-only. Checks cover launch, spawn settling, movement/crouch, raw-count camera scaling, configurable wheel/key bindings, numeric sensitivity, persistence, auto-bhop/manual styles, focus/menu/restart, practice saves, map switching, completion, record protection and resizing. The complete command replay finished in 39.495359573 s with ordered splits of 16.594048415 and 32.681057494 s. Final results are recorded in `fixtures/browser-boreas-results.json`; inspected screenshots are in `docs/screenshots/boreas/`. This headless browser validation establishes event flow and functional behavior, not subjective human feel or physical input latency.

## Remaining fidelity gaps

1. Exact native CSS build and current KSF cvar/plugin manifest remain unknown. Global hold-jump auto-bhop and open prestarts are requested local rules, with separate records; they are not advertised as universal KSF normal-style rules.
2. Small native float/contact differences remain, as quantified above. VPhysics/displacement edge filtering, contact ordering and all arbitrary approach cases are not proven identical.
3. The authored .9999 no-jump modifier is modeled from hull overlap. Native telemetry suggests a small entry/I/O scheduling difference; it is reported rather than hidden by changing trigger bounds.
4. Native client-frame fractional keyboard commands, every partial-duck reversal/spam case, step-camera adjustment, and native client prediction are not fully reproduced. Pointer Lock counts also depend on browser/device support.
5. The local timer sweeps actual trigger geometry. Its checkpoint fractions differ slightly from KSF bookmark/display splits; exact KSF timer internals are unavailable. Local records are not KSF-comparable records.
6. Some Source material passes and map effects remain simplified: directional bumped lighting, reflection/refraction/water details, HDR, proxies, animation, particles, sounds and two unavailable stock textures. Actual traversal geometry and original assets are present.
7. Local native CSS testing now covers limited hull/trigger contact probes only. The user has provided positive subjective movement feedback, but there is no controlled experienced-player parity study or whole-route native harness. Reference recordings cannot establish all-case equivalence.

## Reproduce

`npm test` runs automated regressions. `npm run validate` regenerates both normal-command witnesses and the native comparison report. With a local preview running, `npm run test:browser` performs browser integration checks; set `SURF_QA_URL=http://localhost:4173` for production. Offline importer/visual checks are documented alongside their scripts. Map and physics versions namespace records and replays.
Performance measurements

Download this document

# Rendering performance

The renderer keeps the imported geometry, materials, baked lighting and direct camera response. Movement code and simulation rate were not changed by these renderer optimizations.

## Measurement

`scripts/profile-renderer.ts` replays the saved Boreas command fixture in the headless simulation and extracts 690 camera poses across the complete route. An isolated browser scene renders the same poses twice, after a warm-up covering the route. This measures rendering separately from input, simulation and HUD costs. It does not inject gameplay state or establish additional physics fidelity.

The measurements below used headless Microsoft Edge on the local RTX 3090 through ANGLE/D3D11, a 1600 × 900 CSS-pixel viewport, 1,380 measured frames and approximately 346 GPU timer queries. CPU time surrounds renderer submission; GPU time uses `EXT_disjoint_timer_query_webgl2`, excluding disjoint samples. Browser frame intervals were around 2.8–2.9 ms in both versions, so these results establish lower rendering cost, not a measured increase in displayed FPS or lower input-to-photon latency.

| Condition | CPU mean / p95 | GPU mean / p95 | Mean draws | Mean submitted triangles |
| --- | --- | --- | --- | --- |
| Original, DPR 1 | 0.497 / 1.000 ms | 0.538 / 1.223 ms | 221.3 | 887,359 |
| Optimized, DPR 1 native | 0.264 / 0.500 ms | 0.495 / 0.869 ms | 70.8 | 821,283 |
| Original, DPR 2 native | 0.492 / 1.000 ms | 1.249 / 1.993 ms | 221.3 | 887,359 |
| Optimized, DPR 2 native | 0.243 / 0.400 ms | 0.842 / 1.330 ms | 70.8 | 821,283 |
| Optimized, DPR 2 balanced | 0.248 / 0.500 ms | 0.536 / 1.005 ms | 70.8 | 821,283 |

The live geometry count fell from 755 to 159 for this route; texture and shader program counts stayed at 60 and 21. Renderer construction took 25–31 ms in the final runs, versus 57–58 ms before. Construction excludes first-use shader compilation and texture upload. Map-loading checks separately exercise those cold paths; their large first frame is not a sustained rendering measurement.

Source reports are `fixtures/renderer-profile-before.json`, `renderer-profile-before-hidpi.json`, `renderer-profile-after-branchless.json`, `renderer-profile-after-hidpi-native.json` and `renderer-profile-after-hidpi-balanced.json`. Earlier `after`/`after-repeat` reports retain an investigated GPU regression: a dynamic per-vertex lighting branch was slower. The final branchless lighting selection removed that regression; tolerances or timer results were not adjusted to conceal it.

## Changes and visual preservation

- Opaque prop instances share larger model/material batches, while conservative per-instance frustum spheres exclude wholly invisible instances. Original transforms and per-instance lighting offsets remain intact. A small bounds margin avoids edge clipping.
- Transparent model batches keep their original spatial grouping and ordering. No additional approximation to transparent sorting was introduced.
- Immutable model vertex/index buffers are shared across batches instead of decoded and uploaded repeatedly. Instance matrices and lighting offsets remain independent.
- Static objects no longer recalculate unchanged world matrices. Moving zone labels explicitly update their own matrices. Camera position and current mouse angles still apply every rendered frame, without easing.
- Visibility lists and instance-buffer uploads change only when the camera frustum or visible instance set changes. Model LOD 0, displacement resolution, shaders, texture sampling and source-unit scale remain unchanged.

Three matching route views at DPR 1 have **zero differing pixels** before versus after. At DPR 2, the start and late views are identical; the middle view has 22 differing pixels out of 5,760,000, with maximum channel difference 1/255. These results are recorded in `fixtures/renderer-pixel-comparison.json`; screenshots are under `docs/screenshots/performance/`. This compares this browser renderer before and after optimization, not the browser output against CSS.

## Stable rendering choices

| Setting | Drawing-buffer ratio | Anisotropy |
| --- | --- | --- |
| Native | Device pixel ratio, capped at 2 | Up to 8× |
| Balanced | Device pixel ratio, capped at 1 | Up to 8× |
| Performance | 0.75 × min(device pixel ratio, 1) | Up to 2× |

Balanced is the application's default. On a DPR-2 display it submits one quarter as many pixels as Native, preserving the CSS-pixel viewport and identical camera FOV. On a DPR-1 display Native and Balanced match. Performance deliberately trades sharpness and oblique texture filtering for lower rendering cost. The chosen setting is stable during a run; no automatic resolution adaptation changes the image mid-run. Rendering choices do not change collision, simulation commands, record keys, input sensitivity or timing.

Changing anisotropy can trigger a one-time texture upload while the menu is open. Native-to-Balanced changes retain anisotropy and avoid redundant texture reuploads.

## Generic map and lifecycle checks

`loadBspVisuals(slug)` loads one map; `loadBoreasVisuals()` remains a compatibility alias. Missing sky, fog, prop and lighting metadata have explicit defaults. Image/mesh loading has bounded concurrency. Renderer disposal releases geometry wrappers, materials, textures, cubemaps and marker resources and resets shared WebGL pixel-store flags before context reuse.

`scripts/bsp-loader-qa.ts` cycles Boreas → Utopia → Mesa → an empty map with optional data omitted → Boreas in one canvas at DPR 2. It asserts all three quality sizes and verifies a synthetic half-height sky sampling fixture. `fixtures/bsp-loader-qa.json` records zero console errors or warnings and all size/sampling assertions passing.

Utopia's packed sky has half-height side textures, a 1 × 1 bottom and authored texture scaling. WebGL cubemaps require equally sized square faces. The loader bakes the authored transform into clamped square sky images once, sampling color in linear space; already compatible Boreas and Mesa skies pass through unchanged. This removes invalid cube upload warnings without stretching the authored sky.

The whole-game UI, native controls, audio, map switching and practice checks are in `scripts/browser-classic-qa.ts` / `fixtures/browser-classic-results.json`: **10 checks pass, zero console errors or warnings**. This includes actual Pointer Lock and forward input on all three maps, quality and audio persistence, pause/resume audio lifecycle, all eight lab stations, and two complete map-switch cycles with stable per-map geometry/texture/program counts from matching fresh-spawn views. Live resource counts can identify growth across switches, but do not prove absence of every retained JavaScript or driver allocation. Finish-marker screenshots use separate inspection cameras; they do not establish complete runs on the additional maps.

The final marker-only follow-up (`SURF_QA_MARKERS=1`) uses the actual recorded CSS positions/angles 80, 50 and 30 ticks before each finish and at entry, adding the standing/crouched eye height. Its 15 views cover all map starts and four finish approaches per map. Visual inspection confirmed corrected Mesa start markings on the deck and visible gold finish signs/landing borders on the native approaches. `fixtures/browser-classic-marker-results.json` records each source frame and zero errors/warnings; images are under `docs/screenshots/classics/`. Those cameras are an inspection aid, not command-driven gameplay or an independent physics comparison.

A short active, stationary whole-game sample after native movement and restart used 1280 × 720 CSS pixels, DPR 2 and Balanced quality. Frame interval median/p95 was 2.8/2.9 ms for all three maps. The application's smoothed render-submission average during that sample was 0.501 ms (Boreas), 0.149 ms (Utopia), 0.196 ms (Mesa); corresponding smoothed physics cost averaged 0.020/0.015/0.018 ms per render frame, including frames with no simulation tick. This is a current spawn observation, not a whole-course benchmark or a before/after whole-game comparison.

## Additional-map route views

The same isolated renderer profiler also covers **500 uniformly sampled native CSS camera poses from start to finish on each additional map**, with two measured passes after warm-up. It uses 1600 × 900 pixels, DPR 1, Balanced quality and the same RTX 3090/Edge environment. Camera origins come from recorded positions plus 47/64-unit eye height inferred from the duck button; these views are inspection inputs, not command-driven playback and not playability evidence. The UI, audio and movement simulation do not run in this measurement.

| Map | CPU mean / p95 | GPU mean / p95 | Draws mean / p95 | Triangles mean / p95 |
| --- | --- | --- | --- | --- |
| Utopia | 0.080 / 0.200 ms | 0.104 / 0.146 ms | 12.97 / 15 | 59,001 / 59,299 |
| Mesa | 0.121 / 0.200 ms | 0.224 / 0.364 ms | 36.66 / 60 | 279,736 / 413,858 |

Each report includes 1,000 CPU/draw samples and 250 valid GPU queries, zero console errors or warnings, and start/middle/late screenshots. Utopia samples native frames 310–3868; Mesa samples 144–3395. These measurements do not identify a sustained rendering bottleneck in the middle or final sections on this GPU. They do not establish FPS on other hardware. Frame intervals remained approximately 2.8–2.9 ms and are not used to claim an FPS improvement.

The saved reports are `fixtures/renderer-profile-utopia-balanced.json` and `fixtures/renderer-profile-mesa-balanced.json`. Utopia's one-time renderer creation was 332 ms, primarily while normalizing its authored non-square sky faces; Mesa's was 28 ms. This occurs during map loading, outside simulation. No additional runtime change was made for this acceptable one-time cost.

To reproduce, set `SURF_PROFILE_QUALITY=balanced` and run `node --import tsx scripts/profile-renderer.ts utopia-balanced --slug utopia` (or substitute `mesa` in both places).

Exact Source PVS and GPU occlusion, model LOD selection, displacement tessellation, and independent CSS visual parity remain outside this renderer's evidence.

With the development server running, reproduce the renderer profile with `node --import tsx scripts/profile-renderer.ts current`. Set `SURF_PROFILE_DPR=2` and `SURF_PROFILE_QUALITY=balanced` for the HiDPI balanced comparison. Production builds are not required by these isolated development checks.
Utopia & Mesa provenance

Download this document

# Classic CSS map imports

The added courses are the actual **surf_utopia_njv** by **Panzer** and **surf_mesa_fixed** by **Arblarg**. KSF lists both as tier-one linear CSS courses with three checkpoints. Utopia was added in 2012 and Mesa in 2014. These are the CSS versions, not similarly named CS:GO, CS2, or TF2 ports. [KSF Utopia](https://ksf.surf/maps/surf_utopia_njv?game=66t&mode=fw), [KSF Mesa](https://ksf.surf/maps/surf_mesa_fixed?game=66t&mode=fw).

## Provenance and reproducibility

The public [KSF/OuiSURF mirror index](https://main.fastdl.me/maps_ksfthings.html) identifies the exact files. [OuiSURF's collection](https://github.com/OuiSURF/Surf_Maps) describes its collection as maps from KSF CSS servers. A matching filename alone is not proof of the exact live server revision; the independently recorded movement comparisons provide a second check.

| Map | SHA-1 of decompressed BSP | Bytes | VBSP / revision |
|---|---|---:|---|
| [Utopia download](https://main.fastdl.me/h2/50b99557a4b754696ce16e9e920cb1b6072dd4bd/surf_utopia_njv.bsp.bz2) | `50b99557a4b754696ce16e9e920cb1b6072dd4bd` | 56,273,716 | 20 / 3009 |
| [Mesa download](https://main.fastdl.me/h2/f4897c2472b32b33bc22b072ffafef5caa0de8fb/surf_mesa_fixed.bsp.bz2) | `f4897c2472b32b33bc22b072ffafef5caa0de8fb` | 62,212,961 | 20 / 90 |

The offline converters are independently authored from published BSP, VPK, MDL/VVD/VTX, VTF, and PHY layouts. They preserve the original map authorship. The map downloads do not establish a general redistribution license, and no such license is claimed here. Imported art remains the property of its respective authors. The requested local imports also read a small number of stock materials/models from the user's installed Counter-Strike: Source archives; installed game files are never changed. Each export records these fallback resource paths in `localGameResources`.

With Python and Pillow installed, decompress the pinned downloads and run from the project directory (replace paths with the local BSP and CSS installation):

```powershell
python scripts/import_classic_maps.py utopia C:/maps/surf_utopia_njv.bsp --game-dir 'C:/Program Files (x86)/Steam/steamapps/common/Counter-Strike Source'
python scripts/import_boreas_visuals.py C:/maps/surf_utopia_njv.bsp --slug utopia --map-id surf_utopia_njv --author Panzer --game-dir 'C:/Program Files (x86)/Steam/steamapps/common/Counter-Strike Source'
python scripts/import_classic_maps.py mesa C:/maps/surf_mesa_fixed.bsp --game-dir 'C:/Program Files (x86)/Steam/steamapps/common/Counter-Strike Source'
python scripts/import_boreas_visuals.py C:/maps/surf_mesa_fixed.bsp --slug mesa --map-id surf_mesa_fixed --author Arblarg --game-dir 'C:/Program Files (x86)/Steam/steamapps/common/Counter-Strike Source'
npx tsx --test tests/classic-map.test.ts
```

Collision outputs are `public/maps/{utopia,mesa}-collision.json`; visual manifests are `public/maps/{utopia,mesa}-visuals.json` with textures and binary meshes in their respective subdirectories. The Boreas default importer profile and existing Boreas outputs remain unchanged.

## Geometry and route rules

All geometry stays in Source X/Y horizontal, Z up, feet-origin units. Renderer conversion remains separate. Convex BSP brush planes include compiled bevels; static solid props use their actual PHY convexes. Mesa displacements retain full-resolution triangles and honor the Source hull-exclusion/remove flags. Rendering uses the same BSP revision, including original textures, authored blends, baked lightmaps, static prop vertex lighting, and sky transforms.

| Imported content | Utopia | Mesa |
|---|---:|---:|
| Collision convexes | 3,633 | 5,002 |
| Displacement triangles | 0 | 183,040 |
| Static props rendered | 0 | 234 |
| Static props with PHY collision | 0 | 230 |
| Authored reset trigger models | 75 | 9 |
| Local ordered checkpoints | 3 | 3 |

Utopia's authored reset destination is `start`, feet origin `(-14096,0,12816)`, yaw 0. The supporting deck traces to `Z=12800.03125`, also the independent native record's standing height. Mesa's destination is `Spawn`, `(0,-800,10251)`, yaw 90; its deck traces to `Z=10144.03125`, also confirmed independently. Utopia has one additional teleport aimed at nonexistent `jail_top`; Valve's teleport implementation does nothing when a destination is missing, so it is recorded as metadata rather than an active reset.

There are no authored gravity or air-acceleration overrides in either BSP. Both maps use the established CSS 0.015-second simulation profile. Their independent KSF recordings show a **3500 u/s component limit**, exported as `physicsOverrides.maxVelocity=3500`. This is an inference from the records, not an authored BSP cvar or a claim about every historical KSF server. Horizontal speed can exceed 3500 when both horizontal components contribute.

Local start/checkpoint/finish boxes are defined in `scripts/import_classic_maps.py`, aligned to the actual route apertures and independent native bookmark positions. Their exact bounds are **not claimed to be KSF's server-side timing zones**, which are absent from BSP files. The first and third Utopia checkpoints and first two Mesa checkpoints are unions of mirrored boxes so both intended branches count without filling the empty space between them. PBs are local and versioned by map and physics configuration.

Mesa's authored continuous `trigger_push` is preserved: bounds `(-384,-4352,-12288)` to `(384,-3328,-11808)`, direction +Y, speed 3500, clients flag 1. The native run independently shows its displacement contribution without the same addition to stored velocity. See [MAP-PUSH.md](MAP-PUSH.md) for the Source base-velocity semantics and validation.

## Import checks and precise limits

`tests/classic-map.test.ts` checks pinned identity, native standing heights, finite/unit collision planes, convex bounds, mirrored checkpoint unions, local ordered timing crossings, the Mesa push, and existence of every visual resource. Its native-position timing test assesses zone placement only; **a sequence of injected positions does not prove surfability**. Separate complete command replay tests establish the playable routes. The native telemetry files include public source URL, hash, bookmarks, and the decoded tick samples. `scripts/decode-classic-replays.ts` reproduces decoding.

## Complete normal-command routes

Both imported courses have complete witnesses from a legal stationary start. The shipped Mesa route and a separately planned alternative both retain every authored reset volume. All runs use the normal default browser profile, including the documented 3500 component limit; no practice restores, position or velocity injection, noclip, altered geometry, or reset exemptions occur during these runs.

| Course / witness | Commands | Local time | Ordered events |
|---|---:|---:|---|
| Utopia, `public/replays/utopia-complete.json` | 3,867 | 53.349 s | Start, CP1, CP2, CP3, finish |
| Mesa, selected `fixtures/mesa-straight-complete.json` | 3,653 | 52.635 s | Start, CP1, CP2, CP3, finish |
| Mesa, alternative `fixtures/mesa-launch-cem-complete.json` | 3,598 | 51.810 s | Start, CP1, CP2, CP3, finish |

The release publisher copies the selected Mesa witness to `public/replays/mesa-complete.json`. `scripts/validate-classics.ts` reconstructs each initial state from a stationary start-deck spawn, accepts only normal command fields and magnitudes, then independently runs the entire course through `GameSession`. It requires all checkpoints in order, no falls or invalidation, and a finish event on the final command. Every tick's state, collision contacts, events, splits, and time agree exactly at 30, 60, 144, and 240 render FPS. The separate Mesa reports are `fixtures/mesa-straight-command-validation.json` and `fixtures/mesa-alternate-command-validation.json`; the release validation report identifies the canonical replay by SHA-256.

The offline planners select ordinary mouse angles and key presses. They can cache a prefix already produced by normal simulation while searching, but every completed witness is rerun from its original stationary start before acceptance. Utopia's line uses small view-angle corrections to clear its authored reset edges. The Mesa alternatives use different normal turns and descents, then surf the original lower ramps and pass through the original continuous push trigger. No such planner runs in the playable game. These witnesses establish whole-course playability and deterministic replay in this implementation; they do not establish exact parity with a private KSF server or make the local timer boundaries into KSF boundaries.

## Remaining native and entity differences

The following differences require explicit separation from verified movement:

- The native KSF recordings cross a few authored reset-volume edges without resetting. This occurs in both recent and older independent runs. Latest Utopia frames 797–801 overlap trigger models `*24`/`*86`; latest Mesa frames 401–402 overlap `*1`, 2520–2526 overlap `*1`/`*10`, and 2773–2775 overlap `*8`. Exact model ownership, transforms, solid contents, and entity flags were checked. The corresponding PHY model convex counts match the compiled brushes and their surfaces differ by roughly the ordinary half-unit inset. **A direct isolated CSS server test corroborated the imported reset shapes:** stock build 11003710 reset a crouched bot at the tested Utopia/Mesa positions and measured the same 0–45 crouched hull. See [NATIVE-CSS-PROBE.md](NATIVE-CSS-PROBE.md). The KSF server/revision difference remains unresolved. The browser retains the complete authored reset volumes and full player hull; completed normal-command witnesses are evaluated separately from KSF's recorded line.
- Mesa isolated native states 521–523 are about 0.05 units inside playerclip brush 2281 according to the downloaded compiled planes. Side 10 uses original plane 55800: normal `(0.7808678150,0.4417394698,0.4417144656)`, distance `5514.1142578125`. A one-step trace from that supplied state corrects by about 0.084 units. This is retained as a precision/revision gap; continuous traversal is a separate test.
- Four Mesa static prop instances lack a PHY resource even after mounting the installed game: two credits models and two crystal models. Their render meshes remain visible; no invented collision mesh is substituted.
- Mesa's four decorative crystal `func_tanktrain` brush models remain at their authored initial transforms. Full train animation and the late decorative dynamic blast door are not simulated. Soundscapes, particles, and multiplayer/gameplay entities are not recreated. The main surf route and completion point precede the blast door.
- Utopia uses half-height sky side images and a 1×1 bottom texture with authored VMT transforms. The renderer applies these transforms while preparing equally sized cube faces; direct upload as a conventional cubemap would be invalid.

Primary trigger references: [Valve CTriggerTeleport and CBaseTrigger](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/server/triggers.cpp), [Valve PhysicsTouchTriggers](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/server/baseentity.cpp), [Valve collision property](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/shared/collisionproperty.cpp). These shared SDK sources guide investigation; they do not prove CSS-specific engine internals or KSF's private server configuration.
Movement practice facility

Download this document

# Movement laboratory

The rebuilt `lab-chamber-2` is an original, practice-only Source-style chamber. `src/map/lab.ts` owns both collision/render brush data and eight named stationary starts; the original `course.ts` test map remains unchanged for earlier regression fixtures. Gravity, acceleration, hulls, jump impulse and movement code are unchanged.

The two long orange/blue faces share the proven opening-transfer dimensions from Northline, translated vertically. The run-up starts at rest. Orange uses A; the transfer changes to D on blue. A separate right-ramp platform permits practicing that face without completing the first. Missing a ramp lands on the recovery floor. Restart returns to the run-up, and the station selector provides explicit practice repositioning with no momentum injection.

Ground stations include a marked acceleration strip, 45/56-unit jump blocks, six 18-unit steps, a 49-unit crouch tunnel, two coplanar solid brushes and a one-unit wall. All starts have clear standing hulls and real ground support. Concrete grids use a 128-unit scale; signs, floor arrows, distinct ramp colors, a roof and fluorescent strips replace the former empty mountain backdrop. Static brush meshes are batched by material.

Validation: `npx tsx --test tests/lab.test.ts` passes seven tests. Normal WASD/view commands traverse both faces and their transfer in 799 ticks, with 232 orange-face and 137 blue-face contacts and peak horizontal speed 1735.13 u/s. The independent right entry produces 193 surf contacts from a stationary walking start. Ordinary inputs clear both jump blocks, walk all steps, crouch through the tunnel and stand only after clearing its ceiling. Swept hull tests verify the seam and thin wall.

`npx tsx scripts/lab-visual-qa.ts` renders the actual map in Edge and saves five views under `docs/screenshots/lab-chamber-*.png`, including a state reached through normal route commands. The inspected views have 11–18 draw calls and about 2070 triangles, with no browser errors. These screenshots validate appearance and rendering; the separate command tests establish surfability. The browser fixture is isolated from the main menu; integrated station UI validation belongs to the main application QA.
Authored push volumes

Download this document

# Authored Source push volumes

Mesa contains a continuous `trigger_push`, flags 1, speed 3500, direction +Y, bounds (-384,-4352,-12288) to (384,-3328,-11808). Its compiled brush hull is imported with the map. This is authored map behavior, not a surf assist or a velocity boost added to compensate for geometry.

Valve's [trigger implementation](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/server/triggers.cpp) sets base velocity during continuous touching. Overlapping continuous pushes add. Positive vertical pushes release ground and raise the origin one unit. Flags 1 allows players; flags 128 is a different, one-shot mode. The present helper supports continuous player pushes; it does not emulate one-shot entity deletion or arbitrary entity I/O.

The server's [CheckMovingGround](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/server/player_command.cpp) converts unrefreshed base velocity into player momentum before movement, using `previousBase * (1 + tickInterval/2)`, then clears it. In [shared player movement](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/shared/gamemovement.cpp), StartGravity consumes vertical base velocity as a force. AirMove adds horizontal base velocity after air acceleration, sweeps collisions with the combined velocity, and subtracts it before categorization/final gravity. The non-player `PhysicsAddGravityMove` path is not a replacement for these player rules.

`prepareMapPush` returns optional base velocity and retains the previous horizontal component in optional player state. Save/restore and replay initial states consequently retain exit momentum correctly. Maps without pushes leave that field absent and use exactly the previous movement path. The movement core receives an optional third argument; it neither changes the authoritative tick interval nor runs extra acceleration ticks.

Independent evidence comes from the [public native KSF Mesa replay](https://ksf.surf/replays/surf_mesa_fixed/replay_css_1777_0_576582_1775395546.rec), decoded in `fixtures/mesa-ksf-telemetry.json`. At tick 3058 the player travels about 104.334 Y units, consistent with `(storedVelocityY + 3500)*0.015`; stored player velocity remains about 3455.614, so directly adding 3500 to the stored velocity is wrong. Push displacement continues through 3067. On exit 3068, inherited momentum is limited before acceleration. Subsequent stored Y velocity clamps to 3500. That cap is an observed Mesa/reference-map setting; Boreas's 5000 profile remains unchanged.

`tests/map-push.test.ts` passes seven tests, including independent one-step replay comparisons for every state 3055→3070 against actual Mesa geometry. Predeclared tolerances remain .002 Source units and .002 u/s: maximum position error .001137880, maximum velocity error .000222171, first out-of-tolerance tick none. Analytical fixtures additionally verify acceleration order, wall sweeps, vertical force/ground release, one-time exit momentum and absent-map state identity. These comparisons establish the tested push transition; native contact flags, the complete entity touch queue, arbitrary filters, moving conveyors and skipped-over thin push volumes remain outside this implementation's verified scope.

After adding the optional movement argument, all 27 focused Boreas/playability/revision/laboratory checks pass, including both full-course command witnesses and identical 30/60/144/240 FPS states. No source implementation was copied into runtime code.
Mesa complete command route

Download this document

# Mesa complete command witness

`fixtures/mesa-straight-complete.json` is a complete run using the current default surf profile and Mesa's documented map overrides. It starts stationary and grounded in the real start zone. The final verification reconstructs this state from the spawn coordinates; it does not inject velocity, contact state, or intermediate positions.

The unchanged `GameSession` processes all commands, movement, authored push volumes, reset volumes, and timing triggers. The run fires only these events:

| Event | Command tick |
| --- | ---: |
| Start | 144 |
| Checkpoint 1 | 1435 |
| Checkpoint 2 | 2072 |
| Checkpoint 3 | 2519 |
| Finish | 3653 |

The simulated time after start-zone exit is **52.63500759744885 seconds**. There are **1,302 airborne ramp-contact ticks**. Peak horizontal speed is **3,570.9044372625117 units/s**; Mesa's 3,500 limit applies per component, so this vector magnitude is permitted.

`scripts/validate-classics.ts` independently checks the legal initial state, complete ordered trigger sequence, normal input fields and magnitudes, absence of resets or assists, and final completion. It then replays all 3,653 commands at 30, 60, 144, and 240 FPS. Every tick's serialized player state, movement result, contacts, events, and timer agrees exactly across those schedules. No tolerance is applied to schedule comparison. The detailed result is `fixtures/mesa-straight-command-validation.json`.

Replay SHA-256: `a10daf80b98a3c263986a5ec952edd9125bd97e8056f9851797d04053ff7284b`.

## How the commands were developed

The route starts with the independently prepared legal command prefix in `fixtures/mesa-clear-ceiling-v1.json`. `scripts/plan-mesa-edge.ts` explored wider ordinary strafe lines around the last reset brush. Its preserved result is `fixtures/mesa-late-straight-v1.json`. `scripts/plan-mesa-straight-descent.ts` then generated ordinary view-angle and strafe commands from tick 2840 through the descending section, bottom push, and final ramp.

The successful final ramp line aims near X=100 on the positive-X ramp face, then holds the strafe key into the ramp at yaw 96 degrees from Y=3000 to Y=4500. This converts the permitted existing momentum into a higher departure through normal collision clipping. No ramp geometry, reset bounds, movement constants, acceleration, or velocity was changed to make the route work.

The offline search reads position to choose candidate inputs; its output contains only tick-indexed keyboard inputs and view angles. This planner is not part of browser gameplay. The saved complete replay is subsequently simulated again from the legal stationary start without the planner, state restores, or position/velocity edits.

## Scope

This proves whole-course playability with normal commands in this implementation and independence from rendering frequency. It does not prove exact CSS/KSF parity or that a human has played this route. Stock CSS native trigger tests and public KSF recordings differ at several authored reset contacts; the game preserves the imported map's authored reset geometry, and this route avoids those volumes. See `NATIVE-CSS-PROBE.md` and the separate movement comparison reports for the evidence and remaining fidelity gaps.
Native CSS engine investigation

Download this document

# Native CSS trigger probe — 2 October 2026

An isolated, local Counter-Strike: Source dedicated server was used to investigate the remaining reset-trigger disagreement with public KSF replays. This is a direct, limited native-engine test. It is **not** a claim that the browser reproduces a complete native run exactly.

## Environment and isolation

- Installed executable: `C:/Program Files (x86)/Steam/steamapps/common/Counter-Strike Source/srcds_win64.exe`.
- Native `version`: build/server/network patch **11003710**, protocol **24**, server AppID **232330**.
- Startup reported `SV_ActivateServer: setting tickrate to 66.7`; this display is rounded and does not replace the independently established 0.015-second simulation interval.
- Test mod and writable files: `node_modules/.native-css-probe/cstrike` inside this project. Installed binaries and asset packs were mounted as read-only search paths. No installed configuration or map files were changed.
- Server used `-insecure -ip 127.0.0.1 -port 27025`, a local password, hidden window and no human client. Bots were used. There were no SourceMod, Metamod, KSF or other movement plugins.
- The probe loaded the same downloaded Mesa/Utopia BSP files used by the browser importer. Their provenance and hashes remain in the map import metadata.
- The server was stopped with its `quit` command after testing. The process was confirmed absent.

## Measured bounds

Built-in VScript `GetBoundingMins()` and `GetBoundingMaxs()` returned:

| State | Minimum, relative to feet | Maximum, relative to feet |
| --- | --- | --- |
| Standing | `(-16, -16, 0)` | `(16, 16, 62)` |
| Crouched | `(-16, -16, 0)` | `(16, 16, 45)` |

Crouched `GetCenter()` was feet plus 22.5 units vertically. The observed entity bounds do **not** support raising the crouched trigger hull's bottom by 9, 31 or 32 units. Those candidate changes were rejected.

## Native trigger outcomes

The bot had the measured 45-unit crouched bounds at each recorded test. `Teleport()` placed it at the specified origin with supplied velocity, without tracing a movement path from spawn. The script printed the immediate origin to confirm the placement; a following RCON read inspected the subsequent native result.

| Probe | Position supplied | Result |
| --- | --- | --- |
| Mesa recorded frame 401 | `(159.6418, 3327.4126, 9528.7471)` | Native authored reset returned the bot near `(0, -800, 102xx)` |
| Mesa approach from frame 400 | `(167.6383, 3314.57495, 9536.78809)`, velocity `(-566.536, 833.601, -530.092)` | Native authored reset returned the bot near spawn |
| Mesa recorded frame 2523 | `(477.62857, 6157.87744, 361.0672)` | Native authored reset returned the bot near spawn |
| Utopia recorded frame 798 | `(-1064.533813, -457.993744, 9986.02832)` | Native authored reset returned the bot to `(-13368.400391, -26.910000, 12795.299805)` |

The Mesa trigger output was independently logged as model `*1`. The position in that output is already the post-teleport position, so it is not used as pre-contact telemetry. Exact captured outputs are in `fixtures/native-css-mesa-trigger-probe.txt`, `fixtures/native-css-utopia-trigger-probe.txt` and `fixtures/native-css-trigger-events.txt`.

The reset convexes were separately checked using BSP model-to-brush membership and the BSP's decoded VPhysics model data. Their native-recorded points genuinely penetrate the trigger shapes; this is not just an AABB corner false positive. For example, Utopia frame 798 is approximately 19.45 units inside the nearest VPhysics plane. All original reset volumes therefore remain present. The browser does not shrink their hulls, remove selected resets or exempt replay positions to force a passing record.

## Interpretation and limits

The downloaded BSPs, stock installed CSS and the public KSF recordings disagree at these particular reset contacts. The direct native tests support retaining the authored reset geometry and the measured full crouched hull. They do not identify the cause of the KSF disagreement. A server-side map revision, entity modification or plugin behavior remains possible; no public KSF configuration establishing a specific explanation was found.

These are short contact probes, not a whole-route command replay in the native server. Repositioning can affect native contact state, and the subsequent inspection occurs several native ticks later. We also have not established that installed build 11003710 is exactly the build on which the KSF records were made. Those limitations prevent claiming native whole-route parity or declaring a specific KSF fix as fact.

## Reproduction

Use a locally installed, licensed CSS copy. Make a separate `cstrike` directory under the project; do not modify the installation. Its `gameinfo.txt` needs the installed `cstrike/bin` as `gamebin`, the installed CSS VPK as `game+mod`, and the installed HL2 packs as `game`. Put `mod+mod_write+default_write_path` and `game+game_write` on the local probe directory. Using only `game` for the CSS assets is insufficient: encrypted weapon data is read through the `MOD` search path. Add `cfg/valve.rc` containing `stuffcmds`, and local configuration with `sv_lan 1`, `sv_cheats 1`, a test RCON password and `bot_join_after_player 0`.

Launch the installed dedicated executable hidden with the isolated directory as `-game`, `-insecure -ip 127.0.0.1 -port 27025 +exec probe.cfg +map surf_mesa_fixed`. Add two bots, use `bot_stop 1` and `bot_crouch 1`, then run built-in VScript through local RCON:

```squirrel
p <- Entities.FindByClassname(null, "player");
printl(p.GetBoundingMins());
printl(p.GetBoundingMaxs());
p.Teleport(true, Vector(167.6383, 3314.57495, 9536.78809),
           false, QAngle(0, 0, 0),
           true, Vector(-566.536, 833.601, -530.092));
printl(p.GetOrigin());
```

Read `p.GetOrigin()` again after native movement has run. Put multiple Squirrel statements in a `.nut` file and invoke `script_execute`; unquoted console semicolons separate console commands rather than Squirrel statements. Repeat after a `changelevel surf_utopia_njv`, recreating the bots if needed. Shut down the isolated server when finished.
Independent release review

Download this document

# Independent integration review — 2 October 2026

Reviewed movement/base velocity, convex and displacement collision, BVH ordering, trigger/timer integration, fixed-step scheduling, mouse/keyboard/wheel input, map switching, replay ownership, local records and procedural audio against the current source files.

## Actionable findings resolved

1. **Replay rules persisted after Escape.** Watching a route creates a session with the replay's rules. Previously Escape cleared the playback flag before Restart could identify that session, so normal play could keep different auto-bhop/start rules from the options UI. A separate replay-session flag now survives stopping playback. Restart or Join recreates a normal session from current preferences and refreshes the matching personal best.
2. **Stale animation-frame timestamps stopped playback immediately.** A click/lock handler can reset the wall-clock baseline slightly after the timestamp attached to a queued animation frame. Passing the resulting negative delta into the fixed clock stopped the game at tick zero. The browser loop now treats that stale interval as zero without moving its baseline backward. The fixed clock still rejects genuinely invalid/long deltas; physics interval and stall protections were not changed.

Both issues were investigated in real Edge. The immediate-pause failure reproduced twice with the page focused and visible and no console errors. After the fixes, all three focused browser checks pass: initial manual-profile selection, Watch → Escape → Restart, and Watch → Escape → Join with real Pointer Lock. Checks verify exact movement configuration, practice state, fresh initial tick, matching record namespace and preserved preference values. Two synthetic PB entries exist only in an isolated browser context to test record selection; these are not gameplay records or completion evidence.

Reproduce with `npx tsx scripts/browser-replay-state-qa.ts` against a local preview; use `SURF_QA_URL` to select its address. Captured result: `fixtures/browser-replay-state-results.json`.

## Focused validation

**61/61 automated tests passed**, none skipped, across input, game/timer/practice, authored push, storage, experience settings and collision review fixtures. The command was:

```text
npx tsx --test tests/input.test.ts tests/map-push.test.ts tests/game.test.ts tests/review.test.ts tests/storage.test.ts tests/experience.test.ts
```

This includes identical tick results and timing at 30/60/144/240 FPS; wheel pulses unaffected by HUD reads; raw-input fallback and focus cleanup; practice restore and record separation; ceiling, crouch, step and corner contacts; and Mesa's authored push entry/exit compared to 15 independently recorded native transitions. Push comparison maxima remain .001138 units position and .000223 u/s velocity, below the unchanged .002/.002 limits.

The rendering optimization leaves acceleration and gravity on the authoritative fixed interval. Camera yaw/pitch use immediate mouse-event angles on every active render frame, while HUD reads are throttled and non-consuming. BVH candidates retain original order before narrowphase. Optional base velocity remains absent on ordinary maps; its push-specific state survives practice/replay cloning without changing Boreas state fields.

## Remaining limits

- The exact KSF executable/plugin versions remain unknown. Public recordings lack native contact flags and complete command/hull-transition metadata. Float/trace residuals remain quantified in the main validation report.
- The new installed-CSS probes verify stock standing/crouched bounds and specific reset contacts, not a complete live native command replay. Installed build 11003710 may differ from the recording server. See `NATIVE-CSS-PROBE.md`.
- Mesa and Utopia public record paths intersect resets in the downloaded BSPs; stock installed CSS also resets at tested disputed points. The project retains those authored triggers. A legal complete command witness for each shipped course is a separate acceptance check and is not established by this integration review alone.
- Map-effect touch/event timing is sampled at tick boundaries. Boreas's tiny speed-modifier entry discrepancy remains documented; the browser is not a complete Source entity-I/O system. Continuous player push is implemented for the actual Mesa zone. One-shot push, arbitrary trigger filters, moving parents and other general-purpose Source entity behavior are outside the current map contract.
- Mouse count equivalence depends on browser/device delivery. Fractional initial/released keyboard command magnitudes, complete duck-spam behavior, native prediction/step camera and repeated-jump stamina remain explicit fidelity gaps. No experienced human CSS comparison is claimed.

No additional current-map blocker was found in the reviewed base-velocity path, collision broadphase, input sampling, map/resource switching or audio lifecycle. This finding does not replace the separate whole-course witnesses and final production-browser checks.
Online architecture and deployment

Download this document

# Online records and deployment

Movement remains local at the same fixed Source interval. Accounts and ranked
records are optional: losing the service does not stop surfing, practice or local PBs.

## Architecture

- Vercel CDN serves the Vite build, visuals and immutable gzip collision packs.
  Compression changes transfer size, never geometry coordinates or physics.
- Supabase Auth handles Google/X OAuth with PKCE. Only the project URL and
  publishable key reach the browser. The Node API authorizes private requests
  using Auth `getUser`, never by trusting a decoded client token.
- Vercel Node functions run in Frankfurt beside Supabase. `api/surf.ts` handles
  profiles, leaderboards, attempt tickets and submissions. Private replay uploads
  go directly to Storage, avoiding function request-body limits.
- The durable `surf-verify` queue invokes `api/verify.ts`, which re-simulates
  commands against pinned server geometry and movement settings.
- Postgres transactions enforce quotas, worker leases, atomic PB replacement,
  duplicate prevention and deletion. Surf tables have RLS enabled with no browser
  grants or policies. Only the trusted service role accesses them. Supabase's
  informational [RLS-without-policy notice](https://supabase.com/docs/guides/database/database-linter?lint=0008_rls_enabled_no_policy)
  is intentional here; adding a permissive client policy would weaken this design.

The server derives time and ordered splits from fractional simulation events,
stored as integer microseconds. It requires the canonical normal spawn, no inherited
momentum, exact configuration, bounded commands, every checkpoint and a finish
without resetting. Browser-supplied elapsed times are never accepted.

Practice, restores, demonstrations, pauses, focus interruptions and changed rules
are excluded in the UI. Server validation independently checks the complete run.
This is **server-validated movement**, not proof of human input: valid command
sequences can be synthesized. Exact duplicate digests are rejected, but this is
not comprehensive anti-cheat. Keep the public leaderboard labelled beta.

## Version identity

`scripts/build-online.ts` hashes collision JSON bytes and movement/session/timer
sources, normalizing source line endings for consistent Windows/Linux identities.
Board IDs include map version, both SHA-256 hashes, all movement settings, protocol
and canonical-spawn policy. The browser refuses ranking against a different build.
Rendering/audio changes do not create new boards. Verification-rule changes need
deliberate protocol review even when the movement source remains unchanged.

The small generated `src/online/catalog.generated.json` is tracked. The server
packs in `.online-build/` and public packs in `public/packed/` are generated by
`npm run prepare:online`, automatically run before development, tests and builds.
New movement/map identities need new board rows, not changes to an old board.

## Configuration and deployment

The existing Vercel project is `surfd`. Node 22 is pinned by `package.json`.
`vercel.json` specifies Frankfurt, queue delivery, daily maintenance and server
map inclusion. GitHub checks run tests, build and the production dependency audit.

Configure these server variables for each deployment environment:

| Variable | Purpose |
| --- | --- |
| `SUPABASE_URL` | Project HTTPS URL |
| `SUPABASE_PUBLISHABLE_KEY` | Public `sb_publishable_…` key |
| `SUPABASE_SECRET_KEY` | Private `sb_secret_…` key, marked sensitive |
| `SURF_AUTH_PROVIDERS` | Actually enabled providers, e.g. `google,x` |
| `CRON_SECRET` | Random private maintenance secret |

Never prefix private credentials with `VITE_`. `.env.local`, `.vercel/` and test
outputs are ignored. The config endpoint returns only explicitly allowed public
values. Missing cloud settings produce an honest local-only state.

Apply the migrations under `supabase/migrations/` in order. Seed the generated
catalog into `surf_boards`: `boardId` becomes `id`, `id` becomes `map_id`, `version`
becomes `map_version`; include both hashes and config, and set `active=true`.
Deactivate retired boards instead of silently changing their rules.

Google/X client credentials belong in Supabase Auth. Provider callback:
`https://wzyozuhomwufeuqakuai.supabase.co/auth/v1/callback`. Supabase's separate Site
URL/redirect allowlist must allow the actual app origin (and specific previews
used to test login). The browser returns to `/`. Google testing mode requires
listed test users; public login needs the appropriate audience setting.

Deploy and validate a preview before promoting. Deployment protection must allow
the intended audience before describing the beta as public. Preview and production
currently share Supabase; separate projects are preferable if strict isolation is
needed. OAuth provider configuration is distinct from local browser fixture tests.

## Resource bounds and recovery

Restart tickets expire after 45 minutes and grant no Storage access. Only finishing
requests signed upload permission. A database reservation covers outstanding tokens
and existing objects. Capacity is capped at **32 MiB per account and 700 MiB globally**,
below the free Storage allowance. Each signed upload reserves its full 1 MiB limit
for **125 minutes**, even if its current object is smaller. With no older stored
replays, this permits up to **32 upload authorizations per 125 minutes**; retained
replay bodies reduce the available allowance. Reauthorizing the same attempt renews
its existing reservation. Restarts consume no storage allowance. Accounting uses
the larger of the live reservation and actual object size for each path, in one
database snapshot; account deletion cannot release still-live token capacity.

Uploads are capped at 1 MiB gzip, 8 MiB after expansion and 40,000 commands (about
ten minutes including preparation). Per-account request quotas allow 1,200 attempt
tickets and 120 submissions per hour. These are beta bounds, not unlimited hosting.

Signed uploads cannot overwrite existing objects. A lost upload response recovers
through idempotent submission; reloading between upload and submission also retries
submission. Database leases and transactional completion tolerate duplicate queue
delivery. Operational errors are retried rather than labelled invalid movement.

Authenticated `/api/maintenance` recovers a bounded batch of stranded submissions,
removes abandoned/rejected replay bodies after signed-token expiry, and removes
non-best replay bodies after seven days. Best bodies remain; verified numeric
history remains after body expiry. Daily Vercel Hobby cron runs in production only.
Previews require manual authenticated maintenance. Daily recovery can take up to
a day; queue delivery and active submission polling normally recover sooner.

Maintenance checks `CRON_SECRET` before any work, with bounded batches and a work
deadline below its function limit. Account deletion hides records, removes replay
bodies, revokes sessions and deletes the Auth user. Outstanding token reservations
outlive deletion until expiry to prevent a storage quota bypass.

Watch database size, Storage use, egress, verifier errors and queue age. Upload
allowances do not cap every infrastructure bill or prevent every denial of service.
When capacity is exhausted, ranked uploads fail gracefully and local play continues.

## Validation

`npm test` includes movement regressions, strict replay validation, gzip loading,
API authorization, retry/crash recovery, actual PostgreSQL through PGlite, quotas,
atomic PBs, rank ties, account deletion, maintenance guards and client lifecycle.
`npx tsx tests/online-client.browser.ts` exercises browser flows with explicit
service fixtures; these do not establish live OAuth or queue operation.

`fixtures/online-canonical-replay.json.gz` completes Utopia from its unchanged
production spawn. The first 664 ticks walk across the start deck using ordinary
commands before joining the established route. The production verifier reproduces
**53.349069 seconds** and all three checkpoints. Its 4,531 total commands take
about 67.965 seconds including preparation; cloud testing must allow that wall time
between issuing the ticket and submitting. Automated QA accounts/records must be
removed from public standings after testing.

## Privacy and limitations

Supabase Auth stores provider account identity. Public records expose username,
account UUID, time, splits, date and available verified command replays, not email
addresses or OAuth credentials. No analytics or advertising SDK is added.

Original CSS map assets retain their authors' rights; hosting does not grant a new
licence. Existing uncertainties remain in `THIRD_PARTY_NOTICES.md`. Exact universal
CSS/KSF parity, human-only anti-cheat and unlimited free operation are not claimed.

## Verified deployment evidence (3 October 2026)

The full 232-test suite and production dependency audit passed (zero vulnerabilities).
Replay/database checks also passed on Node 22. Native Node ESM loading is tested
without TypeScript hooks: `scripts/build-server.ts` bundles internal server and
simulation imports into explicit `.mjs` entrypoints before Vercel packages them.
This fixes the startup failure found in the first real preview; local TypeScript
tests alone did not detect that packaging difference.

`fixtures/online-cloud-validation.json` records a successful real preview run:
Auth account creation/sign-in, profile update, ordinary attempt/upload APIs, private
immutable Storage upload, queue verification, exact time/splits, atomic repeated
submission, public leaderboard, intact replay download and account deletion.
A subsequent direct database check confirmed zero remaining QA users, records or
replay objects. Both temporary QA deployments and the QA secret were removed.
The helper is preserved only as an opt-in test fixture under `tests/support/`;
no test bootstrap endpoint is present in the normal deployed API.

The deployed browser loaded Boreas and its leaderboard with no console errors.
Google login reached Google's real sign-in page. Completing a human Google/X login
and verifying the final return remains a user check; this is separate from the
successful real Auth-token/backend integration test.

## UI review branch — 3 October 2026

The UI pass retains the Source/VGUI panel style with a shared visual system for
the main menu, Settings, map picker, accounts, leaderboards and finish screen.
The visual pass itself leaves movement and ranked-board identities unchanged (the
subsequent capped-start rule change is documented below). Google uses its official
current sign-in mark; provider actions remain optional. The later guest-claim
flow below supersedes this pass's initial next-run-only sign-in prompt.

`GET /api/surf?action=run&runId=UUID` exposes the public name, map, server time and
splits of a visible verified replay on a current active board. It excludes private
upload paths and account data. `/?map=boreas&run=UUID` opens a run card with replay
playback. Sharing opens an editable X draft; it never posts automatically. Local,
practice and watched-route shares explicitly say what they are and link to the
map, rather than presenting a verified replay link. All displayed times round to
milliseconds consistently, including across minute boundaries.

For local review, run `npm run dev -- --port 4190` and open `/ui-review.html` for
sample finish, sign-in, leaderboard and sharing states. This gallery uses an
isolated fixture client; no accounts or records are created. It is not a production
build entry. The real playable preview remains `/`. Production deployment was
held for review; the user approved this release on 3 October 2026.

Validation for this pass: all 243 automated tests passed, as did 14 isolated
browser integration contexts and 22 UI checks. `npm run test:online:browser`
exercises auth handoff, submission, replay, cancellation and sharing against
fixture APIs; it does not complete a real Google/X login or publish a record.
With the dev server on port 4190, `npm run test:ui` checks the playable menu and
the isolated gallery, including keyboard focus and 390×740 / 800×480 layouts.
Its report and seven screenshots are written to `test-results/`. Override
`UI_BASE_URL` to use a different local server.

The production build's normal Boreas command replay completed in 00:39.495,
with checkpoint splits 00:16.594 and 00:32.681. Browser inspection found no
console errors. The embedded review browser cannot capture the mouse, so use
Chrome or Edge for manual surfing. New online UI flows were checked with fixture
APIs; their deployed integration still needs a preview check before promotion.
The review gallery is excluded from the production build.

## Capped ranked starts — 3 October 2026

The normal client profile, build catalog and trusted verifier now use
`RANKED_CONFIG` (`css-surf-capped-1`): auto bunnyhop enabled, unrestricted start
speed disabled. The existing Boreas-derived end-tick XY start cap is enabled;
see [the movement reference](REFERENCE.md) for its exact semantics and evidence
limits. Old `SURF_CONFIG` open-start witnesses remain replayable and unchanged.
They are rejected by the new ranked verifier. New local record keys and generated
board IDs keep the categories separate; old records must never be relabelled.

Preferences v3 imports v2 controls, sensitivity, view, audio and map preferences,
but resets the old default unrestricted-start flag to false. A fresh explicit
unranked opt-in persists. Settings and leaderboard panels explain the capped rule.
Guest messaging distinguishes eligible prepared runs from local-only finishes;
the guest-claim flow below permits authentication after an eligible finish.

Before deployment, seed the three new catalog board rows as described above and
retire the old boards without deleting their records. The approved release has
seeded the new boards without relabelling older records. Check the new boards
and a real submission on a preview before promoting the UI and rule changes.
Drain old-profile pending verification jobs before cutover; the new verifier
cannot finish those jobs under different rules. Replays and published times keep
their original identities. The unranked open-start option also preserves access
to existing local PBs by using the legacy configuration version.
The canonical Utopia fixture has a newly verified envelope/report for the capped
profile; its normal command sequence is unchanged. The prior cloud validation
file remains historical evidence for the previous deployment, not a cloud test
of these new board IDs. `tsx scripts/validate-classics.ts --ranked` regenerates
`fixtures/ranked-playability-results.json` for all three capped command routes
and exact 30/60/144/240 FPS schedule comparisons.

Local validation passed: 263 automated tests, 14 isolated online browser contexts,
23 UI checks, and the production build. All three capped routes complete, with
exact per-tick results at 30/60/144/240 FPS. No real account or database record was
created during this follow-up.

## Finish first, sign in to save — local review

The normal default-rules guest flow now requests a signed guest ticket before the
first movement command. A slow or unavailable service never blocks play: a run
started before its ticket is ready remains local, with honest finish messaging.
Finishing an eligible run stores its exact command replay and ticket in IndexedDB.
Google/X buttons commit an explicit save intent before leaving for OAuth. On return,
the finish screen and splits are restored, the ticket is claimed by the signed-in
account, and the existing immutable upload and server verification flow runs.
Only a verified server response upgrades sharing to a public replay link.

`POST guest-attempt` allocates no Auth account, database row or Storage object.
Its 24-hour HMAC proof binds a random attempt UUID, board identity and server issue
time. The signing key is domain-separated from `SUPABASE_SECRET_KEY`; no new secret
is needed. Treat the proof as a private bearer capability: it never belongs in a
URL, share link or log. Rotating the server secret invalidates unclaimed proofs.
`POST guest-claim` requires a real Auth user and matching `expectedOwnerId` before
claiming. The atomic database ledger binds that nonce to exactly one account,
including after account deletion, until the proof expires. Same-owner retries
return the same attempt; the upload window is not extended. A new claim grants
the ordinary 45-minute window. Registration time, separately from original issue
time, enforces the shared 1,200-attempt/hour quota.

The browser keeps one completed guest replay, bounded by the existing 8 MiB /
40,000-command limits. A newer finish can replace an unclaimed draft only before
the player has requested saving it. Authorized, owned and claimed drafts are
protected until saved or explicitly dismissed. IndexedDB transactions bind owner,
claim progress and conditional deletion to the attempt UUID so stale tabs cannot
overwrite another run. Unclaimed drafts expire with their 24-hour ticket; claimed
drafts remain recoverable for seven days, including when only verification remains
after the upload window closes. Expired entries are removed on the next access.
Storage failure stops OAuth navigation and offers a retry instead of silently
losing the replay. Cancelling login keeps the run available in Account.

Practice, open starts, changed movement rules, interrupted runs, expired/unprepared
tickets and watched replays do not become ranked through login. The browser's time
and splits are presentation only; server simulation computes the accepted result.
This is not evidence of human-only input. The original server verification and
anti-automation limitations still apply.

Release prerequisites: apply `20261003155331_signed_guest_attempt_claims.sql`, seed
the new capped-start boards, and validate before promotion. The schema and board
setup were applied after the user's release approval on 3 October 2026. The
browser integration suites use explicitly routed fixture services, not real Google
or X identities, and the SQL tests apply all migrations to local PGlite.

Local validation passed: 283 automated tests, 14 existing online browser contexts,
15 new guest-save browser contexts, 11 real IndexedDB scenarios, two actual-game
restored-finish scenarios, 26 UI checks, TypeScript and the production build.
The guest flow exercises the real Supabase PKCE client against intercepted fixture
Auth responses, asserts the uploaded gzip replay matches the retained commands,
and tests account changes, login cancellation, duplicate returns, lost responses,
expired upload windows, unavailable storage, and both protected-slot and retry
recovery. This does not claim a completed real Google/X account login on the new
deployment. `npm run test:guest:browser` runs the guest suites; its actual-game
checks need the dev server at `UI_BASE_URL` (default port 4190). Test reports and
screenshots are written under ignored `test-results/`.

A domain change does not migrate local site data: OAuth must return to the same
origin that stored the replay. Keep the existing origin allowed during a domain
transition and avoid redirecting an in-progress old-origin callback to the new one.

## Custom domain — 3 October 2026

`https://surfd.net/` is attached to the existing Vercel production project;
`www.surfd.net` redirects to it with HTTP 308, preserving paths and queries.
The original `surfd-five.vercel.app` origin remains available. HTTPS, all three
collision packs, the scripts, legal pages and records API were checked successfully.
The production deployment was not changed by attaching the domain. The UI,
capped-start and guest-save release was subsequently approved separately.

The user confirmed saving Supabase Site URL `https://surfd.net` and adding
`https://surfd.net/` to the redirect allowlist while preserving existing entries.
The agent could not independently read this setting: the connected database tools
do not manage Auth configuration and the browser dashboard was signed out.
Google and X still use the existing Supabase callback URL above. Public provider
website/privacy/terms links can use the new domain. Online accounts and times use
the same backend; browser-local PBs, settings and login sessions do not move across
origins automatically.

## Approved release checks — 3 October 2026

The guest-claim migration is applied, with RLS enabled and no anonymous or ordinary
authenticated table/RPC privileges. Only the trusted service can consume claims.
All three new board identities were inserted alongside the original boards; the
old boards are retired at cutover without deleting the existing historical record.
There were no pending/verifying jobs at the pre-release check.

Security advisors report the intentional server-only RLS configuration described
above, plus an existing [leaked-password protection advisory](https://supabase.com/docs/guides/auth/password-security#password-strength-and-leaked-password-protection).
The game's sign-in UI uses Google/X, not password registration. No authentication
settings were weakened for this release.

Creating a temporary real-cloud QA account and preview guard secret was rejected
by automatic approval review as outside the deployment request. Neither was
created, and no temporary helper is included in the release. Validation instead
uses the completed local/browser suites, live public endpoints, schema/permission
checks, and production runtime/browser inspection. The optional `cloud-smoke.ts
--guest` fixture is available for a separately authorized cloud-account test; this
release does not claim that new authenticated end-to-end cloud test passed.
Local and online records

Download this document

# Records and online support

Local records always work. Optional accounts and server-validated leaderboards are now implemented; see [online setup and validation](ONLINE.md) for deployment requirements and evidence. The notes below describe the local boundary and integrity requirements.

The three stable course IDs are `surf_boreas`, `surf_utopia_njv`, and
`surf_mesa_fixed`. Each course has a geometry/timing version. Records and replays
also carry the full movement configuration, including tick interval, auto-bhop,
start rules, and map-specific velocity limit. A map or movement change therefore
does not silently compete against an incompatible local personal best. Graphics,
audio, and the last-selected map are preferences, not record categories.

Ranked play now uses capped starts. Unrestricted start speed is an explicit
unranked local category; its old records cannot be submitted or relabelled as
capped-start times. Eligible guests can finish first, then sign in from the result
screen to save that run. A signed guest ticket must have been prepared before the
first command; login alone cannot make an unprepared or assisted run eligible.
The completed command replay is kept in this browser through login, then claimed
by the account and independently verified on the server. Sign in within 24 hours
of ticket issuance. Local personal bests remain available without an account.

New local best entries include `mapId`, `mapVersion`, `physicsConfig`, elapsed
time, ordered splits, and date. Existing Boreas storage keys remain compatible.
The local key's compact hash is only a storage convenience; it must not become
the sole identity or an integrity check for an online record.

`GameSession` owns authoritative simulation events and command recording without
depending on the renderer or DOM. A replay contains a declared initial state and
tick-indexed movement/buttons/view angles. It can be replayed in a server process
using the same map and configuration. Normal records are separate from practice,
restores, demonstration playback, focus/pause interruptions, and changed rules.

Online support authenticates the player and validates each submitted
replay on the server against pinned geometry/configuration and permitted initial
states. Derive elapsed time and checkpoint order there; do not trust browser
times, positions, local storage, or its `practice` flag. Store the complete
version identity and the replay digest with the result. A leaderboard can then
partition by map revision and movement rules while sharing the existing map
catalog and simulation. Migrated local times should be clearly marked unverified
unless their original command replays can be validated.

The imported maps/assets retain their original owners' rights. Check hosting and
redistribution permission before a public service release; this local build does
not confer those rights.
Independent KSF comparison

Download this document

# Revision review and independent KSF evidence

Reviewed 2 October 2026. This supplements the original validation report. The earlier statement that no CSS telemetry was available is superseded by the public replay described below. It does not establish whole-game or current-server parity.

## Requested play profile and controls

`DEFAULT_CONFIG` remains the researched manual-jump profile. `SURF_CONFIG` enables held-jump autobhop and unrestricted prestart hops under a different configuration/version, so records are separated. Gravity, acceleration, wish-speed rules, friction, jump impulse and simulation interval remain unchanged. Tests verify repeat jumps only from ground, identical jump impulse across successive hops, preservation of earned horizontal momentum, no automatic horizontal boost, and an unrestricted start after twelve prehops at 1,200 u/s.

No stamina or vanilla bunnyhop speed penalty was added. This is an explicit surf-profile choice, supported by the CSS-derived Momentum surf mode and the user's requested behavior, not proof of a live KSF plugin manifest. A first crouch jump in the KSF recording independently matches the implemented impulse/order. It alone cannot prove stamina behavior after repeated native CSS jumps. [CSS-derived jump implementation](https://github.com/momentum-mod/game/blob/9da88b97769e0f2306623946ebbcb5d0f919a1f0/mp/src/game/shared/momentum/mom_gamemovement.cpp).

Actions accept multiple physical keyboard codes, mouse buttons and wheel directions. Defaults retain Space and add Wheel Down for jump. One wheel event becomes one simulation-tick pulse followed by a release tick; another scroll during release is retained for the next press tick. Same-tick wheel events coalesce. Held Space continues to hold jump through wheel release ticks. `peek()` never consumes events; `sample()` is called once per simulation tick. Focus loss, release of Pointer Lock and binding changes clear pending input. Mouse angles remain immediate, using 0.022 degrees/count times sensitivity and no frame-duration multiplier.

Sixteen input tests and thirteen revision tests cover the revised behavior. Tick-indexed wheel inputs produce identical command sequences and terminal physics states at 30, 60, 144 and 240 render FPS, including extra HUD reads. This checks consumption and render independence; browser event dispatch time relative to a tick still determines which command receives a real physical event.

## Public Boreas telemetry

The KSF website publishes an unauthenticated [replay viewer](https://ksf.surf/replays/surf_boreas/replay_css_4060_0_712551_1763914843.rec) and [replay bytes](https://ksf.surf/api/replays/replay_css_4060_0_712551_1763914843.rec?game=66t) for `.x`'s 39.495121-second CSS forward-style run recorded 23 November 2025. The public viewer specifies 66.66666666666667 ticks/second, corroborating nominal 15 ms. The simulation uses binary32 `0.015` as documented in the reference.

The 121,036-byte recording has SHA-256 `989a61f3682ccbb04026561103e951c90b267c43aa9b09eb66fc6e2c4cdb4d15`. Its version-2 format is documented in [Crashfort ReplayViewer's frame structures](https://github.com/crashfort/ReplayViewer/blob/0341fea8ba85fbb7c3d352b4b5ddf704a659fd4d/src/rv_priv.inc). The fixture `fixtures/boreas-ksf-telemetry.json` contains exact decoded binary32 values and provenance. No viewer code was copied. The decoded layout is a 16-byte header, five 524-byte bookmarks, then 2,960 40-byte frames. Each frame includes buttons, feet position, pitch/yaw/roll and velocity.

| Event | Recorded frame | Notes |
|---|---:|---|
| Initial stationary state | 0 | Position (12587.87793, -12034.27148, 14736.03125) |
| First crouch jump | 74 | End-tick vertical velocity 289.9933777 |
| Timer start | 125 | Horizontal exit speed 350 u/s |
| Checkpoint 1 | 1231 | Bookmark stage 2 |
| Checkpoint 2 | 2303 | Bookmark stage 3 |
| Finish | 2758 | Bookmark stage 99 |

The 2,633 start-to-finish intervals equal 39.495 seconds at decimal 15 ms. The published time differs slightly, so these bookmark indices do not establish exact KSF sub-tick timing semantics.

This run includes a prestart jump and a 350 u/s exit. The 2013 announcement's 270 u/s prehop restriction must therefore not be treated as a universal present-day Boreas rule. Map-specific falling-start behavior or changed rules remain possible. The recorded start transition demonstrably clamps velocity to 350 after displacement, whereas the requested unrestricted browser profile deliberately permits higher starts.

## Command reconstruction and comparison

Independent one-step comparisons establish the recording's alignment: to advance state **i** to **i+1**, use **buttons from i** and **view angles from i+1**. Using next-frame buttons creates approximately 60 u/s errors at some strafe reversals; using current-frame angles produces a median velocity error of about 27.57 u/s in the examined air transitions.

Buttons reconstruct full held forward/back/side commands at magnitude 400, but the recording lacks actual analog command magnitudes. Source `CInput::KeyState` gives an initial key press half strength. The recording's first forward movement gains 15 u/s, matching command 200; assuming 400 incorrectly predicts 19.5 u/s. This is covered by the ground fixture. The browser currently applies full held movement immediately, so native fractional keyboard command generation remains a known input difference. [Valve keyboard command generation](https://github.com/ValveSoftware/source-sdk-2013/blob/b8cfb12c0e083a2ef5b2f9f9b50f3902fa034474/src/game/client/in_main.cpp).

The replay does not encode grounded state, active crouch hull, partial-duck timer, surface friction, exact native build, cvars or plugin versions. An IN_DUCK bit alone does not establish the active hull: blocked uncrouch and a ground-to-air transition can delay a hull change. Surface friction for an isolated air step is reconstructed from the prior categorization velocity, which precedes FinishGravity; use recorded vertical velocity plus half-gravity, not recorded end-tick velocity alone.

Comparison tolerances were set to **0.002 Source units** for position and **0.002 u/s** for velocity, allowing roughly two binary32 position ULPs near 16k coordinates and native float/trigonometric differences at surf speeds.

| Independent fixture | Steps | Maximum position error | Maximum velocity error | First tick outside tolerance |
|---|---:|---:|---:|---|
| KSF flat start and first crouch jump, equivalent floor at Z=14736 | 65 | 0 | 0.0000314568 | None |
| KSF isolated air transitions | 1672 | 0.00048828125 | 0.00088026154 | None |

Air steps are selected from recorded constant-gravity velocity and ballistic vertical displacement, excluding collision, hull-origin shifts, and the recorded start-zone speed cap. These are conditional one-step checks, resetting to each independently recorded initial state. They verify the tested air/ground formulas; they are **not a continuous full-route replay or a test of native ramp collision parity**. Contact-state error cannot be measured from this file because contact state is absent.

## Collision review

The BVH broadphase was compared with independent linear AABB overlap queries for 350 bounds and 400 queries, including exact boundary contact. Candidate membership and original order agree. Preserving original order protects collision-plane tie behavior. Analytic displacement tests verify a swept 62-unit hull cannot tunnel through thin terrain and can travel tangentially across a coplanar two-triangle seam without an invented impact.

The actual BSP/PHY geometry then allowed independent collision debugging. At ticks 1010, 1807 and 2395, adding the trace margin to every convex plane had manufactured a hit across disjoint corners: the swept hull left an edge plane before reaching the face. An additional unpadded interval check rejects those false convex intersections within the finite sweep. It preserves shallow VPhysics skin contacts when the outgoing edge lies beyond this tick, as at 906. This changes geometric hit selection rather than preserving speed artificially. BSP departure ticks 1173 and 2310 reject a brush when both endpoints remain outside a plane, even within the backoff margin. All five seam/departure regression steps agree within the unchanged .002/.002 tolerances. Tick906 now matches native velocity within .000864 u/s, but its contact fraction still produces a .00691-unit position difference, which remains reported.

Native frame2756 independently demonstrates a neutral uphill landing: movement stops at the first walkable contact plus .1 Z, horizontal velocity remains incoming, and vertical velocity becomes zero. This matches the eligibility and offset documented by [RNGFix's pre-tick incline correction](https://github.com/jason-e/rngfix/blob/9831d25e9f6747566a6adc72d75ae3fc671a656c/plugin/scripting/rngfix.sp). The explicit `inclineFix` setting reproduces both this landing and the next manual-jump-profile tick within .002/.002. Frame2757's upward velocity comes from walking up the slope; continuous IN_JUMP in the replay does **not** establish a new jump or global KSF autobhop. The requested browser autobhop remains a separate profile choice. Evidence of this behavior does not identify the installed plugin version.

The authored Boreas `player_speedmod` zone suppresses jump and multiplies movement frame time by .9999. Independent recorded gravity inside the zone corroborates this modifier. The authoritative server tick and timer remain unchanged; no extra acceleration or gravity ticks are introduced. See [map extraction evidence](BOREAS-IMPORT-RESEARCH.md).

## Complete native-route comparison

Run `npx tsx scripts/validate-boreas-reference.ts` to regenerate `fixtures/boreas-reference-validation.json`. It records the exact geometry SHA-256, complete configuration, source provenance and all 2,758 per-tick errors/contact predictions for two comparisons. Both use manual jumping plus the documented incline correction, authored no-jump effect and observed 350 u/s post-displacement clamp at tick125. They do not claim the user's intentionally different autobhop/unrestricted-start profile is identical to KSF.

| Comparison | Maximum position error | Maximum velocity error | First tick outside .002/.002 | Ticks outside |
|---|---:|---:|---:|---:|
| Independently initialized native state each tick | .006905340 at 906 | .003744595 at 2402 | 334 | 27 / 2758 |
| Continuous run from native frame0 and commands | .031625415 at 2755 | .006143667 at 2112 | 199 | 2537 / 2758 |

Continuous final position error is .011624434 units and final velocity error .003204201 u/s. The continuous run receives no recorded position or velocity after its initial state. It reaches the native finish location from reconstructed normal commands. Each mode reports 1,070 simulated collision ticks; native contact/ground flags are absent, so a contact-state error count would be invented. Timed-trigger completion is verified separately by the game-session route witness.

The isolated residuals are concentrated at BSP ramp contacts (334,535–613), shallow VPhysics contact906, curved VPhysics normals (2181–2408), and entry to the map's speed modifier (2641–2642). The contact differences are consistent with native float/trace arithmetic differences, but that explanation is not proven. For the modifier, the exact six-plane trigger begins hull overlap at frame2640, origin entry at2641, and native scaled gravity first appears in transition2642→2643. The current immediate hull-overlap rule acts two ticks earlier. General Source touch/event-queue timing has not been reproduced; shifting the authored bounds would hide this uncertainty. Neither group is hidden by loosening tolerances. The original .002 thresholds remain strict for both comparisons, so accumulated continuous drift is explicitly counted even though the final spatial error is small.

These results are strong evidence for this real CSS/KSF route and its physics/collision behavior. Remaining gaps are native VPhysics and displacement contact implementation, entity-I/O timing at trigger boundaries, keyboard fractional press/release magnitudes, exact native build/cvar/plugin versions, native grounded/duck metadata, detailed repeated-jump stamina rules, and exact KSF timer internals. An instrumented CSS build and experienced human comparison would still improve coverage beyond this single independently recorded run.
Boreas import & authorship

Download this document

# Actual CSS Boreas import

Research and extraction date: 2026-10-02. This replaces the earlier inferred Northline layout as the playable map source. It does not establish exact CSS engine equivalence.

## Source and authorship

The imported file is the **CSS** `surf_boreas`, not a CS2 port. The public [KSF/OuiSURF mirror index](https://main.fastdl.me/maps_ksfthings.html) lists the map with SHA-1 `9bd9daa0a23288c7e6f439fb7a899beade34a80b`. The [pinned download](https://main.fastdl.me/h2/9bd9daa0a23288c7e6f439fb7a899beade34a80b/surf_boreas.bsp.bz2) decompresses to 36,649,534 bytes, and its SHA-1 was independently checked. It is VBSP version 20, map revision 1040.

[OuiSURF's map collection](https://github.com/OuiSURF/Surf_Maps) supplies public archive links. The [Boreas workshop release by granis and Syncronyze](https://steamcommunity.com/sharedfiles/filedetails/?id=2424739354) identifies the CSS/66-tick original and links its CSS download; that older Drive link was not usable during research. [KSF's CSS map entry](https://ksf.surf/maps/surf_boreas?game=66t&mode=fw) supplies the target game/style context. The mirror copy is identifiable and reproducible without relying on a similarly named port.

Authorship is retained as Syncronyze and granis; the workshop lists both contributors. Map geometry, models, textures, and sounds retain their respective authors' rights. Public availability is **not** evidence of a general redistribution licence. No such licence was found in the archive README, workshop description, or packed file names. This project imports the publicly available map for the user's requested local playable version; it does not relicense those assets or claim ownership. Publishing the extracted asset bundle would require resolving the applicable redistribution rights. No permission question was needed to perform the authorized local research/import.

The Source SDK is a reference for binary layouts and mechanics, with its own [Source 1 SDK licence](https://github.com/ValveSoftware/source-sdk-2013/blob/master/LICENSE). The Python importers are newly authored; they do not embed the SDK. PHY layout cross-checks used [TAServers/PHYParser](https://github.com/TAServers/PHYParser), which is MIT licensed, and [Hona/bsp-to-glb](https://github.com/Hona/bsp-to-glb). Runtime movement was not substituted with another viewer's movement code.

## Reproducible import

Run with Python 3, from the project root:

```text
python scripts/import_boreas_collision.py /path/to/surf_boreas.bsp
```

The script also accepts the `.bsp.bz2`. It rejects a different SHA-1 so a changed map cannot silently inherit this map's record version. Output: `public/maps/boreas-collision.json`, map identity `surf_boreas`, version `bsp-9bd9daa0-v1`.

Importer and runtime geometry checks:

```text
python -m unittest discover -s tests -p test_bsp_import.py
npx tsx --test tests/boreas-map.test.ts
npx tsc --noEmit
```

The Python geometry suite passes seven tests and the TypeScript suite passes nine. The Python suite checks independent analytic rotations and tetrahedron intersections, exported convex invariants, trigger membership, terrain winding, and the KSF standing height. The TypeScript suite additionally exercises the actual runtime sweep from the authored spawn onto the deck, swept checkpoint fractions, and the empty southwest gap inside the finish's broad bounds. It checks a raw PHY vertex at byte offset 4848 of packed `ramp_c1.phy` against two authored prop transforms, including a non-cardinal yaw, and preserves the no-jump outputs and VPhysics collision provenance. This verifies the IVP-to-Source conversion without treating importer-generated expected positions as ground truth. The preselected standing-height tolerance is 0.01 unit; analytic trigger fractions and rigid transforms use 1e-8.

`scripts/bsp_common.py` handles Source's per-lump and game-child raw LZMA payloads. Source raw LZMA can omit the usual end marker, so the declared output length is validated instead of requiring the general-purpose decoder's stream-end marker. Static props use game-lump version 10 with a measured 72-byte record stride in this file. The pak lump is a standard ZIP containing 1,929 files.

Coordinates throughout the collision data are Source X/Y horizontal, Z up, feet origin. No renderer coordinate conversion enters collision. PHY coordinates use IVP metres and transform as `(x, z, -y) / 0.0254`, followed by the authored Source pitch/yaw/roll transform and prop origin.

## Actual map configuration and route

The map's `logic_auto` contains the following `OnMapSpawn` commands, preserving repeated entity output keys:

- `sv_airaccelerate 150`
- `sv_maxvelocity 5000`
- `sv_enablebunnyhopping 1`
- `sv_cheats 1`
- `mp_freezetime 0`

These establish **map-requested settings**, not the final live KSF server configuration: server plugins or cvar enforcement can override map commands. Gravity is not set by this map's spawn outputs. Tick interval is not encoded as a map setting; the separate movement reference and KSF replay research establish the 0.015-second target.

The map has 162 team spawn entities in an off-course room. Those are not the correct browser start. The room's teleporter targets the actual `info_teleport_destination`:

| Purpose | Source position | Angles |
|---|---|---|
| `tele_start` | (12768, -12048, 14870) | pitch 0, yaw 90, roll 0 |

The start is deliberately above the deck. Its imported PHY deck top is Z=14736; the independently downloaded KSF run begins standing at Z=14736.03125. This is a useful absolute coordinate and collision-distance cross-check, not a proof of whole-run parity.

The three-part route crosses the following authored triggers in order. These are broad bounds; runtime tests use the actual convex hull union, not these bounds alone.

| Trigger | Minimum X,Y,Z | Maximum X,Y,Z | Shape |
|---|---|---|---|
| `zone_start` | (12466,-12312,14736) | (13104,-11776,15264) | one box |
| `zone_cp1` | (-2560,10240,6912) | (-2304,13952,10496) | one box |
| `zone_cp2` | (5792,-16192,3040) | (6048,-14912,4448) | one box |
| `zone_end` | (6816,8192,224) | (11720,12816,2880) | union of two boxes |

The course travels from the high southeast start north through several descending curved ramps, then west through CP1. It bends south through the western mountain corridor and east along the low southern route to CP2, then returns north toward the finish. Exact ramp positions and orientations come from the BSP, rather than inferred screenshots.

There are 21 authored `trigger_teleport` entities, all targeting `tele_start`, plus one `trigger_hurt` near the finish. The reset volumes often contain three to eight separate convex hulls and oblique planes. Treating their broad AABBs as active reset shapes would reset players in valid gaps. The finish trigger likewise needs its two-box union. All 26 gameplay zones and full trigger/entity metadata are exported.

The map contains a `player_speedmod` named `nojump`, with spawnflags 4. [Valve's player.cpp](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/server/player.cpp) defines bit 2 as jump suppression: `ModifySpeed` with a value other than 1 disables `IN_JUMP`, while value 1 enables it. The same input sets the player's lagged movement value. [Shared ProcessMovement](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/shared/gamemovement.cpp) scales its saved frame interval by that value for movement, then restores the interval. Thus the shared SDK semantics are **jump-button suppression plus a tiny movement-time scale**, not an arbitrary velocity multiplier.

The actual late-course trigger is model `*57`, one six-plane box `(9280,800,256)..(13504,4800,2048)`, spawnflags 1 (clients), enabled at map load. It sends `nojump,ModifySpeed,0.9999` immediately on `OnStartTouch`. Its three distinct `OnEndTouch` outputs restore 1 at delays **0, 0.03, and 0.06 seconds**. This is an immediate restoration with two repeats, not a mandatory 0.06-second delay. Duplicate output keys are retained in `_pairs`; a dictionary-only parser would incorrectly keep only the last delay. The separate small start trigger `*56`, box `(12744,-12072,14734)..(12792,-12024,14954)`, restores 1 on starting, ending, and testing touch.

`noJumpZones` exports the actual `*57` hull, movement scale 0.9999, and all restoration delays separately from timing/reset zones. A local auto-jump assist should respect authored jump suppression. The requested unrestricted local start rules remain a separate user-selected configuration; the map's no-jump section is not a claim about stock KSF start restrictions.

The independent KSF recording supports that timing factor: frames 2640–2703 overlap the trigger; vertical velocity changes from -1066.5462646484375 at frame 2702 to -1078.5450439453125 at frame 2703. That 11.998779296875-unit gravity decrement agrees with `800 * 0.015 * 0.9999` under float32 rounding and disagrees with the ordinary 12-unit decrement. Frame 2704 leaves the box while still using the scaled interval; frame 2705 resumes a 12-unit decrement. This is specific external evidence for the authored movement-time modifier. The later landing at frame 2756/2757 is already far outside the box, so this no-jump trigger cannot justify suppressing that later landing's jump.

## Collision extraction

The import contains **178 solid BSP brush instances plus 148 PHY convex instances**, for 326 convex solids total. World and brush-entity membership is derived by walking each model's BSP headnode, leaves, and leaf-brush references. The contents mask includes solid, moveable, playerclip, window, monster, and grate contents. Compiled BSP collision planes are exported unchanged, including bevel planes; render triangles are not substituted for brush collision. Vertices/faces are reconstructed only for bounds, diagnostics, and shared display.

Static props are essential to Boreas. Of 1,587 static prop instances, only 11 are solid: the start deck and ten curved ramps. The pine trees, rocks, icicles, and nine straight ramp render props are marked non-solid in the map. The straight sections obtain their collision from BSP brushes; assigning all decorative models solid collision would create an incorrect course.

| Packed collision model | Solid instances | Convex hulls per instance |
|---|---:|---:|
| `ramps/ramp_c1.phy` | 3 | 16 |
| `ramps/ramp_c1m.phy` | 4 | 16 |
| `ramps/ramp_c2.phy` | 1 | 10 |
| `ramps/ramp_c2m.phy` | 2 | 10 |
| `details/dek01.phy` | 1 | 6 |

The importer reads the packed VPHY/IVPS compact-ledge tree and each original convex's indexed vertices. It retains the convex decomposition and constructs separating planes for swept AABB hull collision, including edge/axis bevels. All 148 prop hulls are explicitly tagged `collisionModel: "vphysics"`; compiled BSP brushes remain distinguishable so their engine trace paths can use evidence-supported differences in rejection/tolerance behavior. It neither tessellates the visual model into guessed collision nor replaces curved ramps with straight slabs. Model surface-property metadata is preserved; the curved ramp PHY files specify `ice`. Actual CSS surface-friction lookup and VPhysics tolerance behavior remain separate fidelity questions. The current exported movement friction defaults to 1; steep surf contact does not become a ground surface merely because a material is ice.

All **1,125 displacement surfaces** are decoded at their compiled resolution using the Source grid layout and checkerboard split described in [Valve's builddisp.cpp](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/public/builddisp.cpp). The high bit of `minTess` indicates surface flags. `SURF_NOHULL_COLL` excludes 59 surfaces from player collision; `SURF_NOPHYSICS_COLL` alone does not exclude a player hull. The exported set contains **129,728 nondegenerate collision triangles** after these flags and removal tags. The renderer and collision importer share the same generated vertex grids. Arithmetic at vertex construction is rounded to float32 deliberately.

BSP face loops are clockwise from outside. The collision export reverses displacement triangle winding so the conventional cross product gives the front normal. Face `side` must not cause a second inversion of `planenum`, which already points outwards. The complete triangle payload is kept separate so the runtime can index it spatially without bloating it into hundreds of thousands of full brush records.

## Remaining verification boundaries

- Extracting the exact map establishes geometry provenance, not parity with CSS's proprietary BSP/VPhysics collision implementation. Convex decomposition is preserved, while trace tolerances and contact ordering still require external comparison.
- Displacement grid geometry and authored flags are reproduced. Engine-specific edge ownership, stitching, triangle contact filtering, and start-solid behavior may still differ.
- Rotating rune brush entities are decorative/non-solid in this map and are omitted from player collision. General entity I/O is exported as evidence, not claimed to be a complete Source entity-system emulation.
- Water, particles, sounds, moving decorations, material proxies, and Source's full lighting renderer are separate from map traversal collision. Visual fidelity status belongs to the renderer report.
- KSF's authentic replay positions/velocities are an independent route and collision check. They are not a browser command-only proof of traversal unless the game reproduces them from commands without position/velocity injection.
- No direct CSS executable instrumented comparison or experienced human playtest was available during this extraction. Validation must retain that limitation instead of equating plausible motion with exact CSS/KSF equivalence.

Other investigated tools were [SourceUtils](https://github.com/Metapyziks/SourceUtils) (MIT BSP/WebGL export) and [Crashfort ReplayViewer](https://github.com/crashfort/ReplayViewer) (KSF replay format and Source-based playback). Neither tool's movement was adopted without review. A hidden creator-restricted s&box port was not needed or accessed; the public CSS BSP supplied the authentic geometry directly.
Rendering & visual limits

Download this document

# Boreas visual import

The current scene imports the actual locally supplied `surf_boreas.bsp`. It replaces the original procedural mountain scene. This is an independently written browser renderer for the map's geometry and packed assets; it is not Valve's renderer and does not claim pixel parity with CSS.

## Provenance and rights

- Original map credit: **Syncronyze**. The supplied map's wider provenance also credits **granis**; retain the map's original author and asset credits.
- Input: BSP version 20, SHA-1 `9bd9daa0a23288c7e6f439fb7a899beade34a80b`.
- Download provenance: [the matching FastDL BSP archive](https://main.fastdl.me/h2/9bd9daa0a23288c7e6f439fb7a899beade34a80b/surf_boreas.bsp.bz2).
- Generated map geometry, textures, models and lighting remain their original authors' work. Public download availability is not a permissive redistribution license. This conversion is for the user's local project; no permission to redistribute or publish those assets is asserted.
- The converter and renderer were written independently from format descriptions and mathematical behavior. No Valve source implementation was copied into them. The [Source SDK license](https://github.com/ValveSoftware/source-sdk-2013/blob/master/LICENSE) must not be represented as a general browser-game asset or code license.

Primary technical references: Valve's [BSP structures](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/public/bspfile.h), [studio model structures](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/public/studio.h), [optimized model structures](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/public/optimize.h), [displacement construction](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/public/builddisp.cpp), and [client sky rendering](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/client/viewrender.cpp). Shared SDK structures establish format behavior where applicable; they do not establish exact CSS shader behavior.

## Imported resources

| Resource | Imported result |
| --- | --- |
| Visible brush and displacement faces | 1,783, combined into 35 material/lightmap/sky batches |
| Displacements | All 1,125, full resolution, using the collision importer's shared grid and triangulation |
| Original static props | All 1,587, from 26 distinct model files |
| Studio model geometry | MDL v44/v48, VVD LOD 0, DX90 VTX strip groups |
| Original material images | 233 PNG images decoded from packed VTFs, including normal/detail maps and cubemap faces |
| Baked lighting | One lossless 2,048² RGBExp32 world-lightmap atlas and one original VHV vertex-lighting atlas |
| Total referenced images | 235, including the two lighting images |
| Sky | Original packed sky textures, scaled 3D sky geometry and sky props |
| Brush entities | Authored initial origin/angle transforms and render colors, including the purple finish decorations |

`scripts/import_boreas_visuals.py` creates `public/maps/boreas-visuals.json` and resources beneath `public/maps/boreas/`. It reads the local BSP path by default; pass a different BSP path as its first argument to reproduce the conversion elsewhere. Python requires NumPy and Pillow. `scripts/bsp_common.py` provides the common compressed-lump, entity, transform and displacement readers.

`src/view/bsp-renderer.ts` exposes `loadBspVisuals(slug)`, its compatibility alias `loadBoreasVisuals()`, and `createBspRenderer(canvas, data, map?)`. Geometry/image fetching finishes before renderer creation. Asset decoding never happens in a movement tick. Opaque props use conservative per-instance frustum culling and shared model buffers; translucent props retain spatial batches. The optional map argument supplies visible timer-zone markers.

## Camera and material treatment

Positions remain in Source units throughout export. The renderer's only axis conversion is `(x, y, z) → (x, z, -y)`. Source yaw 0 faces +X; positive pitch looks down. The supplied eye position and current mouse angles are used directly. There is no camera easing, banking, mouse filtering or speed-based FOV. A 4:3 horizontal Source FOV becomes vertical FOV through `2 atan(tan(horizontalFov/2) × 3/4)`; viewport aspect then determines widescreen horizontal coverage.

Brush UVs use the original texture vectors and dimensions. Displacement UVs interpolate their ordered base surface; displacement lightmap UVs stretch the authored luxel rectangle over the grid, as in `CCoreDispSurface::CalcLuxelCoords`. Seamless terrain uses world-coordinate triplanar sampling and the authored rock/snow alpha. Sky sampling reverses the sky-camera expansion for texture scale.

RGBExp32 light samples preserve their exponent. The shader decodes four neighboring luxels to linear values before bilinear interpolation; it never linearly filters the exponent byte. Props use their embedded VHV vertex lighting. Alpha-tested foliage clips the original leaf alpha, then writes opaque alpha to avoid browser compositing fringes. Packed cubemaps are used for reflective materials; `env_cubemap` props select the nearest packed probe. Rock detail textures retain their authored scale and modulation factor.

Fog uses the map's original color (232, 255, 254), start 500 and end 43,420. The default planar fog path is used. Source shrinks the sky camera and its fog ranges together; because this renderer expands sky geometry instead, it retains those original fog ranges. Sky rendering precedes the main world with a depth clear between them.

## Validation

Run `python scripts/validate_boreas_visuals.py` for asset integrity. The saved result is `fixtures/boreas-asset-validation.json`:

- 127,829 mesh vertices and 531,810 triangle indices are finite, in range and structurally valid.
- All 84,405 displacement vertices match the common BSP decoder exactly after float32 export and the documented sky expansion: maximum coordinate error **0 Source units**.
- All 1,587 original props are represented and all 235 referenced images exist.

This is an internal geometry/resource integrity check, not independent proof that every BSP format assumption or rendered pixel matches CSS. The movement validation and external CSS trajectory comparisons are separate deliverables.

With the development server running, `node --import tsx scripts/bsp-visual-qa.ts` launches headless Edge, renders four fixed inspection views and measures a short camera traversal. It uses an isolated visual scene and cannot move the gameplay player. Results are in `fixtures/boreas-render-results.json`; screenshots are `docs/screenshots/boreas-start.png`, `boreas-first-ravine.png`, `boreas-overview.png` and `boreas-finish-basin.png`.

The newer full-route renderer comparison at 1,600 × 900 reduced CPU submission mean from **0.497 ms to 0.264 ms**, p95 from **1.0 ms to 0.5 ms**, while retaining the original geometry. See [rendering performance](RENDER-PERFORMANCE.md) for GPU measurements, stable quality settings, before/after pixel comparisons, reproducible scripts, and limitations. These numbers describe this machine and test, not a guaranteed end-user frame rate, input-to-photon latency, or the complete simulation/UI frame cost.

## Remaining visual differences

1. Two stock game textures are referenced but not packed: `nature/dirtfloor005b` and `models/props/cs_office/clouds`. The missing secondary dirt layer falls back to the primary rock material. The missing translucent cloud surface is omitted instead of drawing an opaque white substitute.
2. Original diffuse baked lighting is retained, but Source's directional bumped-lightmap basis, SSBump lighting and exact vertex-light color conversion are not reproduced. HDR exposure/tonemapping and Source-specific lighting overbright behavior are not claimed equivalent.
3. Displacement alpha is retained, while blend-modulation textures and exact Source seamless sampling are approximated. Displacement normals are recomputed; Source's cross-displacement smoothing details can differ.
4. Cubemap reflections and tangent-space normal perturbations are approximations. Exact CSS reflection contrast, saturation, Fresnel, probe orientation and material shader permutations have not received pixel-level comparison.
5. Refractive ice and water use transparent reflected surfaces. Scene-color refraction, water reflection/refraction render targets and animated normal maps are not implemented.
6. Brush entities appear at their authored initial transforms. Rotating symbols, animated material proxies, moving decoration, dust/particles, laser beams and soundscapes are not reproduced. The original finish symbols are present but their animated effects differ.
7. Rendering uses full model LOD 0 and spatial/frustum culling, rather than Source's PVS, model LOD selection and displacement tessellation. This preserves collision-scale geometry but can differ in distant appearance and GPU cost.

No direct CSS screenshot/pixel comparison or CSS renderer telemetry was available for this visual import. Browser inspection establishes that the actual imported scene renders coherently; movement fidelity rests on its separate evidence.