# Beginner, Year3000, Ace, Legends and Eclipse visuals

These are conversions of the pinned original **CS:S** BSPs and their authored
assets. No artwork or map geometry was generated. Stock resources come from the
installed, licensed CS:S archives mounted read-only. The BSP identities and
original source pages are in `scripts/fixtures/new-maps-sources.json` and
`fixtures/{slug}-gamebanana-source.json`.

The author pages list CC BY-NC-ND 4.0 and permission conditions. Those notices
remain applicable to the original maps/assets. Neither this conversion nor a
public download is a grant of redistribution permission. This document records
local conversion/validation, not permission from the authors or native visual
parity.

## Sources and credits

| Map | Original credit | Pinned BSP SHA-1 |
| --- | --- | --- |
| Beginner | Kiiru | `812ca2188ed4ea7578d51268020d1363ea4155fa` |
| Year3000 | ArchAngel | `f65b3d9f872ef80860f6b84f6286586830e9d163` |
| Ace | Juxtapo; bonus by Syncronyze, skybox by komaokc, Silkroad textures | `f84f89ac3f1149673d21ab0264e243f7a4cf6006` |
| Legends | SintaxError | `aadafc6e05c4da062e05ff2c9bfa0d7aa087417d` |
| Eclipse | Paper-Cut; jail scripting by Turkey Eater | `d3c52f25690bd03d534f6fed5d04c52bfc345836` |

## Reproduction

For each slug, use its registry ID and author:

```text
python scripts/import_boreas_visuals.py node_modules/.map-imports/surf_beginner.bsp --slug beginner --map-id surf_beginner --author Kiiru --game-dir "PATH/Counter-Strike Source" --texture-format lossless-webp --compressed-textures
python scripts/audit-classic-five-visuals.py --game-dir "PATH/Counter-Strike Source"
python scripts/validate_new_map_visuals.py --slugs beginner,year3000,ace,legends,eclipse --game-dir "PATH/Counter-Strike Source"
python -m unittest discover -s tests -p "test*visual*.py"
```

Run `scripts/capture-classic-five-previews.ts` against a Vite development server
using `UI_BASE_URL`, default `http://127.0.0.1:4198`. This deliberately loads the
raw visual manifests so the inspection does not depend on catalog registration.
It renders through the production renderer, not a separate illustration tool.
Unused generated alternatives and superseded batches were removed from these
five asset folders after import; every URL referenced by the final manifests
is retained and verified. A new import can recreate those redundant files.

## Geometry and artwork integrity

| Measure | Beginner | Year3000 | Ace | Legends | Eclipse |
| --- | ---: | ---: | ---: | ---: | ---: |
| Rendered BSP faces | 8,680 | 10,155 | 8,170 | 26,548 | 11,719 |
| Original sky portal faces | 757 | 2,034 | 363 | 695 | 1,824 |
| Displacements | 6 | 0 | 60 | 0 | 0 |
| All geometry batches | 24 | 190 | 186 | 59 | 26 |
| Static props | 2 | 72 | 109 | 6 | 6 |
| Dynamic prop initial poses | 0 | 44 | 0 | 0 | 0 |
| Decoded VTF images | 30 | 301 | 441 | 151 | 33 |
| Native DDS alternatives | 21 | 41 | 19 | 11 | 19 |
| World lightmap pages | 1 | 1 | 1 | 0 | 1 |
| Import warnings | 0 | 0 | 0 | 0 | 0 |

Every decoded image matches its source VTF pixels exactly, including alpha.
Every DDS alternative preserves the original compressed blocks and mipmaps.
Geometry buffers have finite vertex data and valid index ranges. All static
props retain their original models, skins, transforms and scale, including
Legends' source 3D-sky scale. No model was omitted, assigned a fallback skin or
given a substitute texture. Year3000's 44 dynamic props retain initial poses.

These conversion checks share the offline VTF decoder with the importer; they
are **not** an independent test of Valve's shader output. Full reports are in
`fixtures/classic-five-visuals/integrity.json` and the five `*-source-audit.json`
files. The read-only stock resource counts are 50, 130, 15, 39 and 44 respectively.

### Trigger visibility correction

