# Ambient traffic controller versus WebGL preview (r168)

This audit compares the preview's current traffic path with the routines and
assets recovered from the installed PC executable. It answers two separate
questions: whether the preview is reading race-line data, and whether it
reproduces the game's ambient driving controller.

## Route source: free-roam, not event race lines

The preview loads `freeroam-traffic-routes.json`, selecting the file for the
current city region (`webgl-city/viewer.js`, `loadTrafficRoutes`). The exporter
reads `RoutesFreeRoam*.bin`, chunk `0x34121`, which holds keyed route records
and ordered 56-byte waypoints. The separate event-racing route data is chunk
`0x34148` in `Paths*.bin`; it has 24-byte path points and race-route records.
The installed `PathsFreeRoam*.bin` files contain barrier chunks, not `0x34148`
race paths. Thus “the WebGL cars follow the racing line file” is a mistaken
description of the current source input.

That distinction does not make the preview retail-equivalent. It follows a
static free-roam route fragment as a kinematic approximation. It currently
does not run the retail actor's candidate selection, action stack, driver
controllers, or vehicle movement components.

## Controller path side by side

| Retail executable | Current preview | Evidence boundary |
|---|---|---|
| Ambient manager `0x00412be0` assigns class-2 candidates to definition slots using the active density column. `0x00412950` maintains a global active ceiling of seven, retires aged slots and attempts at most one new handle per update. | `refreshNearbyTrafficRoutes` chooses nearby, road-supported route samples in the camera corridor and limits the preview roster to the UI count and retail ceiling. | Static route files do not identify which live actor occupies a route/candidate, its manager slot, or its current phase. The preview's camera-facing roster is presentation logic, not the retail spawn selection.
| Class-2 setup can attach `AIActionDriveTrafficLane` through controller configuration. Its callback `0x004242d0` updates route state through `0x00420ed0` / `0x00420d40`. `0x0041d530` prunes/refills a bounded FuturePoint queue by scanning that actor's candidate pointers, phase, scalar weights and interval checks. | `sampleTrafficRoute` walks decoded `0x34121` waypoints. `sampleTrafficJourney` can follow the `transition_match_record_index` chosen by the retail static walker across reciprocal `0x34122` endpoints with a 3D join gap at most 2 m and aligned travel tangents. | Static exports still lack each actor's live candidate array, selected cursor and weights, so this continuity rule does not reproduce branch policy. The static match is only a preview candidate; runtime traffic can choose a different branch.
| The lane action's queue is consumed by `0x00416120`: first sample distance `clamp(15 + 0.75*abs(q) + 0.04*speed, 15, 30)`, then a second sample 8–12 m farther along. It writes a driver target and derives turn-sensitive control targets. The nearby `0x00405990` helper can slew a 16-bit driver heading by at most `360° * dt`. | `updateTrafficDriverPose` estimates `abs(q)` as the distance from the simulated actor to the first 4 m segment of its decoded static route queue, then applies the recovered lookahead formula with preview speed. If its direct movement step leaves the road triangles it shortens the steering target, down to 1 m, before holding. | The viewer now responds to route cross-track error, but the exact runtime FuturePoint queue, actor speed, target-to-steering filters, and throttle/brake/e-brake response are still unavailable. Its secondary heading sample begins at the first target and extends 12 m beyond it, matching the decoded sample placement; its output is diagnostic only.
| `AIActionObeyTrafficIntersections` can update phase/route state; `AIActionAvoidAvoidableAsTraffic` probes candidate routes and emits a four-channel context command before refreshing the lane queue. | No intersection priority, dynamic branch change, lane-change policy, or collision response is simulated. The viewer only rejects overlapping preview spawns and road-unsupported movement steps. | The avoidance action's four command channels are not named in the executable trace. Applying them as steering/braking without live values would guess their meaning. Candidate and phase inputs for the intersection action are also runtime state.
| `TrafficMover` callback `0x00408820` advances an owner using speed-like scalar `+0x18`, a pivot/arc branch, and body/owner state; it updates the transform and angular state. The scalar is dynamically adjusted from owner commands and coefficient tables, then clamped to `0..24.5865`. | The viewer uses a constant speed `7 + (routeKey % 6)` m/s and a point-mass yaw follower. | The constant is explicitly a preview choice. The executable's cap is not its ordinary cruise speed; the missing owner/controller values and coefficient-table interpolation prevent recovering a per-car speed response from route data alone.

