antipattern

Use when

Testers say controls feel "off" or "unfair" without a clear reason.

What it is. The player pressed the button, the game did not honor it — swallowed, delayed, or resolved against the player’s own eyes. The action was correct; the machine disagreed.

Why it hurts. Every input is a promise. Break it once and the player stops trusting the controls; from then on they blame the game for their own deaths, and they’re right. Trust is the substrate mastery grows in — see pattern-fairness-and-trust. Poison it and no amount of content matters.

The smell

“I pressed jump!” said out loud, mid-run, in a flat betrayed tone. The tester isn’t confused about the rules — they’re certain they did the right thing and the game robbed them. That certainty is the diagnostic. Confusion is an onboarding problem; betrayal is an input lie.

How it happens

The lie is almost never one bug. It’s an accumulation of small honesties skipped:

CauseWhat the player experiences
Input polled once per frame, dropped between framesFast taps vanish
Action only fires while a condition is exactly trueJump one pixel off the ledge = nothing
Buffer window too tight or absentPre-pressed inputs eaten during animation
Hitbox larger than the sprite (enemy) / smaller (player)“That didn’t touch me!”
Visual lags physics by framesYou see contact after damage already landed
Coyote time absentRan off the edge, pressed jump, fell anyway
Priority resolves attack over jump on same frameYou get the move you didn’t ask for

Note the pattern: each is technically defensible and collectively unplayable. The engine is honest to its own timestep and lying to the human holding the controller.

The tell (check YOUR design)

If two testers independently say “unfair” and can’t point at a rule, assume the lie before you assume they’re bad. The corpus proof fixtures render from a headless SVG precisely so the judge sees what the player saw, not what the sim believed.

The fix

Honesty is engineered, not wished for. Grace mechanics turn a hostile timestep into a fair one:

The whole family is anti-frustration design: remove the undeserved loss without removing the challenge — pattern-anti-frustration, system-accessibility.

Twist seams

Seen in

Distinguish from

Verify / guard

Feel is proven, not asserted — see [[design/JUICE.md]] for the input-honesty and grace-window gates, and reference the small-flame precision platformer as the honest-controls floor. Guard rule: any death or miss must be reconstructable as fair from the replay alone. If a human says “unfair” and the replay agrees with them, the lie is in your input layer — fix it before handoff, per process-refine-and-handoff.

This module rendersthe repo's markdowndirectly — edit it there, it changes here.