summerengine/summer/celeste-momentum-platforming

Claude Code and agent skill by summerengine/summer

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Celeste-style 2D precision platformer movement — momentum running, coyote time, variable jumps, dash, wall jump/slide, climb stamina, pixel corner correction.

Install

npx vskill@latest install summerengine/summer/celeste-momentum-platforming

SKILL.md

Celeste-Style Momentum Platforming (Movement System)

Outcome

A 2D character controller for Summer Engine that reproduces the tuning architecture and forgiveness mechanics of Celeste's player movement: momentum-based running with distinct ground/air acceleration, variable-height jumping with coyote time, a multi-directional dash with cooldown and residual speed, wall interaction (jump, slide, climb with stamina), and pixel-scale corner corrections that make near-miss inputs succeed instead of fail.

When to Use

  • Building a precision 2D platformer in Summer Engine where movement feel is the core gameplay.
  • Porting or prototyping Celeste-style mechanics (dash, wall jump, climb stamina).
  • Tuning an existing platformer controller that feels "unfair" or unresponsive — the forgiveness systems below are the primary fix.

Do not use for: 3D character controllers, physics-driven (RigidBody) movement, or games where floaty/arcade jump physics are desired over momentum precision.

Core Principle

Celeste's movement is a single controller class driven by an explicit integer state machine, with all feel-critical numbers as a flat compile-time constants table at the top of the class. The released source (Player.cs, 5,471 lines) defines states Normal=0, Climb=1, Dash=2, Swim=3, Boost=4, RedDash=5, HitSquash=6, Launch=7, Pickup=8, DreamDash=9 (+ a Summit state), each with Begin/Update/End callbacks. State transitions are direct integer assignments.

The second principle: forgiveness at the pixel and millisecond scale. The code repeatedly nudges the player 2–6 pixels or grants 50–200 ms windows so that inputs which are almost correct still succeed. Most of the "tight" feel comes from these windows.

Tuning Constants (verbatim from Player.cs)

Celeste's units are pixels/second for speeds and pixels/second² for accelerations at its native resolution; times in seconds. When porting, preserve the ratios more than the absolute numbers if your pixels-per-meter differs.

Gravity & Falling
ConstantValueFeel role
Gravity900Base downward acceleration
MaxFall160Terminal fall speed (normal)
HalfGravThreshold40Below this vertical speed, gravity is halved (floaty apex)
FastMaxFall240Terminal fall speed when fast-falling (hold down)
FastMaxAccel300Acceleration toward FastMaxFall
Running
ConstantValueFeel role
MaxRun90Top ground speed
RunAccel1000Ground acceleration (~11× MaxRun — near-instant response)
RunReduce400Deceleration when input stops
AirMult0.65Air control multiplier on acceleration
HoldingMaxRun70Reduced top speed while carrying objects
HoldMinTime0.35Min time before hold-reduction applies
WalkSpeed64Slow-walk speed
DuckFriction500Friction while crouched
Jumping
ConstantValueFeel role
JumpGraceTime0.1Coyote time — jump input valid 100 ms after leaving ground
JumpSpeed-105Initial jump velocity
JumpHBoost40Horizontal boost added on jump
VarJumpTime0.2Variable jump — held jump sustains/boosts for up to 200 ms
CeilingVarJumpGrace0.05Grace before ceiling cancels variable jump
UpwardCornerCorrection4px nudge to slip past near-miss ceiling corners while rising
WallSpeedRetentionTime0.06Horizontal speed retained briefly after wall interactions
BounceAutoJumpTime0.1Auto-jump window off bouncy surfaces
Wall Interaction
ConstantValueFeel role
WallJumpCheckDist3px probe distance for wall detection
WallJumpForceTime0.16Duration of forced horizontal speed after wall jump
WallJumpHSpeed130= MaxRun + JumpHBoost; forced away-from-wall speed
WallSlideStartMax20Initial wall slide speed cap
WallSlideTime1.2Time over which wall slide behavior ramps
ClimbGrabYMult0.2Vertical speed multiplied by 0.2 on grab
Super Variants
ConstantValue
SuperJumpH260
SuperWallJumpSpeed-160
SuperWallJumpH170 (= MaxRun + JumpHBoost×2)
SuperWallJumpForceTime0.2
SuperWallJumpVarTime0.25
BounceSpeed / SuperBounceSpeed-140 / -185
DuckSuperJumpXMult / YMult1.25 / 0.5
Dash
ConstantValueFeel role
DashSpeed240Speed during dash
DashTime0.15Dash duration
EndDashSpeed160Residual speed after dash ends (2/3 of dash speed)
EndDashUpMult0.75Residual multiplier for upward dashes
DashCooldown0.2Time before dash input re-accepted
DashRefillCooldown0.1Refill timing after landing
DashAttackTime0.3Active dash collision window
DashCornerCorrection4px nudge on dash near-misses
DashHJumpThruNudge6px nudge for horizontal dashes through one-way platforms
DashVFloorSnapDist3px snap to floor after downward dash
Climb / Stamina
ConstantValueFeel role
ClimbMaxStamina110Total stamina pool
ClimbUpCost~45.5/s (100/2.2)Climbing upward drains ~2.4 s of pool
ClimbStillCost10/s (100/10)Hanging drains ~11 s of pool
ClimbJumpCost27.5 (110/4)Flat cost per climb-jump
ClimbTiredThreshold20Below this, climb behavior degrades
ClimbUpSpeed-45Climb ascent speed
ClimbDownSpeed80Climb descent speed
ClimbSlipSpeed30Slip speed when exhausted
ClimbAccel900Climb velocity acceleration
ClimbCheckDist / UpCheckDist2 / 2px probe for grab detection
ClimbHopX / HopY100 / -120Wall-hop impulse
ClimbHopForceTime0.2Forced duration of hop impulse
ClimbGrabYMult0.2Vertical damp on grab
Other
ConstantValue
LaunchSpeed / LaunchCancelThreshold280 / 220
LiftYCap / LiftXCap-130 / 250
JumpThruAssistSpeed-40 (upward assist through one-way platforms)
ReboundSpeedX / Y120 / -120
ReflectBoundSpeed220
ThrowRecoil80
DuckWindMult0 (ducking negates wind)
SpacePhysicsMult0.6 (low-gravity zones)