### What is already implemented from the driving trace

The preview is not a raw waypoint teleport or event racing spline. It uses the
free-roam route's recovered forward/lateral frame, samples ahead of the current
pose, limits yaw rate using `0x00405990`, increments progress by accepted
travel distance, and constrains each movement step to exported road triangles.
When a direct long-lookahead step leaves the road, it tests shorter lookaheads
on the same authored path so tight bends do not freeze the car.
Its lane-centering fallback considers only direct route selectors 2–5 enabled
by the route header, and requires a positive offset to land on authored
`RDP_LANEA` pavement while clearing a sampled source-texture stripe. The lane
offset remains a preview heuristic: retail uses runtime FuturePoint subtype,
phase, candidate scalar and two weights that the static route export does not
contain.

For clear route continuations, the viewer also follows a `0x34122` link only
when it is the sole reciprocal endpoint record, the endpoint samples are within
2 m in 3D, and the best outgoing tangent agrees by at least 0.8. This keeps
cars moving across verified joins while leaving ambiguous junction choices
unresolved. The method is still only a static approximation: it cannot
reproduce per-car FuturePoint selection, intersection priority, or obstacle
avoidance until the live AI state and controller outputs are captured.

Applying those exact preview filters to the exported route/node tables accepts
293 continuations in L4RA, 66 in L4RB, 9 in L4RC, 6 in L4RD, 3 in L4RF, and 16
in L4RG. L4RH and L4RR have no route objects in their current free-roam exports.
These are geometric/reciprocal static joins, not counts of runtime branches or
traffic lanes.

## Body material boundary

The traffic GLB loader uploads each embedded image, retains that texture array
on its batches, and binds each material's authored
`pbrMetallicRoughness.baseColorTexture`. The ambient roster therefore keeps the
available source maps (`CARBOTTOM`, `WINDOW_TRAFFIC`, `TIREBACK`, and driver
maps on models that have them). In the current traffic GLBs, the untextured
body panels use `paint_body` with source geometry material hash
`0x19e0ecbe`; the installed ambient `TEXTURES.BIN` files are zero bytes. The
retail draw trace separately identifies a state replacement for material run
`0xd6d6080a`. These are different identifiers at different stages and should
not be treated as the same source texture key. The unresolved ambient fallback
is now tagged in GLTF extras and has identity base color; see
[`ambient-car-material-r168.md`](ambient-car-material-r168.md) for the current
asset audit and screenshot.

The retail paint handoff is partly recovered. Class-2 setup requests the
class-`0x3f` descriptor using key `0x253570af`, places the descriptor at the
live car's `+0x68c`, reads its selector at `+0x0a`, and looks up state key
`0x6ba02c05`. The `0x34605` child contains the indexed key/value map for this
state key: 98 of its 99 values resolve to named paint or vehicle-state
resources. Their raw payloads are exported in `traffic-paint-states.json`, but
the payload fields and selected ambient state are still unknown. The requested class-`0x3f`
descriptor and its `+0x0a` selector remain absent from extracted catalogs, so
the state selected for ambient traffic is unknown. The draw-time
color/texture/finish represented by the resolved state is consequently
unknown.
Vertex colors and normals are preserved in the exported meshes; no source
paint image can be restored by changing the WebGL bind path. Do not bind
player-car maps to traffic body material slots: those hashes/UV assignments
are not the retail ambient paint state.

