Quick answer: Melee bugs are timing bugs. Whether an attack connected depends on which animation frame was playing, whether the hitbox was active that window, the attacker and target states, and any cancel or buffer in flight. Capture the current attack id, animation frame, hitbox activation state, and both fighter states per swing so a missed or phantom hit can be replayed exactly.
Melee combat is a negotiation between animation and collision that resolves dozens of times a second. A swing has startup, active, and recovery frames; a hitbox switches on for a narrow window; the target may be blocking, dodging, or stuck in its own animation. When a player reports that a hit did not land or that they got hit by an attack that clearly whiffed, they are reporting on one specific frame in that negotiation, a frame that is long gone. This post covers capturing the attack, hitbox, and animation state that makes melee bugs reproducible.
Why melee bugs are timing bugs in disguise
Every melee strike is gated by frame data. The animation drives a hitbox that is only active for a handful of frames, and the collision check must catch the target inside that window. Miss the window by a frame and a visually solid hit registers nothing. The reverse also happens: a hitbox that lingers a frame too long, or activates during a cancel, lands a hit the player never expected. These are not random; they are deterministic functions of timing that simply move too fast to see.
The symptom space is small but the cause space is large. A missed hit could be a hitbox that activated late, a target whose hurtbox shrank during a dodge, an attack that got canceled mid-swing, or a network rollback that undid the connection. Without knowing which animation frame was playing and whether the hitbox was active, you cannot distinguish these. The report tells you something felt wrong; only the captured combat state tells you why.
Capturing attacker and target state together
A melee bug is always a relationship between two entities, so capture both. For the attacker: the current attack id or move, the animation frame, whether the hitbox is in its active window, the buffered next input, and any cancel flag. For the target: its current state, whether it is blocking, dodging, or in hitstun, and the position and bounds of its hurtbox that frame. A phantom hit usually resolves the instant you see that the target was mid-dodge but its hurtbox had not yet shrunk.
Position and facing matter as much as state. Many melee bugs are really spacing bugs: the attack reached, but the target had already moved, or a turn-around happened a frame before the hit so the swing pointed the wrong way. Recording both entities' positions, facing, and velocity at the moment of resolution lets you reconstruct the spacing exactly. When you can see where both fighters actually were, arguments about whether a hit should have connected become geometry you can check.
Cancels, buffers, and the combo state machine
Combat feel comes from cancels and input buffering, and that is also where the nastiest bugs live. A player buffers an attack during recovery, the cancel window opens a frame early or late, and the resulting attack starts from the wrong state or skips its startup frames. These bugs are invisible without the buffer contents and the state-machine transition that fired. A captured queue of recent inputs and the transitions they triggered turns a baffling combo report into a clear trace.
Record the last several inputs with their timestamps, the state the character was in when each was consumed, and which transition each caused. When a player reports a combo that should not have been possible, or one that dropped unexpectedly, you replay the input sequence against the state machine and watch where it diverged. This is the difference between endlessly mashing in the editor hoping to feel the bug and reading exactly which frame the machine made the wrong call.
Reproducing a swing from captured state
With the attack id, animation frame, hitbox activation, and both fighter states recorded, a melee report becomes a deterministic scenario. You can place two test entities in the captured positions and states, advance the animation to the recorded frame, and watch whether the hitbox and hurtbox overlap. If the bug reproduces you have isolated it; if it does not, the captured state almost always names the missing variable, frequently a frame-rate-dependent step or an order-of-operations issue between movement and collision.
This also protects you from regressions. Frame data is fragile: a small animation retiming or a tweak to hitbox bounds can silently break interactions that used to work. Saved combat states from real reports make excellent regression fixtures. Re-running them after every combat change tells you immediately whether you reintroduced a phantom hit or shifted an active window, long before players have to rediscover the problem in the wild.
Setting it up with Bugnet
Bugnet's in-game report button captures game state automatically, so a melee report can carry the whole combat snapshot. When a player reports a hit that did not connect, you attach the attacker's attack id and animation frame, the hitbox activation flag, the target's state and hurtbox bounds, both positions and facings, and the recent input buffer as custom fields. The player writes one sentence about the swing; Bugnet preserves the frame-accurate state that lets you replay it, instead of relying on a description of something that happened in a few milliseconds.
Occurrence grouping means a recurring hitbox-timing bug shows up as one issue with a rising count rather than dozens of separate, confusing reports. You can filter by custom fields such as move id, target state, or whether a cancel was active to find the pattern fast, and any crash during combat arrives with a stack trace and device context. Everything, the swing data, the duplicates, and the crashes, lands in one dashboard you can triage by impact.
Making combat observable by default
The teams that ship clean melee combat treat the combat system as observable rather than mystical. They keep a rolling buffer of recent attacks and the state around each, so any report can reach back a moment and grab the swing that mattered. They wire the reporter to capture that buffer automatically, because no player will ever describe a hitbox activation window correctly, and they should not have to.
Build this in early, while your combat is still changing daily, and every balance or feel change becomes measurable instead of anecdotal. When a strike feels wrong you check the frame data the player actually experienced, not your assumption of it. That is how melee combat goes from a system you tune by vibes to one you tune by evidence, and how phantom hits stop surviving from build to build.
Melee bugs are frame-timing bugs. Capture the attack frame, hitbox window, and both fighter states per swing and a phantom hit becomes a replayable scenario.