---
name: ferret-unreal-level-look
description: Use when a level ported from Unreal loads but looks wrong in Ferret (black or dark surfaces, smeared or wrong-coloured materials, black metal, flat light) and to check it against the original from the same cameras. Find the cause first; symptom-to-cause table inside.
---

# A ported level that looks wrong

## When to use
Black walls or posters, one floor piece darker than the next, red smears on pillars, metal like coal, tan instead of cream, everything too bright; or any parity check of a port against Unreal.

## Rule one
Find the cause before changing anything. Stacked guesses made a hall darker with every round and hid which change did what. Each symptom so far had one concrete cause (`reference/ue-level-look.md`).

## Steps
1. **Shoot the original** from a camera set (`reference/ue-parity.md`): `tools/ue-export/ue/capture_parity.py` in the running game, one shots folder per level. Without it you cannot tell a bug from the original (the far pillars really are red brick).
2. **Shoot Ferret** from the same cameras, stitch side by side, look at every view.
3. **Name the wrong thing**: `scene.pick` gives mesh and material (it skips thin instances: list meshes whose bounds cover the point too).
4. **Switch one source at a time** (sun, ambient, `environmentIntensity`, the normal map, the mesh itself) and read the pixel.
5. **Compare a wrong and a right mesh**: the compiled defines (`sourceMesh.subMeshes[0].effect.defines`: `LIGHTCOUNT`, `HEMILIGHT`, `REFLECTION`), normals against winding, determinant, UVs.
6. Fix in the right layer: the engine (`@ferret/assets`, `@ferret/levels`) for a general cause, `postprocess.mjs` for an export defect, the level's environment override for by-eye light.
7. Reshoot all views; write what matches and what differs into the port plan.

## Causes found so far
- Instanced meshes drawing with stale lights or shaders (sources out of the scene): fixed in `AssetCache`; if back, compare defines.
- A tile without the baked light (stale defines after a plugin was added): fixed in `AssetCache`; compare the define strings, not the fields.
- Baked light in the mirror image of the level: `bake-gi --mirror-x`; the grid must cover the level's bounds.
- Floors too bright with baked light: the reflection cube's diffuse light counted twice (fixed: with probes the cube only reflects); bloom is `environment.post`.
- Retune after every fix: earlier numbers were tuned against the fault.
- Baked lamps eating every light slot: `--no-lights`.
- Mirrored nodes: own mesh, winding and normals reversed by `postprocess.mjs`.
- Metal black indoors: `environment.reflection`.
- World-aligned materials smeared: `ue/materials.py` + `--world-aligned`.
- 16-bit source textures are linear: encode to sRGB.
- Helpers hidden in game, screens black until a video plays.
- Flat bright interior: baked light; until it is ported, sun down and `environment.ambient.direction` facing down with `ambient.ground` the floor colour, in the level's override.

## Check afterwards
Every parity view matches in layout and materials, light is close, and the remaining differences are written down with reasons.

## What usually goes wrong
- Blaming the browser: "only in Edge" was load order.
- Tuning light to hide a material bug, or the reverse.
- Fixing one view and not reshooting the others.
- A capture launcher that clears another level's shots, or runs with an empty script path.

## Files

- `reference/ue-level-look.md` — Symptoms of a wrong-looking ported level (black or dark surfaces, smeared materials, wrong colours, flat light) with their causes and fixes, and how to find the cause instead of guessing.
- `reference/ue-parity.md` — Comparing a ported level with the Unreal original from the same cameras: the camera set, the axis mapping, taking the Unreal shots in the running game, taking the Ferret shots, and reading the differences.
- `reference/api-levels.md` — every export of `@ferret/levels` with signature and doc comment
- `reference/api-levels-2.md` — every export of `@ferret/levels` with signature and doc comment
- `reference/api-assets.md` — every export of `@ferret/assets` with signature and doc comment
- `reference/api-assets-2.md` — every export of `@ferret/assets` with signature and doc comment
- `reference/commands.md` — 39 commands of these packages with their arguments