I also checked the supplied ISO as a separate source. Its root contains
`Setup.exe` and `data2.cab` through `data4.cab`, rather than loose game
resources. `Setup.exe` identifies as Smart Install Maker 5.03 and asks for an
archive password; the data CAB files are opaque proprietary payloads, not
standard Microsoft CAB archives. This does not expose another paint texture
or descriptor in the ISO. The installed XP tree remains the usable source
unless the installer archive can be legitimately opened or the retail runtime
can be captured.

The current packaged Chrome frames make the result visible in context:
[`261-r171-full-traffic-assets-ready.png`](../webgl-city/review/images/261-r171-full-traffic-assets-ready.png)
shows an upright ambient car in the roadway after all 12 quota-eligible models
load; its body is plain white. [`262-r172-player-road-traffic-collision.png`](../webgl-city/review/images/262-r172-player-road-traffic-collision.png)
shows two similarly plain ambient cars ahead of the player. Their source window
maps are present, but the runtime paint state and the tire tread response are
not represented by the extracted ambient images.

## Actionable XP runtime capture

The static executable trace cannot supply the omitted per-actor arrays or
material state. The next useful capture requires launching the installed game
in XP free roam with the QEMU GDB stub enabled. Set breakpoints at:

```gdb
set architecture i386
set pagination off
target remote 127.0.0.1:1234
break *0x004242d0
break *0x0041d530
break *0x00416120
break *0x00408820
continue
```

For the local QEMU session started for this capture, the ready-made GDB script
is [`tools/capture_nfsu2_traffic.gdb`](../tools/capture_nfsu2_traffic.gdb).
Run `gdb -q -x tools/capture_nfsu2_traffic.gdb` on the host before starting the
game. It installs hardware breakpoints at the four routines above, records
registers, stack words, and controller/mover memory to
`/tmp/nfsu2-traffic-runtime.log`, and automatically continues execution.

At each stop, record the full registers and stack, actor pointer, timer, and
route key. Dump the actor's position/heading/speed (`+0x60..+0x68`, `+0x40c`,
`+0x430`), route cursor/phase, controller block at `+0x31c` (candidate
pointers and values, selected cursor, and FuturePoint XYZ/route refs), driver
target/commands (`+0x224/+0x228`, `+0x20c/+0x210/+0x214`), and mover fields at
`+0x0c..+0x18`. Repeat the same actor over several frames and through a
junction; a single breakpoint cannot reveal branch choice or response curves.

For paint, capture the resource manager at `0x008a2b68` after traffic setup:
the class-`0x3f` entry for `0x253570af`, descriptor selector `+0x0a`, selected
word list at manager `+0x14`, and the `0x6ba02c05` row in manager `+0x1c`. At
vehicle draw, capture owner state `+0x384` plus the replacement material-run
record/value for hash `0xd6d6080a`. A separate raw copy of the XP disk is now
booted at `/tmp/nfsu2-runtime-tools/xp-runtime-copy.raw`; the original disk and
its earlier overlay remain untouched. James was unlocked on the copy, but XP
stops at its product-activation/login flow before reaching the desktop. The
GDB stub is listening on `127.0.0.1:1234`, and the four hardware breakpoints
are armed; `/tmp/nfsu2-traffic-runtime.log` currently contains setup only. The
VM's VNC endpoint is local-only at `127.0.0.1:5901`. No live traffic or paint
snapshot is available until Windows activation/login lets the game run.

Detailed routine notes are in [traffic-manager-pseudocode.md](traffic-manager-pseudocode.md),
[traffic-lane-action.md](traffic-lane-action.md),
[traffic-car-avoidance-action.md](traffic-car-avoidance-action.md),
[traffic-mover.md](traffic-mover.md), and
[traffic-resource-streaming.md](traffic-resource-streaming.md).

## Packaged viewer check (2026-10-15)

