Skip to content
Development
Skill

/game-feel

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

From plugin
awesome-gamedev-agent-skills
6.3k77 skills

Claude Code

$ npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill game-feel --agent claude-code

SKILL.md

game-feel.SKILL.md
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

1. **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. 2. **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. 3. **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. 4. **Reserve hit-stop and shake for impact.** They are the strongest, most abusable tools — short durations, scaled to importance, and never on routine actions. 5. **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. 6. **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. 7. **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 =
Read more
@gamedev-skills
Ships withawesome-gamedev-agent-skills

<img src="docs/assets/awesome-gamedev-agent-skills-banner.png" width="820" alt="awesome-gamedev-agent-skills — game-dev skills for AI coding agents.

Stars on GitHub

Momentum

stars in total
6.3k
Star history of gamedev-skills/awesome-gamedev-agent-skills on GitHub, a chart by star-history.com

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc11d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about game-feel.

Which coding agents can use game-feel?
game-feel installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.