Sokoban is easy to render and brutal to generate: random box/goal placement gives you puzzles that are either trivial or literally unsolvable (a box shoved into a corner it can never leave). I wanted procedurally generated levels that are always solvable and actually interesting.
The naive "scatter boxes and goals" prompt produced unsolvable boards constantly. The fix was to generate levels backwards: start from the solved state and pull boxes away from goals with legal reverse-moves, so every level is solvable by construction. I also had it score difficulty by solution length.
One answer below improved the difficulty tuning. Sharing the generator prompt.
Write a Sokoban game with a procedural level generator in a single HTML canvas file, vanilla JS. Grid of walls/floor, a player that pushes boxes (never pulls), goal tiles; a level is solved when every box sits on a goal. Arrow keys/WASD to move, U to undo, R to restart.
Generate levels so they are ALWAYS solvable, using reverse generation (do NOT scatter boxes randomly):
1. Start from a solved state: place N boxes directly on N goal tiles inside a bounded room with some interior walls.
2. Repeatedly apply legal REVERSE moves (player 'pulls' a box, which is the inverse of a push) to walk boxes away from their goals, recording moves.
3. The resulting scrambled state is guaranteed solvable because the recorded reverse moves, played backward, are a valid solution.
4. Difficulty = length of that solution path and number of boxes; expose a target difficulty and keep pulling until it's met (with a max-attempts cap).
5. Reject boards where a box starts already on its goal (too easy) or where the player can't reach the required push positions.
Rendering + feel: crisp tile art, the player faces its move direction, boxes on goals tint differently, a soft 'thunk' on a push, an undo that animates in reverse, a move counter, and a satisfying flash + chime when the last box lands. Show the seed and difficulty. Framerate-independent input (one move per keypress, with key-repeat handling). Explain in a comment why reverse generation guarantees solvability.