The pack
frogger
function frogger():Pack<{frogger:typeof rules}>
Lane-crossing rules over lane-control for any board: rows, lanes, platforms, bays and rule options are configurable; the classic arcade board is the default preset.
Functions
createFrogger
function createFrogger(definition: FroggerDefinition): FroggerGame
A replayable crossing over a validated definition: hops, time, next-level, undo/redo and validated saves.
froggerBonuses
function froggerBonuses(s: Pick<FroggerState, 'course' | 'time' | 'homes' | 'ladyTaken' | 'frog'>): { fly: number | null; flyKind: string | null; croc: number | null; lady: FroggerObject | null; }
The bay holding the bonus insect (and which kind), the bay holding a threat, and the escort piece while she can be picked up.
froggerDefinition
function froggerDefinition(input: FroggerOptions, attempt = 0): FroggerDefinition
Lay out and validate one candidate course (attempt 0–7 varies the seeded formation). Throws naming the bad option, row or lane.
froggerHint
function froggerHint(g: Pick<FroggerGame, 'state'>): { action: FroggerAction | null; reason: string; }
One safe action from the current state, or why none was found. Never changes the game.
froggerObjects
function froggerObjects(s: Pick<FroggerState, 'course' | 'time'>): FroggerObject[]
Derived objects and timed bonuses use the exact same lane samples as collision and carrying.
generateFrogger
function generateFrogger(o: FroggerOptions): { definition: FroggerDefinition; certificate: FroggerAction[]; complexity: { traffic: string[]; river: string[]; divers: string[]; hazards: string[]; homeOrder: number[]; }; timing: { tickMs: number; hopMs: number; turtleSurfaceMs: number; turtleWarningMs: number; turtleSubmergedMs: number; turtleRisingMs: number; provenance: string; }; }
Generate a course and its completion certificate: up to eight seeded formations are tried, and the winner is replayed independently through every bay without losing a frog. Throws naming the row that blocked every route.
layoutFrogger
function layoutFrogger(o:{seed:number;difficulty:'easy'|'medium'|'hard';level:number;turtleSurface:number;turtleUnderwater:number;board:FroggerBoard;rules:FroggerRules},attempt:number):FroggerLayout
Lay a validated board out as concrete lanes. Every seeded choice is drawn in a fixed order: per row lane its count, then each piece's kind and length, its spacing weights, offset and first diver; then level swaps, overlay lanes and the escort piece.
planFroggerHome
function planFroggerHome(game: Pick<FroggerGame, 'state'>, budget = 50000): FroggerAction[]
Bounded predictive search from the actual state; candidate hops simulate every collision tick. Throws a FroggerSearchError when no route is found.
resolveFroggerRules
function resolveFroggerRules(input:FroggerRulesInput={},base:FroggerRulesInput={}):FroggerRules
Merge rule overrides over the classic defaults and check every range. Throws naming the bad rule.
solveFrogger
function solveFrogger(d: FroggerDefinition): FroggerAction[]
Fill every bay, then independently replay the exact timed commands.
validateFrogger
function validateFrogger(d: FroggerDefinition): void
Check a complete definition, including any edited by hand. Throws on the first problem.
validateFroggerBoard
function validateFroggerBoard(board:FroggerBoard):void
Check a board design. Throws a message naming the row, lane or field at fault.
validateFroggerRules
function validateFroggerRules(r:FroggerRules):void
Check a complete rules object. Throws naming the bad rule.
Constants
froggerDefaultRules
const froggerDefaultRules: FroggerRules
Classic arcade rules.
froggerKind
const froggerKind = (kinds:Record<string,FroggerKind>,kind:string):FroggerKind|undefined=> …
Look up a kind's behaviour without inheriting object prototype names.
froggerPresets
const froggerPresets: Record<'classic'|'curb-hopper',FroggerPreset>
Ready-made designs: classic (the default board and rules) and curb-hopper. Pass one as preset, or copy and edit its board.
Types
Direction
type Direction = 'up' | 'down' | 'left' | 'right'
A one-cell hop.
Frog
type Frog = { … }
The frog: centre x in cells, row (fractional mid-hop), ride the speed it is being carried at, queued a buffered hop.
x: numberrow: numberfacing: Directionhop: FrogHop | nullescort: booleanride: numberqueued: Direction | null
FroggerAction
type FroggerAction = Advance | { kind: 'hop'; direction: Direction; } | { kind: 'next-level'; }
Commands: advance time, hop, or move on after a completed level.
FroggerBoard
type FroggerBoard = { … }
The playfield: any number of rows from start to home, each lane's direction, speed, pieces, gaps and divers, the bays, and timed bonuses. Plain JSON.
name?:string— Presenter name for the board (classic,curb-hopper).width:number— Field width in cells, 4–64. Positions are piece left edges and frog centres in cells; hops are one cell.start?:number— Frog start centre in cells; default the middle (width / 2).rows:FroggerRow[]— 3–30 rows, bottom to top: row 0 must besafe(the start) and the top row must behome.kinds?:Record<string,FroggerKind>— Behaviour of particular piece kinds (turtle parts, crocodile jaws, rideable otters).hazards?:FroggerOverlay[]— Overlay hazard lanes, gated by level.fly?:{kinds?:string[];period:number;active:number}|null— A bonus insect that sits in a random empty bay foractiveof everyperiodseconds; kinds take turns. Absent: none.homeCroc?:{kind?:string;from?:number;period:number;active:number}|null— A threat that occupies a random empty bay for the lastactiveof everyperiodseconds, from levelfrom(default 1). Needsrules.hazards.lady?:{lane:string;kind?:string;period:number;active:number}|null— An escort (the lady frog) riding one piece of a river lane foractiveof everyperiodseconds; land on her and bring her home.messages?:Partial<Record<FroggerCause,string>>— Death message overrides by cause.
FroggerCause
type FroggerCause='vehicle'|'water'|'dive'|'drift'|'miss'|'occupied'|'threat'|'bite'|'hazard'|'timeout'
Why a frog was lost: a vehicle; open water; a support that dived; carried or hopped off the side; the bank between bays; an occupied bay; a bay threat; a mouth; a hazard; the timer.
FroggerDefinition
type FroggerDefinition = { … }
A concrete, validated course: the board laid out as lane-control lanes, with every timing in milliseconds.
attempt: number— Layout attempt 0–7 that certified.options: FroggerSettings— Settings that regenerate this course.rows: { kind: FroggerRow['kind']; name: string; edges: FroggerEdges; }[]— Row kinds, names and edge policy, bottom (start) to top (home).field: LaneField— Wrapping lanes.road: { row: number; lane: string; }[]— Vehicle lanes by row.river: { row: number; lane: string; }[]— Platform lanes by row.hazards: { row: number; lane: string; }[]— Overlay hazard lanes by row.kinds: Record<string, FroggerKind>— Piece kind behaviour.homes: number[]— Bay centres in cells.between: string— Presenter name for the bank between bays.start: number— Frog start centre in cells.hopMs: number— Hop milliseconds.radius: number— Frog half-width in cells.fly: { kinds: string[]; period: number; active: number; } | null— Bay bonus insect, milliseconds; null for none.homeCroc: { kind: string; period: number; active: number; } | null— Bay threat, milliseconds; null when off or below its level.lady: { lane: string; item: string; kind: string; period: number; active: number; } | null— Escort piece, milliseconds; null for none.messages: Record<FroggerCause, string>— Death messages by cause; empty derives the text from the piece kind.
FroggerDive
type FroggerDive = { … }
A diving cycle in seconds. Missing values come from the turtleSurface/turtleUnderwater options and the .75 s warning and .35 s rising defaults.
surface?:number— Seconds surfaced and safe; default theturtleSurfaceoption (5).warning?:number— Seconds of visible warning, still safe; default .75.submerged?:number— Seconds under water, giving no support (for ajawskind: mouth open); default theturtleUnderwateroption (1.1).rising?:number— Seconds coming back up, still giving no support; default .35.offset?:number— Seconds into the cycle at time zero; several divers in one lane are spread evenly from here. Default 0.pace?:number— Runs the whole cycle faster (above 1) or slower (below 1); .25–4, default 1.
FroggerEdges
type FroggerEdges='block'|'open'
Whether a sideways hop past the field edge is refused (block) or allowed, so the frog lands or drifts off (open).
FroggerGame
type FroggerGame = Timeline<FroggerDefinition, FroggerState, FroggerAction> & { hint(): { action: FroggerAction | null; reason: string; }; }
A replayable crossing with a safe-move hint.
FroggerHomeRow
type FroggerHomeRow = { … }
The top row: bays to fill, with bank (bushes, shrubs) between them.
kind:'home'— Row kind.name?:string— Presenter name.bays:number[]— Bay centres in cells from the left edge, 1–16 of them; each must be filled once.between?:string— Presenter name for the bank between bays; defaultbush. Landing on it loses a frog.
FroggerKind
type FroggerKind = { … }
Behaviour of a piece kind beyond its lane's role. Kinds not listed behave plainly: vehicles kill, platforms carry, hazards kill.
parts?:number— Identical parts drawn across one piece, e.g. 3 for a turtle trio that moves and dives as one; 1–8, presentation only. Default 1.cycle?:'dive'|'jaws'— What the activity cycle means:dive(default) — submerged and rising pieces neither carry nor harm;jaws— the piece stays and its mouth is lethal only while submerged (open).mouth?:{length:number;end:'front'|'back'|'left'|'right'}— A lethal end, in cells: crocodile jaws, an otter's head.frontandbackfollow the lane's direction.ride?:boolean— A hazard-lane piece the frog may ride: only its mouth is lethal, and on a river row its back carries the frog.message?:string— Death message for this kind's bite or contact; default derived from the name (A snake caught you,Crocodile jaws).
FroggerLane
type FroggerLane = { … }
One lane of moving pieces: a road row's traffic, a river row's platforms or a hazard overlay.
id?:string— Unique lane id, a lowercase identifier of at most 24 characters. Defaultroad-<row>,river-<row>orhazard-<n>.direction:'left'|'right'— Which way the pieces travel.speed:number— Cells per second at medium difficulty on level one, before difficulty and progression multipliers; 0–30. 0 holds still.pieces:FroggerPiece[]— Piece templates (1–16), used in turn along the lane.count?:FroggerTuned<number|[number,number]>— How many pieces (0–64); a[min, max]range picks by seed. Default one per template.gap?:FroggerTuned<number>— Minimum clear cells between pieces, or between convoys; spare room is shared out by seed. Default 1.group?:number— Pieces per convoy, travellingspacingapart; default 1 (no convoys).spacing?:number— Clear cells between pieces inside a convoy; default the gap.divers?:number|'all'— How many pieces dive, chosen by seed, or'all'. Default 0.dive?:FroggerDive— The divers' cycle.swap?:{from:number;kind:string;dive?:FroggerDive}— From levelfrom, one piece (chosen by seed) becomeskindwith this cycle: the classic crocodile log. Needsrules.hazards.
FroggerLaneRow
type FroggerLaneRow = { … }
A road row (its lane's pieces are lethal vehicles) or a river row (its lane's pieces are the only footing, and carry the frog).
kind:'road'|'river'— Row kind.name?:string— Presenter name.edges?:FroggerEdges— Side edges; defaultblock.lane:FroggerLane— The row's traffic or platforms.
FroggerLayout
type FroggerLayout = { … }
A board resolved into lane-control lanes and row roles; part of a definition.
rows:{kind:FroggerRow['kind'];name:string;edges:FroggerEdges}[]— Row kinds, names and edge policy, bottom to top.field:LaneField— Concrete wrapping lanes.road:{row:number;lane:string}[]— Vehicle lanes by row.river:{row:number;lane:string}[]— Platform lanes by row.hazards:{row:number;lane:string}[]— Overlay hazard lanes by row.kinds:Record<string,FroggerKind>— Piece kind behaviour.homes:number[]— Bay centres in cells.between:string— Presenter name for the bank between bays.start:number— Frog start centre in cells.fly:{kinds:string[];period:number;active:number}|null— Bay bonus insect, in milliseconds.homeCroc:{kind:string;period:number;active:number}|null— Bay threat for this level, in milliseconds.lady:{lane:string;item:string;kind:string;period:number;active:number}|null— Escort piece, in milliseconds.messages:Record<FroggerCause,string>— Death messages by cause; empty means derived from the piece kind.
FroggerObject
type FroggerObject = LaneItem & { lane: string; row: number; phase: LanePhase; speed: number; role: 'vehicle' | 'platform' | 'hazard'; parts: number; }
A piece as sampled for collision, carrying and drawing: lane, row, activity phase, signed speed, role and drawn parts.
FroggerOptions
type FroggerOptions = { … }
Generation controls. Omit board, rules and preset for the classic arcade crossing.
seed: number— Unsigned 32-bit seed for counts, lengths, spacing and divers.difficulty?: 'easy' | 'medium' | 'hard'— Speed multiplier (.8, 1, 1.13) and any per-difficulty lane counts and gaps; defaultmedium.level?: number— Starting level, 1 torules.levels; default 1.lives?: number— Frogs, 1–9; default 3.seconds?: number— Timer seconds per frog, 10–300, or 0 for no timer; default 60.turtleSurface?: number— Default seconds a diver stays surfaced, 3–12; default 5. Lanes may set their own.turtleUnderwater?: number— Default seconds a diver stays under, .6–2; default 1.1. Lanes may set their own.preset?: keyof typeof froggerPresets— A named design fromfroggerPresetssupplying the board and rule defaults; defaultclassic.board?: FroggerBoard— The board, replacing the preset's.rules?: FroggerRulesInput— Rule overrides, merged over the preset's rules.
FroggerOverlay
type FroggerOverlay = { … }
An extra lane laid over a row, such as a snake on the median or an otter in the river. Its pieces are hazards.
row:number— Row index it crosses: not the start row or the home row.from?:number— First level it appears on; default 1. Needsrules.hazards.lane:FroggerLane— Its moving pieces.
FroggerPiece
type FroggerPiece = { … }
One kind of moving piece. A lane uses its piece templates in turn: [log, lily pad] alternates them.
kind:string|string[]— Presenter name, a lowercase identifier (truck,log-small). Several names: each piece picks one by seed.length:number|number[]— Physical length in cells. Several lengths: each piece picks one by seed; repeat a value to weight it.
FroggerPreset
type FroggerPreset = { … }
A complete design: a board and the rules that differ from the defaults.
board:FroggerBoardrules:FroggerRulesInput
FroggerRow
type FroggerRow=FroggerSafeRow|FroggerLaneRow|FroggerHomeRow
One board row, listed bottom (start) to top (home).
FroggerRules
type FroggerRules = { … }
How a crossing plays. Every field has the classic arcade default.
support:'footprint'|'centre'—footprint(default): the whole frog must be on a surfaced piece.centre: only its centre point needs support.drift:number— Cells the frog's footprint may ride past a side edge before the drift death; 0–2, default 0.bayTolerance:number— Cells the frog's centre may land off a bay's centre and still enter it; 0–1.5, default .35.vehicleInset:number— Cells trimmed from each end of every vehicle's hitbox; 0–1, default 0.radius:number— Frog half-width in cells; .1–.45, default .23.hopSeconds:number— Hop duration in seconds, .1–.4 in steps of .01; default .18.bufferHops:boolean— A hop pressed mid-hop is queued and taken on landing; default false (rejected).hopCarry:boolean— A hop from a moving platform keeps the platform's motion, so hops are relative to it; default false (hops are relative to the field).timer:'attempt'|'life'— When the timer refills:attempt(default) — every new frog, after a death or a filled bay;life— only after a death.homeSpeedUp:number— Fraction every lane speeds up per filled bay (compounding); 0–1, default 0.levelSpeedUp:number— Fraction lanes speed up per level, cycling everylevelCyclelevels; 0–.5, default .065.levelCycle:number— Levels in a progression cycle; 1–99, default 5.levels:number— Levels in the game, 1–99, default 99. Filling every bay on the last level wins (status: 'won'); 1 makes a single-board game.hazards:boolean— Level-gated hazards: lane swaps, overlay lanes and bay threats; default true.extraLife:number— Score that awards one extra life; 0 for none. Default 20,000.score:FroggerScore— Points awarded.
FroggerRulesInput
type FroggerRulesInput=Partial<Omit<FroggerRules,'score'>>&{score?:Partial<FroggerScore>}
Rules as a game supplies them: any subset, with score merged field by field.
FroggerSafeRow
type FroggerSafeRow = { … }
Solid ground: the start, a median, a verge. Overlay hazards may still cross it.
kind:'safe'— Row kind.name?:string— Presenter name (curb,median).edges?:FroggerEdges— Side edges; defaultblock.
FroggerScore
type FroggerScore = { … }
Points awarded.
hop:number— Each safe landing; default 10.forwardOnly:boolean— Awardhoponly for a row this frog has not reached since it last started; default false (every safe landing).bay:number— Filling a bay; default 50.second:number— Per whole second left on the timer when a bay fills; default 10.fly:number— Collecting the bay bonus insect; default 200.lady:number— Bringing the escort home; default 200.clear:number— Filling every bay; default 1,000.
FroggerSearchError
type FroggerSearchError = Error & { furthest: number; stood: number; }
A search failure: the furthest row any explored route landed on, and the furthest row a frog could stay on for a hop.
FroggerSettings
type FroggerSettings = { … }
Resolved generation controls, stored in each definition so next-level and saves can regenerate it.
seed: number— Seed.difficulty: 'easy' | 'medium' | 'hard'— Difficulty.level: number— Level of this course.lives: number— Starting frogs.seconds: number— Timer seconds per frog; 0 for none.turtleSurface: number— Default diver surface seconds.turtleUnderwater: number— Default diver underwater seconds.board: FroggerBoard— The board design.rules: FroggerRules— Complete rules.
FroggerState
type FroggerState = { … }
Complete simulation state. best is the highest row this frog has reached; lastCause why the last frog was lost.
course: FroggerDefinitiontime: numberremainder: numberremaining: numberfrog: Froglives: numberscore: numberhomes: boolean[]status: 'playing' | 'level-complete' | 'won' | 'game-over'respawn: numberdeaths: numberflies: numberescorts: numberextraLife: booleanladyTaken: numbermessage: stringlastDeath: stringlastCause: FroggerCause | ''lastHome: number | nullbest: number
FroggerTuned
type FroggerTuned<T>=T|{easy:T;medium:T;hard:T}
A value that may differ by difficulty: one value for all three, or {easy, medium, hard}.
FrogHop
type FrogHop = { … }
A hop in flight. carry is the platform speed it keeps (cells/second) and drift the cells carried so far.
fromX: numberfromRow: numbertoX: numbertoRow: numberelapsed: numberdirection: Directioncarry: numberdrift: number


