Codex mirrors lateral yaw in -Z-forward 3D engines and validates arrival instead of rendered heading
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What issue are you seeing?
Codex produced and then propagated a convention-inconsistent world-direction-to-yaw formula across multiple independent movement/facing paths in a Three.js application.
The project has one already-working movement convention:
world up: +Y
avatar forward: local -Z
manual WASD: correct under that basis
For click-to-move/autonomous movement and several face-target paths, Codex independently used:
Math.atan2(direction.x, -direction.z)
But with Three.js Y-axis rotation, rotating local forward (0, 0, -1) by yaw produces:
(-sin(yaw), 0, -cos(yaw))
Therefore the convention-correct inverse mapping for desired world direction (x, 0, z) is:
Math.atan2(-x, -z)
The incorrect form mirrors the lateral component. The world-space velocity can still move toward the clicked target, while the rendered avatar faces the opposite lateral direction and appears to walk backward or sideways. Pure Z-axis travel can hide the defect, so destination/arrival tests may pass.
This was not one isolated typo. The same incorrect conversion was introduced or retained in four separate paths:
- click/autonomous movement heading;
- procedural face-target heading;
- companion-facing heading;
- humanoid-forward calibration.
The user explicitly reported the key differential diagnosis: WASD worked, while click/autonomous movement made the avatar face or walk backward toward targets. Codex should have treated the working WASD basis as the reference convention instead of applying independent sign guesses.
Minimal deterministic reproduction
import * as THREE from 'three';
const UP = new THREE.Vector3(0, 1, 0);
const LOCAL_FORWARD = new THREE.Vector3(0, 0, -1);
const desired = new THREE.Vector3(1, 0, -1).normalize();
const wrongYaw = Math.atan2(desired.x, -desired.z);
const wrongForward = LOCAL_FORWARD.clone().applyAxisAngle(UP, wrongYaw);
const correctYaw = Math.atan2(-desired.x, -desired.z);
const correctForward = LOCAL_FORWARD.clone().applyAxisAngle(UP, correctYaw);
console.log({
wrongYaw,
wrongAlignment: wrongForward.dot(desired),
correctYaw,
correctAlignment: correctForward.dot(desired),
});
Expected result:
wrongAlignment approximately 0 for this diagonal
correctAlignment approximately 1
For desired direction (+1, 0, 0), the incorrect mapping produces rendered forward (-1, 0, 0), giving a dot product of -1—the exact opposite heading.
What steps can reproduce the model failure?
- Use a Three.js scene whose avatar/model forward basis is local
-Zand whose manual WASD movement already behaves correctly. - Ask Codex to add click-to-move and face-target behavior around world
+Yyaw. - Give it both the working WASD implementation and the model-forward convention.
- Inspect whether it derives yaw from the actual rotation equation or inserts a remembered formula such as
atan2(x, -z). - Test a nonzero-X target, especially pure lateral and diagonal targets.
- Compare all three vectors while the avatar is moving:
- normalized velocity;
- normalized target delta;
- rendered visual forward obtained by rotating the declared local-forward basis.
- Observe that arrival may succeed while visual-forward alignment is zero or negative.
Corrected implementation and proof
The application repair was:
- define one shared direction-to-yaw helper bound to the explicit
-Zforward convention; - replace all four duplicated inline conversions;
- preserve manual WASD and camera semantics;
- add invariant tests that evaluate the rendered forward vector, not only root yaw or eventual arrival.
Focused movement/collision/procedure tests are now 33/33 green, including explicit checks equivalent to:
dot(normalized velocity, normalized target delta) > 0
dot(rendered visual forward, normalized velocity) > 0
dot(rendered visual forward, normalized target delta) > 0
The corrected source is being packaged for moving-runtime acceptance; stationary screenshots and raw rotation values are intentionally not treated as sufficient proof.
Expected Codex behavior
For spatial/engine code, Codex should:
- extract and state the coordinate contract before editing:
- handedness;
- world up;
- declared local forward;
- positive yaw direction;
- existing manual movement basis;
- derive direction-to-yaw from the engine's actual rotation equation or verify it with a round-trip property test;
- compare new autonomous movement against an existing working manual path such as WASD;
- centralize repeated spatial conversions rather than independently recreating sign-sensitive formulas;
- validate visual-forward-to-motion alignment for lateral and diagonal cases, not only final position or a root rotation scalar;
- stop making ad hoc sign edits when the user reports that one related movement system works and another is reversed.
Why this appears systematic
Snap's public Spatial Benchmark reports that all 16 evaluated models failed both its signed-yaw and left-strafe tasks. It identifies the same recurring patterns: wrong cross-product order, right vector returned instead of left, and flipped signed-yaw conventions:
https://eng.snap.com/spatial_intelligence
Related research also documents persistent left/right and 3D-orientation weakness:
- MirrorQA, ACL 2026: https://aclanthology.org/2026.acl-long.1879/
- LRR-Bench: https://arxiv.org/abs/2507.20174
This production incident is a concrete coding manifestation of that broader failure class: the model generated plausible engine code, propagated the wrong convention across related systems, and initially validated the wrong observables.
Impact
The immediate reproduction is a game/avatar movement defect, but the failure class applies directly to XR, simulation, robotics, drones, camera rigs, and other embodied systems. A left/right or yaw-sign inversion in an agent-generated controller can produce materially unsafe movement even when target-position checks appear correct.
Suggested Codex remediation
- Add signed-yaw, left-strafe, local-forward, and vector→yaw→forward round-trip cases to coding/model evaluations.
- Add a spatial-convention analysis step when tasks involve transforms, locomotion, camera direction, or facing.
- Reward generated tests that compare physical/rendered vectors and penalize tests that merely encode the proposed formula.
- Detect duplicate inline
atan2heading conversions and recommend a named convention-bound helper. - When existing WASD/manual motion is correct, require new autonomous/controller code to prove parity against that basis.
- Consider a high-severity warning or verification requirement before agent-generated spatial code is applied to physical/embodied control systems.
Environment
- Codex Desktop task on Windows 11
- Three.js / TypeScript / Electron application
- Observed 2026-09-01
- Exact Codex app build and model were not captured in the exported task receipt; they can be appended from the affected workstation without interrupting the active task.
Privacy
The production repository is private. This report contains a complete standalone mathematical reproduction and no private paths, assets, recordings, credentials, or proprietary source.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the deterministic Three.js reproduction and the stated working WASD basis. Review the Codex spatial-code evaluation or verification entry point; no repository file or test path is named in the report. Done means covering signed-yaw, lateral and diagonal movement, vector-to-yaw round trips, and rendered-forward alignment rather than arrival alone.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, three.js, typescript
- Domain
- ai, testing-qa, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100