# 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.
