Game feel
Context
The term was fixed by Steve Swink in his book "Game Feel" (2008): the sensation of controlling a virtual object in real time — something that cannot be reduced to rules but that the player feels in their hands. The canonical examples are Celeste and Mario: their jumps feel "right" not because of the movement formulas but because of dozens of small things tuned around them. The motto of the craft is "juice it or lose it": without a feedback layer a technically correct mechanic reads as dead.
The key idea an engineer has to accept: what the simulation does and what the player perceives are two different things, and game feel lives precisely in the gap between them.
The mechanism
Game feel is assembled from two families of techniques: input forgiveness and feedback.
Input forgiveness — fair controls without explanation
- Coyote time — the player is still allowed to jump for ~5–6 frames after walking off the edge of a platform. The player "knows" they pressed in time; the code forgives the mismatch between intent and reaction.
- Jump buffering — a jump pressed a few frames before landing still fires at the moment of touching the ground. Without a buffer the early input is lost and the game feels "deaf".
- Variable jump height — jump height depends on how long the button is held: release early → the upward velocity is cut (a lower jump), hold → higher. The basic platformer control the player "feels in their thumb" (there is a toggle for it in Lab 09).
Neither technique is explained to the player — they simply feel that "the controls are fair". That is the illusion of fairness: a concession disguised as responsiveness.
Feedback — selling "weight" and the event
- Hit-stop — freezing gameplay for a couple of frames at the moment of impact: the brain reads the pause as "mass met mass", and the hit gains weight.
- Screen shake — camera shake as a tactile accent on an explosion or a hit.
- Particles — dust under your feet, sparks, splashes: the visual echo of an event.
- Squash-and-stretch — deformation on acceleration and landing; the first of Disney's 12 principles of animation, carried into real time.
- Camera lerp / lookahead — the camera is not glued rigidly but catches up to the target with a delay and looks ahead along the movement.
The common denominator of the whole stack is separating "what the simulation does" from "what the player perceives". The simulation stays honest and deterministic; the feel layer lives on top of it and lies exactly as much as the sensation requires.
The math of timing
Why a "forgiveness window" is needed at all comes down to frame arithmetic. The budget of one frame at 60 fps:
Human reaction time is on the order of 200 ms. In frames that is:
So about a dozen frames pass between "I see the edge" and "my thumb pressed" — which is why a forgiveness window of around ~10+ frames feels not like a cheat but like compensation for the player's physiological delay.
The second basic feel formula is camera smoothing (lerping toward the target every frame):
Convenient, but tied to frame rate: the same k at 30 and at 144 Hz gives a different catch-up speed. The frame-rate-independent variant makes the coefficient a function of dt:
Why exactly that is in the deep end on the math.
🕹 Games to play — and what to notice
Game feel cannot be read — you catch it with your fingers. Four platformers, from a single basic knob to a whole stack of sensations; for each, what is tuned and what to notice hands-on (simple to complex).
Where it all started. Jump height depends on how long you hold the button (hold and you go higher, release early and the upward velocity is cut) plus inertia: Mario neither starts nor stops instantly. One or two knobs, but they are what makes the controls tasty — without them the jump is dead, at a fixed height.
🎮 Play: any Mario (SMB or Odyssey). Make two jumps in a row — a short tap and a held press: the height differs (variable jump). Run and turn sharply — Mario slides on inertia rather than snapping to zero. Those are the two most basic feel knobs.
The benchmark of modern game feel, documented by the developer herself (Maddy Thorson). The "forgiveness" stack: coyote time (a jump ~0.1 s / ≈6 frames after leaving the edge), jump buffering (a press before landing fires on the frame of contact) and corner correction (bump your head on a corner and the game nudges you sideways past it; clip a corner with a dash and it lifts you onto the ledge). All of it fudges in the player's favor just enough to feel responsive rather than magnetic.
🎮 Play: Celeste (or the demo). Jump off an edge deliberately late — coyote time saves you. Jump right against a low ceiling in a corner — notice how you get nudged past the corner (corner correction) instead of bonking and falling. Turn on Assist Mode and you will see the game already forgives; assist only amplifies it.
The opposite pole: minimum concessions, maximum responsiveness. The controls are so direct and grippy (fast acceleration, sticky walls) that a death always reads as "my fault". The key is the instant respawn: zero loading between attempts, so the feel is present on every one of hundreds of deaths rather than once a minute.
🎮 Play: Super Meat Boy (demo or full). Die 20 times in a row on one screen and notice that there is no pause between death and the next attempt — that is part of the feel, not a UX detail. Press against a wall — instant grippy contact and a bounce, with no mushy lag.
Feel extends beyond movement into combat. A nail strike gives hit-stop (a micro-freeze on contact → "mass met mass") and knockback (the recoil pushes you too), while striking downward onto an enemy or a spike gives a pogo: a bounce upward that turns combat into platforming. Plus screen shake and particles. The same stack, applied to fighting.
🎮 Play: Hollow Knight (demo). Hit an enemy point-blank — feel the micro-pause of the strike (hit-stop) and the recoil. Jump onto an enemy or spikes and strike downward — you will bounce (pogo); try hopping along a chain of spikes on your nail. Feel is not only about jumping.
Deep end · design: why forgiveness works and Disney's 12 principlesskippable
Perceptual fairness: a ~200 ms reaction time
The player is not controlling in real time — they are controlling with the lag of their own nervous system (~200 ms, ~12 frames at 60 fps). Without forgiveness every "but I pressed it!" is true: the intent was on time, the motor response was late. Coyote time and jump buffering close the gap between perceived (when the player decided) and actual (when the input arrived). Hence the illusion of fairness: the game feels responsive precisely because it secretly plays along — but within the bounds of human delay, no more, otherwise it feels magnetic.
Disney's 12 principles in real time
Classical animation is a ready-made vocabulary of feel techniques translated into interactivity:
- Squash & stretch — deformation of mass under acceleration and landing; sells springiness and weight.
- Anticipation — a micro wind-up before an action (a crouch before a jump) — the eye gets time to "read" the intent.
- Follow-through & overlap — limbs and cloaks catching up with the body after it stops; removes the "robot".
The difference from film: in cinema the animator owns the timing, in a game the player dictates it — so the principles become procedural (squash as a function of vertical velocity, anticipation as a couple of frames before the start).
The juice stack as a checklist
A practical habit: take the raw mechanic and run it down the list — input forgiveness (coyote, buffer), hit feedback (hit-stop, shake), motion (squash, anticipation, follow-through), ambient (particles, camera lerp/lookahead, sound). Each item is added behind its own toggle so you can turn it off and feel its contribution (which is exactly what Lab 09 does).
Deep end · math: frames↔ms and geometric camera dampingskippable
Frames ↔ milliseconds
All feel timings are easier to keep in frames but should be measured in milliseconds (otherwise "6 frames" at 144 Hz is a different physical duration). The conversion:
A forgiveness window of ~10 frames ≈ 167 ms — less than reaction time (~200 ms), so it compensates for motor delay without tipping into cheating. Hit-stop is specified as N frames (typically 2–6): the gameplay tick freezes for N frames and the strike reads as a collision of masses. Too large an N and the game feels sticky; too small and there is no effect.
Lerp as geometric damping
The naive per-frame lerp p ← p + (target − p)·k leaves an error after m frames of:
This is a geometric progression: the error falls as (1−k)m. But m counts frames, not time. At 144 Hz there are ~2.4× more frames in the same second than at 60 Hz, so (1−k) is applied ~2.4× more often — the camera catches up noticeably faster. The same k → different feel at 30/60/144 Hz. That is the bug in the naive lerp.
The frame-rate-independent form
The fix is moving to a continuous model: damping is an exponential of time rather than of the number of steps. Substituting the real dt:
Now the per-step coefficient depends on dt, and over the same duration the error falls identically at any frame rate. The same trick applies to any exponential smoothing (velocity damping, fades), not just cameras.
Deep end · engineering: juice without losing determinismskippable
Feel breaks a naive game loop more than you would expect. What to keep in mind:
- Hit-stop freezes gameplay, not the UI. The freeze should stop the physics tick and the simulation but not the presentation layer: menus, the cursor and sometimes the particles themselves keep living. If you freeze the global timescale everything stops, the interface included — which looks like a freeze or a bug. Separate feel effects from the simulation tick.
- Determinism. Coyote, buffer and hit-stop change the timing of inputs, and in a networked or replay game that is part of the state. Count the windows in frames of the fixed tick (not in real seconds) and store the counters in simulation state — otherwise replays and netcode drift apart. Keep screen shake and particles purely on the presentation side: they must not affect the simulation.
- Frame-rate-independent timing. All feel constants live in milliseconds/seconds and get multiplied by dt in the step (see the deep end on the math). Then game feel is identical at 30/60/144 Hz. The exception is a fixed physics tick: there the frame is stable and windows can be kept directly in tick frames.
- An A/B juice toggle (Lab 09). Architecturally it pays to put all the juice behind one flag or layer so it can be switched on and off without touching gameplay. That is both a test bench (feeling each contribution) and determinism insurance: if the toggle changes the outcome of the simulation, juice has leaked into the logic, and that is a bug.
Frontend / UX: optimistic UI (showing the result before the server answers = the same jump buffer/coyote time), skeleton screens, perceived performance, input forgiveness in forms.
ML / AI: streaming LLM output (tokens as they are generated — perceived latency drops several-fold at the same real latency); "thinking…" indicators; all the UX wrapping around slow models is game feel for an AI product.
Distributed / networking: latency hiding, prefetching, speculative execution — the same "perceived ≠ actual".
Principle: perceived ≠ actual; engineer the perception, not only the system — and compensate for human delay without tipping into "magnetism".
Why does coyote time feel "fair" when it is technically a concession to the player?
Why does hit-stop sell "weight"?
Can feel be A/B tested?
Can feel be learned by a machine?
Why do engineers underrate this?
- Steve Swink, "Game Feel: A Game Designer's Guide to Virtual Sensation" (2008) — the source of the term.
- "Juice it or lose it" (Martin Jonasson & Petri Purho) — the canonical talk on juice, on a simple example.
- Frame-by-frame breakdowns of the Celeste / Mario jump — coyote time, jump buffering, variable jump height.
- Lab 09 —
labs/lab-09-game-feel/, to feel the difference with a toggle.