Year3000 and Legends exposed an existing importer mistake: their authored
trigger brushes use `SURF_TRANS` (1024), so surface flags alone made orange
`tools/toolstrigger` debug volumes visible. Their volumes are invisible in normal
Source play because [CBaseTrigger::InitTrigger](https://github.com/ValveSoftware/source-sdk-2013/blob/master/src/game/server/triggers.cpp)
applies `EF_NODRAW` when `showtriggers` is zero. The visual importer now excludes
brushes owned by `trigger_*` entities. This is an entity visibility rule, not a
blanket exclusion of tool materials: visible `toolsblack` stage walls remain.

Pinned BSP regression tests independently enumerate 576 Year3000 and 528 Legends
trigger faces with the translucent surface flag, and confirm their debug
material is absent from the final export. All five imports record hidden trigger
counts. The original collision/trigger volumes are unaffected. Existing map
bundles were not regenerated by this correction.

The existing Kitsune source tests still pass: visible black walls, authored sky
portal orientation and depth occlusion remain intact. Each new staged map also
retains its original sky-depth mesh. The nine visual Python tests passed.

## Actual browser inspection

Fifty start/midcourse views cover all seven Beginner stages, both Year3000
stages, eight Ace stages, five Legends sections and three Eclipse stages. They
loaded with no page or console errors. Authored room walls and sky boundaries
remain present; no stage-hiding substitute or invented wall was added.

The five lobby images are real 1280 × 720 screenshots of the final renderer,
with no image edits or added artwork. They show Beginner stage 4 under the
sunset, Year3000's first-stage ramps, Ace stage 5's paired stone ramps, Legends'
curved stone passage, and Eclipse's second-stage ramps against its eclipse sky.
Camera frames, original telemetry indices, renderer counts, screenshot names,
thumbnail hashes and load details are retained in the five `*-browser-views.json`
reports. Legends keeps its native camera pitch for review; its lobby thumbnail
uses the same native position with yaw 45/pitch 10 to show the curve clearly.
The other review poses clamp extreme pitch for readability. These are visual
camera samples, not command-replay playability evidence.

An integration review also exercised all 21 practice destinations for 150 neutral
simulation ticks. It found Beginner stage 7's original airborne spawn could land
exactly on the Z2640 plane and reset on the next tick. Only its practice travel
pose is now settled at Z2640.03125, with explicit practice stage 7; its actual
portal destination and stage spawn remain authored Z2784. All 21 destinations
then settled on ground without resets. The 15-map menu was inspected at widths
1440, 1280 and 390 with no horizontal overflow or console errors.
Browser retests confirmed stage 7 stays grounded in practice, and manual
practice HUD highlights the selected stage. Eclipse stage 3's marker now
projects onto the original deck at Z1881 rather than floating at the airborne
timer box's lower Z1968 plane; the timer box remains unchanged. Finish marker
floor clamping is unchanged. Reports are `practice-integration.json` and
`ui-integration.json` in the same fixture folder.

## Packed delivery and sustained rendering

The production packs retain all original exported bytes and request only one
texture representation. Actual requests were checked against the manifest;
the native run did not fetch the decoded alternatives, and vice versa.

| Map | Native transfer / requests | Decoded transfer / requests | Native peak draws / triangles |
| --- | ---: | ---: | ---: |
| Beginner | 8.38 MB / 4 | 10.13 MB / 5 | 25 / 27,038 |
| Year3000 | 6.83 MB / 5 | 8.66 MB / 5 | 158 / 51,348 |
| Ace | 6.22 MB / 5 | 7.30 MB / 4 | 162 / 50,164 |
| Legends | 2.70 MB / 4 | 3.34 MB / 4 | 53 / 74,459 |
| Eclipse | 5.32 MB / 4 | 6.13 MB / 4 | 26 / 46,817 |

Transfer figures include the compressed manifest and selected packs, use decimal
MB, and exclude gameplay collision data. Exact byte counts and content hashes
are in `fixtures/classic-five-visuals/packed-transfer.json`.

Six native eight-second camera traversals used the same 1280 × 720 balanced
renderer canvas, switching through all five maps before returning to Beginner.
They averaged 359.4–360.0 FPS on this machine, with p95 frame intervals of 2.9 ms.
The slowest individual interval was 13.9 ms on Ace. First/repeated Beginner
ended with identical 25 geometries, 24 textures and nine programs, checking
resource disposal after map switching. These are renderer-only local readings,
not physics performance, measured GPU memory, internet load times or a guarantee
for other devices. The browser appeared limited to about 360 FPS.

All five decoded fallback traversals also passed, averaging 359.3–360.0 FPS
with the same 2.9 ms p95 interval. A separate run disabled the browser's S3TC
extension: automatic selection loaded Beginner's decoded packs, zero compressed
textures, and the expected five requests. All twelve traversals completed with
zero browser/console errors. `performance-unsupported.json` retains that test.

Reproduce with `scripts/new-map-render-performance.ts`, the development server
URL in `UI_BASE_URL`, and `RENDER_CASES` containing the five map slugs with modes
`native` or `fallback`. Reports are retained as `performance-native.json` and
`performance-fallback.json` in the same fixture folder.

## Known native rendering differences

- **Water:** Beginner has two Water materials, Ace four, Legends 23 and Eclipse
  four. Their authored geometry/material inputs survive, but native reflection,
  refraction, underwater fog and scrolling water passes are not reproduced.
  Beginner's pool appearance is consequently simpler than the native shader.
- **Animation and effects:** Animated VTFs use frame zero; material proxies and
  texture scrolling are static. Year3000 has 18 rotating brushes, ten doors,
  four linear movers, 44 initial-pose dynamic props and 33 sprites. Legends has
  two rotators, six rotating doors, seven ordinary doors and three occluders.
  Eclipse has two rotators, one door, four movers, 20 sprites and six dust-mote
  volumes. These general entity animations/effects are not reproduced. Ace's
  four dust-mote volumes are also omitted. Some of these belong to jail/bonus
  scenery; main-course movement coverage is documented separately.
- **Shader layers:** Year3000's two UnlitTwoTexture security-screen materials
  and Eclipse's portal-ball material preserve their first texture but not the
  second-layer shader behavior. Beginner's Modulate binocular overlay is not a
  native Modulate shader. Full self illumination, authored environment masks,
  contrast/saturation parameters, directional bumped lighting and Source HDR
  exposure remain renderer limitations.
- **Legends lighting/fog:** Both original lighting lumps (8 and 53) are empty;
  there are no world lightmaps to recover. The exporter did not discard an HDR
  atlas. The source explicitly enables grey fog from 0 to 2,700 units with
  color `(192,192,192)`. That fog and the 16× 3D sky are retained, rather than
  inventing lighting or removing fog to produce a cleaner thumbnail.
- **Ace's displacement blend:** The authored WorldVertexTransition material
  retains both textures and displacement alpha. This map does not request a
  `$blendmodulatetexture`; no such map-authored layer was dropped.
- Native PVS/areaportal culling, arbitrary entity I/O, sprite glows and particle
  effects are not equivalent. Retained sky-depth surfaces prevent the stage
  leakage caused by treating sky portals as empty holes.

No complete native visual equivalence is claimed. The per-map audits retain the
exact shader parameters and affected entities so these limitations can be
investigated without changing original map artwork.
