Quick answer: Combo bugs are input sequence and timing bugs. Capture the recent input buffer with timestamps, the combo state machine node, and the active cancel windows with every report. With that timeline you reproduce a combo that dropped or misfired, instead of trying to recreate frame-perfect inputs from a player's description of what they pressed.

Combo systems live or die on timing, and that makes their bugs especially slippery. A player swears they input the combo correctly but it dropped on the third hit. Another reports the wrong move came out, or that a cancel did not register. The truth is buried in the exact sequence and timing of their inputs and the state of the combo machine when each input arrived, all measured in frames. A player cannot accurately tell you that, and you cannot reproduce a frame-perfect input by hand. To debug combo bugs you have to capture the input timeline and the combo state. This post covers what that capture looks like and why it is the only reliable approach.

Combos are timing-sensitive state machines

A combo system is a state machine where each move has windows during which the next input is accepted and cancels into the following move. Drop the input too early and it gets ignored or buffered wrong; too late and the combo ends and a fresh move comes out. Every transition is gated by timing measured in frames. This is why combo bugs feel random to players: a difference of two frames between a working and a dropped combo is imperceptible to a human but decisive to the system. The bug is almost always about when an input arrived relative to a window, and you need frame-accurate data to see it.

Because timing is everything, a combo bug report without timing is nearly useless. Knowing the player pressed light, light, heavy does not tell you whether the heavy landed inside the cancel window. The same button sequence works or fails entirely based on the inter-press timing. To reproduce a dropped combo you must recreate the inputs with the same frame spacing, which means capturing each input with a frame-accurate timestamp. Anything coarser, like wall-clock milliseconds without frame context, loses the very information that distinguishes the bug from correct play.

Capture the input buffer with timing

The central artifact is a rolling buffer of recent inputs, each tagged with the frame it was processed on and the raw button or direction. Capture the last second or two of input, which is plenty for any combo. With this you can see the exact sequence and spacing: light on frame ten, light on frame eighteen, heavy on frame thirty-one. Now you can check whether frame thirty-one fell inside the cancel window the second light opened. The input buffer with frame timing is to combo debugging what the seed is to procedural generation: it deterministically reconstructs the situation.

Capture how the input system itself processed each input, not just the raw presses. Many combo systems have an input buffer that holds a press for a few frames so a slightly early input still works. If that buffering is misconfigured, inputs get consumed at the wrong time. Record whether each input was buffered and when it was consumed, and the negedge and edge detection if you distinguish taps from holds. The gap between what the player physically pressed and what the combo logic consumed is where many dropped-combo bugs hide, and you only see it if you capture both.

Combo state and cancel windows

Alongside the inputs, capture the combo state machine: the current move, how many frames into it the character was, and which cancel windows were open at each input. A dropped combo is frequently a cancel window that closed a frame before the input arrived, or one that never opened because the previous move was interrupted. Seeing the windows and the input timeline side by side makes the failure obvious, where either one alone is ambiguous. The combo state is the context that gives the input timing meaning.

Special cases deserve explicit capture. Combos often behave differently on hit versus on block versus on whiff, because cancel windows open only on contact in many systems. A combo that works on a hitting opponent drops against a blocking one, and the player will report it as a random drop. Capture whether each move connected, was blocked, or whiffed. Also capture any resource the combo consumes, like meter or a juggle counter, since a combo that drops because a hidden gravity or scaling limit was reached looks identical to a timing drop from the player's seat but is a completely different bug.

Make combos deterministic and replayable

Combat logic should be deterministic given its inputs, and combo systems especially so. If you can feed a recorded input sequence back into the game at the same frame timing, you can replay any combo exactly. Build an input playback tool that consumes the captured buffer and drives the character through it frame by frame. Now a reported dropped combo becomes a replay you watch in slow motion, stepping frame by frame to find the input that missed its window. This is the single most powerful tool for a combat-heavy game, and it depends entirely on capturing inputs with frame timing.

Decouple your combat update from rendering frame rate so combos behave identically regardless of how fast the player's machine runs. Many combo bugs are really frame-rate dependence: cancel windows defined in frames at sixty frames per second behave differently if the simulation runs at a variable rate. Run combat on a fixed time step so a window is always the same number of simulation frames. With fixed-step combat and input replay, the captured timeline reproduces the bug identically on your machine, and you can fix the window or the buffering with confidence that you are seeing what the player saw.

Setting it up with Bugnet

Bugnet's in-game report button captures device and platform context automatically, which matters because frame timing and input latency vary by hardware and display. You add custom fields, or attach a small payload, containing the recent input buffer with frame timestamps, the combo state at report time, the cancel windows that were open, and whether moves hit or whiffed. Because the button snapshots state at the moment the player reports a dropped combo, you get the actual input timeline that failed, not the player's honest but imprecise memory of what they pressed.

Occurrence grouping reveals which combo failures are systemic. If a specific cancel between two moves drops for many players, Bugnet folds those reports into one issue with a count, exposing a window that is mistuned by a frame or two. Filter by the combo or move using a custom field to isolate the failing transition, filter by frame rate to confirm a timing dependence, and keep every input timeline in one dashboard. A flood of subjective combo dropped complaints, which are notoriously hard to act on, becomes a precise list of windows and buffering rules to adjust.

Tune the feel, lock in the tests

Combo feel is the soul of an action game, and it is tuned in tiny increments of frames. Once you can capture and replay input timelines, you can tune cancel windows and buffer lengths against real player data instead of guessing. When you fix a dropped combo, save the captured input timeline as a regression test that replays the inputs and asserts the expected move sequence comes out. Your test suite then encodes the exact feel you intend, so a later tweak to one window cannot silently break a combo that used to work. This is how fighting games and character action games keep their combat stable across patches.

Treat the combo system as a deterministic machine whose behavior is a function of inputs, timing, and combat state, all of which you can capture and replay. Once reports carry the input timeline, you build playback tooling, and you grow a combo test suite, the maddening category of it dropped and I definitely did it right complaints becomes ordinary, diagnosable bugs. Players feel the difference as combat that does what they expect, and you gain the freedom to refine the feel without fear, because every change is checked against the timelines of combos you have already promised to support.

Combos are frame-timed state machines. Capture the input buffer with frame timestamps and the combo state and dropped-combo reports finally become reproducible.