Scene / Node Shape

Player (CharacterBody2D)
├── CollisionShape2D # compact rectangle; Celeste probes at 2–6 px, so shape must be tight
├── WallProbeLeft (Area2D) # or use move_and_collide probes at WallJumpCheckDist
├── WallProbeRight (Area2D)
├── StateMachine (ref in script)
└── (AnimatedSprite2D / hair, particles optional)
World
├── TileMapLayer (static solids)
├── OneWayPlatforms (TileMapLayer or StaticBody2D with one-way collision)
└── JumpThru zones

Reference Implementation Skeleton (GDScript)

gdscript
extends CharacterBody2D
# === Tuning table (values from Celeste Player.cs; rescale px if needed) ===
const GRAVITY := 900.0
const MAX_FALL := 160.0
const HALF_GRAV_THRESHOLD := 40.0
const FAST_MAX_FALL := 240.0
const FAST_MAX_ACCEL := 300.0
const MAX_RUN := 90.0
const RUN_ACCEL := 1000.0
const RUN_REDUCE := 400.0
const AIR_MULT := 0.65
const JUMP_GRACE_TIME := 0.1
const JUMP_SPEED := -105.0
const JUMP_H_BOOST := 40.0
const VAR_JUMP_TIME := 0.2
const UPWARD_CORNER_CORRECTION := 4
const WALL_SPEED_RETENTION_TIME := 0.06
const WALL_JUMP_CHECK_DIST := 3
const WALL_JUMP_FORCE_TIME := 0.16
const WALL_JUMP_H_SPEED := MAX_RUN + JUMP_H_BOOST # 130
const DASH_SPEED := 240.0
const DASH_TIME := 0.15
const END_DASH_SPEED := 160.0
const END_DASH_UP_MULT := 0.75
const DASH_COOLDOWN := 0.2
const DASH_CORNER_CORRECTION := 4
const CLIMB_MAX_STAMINA := 110.0
const CLIMB_UP_COST := 100.0 / 2.2
const CLIMB_STILL_COST := 100.0 / 10.0
const CLIMB_JUMP_COST := 110.0 / 4.0
const CLIMB_UP_SPEED := -45.0
const CLIMB_DOWN_SPEED := 80.0
const CLIMB_SLIP_SPEED := 30.0
const CLIMB_CHECK_DIST := 2
enum St { NORMAL, CLIMB, DASH, SWIM, BOOST, RED_DASH, HIT_SQUASH, LAUNCH, PICKUP, DREAM_DASH }
var state: int = St.NORMAL
var var_jump_timer: float = 0.0
var jump_grace_timer: float = 0.0 # coyote time
var dash_cooldown_timer: float = 0.0
var dash_timer: float = 0.0
var dash_dir: Vector2 = Vector2.ZERO
var wall_jump_force_timer: float = 0.0
var wall_speed_retention_timer: float = 0.0
var stamina: float = CLIMB_MAX_STAMINA
func _physics_process(delta: float) -> void:
match state:
St.NORMAL: _normal_update(delta)
St.DASH: _dash_update(delta)
St.CLIMB: _climb_update(delta)
# ... remaining states
move_and_slide()
func _normal_update(delta: float) -> void:
# --- Gravity with apex float and fast-fall ---
var max_fall := MAX_FALL
if Input.is_action_pressed("ui_down") and not is_on_floor():
max_fall = FAST_MAX_FALL
var grav := GRAVITY
if absf(velocity.y) < HALF_GRAV_THRESHOLD and velocity.y < 0.0:
grav *= 0.5
velocity.y = minf(velocity.y + grav * delta, max_fall)
# --- Run acceleration, reduced in air ---
var input_x := Input.get_axis("ui_left", "ui_right")
var accel := RUN_ACCEL if is_on_floor() else RUN_ACCEL * AIR_MULT
if input_x != 0.0:
velocity.x = move_toward(velocity.x, input_x * MAX_RUN, accel * delta)
else:
velocity.x = move_toward(velocity.x, 0.0, RUN_REDUCE * delta)
# --- Coyote time bookkeeping ---
if is_on_floor():
jump_grace_timer = JUMP_GRACE_TIME
else:
jump_grace_timer -= delta
# --- Jump with variable height ---
if Input.is_action_just_pressed("ui_accept") and jump_grace_timer > 0.0:
velocity.y = JUMP_SPEED
velocity.x += signf(input_x) * JUMP_H_BOOST if input_x != 0.0 else 0.0
var_jump_timer = VAR_JUMP_TIME
jump_grace_timer = 0.0
if var_jump_timer > 0.0 and Input.is_action_pressed("ui_accept"):
var_jump_timer -= delta
# hold sustains upward velocity; release cuts it
elif var_jump_timer > 0.0:
var_jump_timer = 0.0
if velocity.y < 0.0:
velocity.y *= 0.5 # jump cut on release (standard platformer pattern)
# --- Wall probe and wall jump ---
var wall_dir := _probe_wall() # raycast WALL_JUMP_CHECK_DIST px each side
if wall_dir != 0 and Input.is_action_just_pressed("ui_accept"):
velocity.x = -wall_dir * WALL_JUMP_H_SPEED
wall_jump_force_timer = WALL_JUMP_FORCE_TIME
velocity.y = JUMP_SPEED
var_jump_timer = VAR_JUMP_TIME
if wall_jump_force_timer > 0.0:
wall_jump_force_timer -= delta # lock horizontal input during forced push
# --- Dash entry ---
if dash_cooldown_timer <= 0.0 and Input.is_action_just_pressed("dash"):
state = St.DASH
dash_dir = _aim_direction() # 8-way from input axes
dash_timer = DASH_TIME
dash_cooldown_timer = DASH_COOLDOWN
velocity = dash_dir * DASH_SPEED
func _dash_update(delta: float) -> void:
dash_timer -= delta
velocity = dash_dir * DASH_SPEED # no gravity during dash
if dash_timer <= 0.0 or _collided_during_dash():
state = St.NORMAL
# Residual speed: keep EndDashSpeed, reduced for upward dashes
var residual := END_DASH_SPEED
if dash_dir.y < 0.0:
residual *= END_DASH_UP_MULT
velocity = dash_dir.normalized() * minf(velocity.length(), residual)
func _climb_update(delta: float) -> void:
var input_y := Input.get_axis("ui_up", "ui_down")
if input_y < 0.0:
velocity.y = CLIMB_UP_SPEED
stamina -= CLIMB_UP_COST * delta
elif input_y > 0.0:
velocity.y = CLIMB_DOWN_SPEED
else:
velocity.y = minf(velocity.y + GRAVITY * delta * 0.1, CLIMB_SLIP_SPEED)
stamina -= CLIMB_STILL_COST * delta
velocity.x = 0.0
if stamina <= 0.0 or not _touching_wall():
state = St.NORMAL
if Input.is_action_just_pressed("ui_accept"):
stamina -= CLIMB_JUMP_COST
state = St.NORMAL
velocity.y = JUMP_SPEED

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
65
Repository forks
4
7-day trend score
21

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/summerengine/summer/celeste-momentum-platforming/badge)](https://verified-skill.com/skills/summerengine/summer/celeste-momentum-platforming)

Something wrong with this skill or its page? Tell us.