EVEN STEVEN is a pure 2D puzzle built on graph chip-firing. The board is a graph; every vertex holds an amount of money, and it can go negative. You win by making every vertex hold the same amount. Every generated board sums to $0, so the amount to reach is always $0. There is no way to lose and no undo: every move is made for good, and running long only costs points.
Every player gets the same board for a given level number, because levels are seeded from the number and nothing in the game is random per player.
Two moves, one goal. Vertices draw green once they hold their share and red until they do, so the whole board turns green at exactly the moment it is won.
A vertex gives $1 to each neighbour and pays $1 per incident edge. Firing a degree-3 vertex pays out $3.
Left-click · touch tap · keyboard Enter · gamepad A or left shoulder
The exact inverse: the vertex takes $1 from each neighbour. Green dollars travel for a fire, red ones for a borrow.
Right-click · long-press or second finger · keyboard B · gamepad right shoulder
Reach a position where every vertex holds the same amount. Each level is timed, and a win raises a banner with stars and the score.
Restart or Next: button, keyboard N, or gamepad Y
Money dividing evenly is necessary, not sufficient. The positions a board can reach by firing form one class out of exactly as many as it has spanning trees. A tree has one, so there dividing evenly is the whole condition. Anything with a cycle has more, and which class the money sits in decides the answer.
On a triangle, (1, −1, 0) sums to $0 and can never be evened out, while (1, 1, −2) and (2, −1, −1) both can. The solver decides this exactly; the cheap counting check answers “undetermined” for any board with a cycle rather than guessing.
The game is playable end to end. What is left is polish, tuning and the shape of the release, listed under the roadmap below.
The line that matters: the rules, geometry and easing live in pure classes with no scene dependency, and the board scene only draws and forwards input. That is what keeps them testable.
| Piece | File | Job |
|---|---|---|
| DollarGraph | scripts/dollar_graph.gd | The rules: fire, borrow, the share check. Validates a graph on build and returns null on a bad one. |
| DollarSolver | scripts/dollar_solver.gd | Decides winnability exactly with Dhar's burning algorithm, and returns the true fewest moves (par). |
| LevelGenerator | scripts/level_generator.gd | Runs the game backwards from an all-$0 board, so every level is winnable by construction. |
| BoardLayout | scripts/board_layout.gd | Where vertices sit and which one a click hit. A spring layout that cuts crossings but cannot remove them on dense boards. |
| FirePulse | fx/fire_pulse.gd | Timing and easing for one move. The engine moves the money instantly; the pulse only delays the sight of it. |
| BoardView | scenes/board.tscn | The playing field. Draws the graph and forwards input, owns no rules, geometry or easing. |
| LevelScore | scripts/level_score.gd | Stars and score from moves against par and the time on the clock. |
| LevelDifficulty | scripts/level_difficulty.gd | Rates the board itself, not the player, into five tiers. Also vendored into the level editor. |
| GameProgress | autoload/game_progress.gd | Level reached and best score, stars, time and moves per level, saved to user://progress.cfg. |
| GameSettings | autoload/game_settings.gd | Fullscreen and the three volumes, kept apart so resetting progress leaves them alone. |
Measured, not guessed. Par is the true fewest fires and borrows a board needs, and the generator scrambles until the board is genuinely that much work, so the number asked for is the number that comes out.
What a solved level is worth. The tests assert the shape of the scoring, not its totals, so the constants can move freely.
The score display is finished, so the most useful next input is not code but play: put the current build in front of a few people and see how far they get. That settles whether the scoring constants and the difficulty curve are right, and both feed the level-pack and Demo decisions below.
The activation effect is the cheapest visible upgrade if you want something to work on before then.
| Item | Status | Notes |
|---|---|---|
| Activation effect on fire and steal | Scoped | Squash-stretch, a shockwave ring or a particle burst on top of the existing glow. See docs/activation-effect-scope-2026-09-08.md. |
| Level packs and grouping | Scoped | Levels grouped so they can be sold as packs. See docs/level-grouping-scope-2026-09-08.md. |
| Monetization | Direction set | Two builds, a free Demo and a paid full game, rather than one app with an in-app unlock. Scope docs cover the desktop Demo and the mobile IAP alternative. |
| Tune the score constants | Needs playtests | Base, par bonus and time allowance need real played runs behind them. |
| Re-grade old saves | Not free | Par is never stored, so a star-scale change would mean re-solving every beaten level once. |
| Delete the dev importer UI | Before release | Remove the screen and menu button; keep the JSON parser, importer and open_imported. |
| Task | Command |
|---|---|
| Test | godot --headless -s res://addons/gut/gut_cmdln.gd -gexit |
| Lint | gdlint scripts/ scenes/ tests/ ui/ fx/ autoload/ |
| Format | gdformat scripts/ scenes/ tests/ ui/ fx/ autoload/ |
| Run (virtual display) | DISPLAY=:99 godot --path . |
| Release | ./release.sh |