Phaser AE

Letter wheel word puzzles

Pro packv3.0.0-0WordNew

One word's letters on a wheel, and a crossword of the words they spell. Trace round the wheel to find them; anything else the letters make is a bonus word. The pack builds every level and judges every word.

This is a Pro pack. Upgrade to Phaser Pro to use it in your games.See Phaser Pro →

Released October 21, 2026

Letter wheel word 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

letterWheel

function letterWheel(): Pack<{ letterWheel: LetterWheelApi }>

The letter-wheel pack: letter wheel word puzzle rules over the english-words lists. Pure logic, so it runs headless.

Helpers

createLetterWheel

function createLetterWheel(options: LetterWheelOptions): LetterWheel

Make a level. Throws a RangeError for options out of range: a base word with characters other than letters, a letter count no word list word has, minLength longer than the wheel, or no base word meeting minWords.

layoutCrossword

function layoutCrossword(words: ReadonlyArray<string>, maxSize: number, rng: Rng, limit = Infinity): { placed: Placed[]; width: number; height: number }

Lay words out as a crossword, in the order given, each crossing one already placed where they share a letter, no two words side by side, inside maxSize cells each way, stopping after limit words (default all). Returns the words placed with their first cells, counting from 0 at the top left, and the size. Words that will not fit are left out. Pure in rng.

wheelLevel

function wheelLevel(level: number, options: { seed?: number; maxLetters?: number; maxTargets?: number; levelsPerLetter?: number; extra?: Partial<LetterWheelOptions> } = {}): LetterWheelOptions

Options for level level (from 1) of a rising ladder: more letters and more targets as the levels go up, from 4 letters and 3 targets to maxLetters (default 7) and maxTargets (default 10), one more letter every levelsPerLetter levels (default 8). The seed comes from seed and the level, so each level is always the same. extra is merged over the result.

Types

LetterWheel

interface LetterWheel

A letter wheel level. Make one with createLetterWheel.

  • observation(): LetterWheelView — The level as it stands.
  • spell(path: ReadonlyArray<number>): string | null — What a path round the wheel spells: wheel positions, each used once. Null for a repeated or unknown position.
  • check(word: string): { readonly ok: true; readonly kind: WheelResult['kind'] } | Refusal — Would this word count now, and as what? Changes nothing.
  • trace(path: ReadonlyArray<number>): { readonly ok: true; readonly result: WheelResult } | Refusal — Submit a path traced round the wheel. A repeat is accepted (it changes nothing) so a game can say so; a non-word is refused.
  • type(word: string): { readonly ok: true; readonly result: WheelResult } | Refusal — Submit a typed word, made of the wheel's letters.
  • shuffle(): void — Put the wheel's letters in a new order.
  • hint(): { readonly ok: true; readonly result: { readonly target: number; readonly position: number; readonly letter: string; readonly completed: ReadonlyArray<number> } } | Refusal — Show one hidden letter: the first hidden letter of the shortest unfound target. Refused when the level is complete.
  • undo(): boolean — Take back the last move.
  • answers(): ReadonlyArray<string> — The targets' words in index order, for a solution screen or a test.
  • readonly base: string — The base word, whose letters are on the wheel.
  • snapshot(): HistorySave<LetterWheelMove> — The level as a save: the seed and the moves. Restore it into a level made with the same options.
  • restore(save: HistorySave<LetterWheelMove> | string): void — Replace this level's moves with a save. Throws, changing nothing, when it does not replay.

LetterWheelApi

type LetterWheelApi = typeof rules

game.letterWheel: every function and type this pack carries, as one namespace.

LetterWheelMove

type LetterWheelMove = | { readonly kind: 'trace'; readonly path: ReadonlyArray<number> } | { readonly kind: 'type'; readonly word: string } | { readonly kind: 'shuffle' } | { readonly kind: 'hint' }

A move.

LetterWheelOptions

interface LetterWheelOptions

How a level is made. Only seed is required.

  • seed: number — Picks the base word, the targets and the wheel's order, as an unsigned 32-bit integer.
  • letters?: number — Letters on the wheel: the base word's length. Default 6, or the length of base.
  • base?: string — The base word (or any letters) to use instead of a seeded pick.
  • words?: WordList — The words that count. Default the English lexicon.
  • minLength?: number — Shortest word that counts, in letters. Default 3.
  • targets?: number — Most target words. The rest of the words the letters spell are bonus words. Default 8.
  • minWords?: number — Fewest words the letters must spell for a seeded base word to be chosen. Default 4.
  • attempts?: number — Base words tried to meet minWords. Default 60.
  • layout?: WheelLayout — How the targets are laid out. Default 'crossword'.
  • maxSize?: number — A crossword's widest and tallest, in cells. Default 12. Targets that will not fit are left as bonus words.
  • exclude?: ReadonlyArray<string> — Words never used, as targets or bonus words (any case): a family game's own blocklist.

LetterWheelView

interface LetterWheelView

The level as it stands. Never gives away an unfound word.

  • readonly wheel: ReadonlyArray<string> — The wheel's letters in their current order, lower case.
  • readonly targets: ReadonlyArray<WheelTarget> — The targets: in crossword order (placed first, first) or, in a list, by length then alphabetically.
  • readonly found: number — How many targets are found.
  • readonly complete: boolean — Every target found?
  • readonly layout: WheelLayout — The layout in use.
  • readonly cells: ReadonlyArray<ReadonlyArray<WheelCell | null>> — The crossword, row by row (cells[y][x]), null where there is no cell; empty in a list.
  • readonly bonus: ReadonlyArray<string> — Bonus words found, in order.
  • readonly bonusTotal: number — How many bonus words the letters spell in all.
  • readonly hints: number — Hints used.
  • readonly shuffles: number — Shuffles used.

WheelCell

interface WheelCell

One crossword cell.

  • readonly letter: string | null — The letter, once shown; null while hidden.
  • readonly targets: ReadonlyArray<number> — The targets that use this cell.

WheelLayout

type WheelLayout = 'crossword' | 'list'

How the target words are shown: crossing each other in a crossword, or as a list grouped by length.

WheelPlacement

interface WheelPlacement

Where a target sits in a crossword.

  • readonly x: number — The first letter's cell, x across and y down from 0 at the top left.
  • readonly y: number — The first letter's row.
  • readonly direction: 'across' | 'down' — 'across' (left to right) or 'down' (top to bottom).

WheelResult

interface WheelResult

What a word did: found a target, found a bonus word, or found a word already found.

  • readonly kind: 'target' | 'bonus' | 'repeat' — 'target', 'bonus' or 'repeat'.
  • readonly word: string — The word, lower case.
  • readonly target: number | null — The target's index, for a target or a repeat of one; null for a bonus word.
  • readonly completed: ReadonlyArray<number> — Targets this word completed by crossing them (their last hidden letters were in it).
  • readonly complete: boolean — Is the level complete now?

WheelTarget

interface WheelTarget

A target as a player sees it.

  • readonly index: number — Its place among the targets, which never changes.
  • readonly length: number — How many letters.
  • readonly word: string | null — The word, once found or once the level is complete; null before.
  • readonly shown: ReadonlyArray<string | null> — Each letter as shown: the letter once found, revealed by a hint or crossed by a found word, else null.
  • readonly found: boolean — Found by tracing or typing, or shown in full by hints and crossings.
  • readonly revealed: boolean — Every letter shown without the word being traced or typed.
  • readonly placement: WheelPlacement | null — Its place in the crossword; null in a list.