Quick answer: Wall running is a state machine driven by surface detection and momentum. Bugs cluster at the transitions: entering when you should not, dropping mid-run, or exiting with wrong velocity. To debug them capture the surface raycasts, the movement state and its transitions, and the player velocity across the run. A buffered snapshot of detection and state turns a dropped or stuck wall run into something you can replay.

Wall running lives or dies on feel, and feel is the hardest thing to debug from a report. The mechanic is a tight state machine: detect a runnable surface, enter the wall-run state, preserve and redirect momentum along the wall, then exit cleanly into a jump or a fall. When it works it is exhilarating, and when it fails players notice instantly, a run that drops for no reason, a wall they cannot attach to, an exit that kills their speed or flings them off course. Because the failures are all about timing and surface contact, descriptions are vague. This post covers capturing surface detection, state transitions, and momentum so wall-run bugs become concrete.

Wall running is a state machine on a knife edge

At its core wall running is a small state machine: grounded, airborne, wall-running-left, wall-running-right, wall-jumping, with transitions gated by conditions like surface angle, player speed, input direction, and contact. The whole thing balances on continuous surface detection, usually raycasts or shape casts probing sideways for a wall of acceptable steepness. The mechanic feels good only when those detections are stable and the transitions fire at exactly the right moment. A flicker in detection or a mistimed transition is felt immediately as the run dropping or never starting.

The trouble is that surface detection is inherently noisy. Walls have seams, corners, decorative geometry, and varying normals, so a sideways raycast can hit, miss, or hit a wrong surface from frame to frame as the player moves. The state machine reacts to that noise: a single missed cast can kick the player out of the wall run, and a spurious hit can latch them onto a surface they should not be able to run. Almost every wall-run bug traces to detection noise or a transition condition that did not account for some edge of the geometry.

Capture the surface detection

The first thing to log is the detection state: for each frame around the event, the wall-probe rays and what they hit, the hit surface normal and angle, the distance, and whether that surface passed your runnable criteria. This is the input to the entire mechanic, so when a player reports a wall they could not run, the detection log usually shows the answer directly: the surface angle was just outside tolerance, or the ray missed because the player was a few centimeters too far, or it hit a decorative collider that was not flagged runnable.

Capture both rays when you support running on either side, and capture the moment detection toggled. A dropped run is frequently a single frame where the cast missed, perhaps at a window frame or a pillar, and the state machine treated that one miss as a reason to exit. Seeing the toggle in the log tells you to add hysteresis or a short grace period so a one-frame miss does not break the run. Without the per-frame detection record you are left guessing whether the wall, the ray, or the criteria was at fault, and they fix in different places.

State transitions and momentum

Log the movement state and every transition with its trigger and the conditions evaluated. A wall-run bug is almost always a wrong or missing transition: entering the state when the player should have stayed airborne, failing to exit when they ran out of wall, or exiting into the wrong follow-up state. Recording why each transition fired, the speed check, the input check, the contact check, lets you see precisely which condition was satisfied or not when the mechanic misbehaved, instead of inferring it from the visible result.

Momentum is the other half. Wall running is fundamentally about preserving and redirecting speed, so capture the player velocity going into the run, along the run, and out of it. The most common complaint after dropped runs is a bad exit, where the player loses their hard-won speed or gets redirected at the wrong angle. Logging the velocity at the exit transition and the impulse applied by the wall jump shows you whether momentum was preserved, killed, or misdirected. A run that feels bad almost always has a velocity log that shows exactly where the speed went wrong.

Common wall-running failure modes

The recurring bugs are detection flicker at seams and corners that drops the run; failure to attach because the surface angle, player speed, or approach angle fell outside tolerance by a hair; sticking to a wall the player wanted to leave because the exit condition was too strict; and bad exits that kill momentum or fling the player off line. Add inside-corner and outside-corner cases, where the wall changes direction and detection either loses the wall or latches the new face awkwardly, producing a jerk or a drop. Each shows a clear pattern in the detection and transition log.

There are also interaction bugs between wall running and the rest of the movement system. Coyote time, jump buffering, dashes, and ledge grabs all compete for the same input and contact signals, and a wall run can be interrupted or hijacked by another mechanic firing at the wrong moment. These are nearly impossible to debug without a state transition log, because the player only sees that their run ended weirdly, while the log shows that a ledge-grab transition stole priority. Capturing the full state history is what makes these cross-mechanic conflicts visible.

Setting it up with Bugnet

With Bugnet, a player who just got dropped off a wall mid-run can hit the in-game report button while it is fresh, and the SDK attaches the movement context you buffer: the wall-probe raycasts and surface angles, the state machine history, and the velocity through the run. The report lands in your dashboard with the detection and transition record already attached, so you can see whether a ray missed, a tolerance was exceeded, or a transition fired wrong. There is no need to coax a precise description of a fast, feel-based moment out of a frustrated player.

Wall-run bugs cluster around specific geometry, a particular corner, a window ledge, a too-decorative pillar, so the same spot drops many players the same way. Bugnet folds these into a single issue with an occurrence count, and with the level location or surface id as a custom field you filter straight to the offending wall. Seeing that one corner accounts for hundreds of dropped runs makes the priority obvious and points your level artist at the exact collider to fix, rather than triaging a pile of vague it-felt-wrong complaints scattered across your community.

Testing wall running and tuning the feel

Wall running rewards a deterministic test bench that runs a bot along every runnable surface in your levels: straight walls, inside and outside corners, seams, sloped faces, and the boundaries of your angle and speed tolerances. Assert that detection stays stable without flicker, that the state machine never enters an impossible combination, and that exit velocity falls within an expected range. Run it headless in CI so a tweak to the surface criteria or the player controller that reintroduces dropped runs trips the build instead of shipping to players who will feel it instantly.

Turn captured reports into fixtures by replaying their detection and state history and asserting the run now behaves. Add forgiveness in the shipping build too: a short coyote grace on detection misses, hysteresis so one bad ray does not break a run, and a clear priority order so competing mechanics do not hijack the state. The pairing of deterministic tests, real-report fixtures, and runtime forgiveness keeps wall running feeling fast and trustworthy, while ensuring the rare genuine bug arrives captured and reproducible instead of described as a feeling.

A dropped wall run is usually one missed raycast. Buffer the detection and state transitions and the run that broke becomes a replayable case instead of a feeling.