Phaser AE

Screw relocation puzzles

Free packv3.0.0-12DPhysics

The rules of a screw-moving physics puzzle. Planks are screwed to a board of holes in layers; move the screws that nothing covers into free holes until every plank has swung loose and fallen. Levels can be written by hand or generated, and a search proves a generated level can be cleared.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 19, 2026

Screw relocation puzzles: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

screwRelocate

function screwRelocate(): Pack<{ screwRelocate: ScrewRelocateApi }>

The screw-relocate pack: game.screwRelocate, Nuts and Bolts rules on plates and screws of plate-stack's.

Functions

createScrewRelocate

function createScrewRelocate(level: ScrewRelocateLevel): ScrewRelocateGame

Make a game of a level. Throws, listing every problem, on a level validateScrewRelocateLevel refuses.

generateScrewRelocate

function generateScrewRelocate(options: ScrewRelocateGenerateOptions = {}): ScrewRelocateLevel

Make a level: planks across a grid of board holes, each fastened by a screw at both ends, layered so they cover each other, with the board's other holes free for parking. The search proves it can be cleared, and its moves are the solution and the par. Throws when no level that needs minimum moves comes of the options.

solveScrewRelocate

function solveScrewRelocate(level: ScrewRelocateLevel, options: { maxStates?: number } = {}): ScrewRelocateMove[] | null

Search for moves that make every plate the level names fall, with the plates where they start (a plate stays put while it has a screw, and covers what it covers there). Best first, by the fastenings left to undo and the moves so far, so it finds short solutions quickly, though not always the very shortest. Returns the moves, or null when none is found within maxStates (default 40,000).

validateScrewRelocateLevel

function validateScrewRelocateLevel(level: ScrewRelocateLevel): string[]

Check a level and say what is wrong with it, as plain sentences; empty when it can be played.

Types

ScrewRelocateApi

interface ScrewRelocateApi

What the screw-relocate pack adds to a game: game.screwRelocate.

  • create: typeof createScrewRelocate — Make a game of a level.
  • generate: typeof generateScrewRelocate — Make a level the search can clear.
  • solve: typeof solveScrewRelocate — Search for the fewest moves that clear a level.
  • validate: typeof validateScrewRelocateLevel — Check a level; empty when it can be played.

ScrewRelocateEvent

type ScrewRelocateEvent = | { kind: 'move'; screw: string; from: string; to: string; plates: string[] } | { kind: 'pivot'; plate: string } | { kind: 'fall'; plate: string } | { kind: 'won'; moves: number; stars: number } | { kind: 'lost'; cause: 'moves' | 'stuck' }

What happened, for the presenter.

ScrewRelocateGame

interface ScrewRelocateGame

A game of one level.

  • readonly level: Readonly<ScrewRelocateLevel> — The level, as played (a copy).
  • readonly state: Readonly<ScrewRelocateState> — The state, live.
  • readonly stack: PlateStack — The plates and screws. Replaced by a restart or a restore.
  • movable(screw: string): boolean — Whether a screw can be taken now: it is in, and nothing covers it.
  • move(screw: string, hole: string): boolean — Move a screw to a free hole. False when it cannot.
  • step(dt: number): void — Advance by dt seconds: plates swing and fall.
  • stars(): number — Stars for the moves made: 3 at or under par, 2 within half again, else 1.
  • drain(): ScrewRelocateEvent[] — What happened since the last drain, oldest first.
  • view(): ScrewRelocateView — Everything to draw.
  • restart(): void — Start the level again.
  • snapshot(): ScrewRelocateSave — The game as plain JSON: its moves, replayed on restore.
  • restore(save: ScrewRelocateSave): void — Resume a snapshot of this level. Throws on another level's, and leaves the game as it was.

ScrewRelocateGenerateOptions

interface ScrewRelocateGenerateOptions

How to make a level.

  • seed?: number — The seed. The same options and seed give the same level. Default 0.
  • id?: string — An id for the level. Default screw-relocate-<seed>.
  • cols?: number — Board holes across. Default 5.
  • rows?: number — Board holes down. Default 7.
  • spacing?: number — The distance between holes. Default 90.
  • plates?: number — How many plates. Default 5.
  • parking?: number — How many spare holes the board has beyond the planks' own: the parking places. Few make it a puzzle (screws must wait in holes that falling planks free). Default 2.
  • minimum?: number — The fewest moves the level must need. Default 3.
  • colours?: ReadonlyArray<string> — The plates' colours.

ScrewRelocateLevel

interface ScrewRelocateLevel

A level.

  • id?: string — Its id, which saves carry.
  • name?: string — A name to show.
  • stack: PlateStackSpec — The board, its holes, the plates and the screws.
  • clear?: string[] — The plates that must fall. Default all of them.
  • moves?: number — The most moves allowed. Default no limit.
  • par?: number — Moves for three stars. Default none: every win is three stars.
  • solution?: ScrewRelocateMove[] — A known solution: screws and the holes they go to, in order.

ScrewRelocateMove

interface ScrewRelocateMove

A move: a screw to a free hole.

  • screw: string — The screw.
  • hole: string — The free hole it goes to.

ScrewRelocateSave

interface ScrewRelocateSave

A saved game.

  • format: 'phaser-ae-screw-relocate' — Always 'phaser-ae-screw-relocate'.
  • version: 1 — The save format's version, 1.
  • level: string — The level's id ('' for a level without one).
  • history: ReturnType<History<unknown, Step>['snapshot']> — The moves, as the kernel's history saves them.

ScrewRelocateState

interface ScrewRelocateState

The game's state, to read.

  • phase: 'playing' | 'won' | 'lost' — 'playing', 'won' or 'lost'.
  • cause: 'moves' | 'stuck' | null — Why a lost game was lost.
  • moves: number — Moves made.
  • fallen: string[] — The plates that have fallen.
  • time: number — Seconds played.

ScrewRelocateView

interface ScrewRelocateView

Everything a presenter draws.

  • plates: PlateView[] — The plates as they are now (the plate-stack's view).
  • screws: ScrewView[] — The screws, each with its hole and whether it is covered.
  • holes: { id: string; x: number; y: number; free: boolean }[] — Every board hole, and whether it can take a screw now.