Phaser AE

Title screen

Pro packv3.0.0-32DLook

A whole animated title screen as one data file, played with one line. The key art moves, the logo slams in and shines, characters peek in from the edges, and any press takes the player into the game through a transition.

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

Released October 14, 2026 · updated October 19, 2026

Title screen: 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

titleScreen

function titleScreen(opts: TitleScreenOptions = {}): Pack<{ titleScreen: TitleScreenApi }>

The title-screen pack: game.titleScreen.play(file, { next: 'play' }) plays a phaser-ae-title-screen file in the current scene — key art, shaders, layers, particles, the logo's entrance and shine, the small events that keep the idle alive — and on Start runs the layers' exits and the transition into next. Requires a 2D world to draw on (world-side); every other part is drawn by the pack that owns it, when composed.

Functions

atlasKeys

function atlasKeys(def: Pick<TitleScreenDef, 'layers' | 'events'>): Set<string>

The pictures that must be loaded INTO THE ATLAS (atlas: true): the ones drawn through sprite effects (which read only the atlas) and the scrolling strips. A build that preloads a file's pictures loads these with atlas: true.

attractAt

function attractAt(t: number, c: AttractClock): AttractNow

Attract at t, as a pure function of the clock: runs start after seconds after the later of the last press and the reveal's end, last total seconds, and repeat with after seconds of title between; one asked for starts when asked; a press cuts the one playing. The title fades out as a run starts and back in when it ends.

attractPlan

function attractPlan(def: TitleScreenDef, opts: { flags?: ReadonlySet<string> | readonly string[]; rows?: readonly TitleScore[]; aspect?: (key: string) => number } = {}): AttractPlan

