Playdate game architecture patterns — push-down state machine, screen lifecycle hooks (onEnter, onExit, onPause, onResume), models/systems vs screens/ui module separation, and the 30 FPS update budget.
SkillScore77Maintained
Automatic
◆Coding pack
Last verified 8/3/2026
What it changes
Passed 17 of 22 test cases with the skill, and 9 of 22 without it.
Without skill41%
With skill77%
Checks it passed that the model alone missed
Places save game operations inside the persistence/ directory.
Executes state machine update, then sprite update, then timer update.
Demonstrates screen replacement on the state stack using a swap method.
and 9 more in the full report
8 fixed9 passed either way5 still failing0 broke
Pass-rate lift
+36 pp
Tokens
+23%
Agent turns
0%
Response time
-31%
Model gemini-3.6-flashMeasured 8/3/2026v117 of 22 cases passed with skill
Tokens, turns and time describe resource use, not a dollar price.
See it in action
One of 8 test cases the skill fixed. Same model, same prompt, with and without the skill.
1 of 8
Prompt
When a player opens an inventory pause menu during gameplay in a Playdate title, which lifecycle hook is invoked on the active game screen right as the inventory menu state is pushed on top of the stack?
What was checked, without and with the skill
Checked
Without skill
With skill
Identifies onPause() as the hook called on the underlying screen when a new screen is pushed.
Missed
Passed
case-15 · gemini-3.6-flash · 8/3/2026 · answers are capped and redacted
What's inside
The instructions your model reads when the skill loads.
SKILL.md155 linessingle file
Playdate Game Architecture
Push-Down State Machine
The recommended pattern for Playdate games is a push-down automaton managing a stack of screens. This enables nested state — pausing to show a menu without destroying the game state beneath.
-- src/core/StateMachine.lua
StateMachine = {}
StateMachine.__index = StateMachine
function StateMachine.new()
return setmetatable({ stack = {} }, StateMachine)
end
-- Push a new state; pause the current one
function StateMachine:push(state)
local current = self.stack[#self.stack]
if current and current.onPause then current:onPause() end
table.insert(self.stack, state)
if state.onEnter then state:onEnter() end
end
-- Pop current state; resume the one below
function StateMachine:pop()
local current = table.remove(self.stack)
if current and current.onExit then current:onExit() end
local next = self.stack[#self.stack]
if next and next.onResume then next:onResume() end
end
-- Replace current state (no stack growth)
function StateMachine:swap(state)
local current = table.remove(self.stack)
if current and current.onExit then current:onExit() end
table.insert(self.stack, state)
if state.onEnter then state:onEnter() end
end
function StateMachine:update()