platformer
gamedev-skills/awesome-gamedev-agent-skills
Build 2D platformers with tight jump feel: coyote time, jump buffering, variable height, and level structure.
What is platformer?
A compositional skill for side-scrolling platformers that teaches the run/jump controller "feel", level geometry, hazards, and checkpoints. Use this when building a Mario-like or Celeste-like game, or when a jump feels floaty or unresponsive and needs tuning (coyote time, jump buffering, variable height, corner correction).
- Implement run/jump controller with coyote time (~0.1s grace period after leaving ground) and jump buffering (~0.1s input window before landing)
- Tune jump physics from desired height and time-to-apex rather than magic numbers, with asymmetric gravity for snappy falls
- Add variable jump height: tap for short hop, hold for full arc
- Design one-way platforms (solid from above, pass-through from below)
- Structure levels with tiled geometry, hazards (spikes, pits), checkpoints, and respawn logic
- Polish with camera follow (deadzone, look-ahead, bounds clamping) and juice (landing dust, squash/stretch, hit-stop)
How to install platformer
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill platformer- An engine with 2D physics or kinematic body support (Godot CharacterBody2D, Unity Rigidbody2D, Phaser Arcade, or Pygame)
- A tilemap or collision system for level geometry (godot-tilemap, unity-tilemap-2d, or equivalent)
- Basic input handling (jump button, movement input)
How to use platformer
- 1.Derive gravity and jump velocity from your desired jump height and time-to-apex using the kinematics formula in Pattern 1
- 2.Implement the run/jump controller with coyote timer (refresh while grounded, decrement each frame) and jump buffer timer (refresh on button press, decrement each frame)
- 3.Allow a jump only when both timers are positive (buffer_timer > 0 AND coyote_timer > 0)
- 4.Add variable jump height by cutting upward velocity (×0.4–0.5) when the jump button is released while rising
- 5.Implement one-way platforms by enabling the engine's one-way collision flag and allowing drop-through when player holds Down+Jump
- 6.Build level geometry with a tilemap, place hazards and checkpoints, and wire respawn logic to reset the player at the last checkpoint on death
- 7.Add camera follow with a deadzone and smooth lerp, clamped to level bounds
- 8.Polish with landing dust particles, squash/stretch on landing, and sound effects
Use cases
- Tuning a floaty or unresponsive jump by adjusting coyote time, fall gravity, and variable height cut
- Building a single-screen or side-scrolling platformer with multiple checkpoint areas and hazards
- Creating a Celeste-like game with tight, skill-based jump mechanics
- Prototyping platformer controller feel before building full level content
- Fixing "jump didn't register" or "fell off and couldn't jump" problems with input buffering and coyote time
- Game designers tuning moment-to-moment platformer feel
- Developers building 2D side-scrollers or Mario/Celeste-like games
- Programmers implementing kinematic jump controllers with polish
- Level designers laying out platformer geometry and teaching progression
platformer FAQ
You likely have symmetric gravity (same value rising and falling). Use fall_gravity = rise_gravity × 1.5–2.0 to make the descent snappier and less floaty.
Add jump buffering: store the jump button press for ~0.1–0.15 s (6–9 frames at 60 FPS) and allow a jump if the buffer is active AND coyote time is active, even if the press happened before landing.
Pick your desired jump height (in tiles) and time-to-apex (in seconds), then use: gravity = (2 × height) / (time²) and jump_velocity = -(2 × height) / time. This ensures physics match your feel target.
Coyote time (~0.08–0.12 s) allows the player to jump for a brief moment after leaving a platform, making the game feel forgiving and fair. Without it, players feel cheated when they jump just after walking off a ledge.
Skip this skill if you're building top-down movement (no gravity), 3D first-person traversal (use fps-shooter), or grid/turn-based movement (use roguelike). For raw kinematic APIs, use godot-2d-movement or your engine's core movement skill instead.
Full instructions (SKILL.md)
Source of truth, from gamedev-skills/awesome-gamedev-agent-skills.
name: platformer description: > Build a 2D platformer: run/jump control with coyote time, jump buffering, and variable jump height, plus tiled levels and hazards. Use for a platformer or Mario/Celeste-like, or tuning jump feel.
Platformer
A playbook for 2D platformers — the run/jump controller "feel", level structure, hazards, and goals. This is a compositional skill: it wires an engine movement skill, a tilemap skill, and design skills into a working game. It does not re-teach physics or tilemaps; it tells you what to build and how to make jumping feel good.
When to use
- Use when building a side-scrolling or single-screen platformer, a "Mario-like" / "Celeste-like", or any game whose core verb is jump between surfaces.
- Use when a jump feels floaty, unresponsive, or "unfair" and you need feel fixes (coyote time, jump buffering, variable height, corner correction).
When not to use: top-down movement with no gravity → use the engine movement skill
directly. 3D first-person traversal → fps-shooter. Grid/turn movement → roguelike.
For the raw kinematic body API, use godot-2d-movement (or your engine's controller skill).
Core loop
Observe a gap/hazard → commit to a jump or move → land safely (or die) → reach the next checkpoint/goal. A platformer lives or dies on the moment-to-moment feel of that single jump, repeated thousands of times. Tighten the controller first; everything else is content.
Must-have systems
- Run/jump controller — horizontal accel/decel, gravity, jump, with the feel aids below.
- Solid + one-way collision — ground, walls, and "jump-through" platforms.
- Level geometry — a tilemap or hand-placed colliders; the playable space.
- Hazards + death/respawn — spikes, pits, enemies; reset to the last checkpoint.
- Checkpoints / level goal — progress markers and a win condition (flag, door, exit).
- Camera — follows the player with a deadzone and look-ahead, clamped to level bounds.
- Juice — landing dust, squash/stretch, hit-stop, sound. Cheap, huge feel payoff.
Design knobs (make the jump feel right)
Tune these by outcome (height in tiles, time to apex in seconds), not by raw numbers.
| Knob | Effect | Sane starting point |
|---|---|---|
| Max jump height | reach | 3–4 tiles |
| Time to apex | "weight"/snappiness | 0.30–0.40 s |
| Fall gravity multiplier | snappy, non-floaty fall | 1.5–2.0× rise gravity |
| Coyote time | jump just after leaving a ledge | 0.08–0.12 s (~5–7 frames @60) |
| Jump buffer | press just before landing still jumps | 0.10–0.15 s |
| Variable jump cut | tap = short hop, hold = full | cut upward velocity ×0.4–0.5 on release |
| Apex hang | brief float at the top for air control | reduce gravity ×0.5 near ` |
| Ground accel / friction | responsiveness vs. ice | reach top speed in 0.05–0.1 s |
| Corner correction | nudge past a ledge clipped by 1–2 px | nudge up to ~4 px sideways |
Derive gravity and jump velocity from the feel values rather than guessing — see Pattern 1.
Patterns
1. Solve jump physics from height + time (not magic numbers)
# Pseudocode. Pick the FEEL you want, then derive the physics. y-axis points DOWN.
# From kinematics: h = (g * t^2) / 2 and v0 = g * t.
JUMP_HEIGHT = 3.5 * TILE # how high, in world units
TIME_TO_APEX = 0.35 # seconds to reach the top
gravity = (2 * JUMP_HEIGHT) / (TIME_TO_APEX ** 2) # rising gravity
jump_velocity = -(2 * JUMP_HEIGHT) / TIME_TO_APEX # negative = upward
fall_gravity = gravity * 1.8 # heavier on the way down → less floaty
2. Coyote time + jump buffer + variable height (the feel core)
# Pseudocode in the per-frame update. dt = seconds since last frame.
# Timers count DOWN; refresh coyote while grounded, buffer on a fresh press.
if on_floor:
coyote_timer = COYOTE_TIME # 0.1
if jump_pressed_this_frame:
buffer_timer = JUMP_BUFFER # 0.12
coyote_timer -= dt
buffer_timer -= dt
# A jump is allowed if we pressed recently AND were grounded recently.
if buffer_timer > 0 and coyote_timer > 0:
velocity.y = jump_velocity
buffer_timer = 0
coyote_timer = 0 # consume both so we can't double-jump
# Variable height: releasing jump early while still rising cuts the arc short.
if jump_released_this_frame and velocity.y < 0:
velocity.y *= 0.45
# Asymmetric gravity: snappier fall than rise.
g = fall_gravity if velocity.y > 0 else gravity
velocity.y += g * dt
3. One-way platforms
Solid from above, pass-through from below. Most engines expose a "one-way collision" flag on the tile/collider; enable it and let the player drop through by disabling that collision for a few frames when the player holds Down + Jump. Do not re-implement collision math.
Pitfalls / failure modes
- Per-frame movement not scaled by
dt→ speed changes with frame rate. Every velocity integration and timer must usedt. (Seephysics-tuning.) - Floaty jumps → symmetric gravity. Make fall gravity heavier than rise gravity.
- "The jump didn't register" → no input buffering. Buffer presses for ~0.1 s before landing.
- "I fell off and couldn't jump" → no coyote time. Allow a jump for ~0.1 s after leaving ground.
- Sticking to walls / catching on tile seams → use a single capsule/box collider, not per-tile colliders, and add corner correction.
- Tunneling through floors at high speed → enable continuous collision / smaller fixed
timestep for fast bodies (see
physics-tuning). - Camera snaps and induces nausea → smooth/lerp the follow, add a deadzone, clamp to bounds.
- Difficulty wall from bad teaching → introduce one mechanic per area before combining them.
Composition (build it from these skills)
- Controller body:
godot-2d-movement(GodotCharacterBody2D); for other engines use the engine core + physics skill (unity-physics,phaser-arcade-physics,pygame-core). - Levels:
godot-tilemap/unity-tilemap-2dfor geometry;level-designfor layout, pacing, and teaching order. - Feel/physics:
physics-tuningfor timestep, CCD, and stability. - Input:
input-systemsfor buffering, rebinding, and gamepad support. - Polish:
audio-designfor SFX/music; the engine animation skill for squash/stretch. - Process:
prototype-fastto greybox the controller before building content.
References
- For jump math derivation, a full feel-tuning table, corner correction, moving/one-way
platforms, and camera follow, read
references/feel-tuning.md.
Related skills
More from gamedev-skills/awesome-gamedev-agent-skills and the wider catalog.

procedural-gen
Generate reproducible game content—terrain, dungeons, and loot—from seeded algorithms and noise.

prototype-fast
Build a playable mechanic prototype in ~1 hour to answer 'is it fun?' with greybox primitives and a hard timebox.

puzzle
Build grid/board puzzle games with deterministic rule resolution, cascades, undo, and level progression.

pygame-core
Build the core pygame game loop: init, events, delta-time movement, drawing, input, and sprite/group collision.

roblox-datastores
Persist player data in Roblox with DataStoreService: load on join, save on leave, safe updates, and leaderboards.

roblox-luau
Script Roblox experiences in Luau: services, instances, events, and secure client/server communication.