Skills gamedev-skills awesome-gamedev-agent-skills Gamedev Agent Skills
game-feel
- Use it when:
- A hit, jump, pickup or death works but feels weak, weightless or unsatisfying.
- Juice means:
- The brief, exaggerated responses that make an action feel good, such as a flash, a shake or a freeze; they always return to rest.
- It does:
- Hooks feedback onto game events, picking from sound, particles, shake, hit-stop, flashes, knockback, tweens and number pops, then playtests it.
- You get:
- Changes to your game code, with small, medium and large feedback presets assigned to events.
- Code examples:
- Godot 4.7 and Unity 6.3; the techniques themselves are engine-neutral.
Skill 13 of 27 in the Gamedev Agent Skills bundle, after input-systems and before game-ui-ux.
TL;DR
A discipline skill from a game-development collection. Its premise: one satisfying hit is five to eight tiny responses firing within about 100 ms. The workflow checks the mechanic emits events such as on_hit or on_land, starts with two or three feedback channels per event, eases motion instead of moving it linearly, and keeps shake and hit-stop (a split-second freeze) for real impacts. Feedback stays off the simulation: shake moves the camera, never the body, and hit-stop slows time with a real-time timer so the game always resumes. Patterns include shake driven by a decaying trauma value, a hit-stop that survives overlapping hits, and a squash-and-pop tween with overshoot. It warns against over-juicing routine actions and suggests an option to reduce shake and flashing. It polishes a mechanic but doesn't build one: jump physics, camera follow and sound mixing are left to other skills in the repo.
Summarizes the skill at 19d93f9.
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill game-feel skills.sh pageSource on GitHubAll skills from gamedev-skills/awesome-gamedev-agent-skills
- Total Downloads
- 14,300 on skills.sh, Nov 9, 2026
- Repo stars
- 7,863 gamedev-skills/awesome-gamedev-agent-skills
- First seen
- Jun 27, 2026 on skills.sh
Weekly values
| Week to | Installs |
|---|---|
| Sep 21 | 517 |
| Sep 28 | 587 |
| Oct 5 | 593 |
| Oct 12 | 749 |
| Oct 19 | 1,098 |
| Oct 26 | 2,091 |
| Nov 2 | 2,445 |
| Nov 9 | 2,263 |
| Category |
Taste for interfaces that don't look generated: direction, motion and accessibility. Make games: design, genres, game feel and game-jam workflows, whatever the engine. Everything for building software: planning, coding, debugging, design, frameworks, cloud, agents and skills. |
|---|---|
| Type |
A multi-step process the agent follows: interview, debug, run a TDD loop, review. |
| Effect |
Its own steps create or change files, git state or local tools. |
| Needs |
Instructions only. Works in any agent that supports skills. |
| Publisher |
Everyone else. Unverified vendor claims default to community. |
| Topics |
SKILL.md
From gamedev-skills/awesome-gamedev-agent-skills at 19d93f9. Checked daily, last changed Nov 6, 2026.
Frontmatter
name: game-feel
description: >
Add "juice" and game feel that makes actions satisfying — screen shake, hit-stop/freeze
frames, tweened/eased motion, squash & stretch, knockback, and layered audio-visual
feedback — as engine-neutral techniques that pair with the detected engine's tween,
particle, and camera APIs. Use when the user mentions game feel, juice, "make it feel
good/punchy", screen shake, hit stop, screen freeze, easing, squash and stretch, impact
frames, or feedback/polish on hits, jumps, pickups, and deaths.Game feel (juice)
The difference between a mechanic that works and one that feels good is feedback: the layered, slightly-exaggerated response an action provokes. This skill covers the engine- neutral techniques — screen shake, hit-stop, easing, squash & stretch, knockback, and stacked feedback — and tells you how to apply them without burying the underlying simulation. It adds polish on top of an existing mechanic; it does not implement the mechanic.
When to use
- Use when an action (hit, jump, dash, pickup, death, button press) is mechanically correct but feels weak, weightless, or unsatisfying, and you want it to feel responsive and punchy.
- Use to add screen shake, hit-stop/freeze frames, eased motion, squash & stretch, knockback, flashes, or to layer multiple feedback channels onto one event.
- Use to decide how much juice is enough and where it crosses into noise.
When not to use: for the raw controller math (jump height, coyote time) use the
platformer genre and the engine movement skill. For camera follow/deadzone/orbit framing
use camera-systems (this skill only triggers the shake). For mixing, ducking, and adaptive
music use audio-design. For shader-based dissolves/flashes use shader-programming and the
engine shader skill. For the concrete tween/particle node APIs, use the engine animation skill
(godot-animation, unity-animation).
Core principle: feedback is layered and exaggerated
One satisfying hit is usually 5–8 tiny responses firing together within ~100 ms: a sound, a particle burst, a brief hit-stop, a flash, a knockback, a small screen shake, and a number popping up. Each is cheap; stacked, they read as "impact". Two rules keep it from becoming a mess: (1) exaggerate briefly and return to rest (juice is transient, not a new resting state); (2) scale juice to event importance — a footstep is not a boss death.
Core workflow
- Confirm the event hooks exist. Juice attaches to discrete events:
on_hit,on_land,on_pickup,on_death,on_fire. If the mechanic doesn't emit these, add them first. - Pick feedback channels per event from the menu (sound, particles, shake, hit-stop, flash, knockback, tween, number pop). Start with 2–3; add until it reads, then stop.
- Make motion eased, not linear. Route scale/position/UI changes through a tween with an ease (overshoot for "pop", ease-out for "settle"). Linear motion feels robotic.
- Reserve hit-stop and shake for impact. They are the strongest, most abusable tools — short durations, scaled to importance, and never on routine actions.
- Keep feedback off the critical simulation. Shake moves the camera/visual, not the body; hit-stop uses time scale or a real-time pause, not a gameplay-logic stall.
- Tune by importance tiers. Define small/medium/large feedback presets and assign events to a tier, so the whole game's juice stays consistent and proportional.
- Verify by playing and watching. Trigger the event repeatedly; confirm the feedback fires, returns to rest, and is not nauseating or input-blocking. Report what you observed (does shake decay? does input still register during hit-stop?).
Patterns
1. Screen shake by decaying "trauma" (smooth, not a random jitter)
# Godot 4.7. Store trauma 0..1; shake = trauma^2 so small hits barely move, big hits punch.
# Drives a Camera2D OFFSET (the visual), never the player body. Decays every frame.
# Camera2D.ignore_rotation defaults to true, so set it false or the roll does nothing.
@export var decay := 1.2 # trauma lost per second
@export var max_offset := Vector2(12, 8)
@export var max_roll := 0.1 # radians
var trauma := 0.0
var _t := 0.0
func add_trauma(amount: float) -> void:
trauma = clampf(trauma + amount, 0.0, 1.0) # hits ADD; they don't reset
func _process(dt: float) -> void:
if trauma <= 0.0: return
trauma = maxf(trauma - decay * dt, 0.0)
var shake := trauma * trauma # quadratic: gentle low, sharp high
_t += dt * 30.0
# Smooth pseudo-random via sampled noise/sin, NOT rand each frame (that buzzes).
offset = Vector2(max_offset.x * shake * sin(_t * 1.7),
max_offset.y * shake * sin(_t * 2.3))
rotation = max_roll * shake * sin(_t * 1.1)
# Unity 6.3 LTS: identical model on a CinemachineCamera via CinemachineBasicMultiChannelPerlin
# (set AmplitudeGain/FrequencyGain from trauma^2); for one-off impacts, CinemachineImpulseSource
# on the hitter + CinemachineImpulseListener on the camera — see camera-systems.
2. Hit-stop / freeze frame (sell impact by briefly stopping time)
# Godot 4.7. Drop time scale, then restore after a REAL-TIME delay (unaffected by time_scale).
var _hit_stop_id := 0
func hit_stop(duration := 0.08, slow := 0.05) -> void:
_hit_stop_id += 1
var my_id := _hit_stop_id
Engine.time_scale = slow
# 4th arg ignore_time_scale=true → the timer still fires while the game is frozen.
await get_tree().create_timer(duration, true, false, true).timeout
if my_id == _hit_stop_id: # a newer hit-stop owns the restore; don't cut it short
Engine.time_scale = 1.0
// Unity 6.3 LTS (C#). WaitForSecondsRealtime ignores Time.timeScale, so the timer still elapses.
IEnumerator HitStop(float duration = 0.08f, float slow = 0.05f) {
Time.timeScale = slow;
yield return new WaitForSecondsRealtime(duration);
Time.timeScale = 1f; // RIGHT: real-time wait. WRONG: WaitForSeconds (never resumes at scale 0)
}
3. Squash & stretch + overshoot via an eased tween (the "pop")
# Godot 4.7. Conserve volume: stretch one axis, squash the other, then spring back with overshoot.
func pop(node: Node2D) -> void:
node.scale = Vector2(1.3, 0.7) # instant squash on the event
var tw := create_tween()
tw.tween_property(node, "scale", Vector2.ONE, 0.18) \
.set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT) # BACK = overshoots past 1, settles
# RIGHT: ease back (TRANS_BACK/ELASTIC) for life. WRONG: linear tween → mechanical, dead.
4. A feedback bundle scaled by importance (keep juice proportional)
# One call per event; the tier decides intensity so the whole game stays consistent.
func feedback(event_pos: Vector2, tier: String) -> void:
match tier:
"small": AudioBus.play("tick"); Camera.add_trauma(0.15)
"medium": AudioBus.play("hit"); Camera.add_trauma(0.4); hit_stop(0.05); spawn_particles(event_pos, 6)
"large": AudioBus.play("boom"); Camera.add_trauma(0.8); hit_stop(0.12); spawn_particles(event_pos, 30); flash_white(0.06)
Pitfalls
- Shaking the player/body instead of the camera offset desyncs collision and aim. Shake the camera (or a visual pivot), never the simulated transform.
- Random offset every frame buzzes like static. Drive shake from sampled noise/sin and a decaying trauma value so it's smooth and self-ending.
- Hit-stop with
WaitForSeconds/ a scaled timer never resumes (at time scale 0 the timer never advances). Use a real-time wait (WaitForSecondsRealtime, or Godot'signore_time_scaletimer). - Hit-stop on every frame of a held attack locks the game. Trigger it once per impact.
- Overlapping hit-stops (two hits 30 ms apart) let the first timer restore time scale in the middle of the second freeze. Let only the newest call restore it, as above.
- Linear tweens everywhere feel robotic. Ease almost everything; reserve overshoot (BACK/ELASTIC) for "pop" and ease-out for "settle".
- Permanent exaggeration (scale never returns, shake never decays) becomes the new normal and stops reading as feedback. Juice must return to rest.
- Over-juicing routine actions (full shake + hit-stop on every footstep) causes nausea and hides real impacts. Scale to importance; add a "reduce screen shake"/"reduce flashing" accessibility option.
- Feedback that blocks input (long freeze, un-cancelable animation) hurts responsiveness. Keep juice short and let input buffer through it.
References
- For the trauma-shake math, easing-curve cheat sheet (which ease for pop vs settle), knockback
- flash + number-pop recipes, importance-tier presets, and per-engine tween/particle bindings,
read
references/feedback-recipes.md.
- flash + number-pop recipes, importance-tier presets, and per-engine tween/particle bindings,
read
Related skills
camera-systems— owns camera follow/deadzone/orbit; this skill only feeds it shake trauma.godot-animation,unity-animation— concrete tween/AnimationPlayer/particle APIs juice rides on.audio-design— the sound layer of every feedback bundle; ducking and SFX variation.physics-tuning— knockback forces and the timestep juice must not destabilize.platformer,fps-shooter,roguelike— genres whose moment-to-moment feel this elevates.