# Fornax local visual import

The visual bundle converts the original CSS `surf_fornax` BSP and its authored
assets. The pinned source is 174,311,018 bytes with SHA-1
`2194b0e9d8153d75837dfb8e421d040c8072c700`, credited to iNooVa. No map artwork was
generated or replaced. The installed CSS directory is a read-only fallback
mount for ten original stock resources.

This work remains local. The [author's source page](https://gamebanana.com/mods/137780)
lists CC BY-NC-ND 4.0 and additional permission conditions. The conversion does
not establish permission to redistribute converted assets; see the separately
retained source/licence evidence in `fixtures/fornax-gamebanana-source.json`.

## Reproduction

```text
python scripts/import_boreas_visuals.py node_modules/.map-imports/surf_fornax.bsp --slug fornax --map-id surf_fornax --author iNooVa --game-dir "PATH/Counter-Strike Source" --texture-format lossless-webp --compressed-textures
python scripts/validate_new_map_visuals.py --slugs fornax --game-dir "PATH/Counter-Strike Source"
python scripts/audit-fornax-visuals.py --game-dir "PATH/Counter-Strike Source"
```

The shared importer and renderer were not changed for this import. No invalid
skin override is required. The bundle is `public/maps/fornax-visuals.json` and
`public/maps/fornax/`. Source audit and integrity evidence are retained in
`fixtures/fornax-visuals/`.

## Export and integrity

| Measure | Fornax |
| --- | ---: |
| Rendered BSP faces | 18,154 |
| Displacement surfaces | 434 |
| World material batches | 1,270 |
| Authored sky portal faces | 1,447 |
| Hidden entity faces | 6 |
| Static prop instances | 198 |
| Dynamic prop initial poses | 22 |
| Model variants | 158 |
| All geometry batches | 2,054 |
| Exported materials | 2,041 |
| Decoded texture images | 1,019 |
| Native compressed texture alternatives | 178 |
| Original environment cubemaps | 139 |
| World lightmap atlas pages | 1 |

All 1,019 images match their decoded source VTF pixels exactly, covering
93,390,848 pixels. All 178 DDS alternatives retain the original compressed
texture blocks and mipmaps byte for byte. The 2,054 geometry batches have valid
buffer lengths, finite vertex components and in-range triangle indices. All
198 static props retain the original model, origin, angles and scale. All 22
dynamic initial poses retain the original model and transform. All static prop
skin indices are zero; no props were dropped or assigned fallback skins.

These checks use the importer's decoders and do not establish independent native
rendering parity. Browser capture and sustained rendering checks are recorded
below.

The referenced bundle contains 142,787,795 bytes across both texture paths,
excluding the manifest and before transport compression. The decoded path is
78,955,595 bytes; the native path is 94,551,867 bytes. Both use 3,075 individual
asset URLs before pack generation. DDS files can be larger on disk than WebP;
their purpose is to preserve GPU compression. The compressed subset has
63,809,416 bytes of native mip data versus 342,359,976 bytes of corresponding
RGBA mip data, about 81.4% less. This comparison is not a browser/GPU memory
measurement. Packed transfer and browser performance are separate checks.

## Source artwork and transparency

The original `inoovasky` comprises six 2048 by 2048 images with identity UV
transforms. There is no `sky_camera` or fog controller. The importer retains
all 1,447 authored sky portal faces for the renderer's depth-only sky pass.
No artificial room hiding, walls or exposure adjustment was added.

The material inventory contains 1,242 LightmappedGeneric, 666 VertexLitGeneric,
122 UnlitGeneric, five Water and six UnlitTwoTexture materials. The audit records
95 materials with translucency, partial opacity or alpha testing, including
their decoded alpha ranges, cutoff thresholds and culling flags. Authored glass,
metal grates and the two-sided, alpha-tested stock tree material are retained.
The original diffuse lightmap atlas and available prop vertex lighting remain
in the bundle.

Two original resources are absent from both the BSP and mounted CSS archives;
searching those resources also found no matching basename elsewhere:

- `materials/saspatoon/space/metal/honeycombnormal.vtf` is referenced by three
  materials. Its diffuse honeycomb texture survives, while the normal texture
  is unavailable. This also affects static prop 128, the bonus ceiling model
  `models/surf_nebula2/b4/celling03.mdl`.
- `materials/models/surf_nebula2/fpsbramp2/glass_refract_02.vmt` is referenced by
  one mesh in static prop 89, `models/surf_nebula2/fpsbramp2.mdl`, at
  `(-9760, -11908, -15084)`. The mesh remains, but its material has the existing
  generic missing-material fallback. Its native appearance is unverified.

Both remain visible import warnings. No similarly named or newly created asset
was substituted.

## Known rendering differences

- The six UnlitTwoTexture forcefield materials preserve their first texture and
  additive/translucent flags, but their `$texture2` layer and Source shader/proxy
  behavior are unsupported. The browser's unlit flag currently applies only to
  UnlitGeneric, so these forcefields do not reproduce native lighting either.
- Five Water materials retain authored geometry and available texture data;
  Source reflection/refraction, underwater fog and water shader behavior are
  unsupported. Water and forcefield VTFs with 29 and 31 animation frames export
  frame zero. Scrolling ramp material proxies are also static.
- All 19 rotating brushes and both linear movers stay at their authored initial
  transforms. Eighteen of the 22 dynamic props are parented rotators, one is the
  end door, and one is a rotating signature; two arrow props are unparented.
  Rotation, parent animation and the end-door movement are not reproduced.
- Thirty `env_sprite` entities, 36 dust-mote volumes, one dust-cloud volume and
  two screen fades are not reproduced. General entity visibility/I/O and native
  PVS/areaportal culling are outside the visual importer.
- Original baked diffuse lighting is retained, but Source HDR exposure,
  directional bumped lighting and material response are not equivalent. The
  audit identifies 375 materials requesting self illumination, 15 SSBump
  materials and 13 explicit environment-mask materials. Complete self
  illumination, SSBump basis, those masks and authored reflection
  contrast/saturation/light-scale behavior remain renderer limitations.

The source audit retains exact material indices, original parameters, affected
prop transforms, sky material definitions and relevant entity data so these
limits remain reviewable. Native visual parity is not certified.

## Browser preview and rendering review

The lobby preview is an actual 1280 by 720 browser render of the industrial
main-route chamber. Its fixed Source-coordinate eye position is
`(1000, -3776, 7900)`, yaw 180, pitch 15 and FOV 90. The elevated camera shows the
paired ramps and illuminated walls together; it is a visual review camera,
not a claim that a player occupied this position. Geometry, lighting and artwork
remain unchanged, and the screenshot has no image edits.

`scripts/capture-new-map-previews.ts` contains this Fornax-only camera. Reproduce
with `UI_BASE_URL=http://127.0.0.1:4196`, `CAPTURE_MAPS=fornax` and
`CAPTURE_FRACTIONS=0.05,0.45,0.8`. The retained report also includes the authored
start and three native-recording camera positions. All five final captures
completed without browser errors. `fixtures/fornax-visuals/preview.json` pins the
preview image SHA-256 and complete camera settings; `browser-views.json` records
the views and renderer counts. The full-quality review capture is
`docs/screenshots/new-maps/fornax-preview.jpg`; the lobby image is
`public/previews/fornax.jpg`.

The packed native, decoded fallback and repeated native texture paths each
completed an eight-second camera traversal in the same browser canvas, using
1280 by 720 balanced quality. This animates the camera along the original native
recording and does not run or certify player physics. Exact selected pack URLs
were asserted, including rejection of downloads for the other texture path.
No page or console errors occurred.

| Texture path | Average FPS | p95 interval | Longest interval | Local preparation |
| --- | ---: | ---: | ---: | ---: |
| Native | 359.7 | 2.9 ms | 5.7 ms | 716 ms |
| Decoded fallback | 356.6 | 2.9 ms | 5.7 ms | 1,774 ms |
| Native repeat | 357.9 | 2.9 ms | 5.6 ms | 923 ms |

Peak sampled work was 1,451 draw calls and 214,121 triangles. First and repeated
native rendering ended with exactly 2,125 geometries, 321 textures and 25 shader
programs. Those matching counts are a resource-disposal regression check, not a
measurement of total browser/GPU memory. The fallback ended with 329 textures;
decoded textures are prepared differently. These results reflect this machine
and its apparent 360 FPS limit, not a device guarantee. Preparation uses a local
development server and is not an internet download estimate.

| Packed visual transfer, including manifest | Bytes | Requests |
| --- | ---: | ---: |
| Native | 52,013,837 | 25 |
| Decoded fallback | 65,344,972 | 21 |

Exact output is retained in `fixtures/fornax-visuals/performance.json` and
`packed-transfer.json`. Reproduce with `scripts/new-map-render-performance.ts`,
`UI_BASE_URL=http://127.0.0.1:4196` and
`RENDER_CASES='[["fornax","native"],["fornax","fallback"],["fornax","native"]]'`.