The packaged viewer was opened in headless Chrome with WebGL enabled at
`http://127.0.0.1:8095/webgl-city/?debug`. The route source loaded successfully;
12 ambient body models were available, the preview's active ceiling was seven,
and five traffic cars were rendered on supported road surfaces. The observed
route keys were 450, 744, 741, 740, and 739. Chrome reported no page or console
errors. The browser image is `/tmp/nfsu2-free-roam-traffic-verify.png`.

This confirms the current free-roam route preview is operating, not that the
retail AI is reproduced. The unresolved runtime inputs remain each actor's
candidate list and selected phase/cursor, FuturePoint values and queue,
controller outputs, mover state/coefficient inputs, and the live branch choice
at junctions. The preview still chooses nearby traffic for presentation and
uses a kinematic route follower with preview speeds; it cannot derive those
values from `0x34121`/`0x34122` static exports alone.


## Packaged full-load drive and traffic audit (2026-10-15)

Chrome 150 opened the packaged L4RA scene at route 450, distance 7.2, with
WebGL enabled. The page reported `City scene ready`, all 251 nearby textures
uploaded, 101,011 nearby triangles, 832 routes, and 12 ambient body models.
With a five-second W hold, the player moved from `(-399.51, -524.50)` to
`(-428.97, -515.32)` and reached `12.26 m/s` (about 27 mph). The HUD showed
28 mph after the hold. Four traffic cars were rendered. All four sampled
positions had road support, and their model frame up-axis Z values ranged from
0.995 to 1.000. Route 587 moved about 20.3 m between samples over the same
five-second interval; the other initial route also advanced. No browser
console errors were recorded. The visual capture is review item 340.

This verifies that the packaged scene can be driven after its full texture
load and that the current traffic preview moves upright on road-supported
routes. The displayed cruise targets (7–12 m/s) are still synthesized by the
viewer; the retail actor's live FuturePoint candidates, speed target,
controller output, and mover state are not present in the static exports. Only
one ambient car is clearly visible in the captured camera view, and traffic
paint remains an unresolved neutral fallback.

## Current lane-action and motion fidelity review (2026-10-15)

The current ambient cars start from retail free-roam route records
(`RoutesFreeRoam*.bin`, chunk `0x34121`), not event-racing path chunks. They
are still a synthetic path follower rather than the retail traffic controller.
In `webgl-city/viewer.js`, `loadTrafficRoutes` reverses each route where needed
to match its recovered forward basis, then assigns phase
`(routeKey * 37 % 1000) / 1000 * route.length` and speed
`7 + (routeKey % 6)` m/s. `updateTrafficDriverPose` follows that static route
with point-target bearing, a 4 m static-chord proxy for retail queue deviation,
the retail 15–30 m first lookahead and second +12 m sample, and a road-triangle
shortening fallback. `retailRouteLaneOffset` chooses among available direct
selector-bank offsets 2–5, then checks recovered `RDP_LANEA` pavement and
source paint. These are constrained preview rules, not the retail lane decision
or steering output.

The executable path explains the gap. `AIActionDriveTrafficLane` callback
`0x004242d0` updates route/cursor state and refreshes the forward FuturePoint
queue through `0x00420d40` / `0x0041d530`. Queue population scans that actor's
live candidate-pointer array, applies its selected phase, route subtype,
candidate weights and interval checks, and appends resolved points.
`0x00416120` samples the queue to create driver targets and turn-aware control
inputs; the desired-speed handoff at `0x0041c380` also uses live candidate
values and a dynamic controller bound. The mover at `0x00408820` advances from
owner/command state and updates its motion scalar from owner fields and
coefficient tables. Static `0x34121` records preserve route geometry, direction
and corridor fields; `0x34122` records and walker `0x005d8760` provide endpoint
matches only. They do not contain the live actor-to-candidate assignment,
chosen phase, FuturePoint queue, or per-car junction branch. An endpoint match
cannot safely be made an unconditional turn.