Lay the run out: every card the flags let in, in order, each drawn as layers (a panel, a heading, pictures and words) with entrances timed on the run's clock. rows fills the scores cards; aspect(key) is a picture's height over its width (default from the file's assets, else square).

attractStyle

function attractStyle(def: Pick<TitleScreenDef, 'attract' | 'layers' | 'palette'>): AttractStyle

The style the cards are drawn in: the file's attract choices, else the prompt's font and colour and the palette.

beatClock

function beatClock(t: number, audio: { bpm?: number; beat?: number }, lock: BeatLock = FREE_BEAT): BeatClock | null

The beat clock at screen time t for a file's audio, or null when it has no bpm. With no lock (a tool seeking, or no music) it is the screen's own clock from audio.beat; with one, it follows the music.

beatCycles

function beatCycles(c: BeatClock, beats: number): number

Cycles of an idle that turns once every beats beats, at this beat: a whole number on each of its beats. While the lock eases, each cycle slides the shorter way round onto the music's, so nothing runs more than half a cycle fast or slow.

cardAt

function cardAt(plan: AttractPlan, u: number): PlannedCard | null

The card playing u seconds into a run, or null.

ease

function ease(name: TitleEase, x: number): number

The eased value of x (0..1) along a named curve.

eventSchedule

function eventSchedule(count: number, every: [number, number], from: number, until: number, seed: number, durations: (i: number) => number): Array<{ at: number; item: number }>

The idle loop's schedule: the surprises at and after from seconds, up to until, as [start, item index] pairs. Pure: the gaps come from the seed, so the same file shows the same surprises at the same moments.

flagsAllow

function flagsAllow(item: TitleFlagged, flags: ReadonlySet<string> | readonly string[]): boolean

Is something shown with these flags on? (when must be on, unless must be off; neither means always.)

followMusic

function followMusic(lock: BeatLock, t: number, music: number): BeatLock

The lock one step on: t is the screen's time and music the track's (game.sound.musicTime, 0 while nothing plays). When the music starts, restarts or goes round (its time went back), or jumps, the beat eases from where it is onto the music's over BEAT_EASE; between, it follows the music's small drift; while nothing plays it keeps the lead it had. Held (after a seek), only a start or a loop takes it back.

hash1

function hash1(n: number): number

A repeatable hash of a number to 0..1 (no state; the same input always gives the same output).

holdBeat

function holdBeat(lock: BeatLock): BeatLock

What a seek does to the lock: the screen's clock rules, so the same moment shows the same beat.

idleBeats

function idleBeats(m: Pick<TitleIdle, 'kind' | 'beats'>, bpm: number | undefined): number | null

The beats an idle really keeps (m.beats, doubled until the kind's top rate allows it: three a second for anything that flashes), or null when it keeps none: no beats, no tempo, or a kind with no rate.

idleCycles

function idleCycles(m: TitleIdle, t: number, beat?: BeatClock | null): { cycles: number; hz: number; locked: boolean }

Where an idle's rhythm is at t: cycles so far (its phase included), and how many a second; locked when on the beat.

keptInAttract

function keptInAttract(l: Pick<TitleLayer, 'role' | 'kind'>): boolean

Does a layer stay up during attract? The scenery (role scenery or fx, and particle fields and strips with no role) stays, as the cards' backdrop; the logo, words, prompt, characters and props make way for the cards.

layerWantsFx

function layerWantsFx(l: TitleLayer, def: Pick<TitleScreenDef, 'events'>): boolean

Is this layer's picture drawn through sprite effects: a glow, outline or shine of its own, a shine surprise, or an entrance or exit the effects draw (a wipe, iris, dissolve, glitch, a slam's flash, or one from behind a line)?

letterPose

function letterPose(layer: TitleLayer, index: number, t: number, reduced: boolean): { scale: number; alpha: number; dy: number }

One letter's pose in a letters enter: each letter pops in stagger seconds after the last.

parseTitleScreen

function parseTitleScreen(input: unknown, warnings?: string[]): TitleScreenDef

Read a title screen file leniently. warnings collects what was dropped or changed. Throws only when input is not an object, names another format, or holds nothing to show.

poseAt

function poseAt(layer: TitleLayer, t: number, ctx: PoseContext, seed = 0): LayerPose

The pose of layer at t seconds after the screen started. Before its enter begins a layer is hidden (alpha 0) unless its enter is none; idle motions ease in over 0.4 s once it has arrived; after Start (ctx.exitAt) its exit plays. Hidden layers (shown only by events) are posed by their events, not here.

postParamKind

function postParamKind(p: TitlePostParam): 'number' | 'color' | 'rgb'

What kind of value a post param holds: 'number', 'color' or 'rgb'.

scoreRows

function scoreRows(given: ReadonlyArray<{ name?: unknown; score?: unknown }> | null | undefined, rows: number): TitleScore[]

The rows a scores card shows: the game's, cleaned (names trimmed to 16 characters) and best first, else the stand-in.

serializeTitleScreen

function serializeTitleScreen(def: TitleScreenDef | unknown): string

The canonical file: parsed (so it is valid), numbers rounded, pretty-printed.

settleTime

function settleTime(def: Pick<TitleScreenDef, 'layers'>, flags: ReadonlySet<string> | readonly string[] = []): number

When the reveal is over: the last arrival among the layers shown with these flags on (none on, by default). The idle loop's events start after it.

Constants

ATTRACT_AFTER

const ATTRACT_AFTER: TitleKnob

Seconds of no press before attract mode, when the file does not say. 0 is allowed too: only when asked.

ATTRACT_FADE

const ATTRACT_FADE: 0.35

Seconds the title takes to fade out as attract starts, and back in as it ends.

BEAT_EASE

const BEAT_EASE: 0.5

Seconds the beat takes to slide onto the music when it starts or restarts: the phase eases there, never jumps.

BEAT_IDLE_KINDS

const BEAT_IDLE_KINDS: readonly ["bob", "breathe", "sway", "pulse", "blink", "flicker", "hum", "cycle", "twinkle", "orbit"]

The idle motions with a rate, which can keep time with the music instead (beats).

BEHIND_KINDS

const BEHIND_KINDS: readonly ["rise", "drop", "slide"]

The entrances that can come from BEHIND a line at the layer's resting edge (enter.behind).

BLENDS

const BLENDS: readonly ["normal", "add", "screen", "multiply"]

How a layer's pixels combine with what is beneath.

CARD_ENTER_KINDS

const CARD_ENTER_KINDS: ("none" | "fade" | "drop" | "slide" | "pop" | "zoom" | "spin" | "slam" | "rise" | "glitch" | "wipe" | "iris" | "dissolve")[]

The entrances a roll call's pictures may use: the catalogue without the flicker (attract never flashes) or letters.

CARD_EXIT_LEAD

const CARD_EXIT_LEAD: 0.4

Seconds before its end a card item starts to fade out.

CARD_KINDS

const CARD_KINDS: readonly ["rollcall", "howto", "scores", "logo"]

What an attract card shows.

CARD_SECONDS

const CARD_SECONDS: Record<TitleCardKind, TitleKnob>

How long each kind of card shows, seconds (a roll call: each character's turn).

CUT_FADE

const CUT_FADE: 0.2

Seconds a card takes to vanish when a press cuts attract short.

EASE_FAMILIES

const EASE_FAMILIES: readonly ["sine", "quad", "cubic", "quart", "quint", "expo", "circ", "back", "elastic", "bounce"]

Easing curves: linear, or a family with In, Out or InOut.

EASES

const EASES: TitleEase[]

Every easing name: linear, then each family's In, Out and InOut.

ENTER_DEFAULTS

const ENTER_DEFAULTS: Record<TitleEnterKind, { duration: number; ease: TitleEase }>

Each enter kind's default duration and ease.

ENTER_KINDS

const ENTER_KINDS: readonly ["none", "fade", "drop", "slide", "pop", "zoom", "spin", "slam", "rise", "flicker", "glitch", "wipe", "iris", "dissolve", "letters"]

How a layer arrives. wipe is a straight soft-edged wipe from its from side; iris a circle opening from the centre.

EVENT_KINDS

const EVENT_KINDS: readonly ["shine", "peek", "cross", "burst", "shooting-star", "wiggle"]

The idle loop's surprises, one at a time.

EXIT_CELLS

const EXIT_CELLS: TitleKnob

The exit's cells: its range and the transition's default.

EXIT_DEFAULTS

const EXIT_DEFAULTS: Record<TitleExitKind, { duration: number; ease: TitleEase }>

Each layer exit kind's default duration in seconds and ease.

EXIT_KINDS

const EXIT_KINDS: readonly ["none", "fade", "fly", "zoom", "shrink", "drop", "dissolve"]

How a layer leaves when Start is pressed.

FRAME_TRANSITIONS

const FRAME_TRANSITIONS: readonly ["crossfade", "zoom", "shatter"]

The exit transitions that cover with the title's own last frame (the transition pack's FRAME_KINDS).

FREE_BEAT

const FREE_BEAT: BeatLock

The beat on the screen's own clock: no music heard yet.

IDLE_BEATS

const IDLE_BEATS: readonly [0.5, 1, 2, 4, 8]

An idle's beats: one cycle every this many beats of the music (half a beat to two bars of four).

IDLE_KINDS

const IDLE_KINDS: readonly ["bob", "breathe", "sway", "pulse", "blink", "drift", "scroll", "spin", "flicker", "hum", "cycle", "twinkle", "orbit"]

How a layer stays alive once it has arrived. Any number may run together (up to TITLE_LIMITS.idle).

IDLE_KNOBS

const IDLE_KNOBS: Record<TitleIdleKind, { amount: TitleKnob; hz: TitleKnob }>

Each idle kind's knobs: amount and hz ranges and defaults. Rates that flash are capped at 3 a second.

LAYER_KINDS

const LAYER_KINDS: readonly ["image", "text", "particles", "strip", "shape"]

What a layer is.

LAYER_ROLES

const LAYER_ROLES: readonly ["logo", "subtitle", "prompt", "hero", "prop", "scenery", "fx"]

What a layer is FOR: the tool and the events read it (the logo is shined; the prompt pulses; a hero peeks).

NO_ATTRACT

const NO_ATTRACT: AttractPlan

No attract at all.

PARTICLE_COUNTS

const PARTICLE_COUNTS: Record<TitleParticlePreset, { def: number; max: number }>

Each preset's particles alive at once by default, and the ceiling.

PARTICLE_PRESETS

const PARTICLE_PRESETS: readonly ["embers", "dust", "fireflies", "snow", "rain", "petals", "leaves", "bubbles", "sparkles", "stars", "confetti", "smoke", "ash"]

Particle presets: each a tuned emitter the pack builds.

PLACEHOLDER_SCORES

const PLACEHOLDER_SCORES: readonly TitleScore[]

The table a scores card shows when the game gives none: obviously a stand-in, so nobody mistakes it for theirs.

POST_KINDS

const POST_KINDS: ("grain" | "bloom" | "vignette" | "crt" | "scanlines" | "chroma" | "pixelate" | "grade")[]

Every post effect name, in POST_PARAMS order.

POST_PARAMS

const POST_PARAMS: { readonly bloom: { readonly threshold: { readonly min: 0; readonly max: 1; readonly def: 0.55; }; readonly strength: { readonly min: 0; readonly max: 2; readonly def: 0.8; }; readonly radius: { readonly min: 0.5; readonly max: 6; readonly def: 2.5; }; }; ... 6 more ...; readonly grade: { ...; }; } …

Post effects (each a post-* pack) and the params each takes, with ranges. The ranges are narrower than the packs allow, so that every value a file can hold still looks like a title screen.

SCORE_ROWS

const SCORE_ROWS: TitleKnob

How many rows a scores card shows.

SHAPES

const SHAPES: readonly ["glow", "ray", "scrim", "bar", "spark"]

Shapes the pack paints itself, white, so tint colours them.

TITLE_LIMITS

const TITLE_LIMITS: { readonly layers: 48; readonly shaders: 4; readonly assets: 64; readonly fonts: 4; readonly palette: 8; readonly idle: 4; readonly events: 12; readonly post: 6; readonly text: 120; readonly code: 8000; ... 9 more ...; readonly castName: 32; } …

Caps, so a file can never ask for more than a title screen needs.

TITLE_SCREEN_FORMAT

const TITLE_SCREEN_FORMAT: "phaser-ae-title-screen"

The format every title screen file carries.

TITLE_SCREEN_VERSION

const TITLE_SCREEN_VERSION: 1

The newest version this module reads and writes. A newer file is read for what is understood, with a warning.

TRANSITION_KINDS

const TRANSITION_KINDS: readonly ["cut", "fade", "iris", "wipe", "diamonds", "blinds", "dissolve", "pixels", "radial", "crossfade", "zoom", "shatter"]

How the whole screen goes into play (the transition pack's kinds). crossfade, zoom and shatter cover with the title's last frame instead of a colour: it fades, flies into exit.at, or breaks from it.

WIPE_ANGLES

const WIPE_ANGLES: Record<TitleSide, number>

A wipe's angle for the side it comes in from (effects-2d's reveal convention: the direction the edge travels).

WIPE_SOFT

const WIPE_SOFT: TitleKnob

A wipe's soft edge: its range and default, as a fraction of the layer's diagonal.

Types

AttractClock

interface AttractClock

Where attract stands: the inputs of attractAt, each a moment in seconds since the screen started.

  • after: number — Seconds of no press before attract starts by itself; 0 = never by itself.
  • total: number — The run's length (0: no attract).
  • settleAt: number — The reveal's end: the idle count never starts before it.
  • pressAt: number — The last press.
  • forcedAt: number | null — When attract was asked for (handle.attract()), or null.
  • cut: { from: number; to: number } | null — The last run a press cut short: its start and the press.
  • exitAt: number | null — When Start was pressed, or null: no run starts after it.

AttractNow

interface AttractNow

Attract at one moment.

  • on: boolean — A run is playing.
  • u: number — Seconds into the latest run (playing or over), 0 when there has been none.
  • from: number | null — The latest run's start and end (its natural end, or where a press or Start cut it), or null.
  • to: number | null — The latest run's end in seconds (its natural end, or where a press or Start cut it), or null when there has been none.
  • stage: number — 0..1: how much of the title shows (1: all of it; 0: the run has the screen).

AttractPlan

interface AttractPlan

The whole run: its cards, their length, what each draws, the title layers it brings back.

  • cards: PlannedCard[] — The cards that play with these flags, in order.
  • total: number — Seconds the run lasts (0: there is no attract).
  • items: CardItem[] — Everything the cards draw.
  • replays: CardReplay[] — Title layers shown again.

AttractStyle

interface AttractStyle

The cards' look, with the file's gaps filled from its layers and palette.

  • font: string — The font family.
  • color: string — The words' colour.
  • accent: string — Headings, names and the top score.
  • gradient?: TitleGradient — Headings and names filled with this instead of accent, when the file gives one.
  • shade: string — Outlines and the panel.
  • panel: number — 0..1: how solid the panel is.

BeatClock

interface BeatClock

The music's beat at one moment, as poseAt reads it: the tempo, the screen's beat time and the lock's lead.

  • bpm: number — Beats a minute.
  • time: number — Seconds since the first downbeat on the screen's clock: screen time − audio.beat.
  • lead: number — Seconds the music runs ahead of time.
  • from: number — The lead it is easing from.
  • since: number — Seconds since the ease began (Infinity: none).

BeatLock

interface BeatLock

The pack's hold on the music's beat, between steps: how far the music runs ahead of the screen's clock (lead, seconds), the lead it is easing from and since when, and what the music did last step. followMusic moves it on.

  • lead: number — Seconds the music's beat is ahead of the screen's clock: music time − screen time while it plays.
  • from: number — The lead the phase is easing from.
  • at: number — Screen seconds the ease began (−Infinity: none, the lead holds).
  • music: number — The music's time at the last step (0: not playing).
  • playing: boolean — It was playing at the last step.
  • held: boolean — A seek let go of the music: the screen's clock rules until the music starts or goes round again.

CardItem

interface CardItem

One thing a card draws: an ordinary layer, posed on the attract run's clock.

  • layer: TitleLayer — What it draws, where (design px) and how it moves, with times in seconds from the start of the run.
  • card: number — The card it belongs to (its index in the file's attract.cards).
  • from: number — Seconds into the run it shows from and until (it fades out over the last CARD_EXIT_LEAD).
  • to: number — Seconds into the run it shows until; it fades out over the last CARD_EXIT_LEAD.
  • maxW?: number — Text only: the widest it may be, design px; wider is drawn smaller.
  • align?: 'left' | 'right' — Text only: layer.x is this edge rather than the centre (a table's columns).
  • panel?: boolean — The soft panel behind a card.

CardReplay

interface CardReplay

A layer of the title shown again during the run (the logo card).

  • layer: string — The layer's id.
  • at: number — When its entrance plays again, and when it leaves, in seconds into the run.
  • from: number — Seconds into the run the logo card starts; the layer shows from here.
  • to: number — Seconds into the run the logo card ends; the layer leaves here.

LayerPose

interface LayerPose

Where a layer is, relative to its resting place, and how it looks, at one moment.

  • dx: number — Offset from the layer's x, y, design px.
  • dy: number — Vertical offset from the layer's y, design px; positive is down.
  • sx: number — Scale on top of the layer's size (sx, sy apart for squash).
  • sy: number — Vertical scale; differs from sx for a squash.
  • rot: number — Degrees added to the layer's rotation.
  • alpha: number — Opacity multiplier.
  • reveal?: number — Sprite effects this moment wants: a reveal (0 hidden → 1 shown, effects-2d's reveal t), a dissolve (0 whole → 1 gone), a glitch amount. Present only while the entrance runs.
  • revealShape?: 'circle' | 'wipe' — The reveal's shape: 'circle' (an iris) or 'wipe' (a straight edge). Default the circle.
  • revealAngle?: number — A wipe's direction, degrees, effects-2d's reveal convention: 0 in from the left, 90 from the top, 180 the right, 270 the bottom.
  • revealSoft?: number — A wipe's soft edge, a fraction of the layer's diagonal (0: hard).
  • dissolve?: number — A dissolve amount for the sprite effect, 0 (whole) to 1 (gone); set only while a dissolve runs.
  • glitch?: number — A glitch amount for the sprite effect, from 14 down to 0 as the entrance settles; set only while a glitch runs.

PlannedCard

interface PlannedCard

A card in the run.

  • index: number — Its index in the file's attract.cards.
  • kind: TitleCard['kind'] — What it is.
  • from: number — Seconds into the run it starts and ends.
  • to: number — Seconds into the run it ends.

PoseContext

interface PoseContext

What poseAt needs to know besides the layer and the time.

  • width: number — Design size.
  • height: number — The design height, design px.
  • w: number — The layer's drawn size, design px.
  • h: number — The layer's drawn height, design px.
  • exitAt: number | null — When Start was pressed (seconds), or null.
  • reduced: boolean — Reduced motion: movement becomes fades, idle movement stops.
  • beat?: BeatClock | null — The music's beat, for idles with beats (beatClock); none: they run at their hz.

TitleAsset

interface TitleAsset

A picture or sound the file uses, by its key (the game's assets.json key); url loads it when the key is not loaded.

  • kind: 'image' | 'audio' — Whether the asset is a picture or a sound.
  • url: string — Where it loads from when its key is not already loaded; at most 2048 characters.
  • w?: number — Pixel size of the picture, so layouts never wait for it.
  • h?: number — Pixel height of the picture, 1 to 16384.
  • points?: [number, number][] — A picture's opaque points, 0..1 of its box: where a twinkle puts its sparkles (a tool measures them).

TitleAttract

interface TitleAttract

ATTRACT MODE: when the title has sat with no press for after seconds, the cards play in turn over the same shaders, then the title comes back. Any press during them returns to the title (it does not start the game).

  • after: number — Seconds of no press before it starts; 0 = only when asked (handle.attract()).
  • cards: TitleCard[] — The run, in order.
  • font?: string — The cards' font: a family from fonts or a shared one (default the prompt's font, else sans-bold).
  • color?: string — Their words' colour (default the prompt's colour, else white).
  • accent?: string — Headings, names and the top score (default the palette's brightest other colour).
  • gradient?: TitleGradient — Headings and names filled with a gradient instead of accent.
  • shade?: string — Outlines and the panel behind a card (default the palette's darkest colour, else black).
  • panel: number — 0..1: how solid the panel behind a card is (0: none).

TitleAudio

interface TitleAudio

The music and sounds a title screen plays.

  • music?: string — Music by asset key; it starts with the screen (or on the first tap, where the browser waits for one).
  • volume: number — Music volume, 0 to 1; default 0.8.
  • fadeIn: number — Seconds the music takes to fade in, 0 to 10; default 1.
  • start?: string — A sample played when Start is pressed.
  • reveal?: string — A sample played as the logo lands.
  • bpm?: number — The music's tempo, beats a minute (30..300): idles with beats keep time with it. To land the logo on a downbeat, end its entrance there: enter.at + enter.duration = beat + n * 60 / bpm.
  • beat?: number — Seconds into the track of its first downbeat (0..60), where the beat count starts.

TitleBackground

interface TitleBackground

The key art, drawn full screen under the shaders (backdrop.background); a shader can read and move it.

  • image: string — The key of an image asset.
  • fit: 'cover' | 'contain' — cover fills the screen, cropping the picture; contain shows all of it. Default cover.

TitleBlend

type TitleBlend = (typeof BLENDS)[number]

A blend mode: one of BLENDS.

TitleCamera

interface TitleCamera

The camera: a slow sway and push of the whole stage, and the pointer's parallax, each scaled by a layer's depth.

  • drift?: { x: number; y: number; hz: number } — A slow sway of the whole stage, design px, scaled by each layer's depth.
  • zoom?: { amount: number; hz: number } — A slow push in and out: 1 + amount · sin.
  • pointer: number — Design px each layer moves at depth 1 when the pointer is at the screen's edge.

TitleCard

type TitleCard = TitleRollcallCard | TitleHowtoCard | TitleScoresCard | TitleLogoCard

One card of the attract run.

TitleCardBase

interface TitleCardBase extends TitleFlagged

What every attract card has.

  • kind: TitleCardKind — What it shows.
  • seconds: number — How long it shows, seconds; a roll call's is each character's turn.
  • title?: string — A heading over it ('How to play').

TitleCardKind

type TitleCardKind = (typeof CARD_KINDS)[number]

An attract card kind: one of CARD_KINDS.

TitleCastMember

interface TitleCastMember extends TitleFlagged

A character in a roll call: their picture enters, then their name, then their line.

  • image: string — Their picture: an image asset's key.
  • name: string — Their name, drawn large in the accent colour.
  • line?: string — One line about them ('the lounge cat with a plan').
  • enter: TitleEnter — How the picture arrives; at counts from the start of their turn. Default a slide, from alternate sides.

TitleEase

type TitleEase = 'linear' | `${(typeof EASE_FAMILIES)[number]}${'In' | 'Out' | 'InOut'}`

An easing curve name: linear, or a family from EASE_FAMILIES with In, Out or InOut added ('cubicOut').

TitleEnter

interface TitleEnter

How a layer arrives. Times in seconds from the start of the screen.

  • kind: TitleEnterKind — Which entrance plays; none shows the layer at once.
  • at: number — Seconds after the screen starts.
  • duration: number — Seconds it takes.
  • ease: TitleEase — The easing curve applied across duration.
  • from?: TitleSide — Where it comes from: slide, drop, rise, fly; the side a wipe starts from (default the left).
  • distance?: number — Design pixels it travels (slide, drop, rise); 0 = from off screen (a rise: most of its own height).
  • shake?: number — 0..1 camera shake when it lands (slam).
  • flash?: boolean — A white flash on the layer when it lands (slam).
  • stagger?: number — Seconds between letters (letters).
  • soft?: number — wipe: the soft edge's width, 0..0.5 of the layer's diagonal (0: a hard edge). Default 0.04.
  • behind?: boolean — rise, drop, slide: it comes out from BEHIND a line at its resting edge on the side it comes from, as if from behind the hills or a wall, rather than across the screen. With no distance, a rise travels its own height, so it starts wholly hidden.

TitleEnterKind

type TitleEnterKind = (typeof ENTER_KINDS)[number]

An entrance kind: one of ENTER_KINDS.

TitleEvent

interface TitleEvent extends TitleFlagged

One kind of surprise in the idle loop.

  • kind: TitleEventKind — Which surprise this is.
  • layer?: string — The layer it acts on (shine, peek, cross, wiggle).
  • from?: TitleSide — peek and cross: the edge it comes from.
  • hold?: number — peek: seconds it stays · shine: seconds the sweep takes.
  • speed?: number — cross: design px a second.
  • preset?: TitleParticlePreset — burst: the preset and where (design px).
  • x?: number — burst: horizontal position, design px; default the middle of the screen.
  • y?: number — burst: vertical position, design px; default the middle of the screen.
  • count?: number — burst: particles let off, 1 to 200; default 24.
  • colors?: string[] — burst: hex colours the particles are picked from (default the preset's). shooting-star: the first is the star's colour.

TitleEventKind

type TitleEventKind = (typeof EVENT_KINDS)[number]

An idle surprise kind: one of EVENT_KINDS.

TitleEvents

interface TitleEvents

The idle loop's surprises and how often they come.

  • every: [number, number] — Seconds between surprises, at least and at most.
  • items: TitleEvent[] — The surprises to choose from, up to TITLE_LIMITS.events; one at a time, never the same twice running.

TitleExit

interface TitleExit

Start: the layers leave, then the transition covers, the next scene starts under it, and it uncovers.

  • kind: TitleTransitionKind — How the screen goes into play: the kind of transition.
  • duration: number — Seconds the transition takes, 0 to 3; default 0.7.
  • color: string — The cover colour (unused by crossfade, zoom and shatter, which cover with the title itself).
  • at: 'logo' | 'center' | 'pointer' — Where an iris or a radial closes, a zoom flies into and a shatter breaks from: the logo, the centre, or where the player pressed.
  • angle: number — wipe and blinds: degrees.
  • lead: number — Seconds the layers' own exits run before the cover starts.
  • in?: TitleTransitionKind — How the next scene is uncovered; default the same. Any kind: after a frame cover a mask takes the title away by that mask.
  • cells?: number — Cells across the screen's short side: the shatter's shards near at (bigger toward the edges), and the diamonds, blinds and pixels. 2..40; default the transition's (10).

TitleExitKind

type TitleExitKind = (typeof EXIT_KINDS)[number]

A layer exit kind: one of EXIT_KINDS.

TitleFlag

interface TitleFlag

A FLAG: a switch the title changes with, so it can evolve with the player's progress (the game beaten, a character unlocked, a festive week). The file declares its flags; the game says which are on (play(file, { flags })).

  • id: string — The name the game passes and when / unless use.
  • label: string — What it means, for the tool ('Game beaten').

TitleFlagged

interface TitleFlagged

A layer, shader, event or attract card that shows only with a flag on, or only with it off.

  • when?: string — Shown only while this flag is on.
  • unless?: string — Hidden while this flag is on.

TitleFont

interface TitleFont

A baked GLB font from the CDN, loaded and registered under family.

  • family: string — The name the font is registered under, which TitleText.font refers to (up to 48 characters).
  • url: string — Where the baked GLB font loads from (up to 2048 characters).

TitleGradient

interface TitleGradient

A gradient fill for words: two to four colours at an angle (gold, chrome, neon). It replaces the text's color; the outline and shadow keep theirs.

  • colors: string[] — Two to four hex colours, first to last.
  • angle: number — The direction they run, degrees: 90 top to bottom (the default), 0 left to right, 180 right to left.
  • stops?: number[] — Where each colour sits, 0..1, one per colour, ascending (default evenly spaced). Two equal stops make a hard band.

TitleHowtoCard

interface TitleHowtoCard extends TitleCardBase

How to play: a few big lines, and a picture if it helps.

  • kind: 'howto' — A how-to card.
  • lines: string[] — The lines ('Arrows to move', 'Space to jump').
  • image?: string — A picture over the lines: an image asset's key.

TitleIdle

interface TitleIdle

How a layer stays alive. amount and hz mean what each kind says.

  • kind: TitleIdleKind — Which idle motion this is; amount and hz mean what that kind says.
  • amount: number — bob/orbit: design px · breathe: scale fraction · sway: degrees · spin: degrees a second · pulse/flicker/hum: how deep the dip (0..1) · twinkle: sparkle size px.
  • hz: number — Cycles (or, for flicker, hum and twinkle, events) a second.
  • phase: number — 0..1 of a cycle, so neighbours don't move together.
  • beats?: number — In time with the music: one cycle every this many beats (0.5, 1, 2, 4 or 8), locked to the beat of audio.bpm from audio.beat, instead of hz. Ignored when the file has no bpm. A cycle starts on the beat: a pulse is brightest, a blink comes on, a flicker dips. Never faster than the kind's hz allows (three a second for anything that flashes): a fast tempo doubles the beats until it is not.
  • x?: number — drift/scroll: design px a second.
  • y?: number — drift/scroll: design px a second down the screen (negative goes up), -2000 to 2000.
  • colors?: string[] — cycle: the colours it moves through (default the palette); twinkle: the sparkle colour.

TitleIdleKind

type TitleIdleKind = (typeof IDLE_KINDS)[number]

An idle motion kind: one of IDLE_KINDS.

TitleKnob

interface TitleKnob

A number knob: its range, default and what it means — one list drives the parser, the tool's controls and the docs.

  • min: number — The smallest accepted value.
  • max: number — The largest accepted value.
  • def: number — The value used when the file gives none.
  • label: string — What the control is called in the tool, with its unit where it has one.

TitleLayer

interface TitleLayer extends TitleFlagged

One layer of the stack. Back to front in file order.

  • id: string — The layer's name: a letter then letters, digits, - or _ (up to 48 characters), unique in the file. Events, logo cards and the tool refer to it.
  • kind: TitleLayerKind — What the layer draws: an image, text, particles, a looping strip or a painted shape.
  • role?: TitleRole — What the layer is FOR (logo, prompt, hero ...), which the tool and the events read. Default none.
  • x: number — Centre, design px.
  • y: number — Vertical centre, design px, 0 at the top.
  • size: number — image, strip, shape: width in design px · text: font size in design px.
  • height?: number — strip and shape: height in design px (an image keeps its aspect).
  • rot: number — Rotation in degrees, -360 to 360; default 0.
  • alpha: number — Opacity from 0 (invisible) to 1; default 1.
  • tint: string — Hex colour multiplied into the layer; default white (no change).
  • blend: TitleBlend — How its pixels combine with what is beneath; default normal.
  • flip: boolean — Whether the picture is mirrored left to right; default false.
  • depth: number — Parallax: 0 still (the prompt) … 1 moves with the camera … 1.5 nearer than the stage.
  • hidden: boolean — Not shown until an event brings it on (a peeking hero).
  • image?: string — The image asset's key (image and strip layers).
  • text?: TitleText — The words and their style (text layers).
  • particles?: TitleParticles — The emitter settings (particles layers).
  • shape?: TitleShape — Which painted shape to draw (shape layers); default glow.
  • fx?: TitleLayerFx — Sprite effects drawn on the picture: a glow, an outline, a shine.
  • enter: TitleEnter — How it arrives.
  • idle: TitleIdle[] — How it stays alive: up to TITLE_LIMITS.idle motions, running together.
  • exit: TitleLayerExit — How it leaves when Start is pressed.

TitleLayerExit

interface TitleLayerExit

How a layer leaves when Start is pressed.

  • kind: TitleExitKind — Which exit plays; none leaves the layer as it is until the screen changes.
  • duration: number — Seconds the exit takes, 0 to 3.
  • ease: TitleEase — The easing curve applied across duration.
  • to?: TitleSide — fly: the edge it leaves towards; default the nearer of top and bottom.
  • delay: number — Seconds after Start is pressed before this layer begins to leave, 0 to 2.

TitleLayerFx

interface TitleLayerFx

Per-layer sprite effects, drawn by effects-2d.

  • glow?: { color: string; size: number; pulse: number } — A halo round the picture (effects-2d's glow): hex color, size in pixels (1 to 64) and pulse, swells a second (0 to 2; 0 holds it steady).
  • outline?: { color: string; size: number } — A hard outline round the picture's pixels (effects-2d's outline): hex color and size in pixels (1 to 16).
  • shine?: { color: string; width: number; angle: number; period: number; sweep: number; intensity: number; phase: number } — A band of light sweeping across the picture (effects-2d's shine): hex color; width as a fraction of the diagonal; angle in degrees; period and sweep in seconds; intensity 0 to 2; phase in seconds.

TitleLayerKind

type TitleLayerKind = (typeof LAYER_KINDS)[number]

A layer kind: one of LAYER_KINDS.

TitleLogoCard

interface TitleLogoCard extends TitleCardBase

The logo alone, arriving again.

  • kind: 'logo' — A logo reprise.
  • layer: string — The layer shown: the file's logo unless it names another.

TitleParticlePreset

type TitleParticlePreset = (typeof PARTICLE_PRESETS)[number]

A particle preset name: one of PARTICLE_PRESETS.

TitleParticles

interface TitleParticles

A particle layer: a preset tuned by a few numbers.

  • preset: TitleParticlePreset — Which tuned emitter to build.
  • count: number — Particles alive at once, roughly.
  • colors?: string[] — Colours, picked per particle (default the preset's).
  • speed: number — Multiplies the preset's speed.
  • size: number — Multiplies the preset's size.
  • area?: { x: number; y: number; w: number; h: number } — Where they are born, in design px (default the preset's: the top edge for snow, the bottom for embers, the screen for dust).
  • wind: number — Degrees the whole field leans (wind).

TitlePlayOptions

interface TitlePlayOptions

What a play is asked to do.

  • next?: string — The scene Start goes to. Leave it out to handle Start yourself in onStart.
  • wait?: () => unknown — What must have landed before leaving (the game pack): called when Start is pressed, awaited before the transition. Anything awaitable: () => game.assets.load(assets, { pack: 'game' }) (a load job) is the usual one.
  • onStart?: () => void — Called the moment Start is pressed.
  • input?: boolean — Read Space, Enter, a click or a tap as Start. Default true.
  • motion?: 'full' | 'reduced' | 'auto' — 'reduced' turns movement into fades and stops idle movement; 'auto' (default) follows the player's system setting.
  • layer?: string — The world layer the sprites draw on. Default the pack's layer option.
  • grace?: number — Ignore presses for this long after the screen starts, seconds (a key still down from the last screen). Default 0.3.
  • flags?: readonly string[] — The file's flags that are on (['beaten']): layers, shaders and events with when / unless follow them. The game decides them, usually from its save (localStorage). Default none on.
  • scores?: () => ReadonlyArray<TitleScore> | null | undefined — The high-score table a scores card shows, best first (it is sorted anyway), asked for each time attract starts. None, or an empty list, shows a stand-in table.
  • attract?: boolean — Start attract mode by itself once the title has sat idle for the file's attract.after seconds. Default true; false leaves it to handle.attract(). Off too when input is false: the pack cannot tell idle from busy.

TitlePost

interface TitlePost

One post effect. params holds every param of the kind (POST_PARAMS): a number, a hex colour (color, tint) or an [r, g, b] triple (lift, gamma, gain).

  • kind: TitlePostKind — Which post effect this is.
  • params: Record<string, number | string | number[]> — Every param of the kind by name: a number, a hex colour string or an [r, g, b] triple, as POST_PARAMS says.

TitlePostColor

interface TitlePostColor

A colour param: a hex colour, black by default for a vignette (the post pack takes any CSS colour; a file takes hex).

  • kind: 'color' — Marks a colour param (a hex string).
  • def: string — The hex colour used when the file gives none.

TitlePostKind

type TitlePostKind = keyof typeof POST_PARAMS

A post effect name: a key of POST_PARAMS.

TitlePostNumber

interface TitlePostNumber

A number param: its range and default.

  • min: number — The smallest accepted value; a lower one is clamped up to it.
  • max: number — The largest accepted value; a higher one is clamped down to it.
  • def: number — The value used when the file gives none.

TitlePostParam

type TitlePostParam = TitlePostNumber | TitlePostColor | TitlePostRgb

One param of a post effect: a number, a colour or an rgb triple.

TitlePostRgb

interface TitlePostRgb

A red, green, blue triple, each in the range; a single number in a file fills all three.

  • kind: 'rgb' — Marks a red, green, blue triple param.
  • min: number — The smallest accepted value of each channel.
  • max: number — The largest accepted value of each channel.
  • def: readonly [number, number, number] — The red, green and blue used when the file gives none.

TitleRole

type TitleRole = (typeof LAYER_ROLES)[number]

A layer role: one of LAYER_ROLES.

TitleRollcallCard

interface TitleRollcallCard extends TitleCardBase

The cast, one at a time: a picture, a name, a line.

  • kind: 'rollcall' — A roll call.
  • cast: TitleCastMember[] — Who is in it, in order.

TitleScore

interface TitleScore

One row of a high-score table.

  • name: string — Who.
  • score: number — How many.

TitleScoresCard

interface TitleScoresCard extends TitleCardBase

The high scores: the game's own (play(file, { scores })), or a stand-in table when it has none.

  • kind: 'scores' — A high-score table.
  • rows: number — How many rows.

TitleScreenApi

interface TitleScreenApi

game.titleScreen.

  • play(file: unknown, opts?: TitlePlayOptions): TitleScreenHandle — Play a title screen file (an object or JSON text) in the current scene. Missing pictures load by their url first.
  • readonly current: TitleScreenHandle | null — The screen playing now, or null.
  • readonly settled: boolean — True once the current screen's reveal is over (what a screenshot of the title waits for).
  • parse(file: unknown, warnings?: string[]): TitleScreenDef — Read a file leniently (as play does), collecting what was dropped.
  • checkShader(shader: TitleShader): string | null — Would this shader draw on every renderer? The problem in one sentence, or null.
  • checkSky(shader: TitleShader): string | null

TitleScreenDef

interface TitleScreenDef

A whole title screen.

  • format: typeof TITLE_SCREEN_FORMAT — Always TITLE_SCREEN_FORMAT.
  • version: number — The file's version, read as at most TITLE_SCREEN_VERSION.
  • name: string — The screen's name, for the tool; up to 80 characters, default 'Title screen'.
  • design: { width: number; height: number } — The size it was laid out at, logical px; the pack fits it to the game's screen.
  • palette: string[] — The colours it is built from, for the tool and the cycle idle.
  • seed: number — Seeds the file's random choices (event timings, glitches, scatter): a whole number, 0 to 2^31 - 1; default 1.
  • flags: TitleFlag[] — The switches it changes with (none: it always looks the same).
  • assets: Record<string, TitleAsset> — The pictures and sounds the file uses, by key (up to TITLE_LIMITS.assets).
  • fonts: TitleFont[] — Baked GLB fonts to load, up to TITLE_LIMITS.fonts.
  • background?: TitleBackground — The key art, when the file has any.
  • shaders: TitleShader[] — The shaders, bottom up over the background. Read from sky in a file that has no shaders.
  • layers: TitleLayer[] — The layer stack, back to front (up to TITLE_LIMITS.layers).
  • camera: TitleCamera — The camera's sway, push and pointer parallax.
  • post: TitlePost[] — Post effects, applied in order (up to TITLE_LIMITS.post, one of each kind).
  • events: TitleEvents — The idle loop's surprises.
  • exit: TitleExit — The transition into play when Start is pressed.
  • audio: TitleAudio — The music and sounds.
  • attract?: TitleAttract — Attract mode, when the file has one.

TitleScreenHandle

interface TitleScreenHandle

A playing title screen.

  • readonly def: TitleScreenDef — The file being played, as read.
  • readonly warnings: ReadonlyArray<string> — What reading it dropped or changed.
  • readonly time: number — Seconds since the screen started (moved by seek).
  • readonly settled: boolean — The reveal is over: every layer has arrived.
  • readonly started: boolean — Start has been pressed.
  • readonly ready: Promise<void> — Resolves once its pictures, fonts and words are in and every layer is made.
  • start(): void — Start, as if pressed: the layers leave, then the transition into next.
  • skip(): void — Jump to the settled screen.
  • seek(t: number): void — Put the timeline at t seconds (for tools; particles and shaders keep their own time).
  • set(file: unknown): void — Replace the file live (for tools): what changed is rebuilt, the timeline keeps its place. Stopped: nothing happens.
  • flags(next?: readonly string[]): string[] — Change which flags are on, live: what they bring on fades in, what they take away fades out, shaders swap. With no argument, only reads. Returns the flags on now.
  • readonly attracting: boolean — Attract mode is playing.
  • readonly card: number — The attract card playing (its index in the file's attract.cards), or -1.
  • attract(card?: number): void — Into attract mode now, from the first card or from card card (its index in the file's attract.cards). For tools. Asked before the cards are made, the run starts once they are; nothing plays when the file has no attract cards the flags let in, or after Start.
  • title(): void — Back to the title now: attract ends at once, and the idle count starts again.
  • stop(): void — Remove everything it made. Leaving the scene does this too.

TitleScreenOptions

interface TitleScreenOptions

Manifest options.

  • layer?: string — The world layer sprites draw on. Default 'world' (world-side's middle layer).

TitleShader

interface TitleShader extends TitleFlagged

A SHADER: a full-screen or overlay shader this file owns, drawn as a backdrop — the backdrops pack's definition contract exactly (code is a WGSL snippet body that leaves premultiplied color; params ≤ 16 numbers; colors ≤ 4 hex, c0..c3 in order). Shaders stack bottom up over the background. The pack checks every one before drawing it. (Files written before shaders had their name call them sky; the parser still reads that.)

  • name: string — Its name in the file (unique; one is made up when missing).
  • code: string — The WGSL snippet body.
  • params: Record<string, number> — Its params and their values, in p0..p15 order.
  • colors: Record<string, string> — Its colours as hex, in c0..c3 order.
  • from?: string — Where it came from (a library look's id), for the tool.

TitleShape

type TitleShape = (typeof SHAPES)[number]

A painted shape: one of SHAPES.

TitleSide

type TitleSide = 'top' | 'bottom' | 'left' | 'right'

An edge of the screen.

TitleSky

type TitleSky = TitleShader
  • deprecated: The old name of TitleShader.

TitleText

interface TitleText

Text drawn into a sprite: the subtitle, the tagline, the prompt.

  • text: string — The words to show, up to TITLE_LIMITS.text characters.
  • touch?: string — On a touch device, said instead ('Tap to start' for 'Press Enter').
  • font: string — A family from fonts, or a shared one: sans, sans-bold, serif, serif-bold, mono, mono-bold.
  • color: string — The fill colour, hex.
  • gradient?: TitleGradient — Fill the letters with a gradient instead of color. With a letters entrance every letter gets the same colours at the same heights.
  • outline?: { color: string; width: number } — An outline round the letters: hex color and width as a fraction of the font size (0 to 0.2).
  • shadow?: { color: string; x: number; y: number } — A drop shadow: hex color and offset x, y as fractions of the font size (-0.3 to 0.3; positive is right and down).
  • letterSpacing: number — Extra space between letters as a fraction of the font size, -0.2 to 1.

TitleTransitionKind

type TitleTransitionKind = (typeof TRANSITION_KINDS)[number]

A transition kind for going into play: one of TRANSITION_KINDS.