EngineLOVE 11.x
LanguageLua
PatternState tables + push/pop stack
Time to run~3 minutes
LevelIntermediate
OutputOne module (~70 lines)
DependenciesNone. Pure LOVE.

The prompt

Open a fresh chat at claude.ai/new, paste, and send.

$ Build me a LOVE2D (LOVE 11.x) game state manager as a single Lua module.

-- state shape
- A state is a plain table that may implement: enter(...), exit(), update(dt), draw(), keypressed(key), mousepressed(x,y,button).
- All callbacks are optional; the manager calls them only if present.

-- manager api
- A stack of states. Expose:
  - switch(state, ...) : exit current top, clear stack, push new (this is the common case).
  - push(state, ...) : keep current, push a new one on top (overlays like pause).
  - pop() : exit top, resume the one beneath.
- switch/push call enter(...) with the extra args; the leaving state's exit() is called.

-- routing
- update(dt) and the input callbacks go to the TOP state only.
- draw() draws the top state; add an option to also draw the state beneath when the top is flagged as an overlay (e.g. state.overlay == true), so a pause menu shows the game behind it.

-- constraints
- Pure Lua, no libraries.
- Nil-safe: never crash if a state omits a callback.
- Return the module table.

-- return format
- The module, plus a short comment showing main.lua forwarding love.update/draw/keypressed/mousepressed to it.
- No prose before or after.
Open in Claude ▸ Run · 3 min

What this gets you

The backbone that keeps a LOVE2D game from turning into one monster main.lua. Each screen is its own tidy table, transitions are one call, and pause-over-gameplay works because the stack keeps the game alive underneath. Add a screen without touching the others.

It is nil-safe, so a minimal state that only implements draw is fine, and it routes every love callback to the right place for you.

Why it matters

The stack is what makes pause work

A single current-state variable cannot show a pause menu over a frozen game, the game is gone the moment you switch. A stack keeps gameplay on the stack, paused, while the menu sits on top, and pop() returns you exactly where you were.

States as tables keep screens isolated

Each screen owning its own enter/update/draw means no cross-talk and no giant conditional in love.update. Adding game-over is a new file, not a new branch in every callback.

Nil-safe routing

Not every state needs mousepressed. Calling callbacks only if they exist means minimal states stay minimal and nothing crashes because a screen did not implement everything.

What good output looks like

How to wire it up

  1. Save the output as state.lua.
  2. In main.lua, local State = require 'state' and call State.switch(menu) in love.load.
  3. Forward the callbacks: function love.update(dt) State.update(dt) end, and the same for draw, keypressed, mousepressed.
  4. Write each screen as a table with the callbacks it needs (menu, game, gameover).
  5. For pause, set pause.overlay = true and call State.push(pause) from the game, then State.pop() to resume.

Common gotchas

Pause menu shows a black screen behind it

The manager is not drawing the state beneath the overlay. Flag the pause state as an overlay and have draw render the one below it first.

Crash when a state omits a callback

Callbacks are being called unconditionally. Guard each with a presence check so optional callbacks stay optional.

Old state keeps updating after a switch

switch is not clearing the stack or not calling exit. Ensure switch tears down the current top and routes update only to the new top.

Where to go next

  1. Transitions. Add a fade between switches by pushing a transition state that draws over both.
  2. Shared data. Pass args through switch/push (enter receives them) to hand the score to the game-over screen.
  3. Resize/quit. Route more love callbacks (resize, quit) through the same top-state pattern.

Use it however you want

The prompt is CC0, paste it, modify it, ship a game with it. The output Claude gives you is yours. A link back to pixeldex.dev in your project's README helps the next solo dev find this stuff.