Consequently static route data cannot make traffic output source-faithful: it
lacks the inputs consumed by the lane selector, action, driver, and mover. The
viewer’s route-derived lane hint and kinematic yaw remain approximations. The
numeric slew borrowed from `0x00405990` rate-limits an internal APsychoDriver
heading field; the executable does not establish it as a chassis-yaw limit.
No further steering or speed constants should be inferred from that helper or
from route keys.

The smallest useful runtime artifact is one identified class-2 actor sampled
over several updates on a straight and through a junction. At `0x004242d0` /
`0x0041d530`, capture actor position/heading (`+0x60..+0x68`, `+0x40c`), speed
(`+0x430`), route state (`+0x2c`, including byte `+0x10`), context phase
(`+0x308` and phase record `+0x30c`), and controller block `+0x31c`: queue
count, candidate count (`+0x04`), candidate pointers (`+0x08`), selected cursor,
route/waypoint references (`candidate +0x5c/+0x5e`), selector scalars
(`+0x3c..+0x50`), and candidate interval/weight fields (`+0x54/+0x58`). At
`0x00416120`, capture FuturePoint XYZ entries and route refs, driver target
(`+0x224/+0x228`), driver state (`+0x22c/+0x230`), and the controller's virtual
`+0x4c` bound. At `0x00408820`, capture mover `+0x0c..+0x18`, owner command
inputs (`+0x20c/+0x214`), frame delta, and the same actor's post-update
position/speed. Keep actor pointer, timer, route refs, and phase/cursor on each
sample so the series joins across callbacks. The capture script already arms
these callbacks; the XP guest remains at activation/login, so no live sample is
available yet.

The source and packaged viewer JS are byte-identical. No steering constants or
runtime code paths were changed in this review.

## Named default material fallback (2026-10-15)

Static analysis recovered the missing-handle fallback resource: the parsed
`GLOBALB.BUN` record `0x2c420d64` is named `DEFAULT` and is installed in
`0x007f399c` by loader `0x0048e070`; `0x0048f6a0` returns it when no mapped
state handle is found. The record and its raw 24-float payload are now
preserved in `traffic-paint-states.json`. This closes the identity/name of the
fallback record, but not the meaning of its floats, the optional class-`0x3f`
descriptor, or the selected paint for ambient traffic. It does not justify a
new WebGL color/finish choice.


### r271 viewer collision alignment

The player hit test now applies the same lane pose used to draw an ambient car. For a recovered traffic-driver pose it uses that pose's selected lane offset; for a static-route preview it uses the existing texture-gated route-lane hint. It then samples the road height at the resulting center. This removes the former mismatch where the model appeared offset from the point used by `playerHitsAmbientTraffic`. The lane selector and traffic decision logic remain approximate until the live XP state is available.

## Static-route replacement audit, revision r169 (2026-10-16)

The exported route files are not enough to replace the preview follower with
the retail traffic controller. `0x34121` preserves ordered route waypoints,
route phase-availability bytes, waypoint widths, and corridor-adjustment
bytes. `0x34122` preserves endpoint-match records for the static graph walker.
These records can describe possible geometry, but not the moving actor's route
cursor, selected phase, or selected cross-route branch.

The missing decisions are made from runtime state. `0x00420ed0` trials a
selector using the actor route-state pointer at `actor+0x2c`, its mode byte at
`+0x10`, phase/context state, and per-car candidate values; `0x00420d40` then
refreshes the forward queue through `0x0041d530`. That builder reads the
actor-specific candidate pointer array at context `+0x31c` (`count +0x04`,
pointers `+0x08`), selected cursor/phase state, candidate route/waypoint refs
(`candidate +0x5c/+0x5e`), selector scalars (`+0x3c..+0x50`), and interval /
weight fields (`+0x54/+0x58`). It appends resolved XYZ points to the bounded
FuturePoint queue. The static route exports do not serialize this per-actor
array or its selected state.

