love2d-core
Structure and debug a LÖVE (Love2D) game in Lua: the love.load/update/draw loop, delta-time movement, input, and screen states. Use when building a LÖVE 11.x game (main.lua, conf.lua, .love).
By gamedev-skills · 1,924 installs
npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill love2d-core
Source repository · Upstream listing
LÖVE (Love2D) Core
Set up and debug the foundation of a LÖVE game in Lua: the callback loop, frame rate
independent movement, input, and screen states. Targets LÖVE 11.5 .
When to use
Use when starting a LÖVE game, wiring up main.lua / conf.lua , or fixing the core loop,
movement that runs at the wrong speed, input handling, or screen switching.
Use when the workspace has main.lua calling love. , a conf.lua , or a .love file.
When not to use: Lua language questions unrelated to LÖVE; physics bodies/joints
(LÖVE uses Box2D via love.physics — a separate concern); shader code ( love.graphics
GLSL is its own topic). For cross engine save/load patterns, use save systems .
Core workflow
1. Confirm the entry points. A LÖVE game runs main.lua ; it should define
love.load() (one time setup), love.update(dt) (state), and love.draw() (rendering).
Window/version setup goes in conf.lua (run before modules load).
2. Pin the version. Set t.version = "11.5" in conf.lua so LÖVE warns on mismatch.
3. Drive all motion by dt (delta time, in seconds) so speed is frame rate independent.
4. Handle input two ways: polled ( love.keyboard.isDown in update , for held keys) and
event ( love.keypressed callback, for discrete presses).
5. Manage screens (menu, game, pause) with a small state stack rather than a pile of
if flags — see Patterns and references/state stack.md .
6. Run and observe. Launch with love . from the project folder; verify the window,
motion speed, and input on screen before assuming it works.
Patterns
1. main.lua skeleton (the callback loop + input)
2. Frame rate independence (the single most common bug)
3. conf.lua (window + version; runs before main.lua )
4. Color is 0–1 in LÖVE 11.x (not 0–255)
5. Screen states (brief — full manager in references)
Pitfalls
Speed varies with FPS → you forgot dt . Every per frame change to position, timers,
or animation must be scaled by dt .
love.conf placed in main.lua → it silently does nothing. It must live in conf.lua ,
which LÖVE runs before loading modules.
Colors washed out or invisible → you used 0–255 values. 11.x does not rescale them;
every channel above 1 draws at full intensity, so setColor(128, 234, 255) comes out
plain white and an alpha of 128 is fully opaque. Use 0–1 floats or
love.math.colorFromBytes (11.3+).
Everything tinted after one setColor → color is global and persists across draws.
Reset with love.graphics.setColor(1, 1, 1) before drawing text/images you want untinted.
Holding a key fires love.keypressed only once → key repeat is off by default.
Call love.keyboard.setKeyRepeat(true) (e.g. for text fields or menu scrolling); the
repeats then arrive with the third argument isrepeat set, so a jump handler can
ignore them. Releases go to love.keyreleased(key) .
References
For a complete push/pop screen state manager (menu → game → pause, with delegated
callbacks), read references/state stack.md .
Related skills
save systems — saving/loading game state (engine agnostic).
input systems — rebindable, multi device input architecture.
pygame core / phaser core — the same loop concepts in other lightweight engines.