The queue consumer is a separate driver object: `0x00416120` reads actor
`+0x220`, queue `+0x10`, and speed-like actor field `+0x430`; it samples the
queue to write driver target `+0x224/+0x228` and turn-control state
`+0x22c/+0x230`, then produces command values. The desired-speed path at
`0x0041c380` also depends on live candidate values and a controller bound.
`TrafficMover` callback `0x00408820` consumes mover state at `+0x0c..+0x18`,
owner command inputs, and the owner's physics/component fields to update
position and motion state. None of those actor, queue, driver, command, or
mover values is part of the exported route records.

Therefore the available static data cannot provide a source-backed lane
change, intersection priority decision, or per-car junction turn. The viewer
continues to use decoded free-roam routes and its marked preview approximations;
the static `0x34122` match remains a graph candidate, not an unconditional
traffic branch. No motion code was changed and no new screenshot was captured.
The required runtime sample remains the class-2 actor and pointer chain listed
above; the isolated XP copy is currently gated at login, so collecting it
requires valid guest credentials or another authorized way to launch the game.

## r336 controller comparison and live Route 736 evidence (2026-10-16)

I rechecked the actual packaged viewer source and its live debug page before
considering a traffic-model change. `viewer.js` fetches
`../reverse-engineering/freeroam-traffic-routes.json`; `loadTrafficRoutes`
selects the region's `RoutesFreeRoam*.bin` export, reverses the waypoint array
when the retail route basis opposes file order, and feeds those `0x34121`
waypoints to `sampleTrafficRoute` / `sampleTrafficJourney`. The event-racing
`0x34148` point stream is not read by the ambient traffic path. The adjacent
`freeroam-traffic-nodes.json` records are decoded `0x34122` transition links,
not race line samples. So the ambient route geometry comes from dedicated
free-roam route data.

The route geometry alone does not define retail vehicle motion. The viewer's
`loadTrafficRoutes` currently assigns `speed: 7 + (routeKey % 6)` m/s. That is
an explicit presentation constant: on Route 736 it evaluates to 11 m/s. Retail
`AIActionDriveTrafficLane` instead gets its action ceiling from controller
virtual slot `+0x7c` (`1000.0` on the traced type-3 AICarController), then
forms the desired-speed handoff from live route-candidate values, the actor's
`+0x430` speed-like field and another controller bound. The static route JSON
does not contain those per-actor candidate scalars or controller values. The
retail ceiling is not a cruise-speed parameter, so replacing 11 m/s with 31.2919
or another value inferred from that ceiling would be wrong. See
[`traffic-lane-action.md`](traffic-lane-action.md#desired-speed-scalar-provenance)
and [`traffic-mover.md`](traffic-mover.md).

The intersection / stopping gap is similarly specific. Retail
`AIActionObeyTrafficIntersections` resolves an intersection ID from the
selected waypoint descriptor, validates the record's route references, and
queries runtime candidates/phase before emitting a context command. The static
`0x34122` walker only returns an endpoint-compatible record; it does not prove
that record is the driver's selected branch. Retail avoidance also emits a
four-channel tuple whose semantics are not identified. The viewer uses a
reciprocal, near-coincident, tangent-aligned static transition only as a
continuity preview; it has no source-backed stop line, right-of-way, signal
phase, or braking value. Adding a guessed stop or turn rule would claim behavior
the available data does not establish.

### Live packaged-page check

The already-running headless Chrome page at
`/dist/webgl-city/?debug&route=736&distance=107&radius=220&trafficModel=PARCELVAN`
reported `City scene ready`, one route candidate, one loaded model, one active
ambient car, and no reported page error. Its live `__nfsuTrafficDebug`
telemetry showed route 736, preview speed 11 m/s, lookahead 15.46 m, second
sample distance 12 m, road-supported state, and the explicit control label
`kinematic preview; retail APsychoDriver and TrafficMover are not simulated`.
`__nfsuTrafficConnectionDebug` reported 832 loaded L4RA free-roam routes and
293 accepted static continuations under the documented reciprocal-endpoint,
3D-gap, and tangent tests. Those are preview connectivity statistics, not
retail branch choices. The current sample had no outgoing continuation at
route 736's endpoint. A live frame is in
[`479-r336-ambient-traffic-live-state.png`](../webgl-city/review/images/479-r336-ambient-traffic-live-state.png).

No traffic steering, cruise speed, stopping, or intersection code was changed
in r336: decompilation and route data do not provide the runtime inputs needed
to set those behaviors faithfully. The next evidence that would unlock such a
change is a free-roam XP trace of one actor's selected route-candidate record,
phase/cursor, target handoff, actor speed, intersection-policy record, and
context command across a junction. The prepared capture points and VM state are
listed in the [traffic runtime capture section](#actionable-xp-runtime-capture).

## r337 static branch and orientation audit (2026-10-16)

I compared `buildTrafficRouteContinuations` with the recovered transition
walker and exported L4RA endpoint graph for a possible safe turn improvement.
The current preview requires a matching `0x34122` walker record, a reciprocal
endpoint record, a 3D join gap at most 2 m, and a unique best outgoing tangent
(dot at least 0.8 and at least 0.15 better than the alternative). These checks
are preview continuity guards; they are not the retail AI's branch policy.

For the concern that the tangent cutoff might reject a real sharp turn, I
enumerated route endpoints that have exactly one indexed successor record, a
single matching endpoint node, a reciprocal target endpoint, and a 3D gap at
most 2 m. There were 29 cases with a best outgoing tangent below 0.8. All 29
were same-route/same-waypoint self-transitions; none was a distinct sharp-turn
continuation. This makes the cutoff unsuitable as a general retail parameter,
but the recovered L4RA static graph gives no evidence to remove it in favor of
a new non-self turn. That change would introduce a branch behavior the static
walker does not prove.

The route and model orientation paths also have current source-backed coverage:
waypoint basis vectors are decoded from the retail route record and all
L4RA route records oppose increasing file order in the route audit, so the
viewer canonicalizes them before sampling while retaining original waypoint
indexes for links. Traffic GLBs separately store signed forward/up/side axes
for each BODY variant, and the renderer uses those axes. The prior packaged
orientation checks cover all twelve normal-quota BODY_A models on Route 450,
plus PARCELVAN BODY_B/C; all were upright and nose-aligned with the recovered
route frame. No source-backed orientation correction was indicated by these
data. See [the route basis audit](traffic-lane-action.md#candidate-point-scoring-0x4198c0)
and [the per-model orientation audit](traffic-orientation-wheel-audit-r291.md).

The remaining missing values are unchanged: route selection among multiple
runtime candidates, the driver's speed target and response, and intersection
priority/command application. Static route keys, geometric tangents, density
quotas, and body axes do not encode those live choices. r337 makes no traffic
motion or orientation code change.

## r453 ambient traffic paint selection table

The newly initialized ambient actor calls the retail random paint selector at
`0x006371e0`. It enumerates descriptors for logical class `0x3f`, selects a
uniform descriptor ordinal with the executable RNG, and stores the resolved
descriptor at actor `+0x68c`. The corrected r453 scan found standalone sibling
chunk `0x34607` before the resource-manager root. Its default class-`0x3f`
group pair is `(0x0377653b, 0)`, with no class-`0x3f` owner override; none of
the 390 class-`0x30` descriptors in GLOBALB matches that group hash. So this
random path selects no class-`0x30` paint descriptor for ambient traffic.
The separate explicit key `0x253570af` and its draw-time material state remain
unresolved. The corrected table and descriptor inventory are documented in
[`ambient-traffic-paint-selection-r453.md`](ambient-traffic-paint-selection-r453.md).

Accordingly, the WebGL ambient body material remains on its neutral fallback.
No guessed paint colors were added. A runtime capture of the eligible group
pair or of the selected descriptor is still needed before wiring retail paint
into traffic.
