Phaser AE

Sector shooter

Pro packv3.0.0-0ArcadeNew

A whole first-person shooter in the 1993 mould, with the mechanics found in games like Doom: levels with height, doors, keys, armour, rockets and a boss, and a modern set that adds double jumps, dashes and style.

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

Released October 24, 2026

Sector shooter: 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

sectorShooter

function sectorShooter(): Pack<{ sectorShooter: typeof kit; }>

Compose the sector shooter rules, its two sets, the sample levels and the autopilot under game.sectorShooter.

Helpers

adminLayout

const adminLayout: MapLayout

Level 2 of the facility, "Administration": slower and stranger. A lobby under a skylight with a turning hologram and a curved staircase up to a mezzanine; dark office corridors whose lamps flicker; offices of filing cabinets; a locker room where not every locker holds clothes; a toilet block where something waits in a stall, and the blue key in another; a security room whose screens show the floor and whose override unlocks the director's wing (and puts the lobby's lights out); the yellow key in the director's safe; the roof, where a gunship circles.

classicEpisode

function classicEpisode(): SectorMapData[]

The classic episode's three maps, ready to play: built from the layouts and grids above with the standard kit.

classicSet

function classicSet(): SectorSet

The classic set, in the manner of the 1993 shooters: fists, a pistol, a pump shotgun, a chaingun, a rocket launcher and a plasma gun on bullets, shells, rockets and cells; grunts and gunners who shoot, fiends who throw fireballs, charging brutes, floating eyes and the towering warden; health from bonuses to the soul orb, two armours, keys in three colours, a backpack and five powers; barrels that burst (and set each other off) and crates that splinter. Every sound is named so a game can give each one its voice.

createSectorPilot

function createSectorPilot(): SectorPilot

A fresh autopilot memory.

createSectorRun

function createSectorRun(config: SectorShooterConfig): SectorRun

Start a level. Throws, naming the problem, on a config it cannot play.

facilityEpisode

function facilityEpisode(): SectorMapData[]

The facility: the Refinery and Administration, ready to play, built with the standard kit.

gatehouseLayout

const gatehouseLayout: MapLayout

Level 3, "Gatehouse": a courtyard under the sky, floating eyes, and the warden waiting in the keep; killing it opens the way out.

hangarLayout

const hangarLayout: MapLayout

Level 1, "Hangar": a pillared hall with a row of barrels along its north wall, stairs to a loft holding the red key, a slime pit, a secret closet and the exit.

modernArena

function modernArena(): SectorMapData

The modern arena, ready to play.

modernSet

function modernSet(): SectorSet

The modern set, the same rules tuned fast: double jumps, an air dash and air control, a blade, a revolver, a wide scattergun, a nailgun and a launcher whose blasts carry the player (rocket jumps); drones that fly and shoot, husks that rush, sentries that snipe from afar and hulks that soak up fire; small health and armour shards; fuel barrels whose blasts throw the player high (barrel jumps) and crates; and style scoring that rewards kills in the air, after a dash, by a barrel and in quick chains, ranked D to S.

overdriveGrid

const overdriveGrid: GridMap

The modern arena, "Overdrive": jump pads up to the perches, low gravity over the slime (double-jump up to the core), barrels by the slime, and waves that come as each is cleared.

pumpStationGrid

const pumpStationGrid: GridMap

Level 2, "Pump Station": a grid of walkways over slime with barrels along the slime's edge, a crusher to time, a blue door and an open yard.

refineryLayout

const refineryLayout: MapLayout

Level 1 of the facility, "Refinery": a control room whose zig-zag window looks down on a slime courtyard; a catwalk along a slime canal whose bridge lies sunk until the computer room raises it; the blue key on an island in the slime; an octagonal pump hub with a window into the computer room; a lift to a sniper balcony over an outdoor yard where a ship passes over and a searchlight sweeps; the red key on a rock shelf; a secret server closet behind glass.

sectorAutopilot

function sectorAutopilot(run: SectorRun, pilot: SectorPilot, dt: number, speed = 7, turn = 6): SectorInput

The controls a simple player would give this step: shoot the nearest enemy it can see with its best weapon, top up health and ammunition when short, fetch a key when the way to the exit is locked, press switches, open doors (hinged ones too), open cabinets for what they hold (supplies, a gun, a key), and go to the exit (a switch to use or a place to enter). speed is units per second (default 7), turn radians per second (default 6). It sets off barrels next to enemies, holds its fire when one close by is in the way, and waits for a crusher to rise before going under it. For attract modes, demos and tests that prove a level can be finished; it does not jump, dash, ride lifts or aim for jump pads.

sectorLevel

function sectorLevel(map: SectorMapData, set: SectorSet, options: { skill?: SectorSkill; par?: number; seed?: number; mutators?: SectorMutators } = {}): SectorShooterConfig

A level config from a map, a set and a skill: the map's things filtered to the skill, damage to the player and ammunition scaled, and on nightmare the dead rising again; mutators change gravity or make every hit lethal. Every field can be changed afterwards.

Classes

SectorRun

class SectorRun

One level of a 2.5D shooter in the manner of the 1993 games and their modern descendants, on sector-map (the map), fps-weapons (the arsenal) and fps-enemies (the AI). A step moves the player with steps, falls, gravity, and optionally jumps, double jumps, dashes and air control; uses doors, lifts and switches; fires, resolving pellets against enemies (aiming up and down by itself) and walls (setting off shoot triggers), and flying projectiles both ways in 3D with splash damage and knockback; runs the map's movers, crushers, damaging floors and triggers (messages, spawns, teleports, exits); runs the enemies with infighting and respawning; and collects health, armour, ammunition, weapons, keys, backpacks and powers. Props stand in the way and break when shot; some burst, hurting and throwing what is near and setting off their neighbours in a ripple. The map's jump pads throw the player, its low-gravity rooms let them float, and its conveyors and winds push them; mutators change gravity everywhere or make every hit lethal. The map's fixtures play too: use opens hinged doors and cabinets (whose contents come out to be picked up, or jump out), and glass stops shots until shots and blasts break it, enemies' shots included. Health and armour share damage; a death restarts the level, or costs a life; the exit gives the tally. Get one from createSectorRun.

  • map!: SectorMap — The map, live.
  • arsenal!: Arsenal — The arsenal, live.
  • horde!: Horde — The enemies, live.
  • bosses!: Bosses — The boss fights, live: bosses.list() for a health bar.
  • constructor(config: SectorShooterConfig)
  • get status(): 'playing' | 'dead' | 'complete' | 'over' — 'playing', 'dead' (waiting for respawn), 'complete' (an exit was used) or 'over' (no lives left).
  • get player(): SectorPlayer — The player (a copy).
  • get stats(): SectorStats — The level's numbers so far.
  • get tally(): SectorTally | null — The last finished level's tally, or null.
  • pickups(): SectorItem[] — The pickups lying about.
  • flying(): SectorProjectile[] — What is flying.
  • decorations(): { type: string; x: number; y: number; z: number; yaw: number }[] — Things on the map that are none of the start, enemies, pickups and props: scenery for the presenter (lamps, trees).
  • props(): SectorProp[] — The props: whole, fusing and broken (a presenter draws the wreck).
  • item(id: string): ShooterItemDef | undefined — An item kind.
  • prop(id: string): ShooterPropDef | undefined — A prop kind.
  • get mutators(): Required<SectorMutators> — The mutators in force (a copy).
  • mutate(m: SectorMutators): void — Change mutators during a level: the fields given replace those in force. Throws on a value out of range.
  • get eye(): number — The player's eye height in the world.
  • respawn(): boolean — After a death with the level to try again: the level starts over with the starting arsenal and health. Lives and score are kept.
  • nextLevel(config: SectorShooterConfig): boolean — After an exit: go on to another level keeping health, armour, the arsenal, lives and score; keys and powers stay behind. Returns false unless the level is complete; throws on a config it cannot play.
  • step(dt: number, input: SectorInput): SectorEvent[] — Run the level on by dt seconds (0 to 0.25) with this step's controls.

Types

PropBurst

interface PropBurst

A prop's burst: splash damage, knockback and a sound, a moment after it breaks.

  • radius: number — Reach in units, above 0 and at most 64.
  • damage: [number, number] — Damage at its heart, [min, max] from 0 to 10000, falling to nothing at radius.
  • knock?: number — How hard it throws the player, units per second at its heart; default 0.
  • delay?: number — Seconds from breaking to bursting, 0 to 10; default 0.2. A row of props that burst ripples one link each delay.
  • sound?: string — A sound by name as it bursts.

SectorEvent

type SectorEvent = | { type: 'shot'; weapon: string; pellets: number } | { type: 'hit'; enemy: string; damage: number; dist: number } | { type: 'wall-hit'; x: number; y: number; z: number } | { type: 'hurt'; damage: number; from: string; armor: number } | { type: 'picked-up'; item: string; id: string } | { type: 'use'; result: string } | { type: 'locked'; key: string } | { type: 'secret'; sector: string } | { type: 'message'; text: string } | { type: 'teleport'; x: number; z: number } | { type: 'exit'; tally: SectorTally } | { type: 'died'; lives: number | null } | { type: 'jump' } | { type: 'dash' } | { type: 'land'; speed: number } | { type: 'launch'; sector: string; x: number; y: number; z: number } | { type: 'prop-hit'; id: string; prop: string; damage: number; x: number; y: number; z: number } | { type: 'prop-broke'; id: string; prop: string; by: string } | { type: 'burst'; x: number; y: number; z: number; radius: number; from: string; prop?: string } | { type: 'style'; points: number; chain: number; rank: string } | { type: 'event'; name: string; data?: unknown } | { type: 'enemy'; event: HordeEvent } | { type: 'boss'; event: BossEvent } | { type: 'map'; event: MapEvent } | { type: 'sound'; sound: string; x: number; y: number; z: number }

What happened in a step.

SectorInput

interface SectorInput

The controls for one step.

  • move: { x: number; z: number } — Where the player wants to go this step, in units (the run handles collision, steps and air control).
  • yaw: number — Facing, the engine's yaw.
  • pitch?: number — Looking up or down (positive down); aims shots that do not lock on. Default 0.
  • fire: boolean — Trigger held.
  • use?: boolean — Use pressed.
  • jump?: boolean — Jump pressed.
  • dash?: boolean — Dash pressed.
  • select?: string — A weapon to raise.
  • cycle?: 1 | -1 — Step through weapons.

SectorItem

interface SectorItem

A pickup lying in the level.

  • id: string — Unique id.
  • item: string — Its item kind.
  • x: number — Position.
  • y: number — Height of its base.
  • z: number — Position.

SectorMutators

interface SectorMutators

Game-wide rule changes, like an arena shooter's mutators.

  • gravity?: number — Multiplies gravity everywhere (falls, jumps and jump pads' arcs), 0 to 10; default 1. Below 1 is a low-gravity game.
  • instagib?: boolean — Every hit the player lands is lethal: enemies die at once (a boss only while it can be hurt), and props that can break, break. Default false.

SectorPilot

interface SectorPilot

An autopilot's memory between steps.

  • route: { x: number; z: number; door?: string }[] — The points it is walking to, next first.
  • replan: number — Seconds until it plans again.
  • goal: string — What it is heading for: 'exit', 'switch', 'key', 'supplies', 'cabinet', 'enemy' or ''.
  • press: { x: number; z: number } | null — A wall to press use on when it gets there, as its midpoint, or null.
  • held: boolean — Whether it held the trigger last step.
  • stuck: number — Seconds without progress.
  • last: { x: number; z: number } — Where it was a moment ago.
  • useWait: number — Seconds before it presses use again.
  • pressed: string[] — Switches it has pressed and cabinets it has opened, by id, so it tries others.
  • target: string — The switch or cabinet it is on its way to press, by id, or ''.
  • engaged: { id: string; time: number; hp: number } — The enemy it is shooting at, and for how long.
  • ignore: Record<string, number> — Enemies it has given up shooting at for now (out of reach or out of range), with seconds left.

SectorPlayer

interface SectorPlayer

The player.

  • x: number — Position.
  • y: number — Feet height.
  • z: number — Position.
  • yaw: number — The engine's yaw.
  • vx: number — Velocity, units per second.
  • vy: number — Velocity, units per second (up is positive).
  • vz: number — Velocity, units per second.
  • onGround: boolean — Standing on a floor.
  • health: number — Health.
  • armor: number — Armour.
  • absorb: number — The share of damage armour takes.
  • keys: string[] — Keys held.
  • powers: Record<string, number> — Powers and seconds left (Infinity for the level).
  • alive: boolean — Alive.
  • lives: number | null — Lives left, or null without lives.
  • score: number — Score.
  • style: number — The style meter, 0 to 100.
  • rank: string — The style rank: 'D', 'C', 'B', 'A' or 'S', or '' with no style.

SectorPlayerDef

interface SectorPlayerDef

How the player moves and what they can take.

  • health?: number — Starting health; default 100.
  • maxHealth?: number — Health most pickups fill to; default 100.
  • armor?: number — Starting armour; default 0.
  • maxArmor?: number — Most armour; default 200.
  • radius?: number — Body radius; default 0.4.
  • height?: number — Body height; default 1.8.
  • eye?: number — Eye height above the feet; default 1.6.
  • step?: number — Highest step walked up; default 0.6.
  • gravity?: number — Gravity, units per second squared; default 20.
  • jump?: number — Jump speed, units per second; default 0 (no jumping, as in the classic games).
  • jumps?: number — Jumps before landing again (2 is a double jump); default 1.
  • airControl?: number — How much the player steers in the air, 0 (none) to 1 (as on the ground); default 1.
  • dash?: { speed: number; time: number; cooldown: number } — A dash: speed units per second for time seconds, then cooldown seconds before the next; default none.
  • lives?: number — Lives; default none (a death restarts the level, as in the classic games).

SectorProjectile

interface SectorProjectile

Something flying.

  • id: string — Unique id.
  • from: string — 'player' or an enemy's id.
  • x: number — Position.
  • y: number — Height.
  • z: number — Position.
  • yaw: number — The engine's yaw.
  • pitch: number — Pitch, positive down.
  • speed: number — Units per second.
  • radius: number — Radius.
  • damage: number — Damage on a direct hit.
  • splash?: { radius: number; damage: [number, number]; knock?: number } — Blast.
  • weapon?: string — The weapon that fired it (player shots).

SectorProp

interface SectorProp

A prop standing in the level, or what is left of it.

  • id: string — Unique id.
  • prop: string — Its prop kind.
  • x: number — Position.
  • y: number — Height of its base.
  • z: number — Position.
  • yaw: number — The engine's yaw.
  • hp: number — Hit points left; Infinity for one that cannot break.
  • state: 'whole' | 'fusing' | 'broken' — 'whole'; 'fusing' (broken, about to burst: it still stands in the way); 'broken' (a wreck, in no one's way).
  • fuse: number — Seconds until a fusing prop bursts.
  • by: string — Who broke it: 'player' or an enemy's id; '' while whole.

SectorSet

interface SectorSet

A set: everything a level needs besides its map.

  • weapons: ArsenalConfig — The arsenal.
  • enemies: EnemyDef[] — Enemy kinds.
  • items: ShooterItemDef[] — Pickups.
  • props?: ShooterPropDef[] — Props the maps place: barrels that burst, crates that break.
  • player: SectorPlayerDef — The player.
  • style?: StyleDef — Style scoring, if the set has it.
  • bosses?: BossDef[] — Boss fights for some of its enemy kinds.
  • sounds: SectorSounds — Sounds.

SectorShooterConfig

interface SectorShooterConfig

One level.

  • map: SectorMapData — The map. Its things are 'start', enemy kinds, item ids and prop ids (anything else is scenery).
  • weapons: ArsenalConfig — The arsenal.
  • enemies: EnemyDef[] — Enemy kinds.
  • items: ShooterItemDef[] — Pickups.
  • props?: ShooterPropDef[] — Props: what the map's barrels, crates and the like are. Default none.
  • mutators?: SectorMutators — Game-wide rule changes; default none. SectorRun.mutate changes them during a level.
  • player?: SectorPlayerDef — The player.
  • skill?: string — The skill level the map's things are filtered by (MapThing.skill); default all things.
  • damageScale?: number — Multiplies damage to the player from enemies and bursting props, 0 to 10; default 1.
  • ammoScale?: number — Multiplies ammunition picked up, 0 to 10; default 1.
  • respawn?: number — Dead enemies rise again after this many seconds; default never.
  • maxAttackers?: number — Most enemies aiming at once; default 3.
  • infighting?: boolean — Enemies turn on another kind that hurts them; default true.
  • par?: number — Par time in seconds; default 0, none.
  • style?: StyleDef — Style scoring; default none.
  • bosses?: BossDef[] — Boss fights for enemy kinds (fps-bosses); every enemy of a boss kind fights as that boss. Default none.
  • sounds?: SectorSounds — Sounds.
  • seed?: number — Seed.

SectorSkill

type SectorSkill = 'easy' | 'normal' | 'hard' | 'nightmare'

How hard: 'easy' halves damage to the player and doubles ammunition; 'nightmare' brings the dead back. Things are filtered by the same name.

SectorSounds

interface SectorSounds

Sounds the run asks for, by name, as sound events (enemies, weapons, pickups and the map's movers have their own).

  • hurt?: string — The player is hurt.
  • death?: string — The player dies.
  • locked?: string — A locked door or switch refuses.
  • nothing?: string — Use with nothing there.
  • secret?: string — A secret found.
  • exit?: string — The exit.
  • jump?: string — A jump.
  • dash?: string — A dash.
  • land?: string — Landing from a fall.
  • teleport?: string — A teleport.
  • burst?: string — A projectile bursting.

SectorStats

interface SectorStats

A level's numbers so far.

  • kills: number — Enemies killed.
  • killsTotal: number — Enemies at the start.
  • items: number — Counted items taken.
  • itemsTotal: number — Counted items at the start.
  • secrets: number — Secrets found.
  • secretsTotal: number — Secrets on the map.
  • time: number — Seconds.
  • par: number — Par.

SectorTally

interface SectorTally

A finished level's tally.

  • kills: number — Kills, whole per cent (100 with none).
  • items: number — Items, whole per cent.
  • secrets: number — Secrets, whole per cent.
  • time: number — Seconds, whole.
  • par: number — Par.
  • exit: 'normal' | 'secret' — The exit used.

ShooterItemDef

interface ShooterItemDef

What a pickup does.

  • id: string — Unique id; the map places it by this name.
  • kind: 'health' | 'armor' | 'ammo' | 'weapon' | 'key' | 'backpack' | 'power' | 'treasure' — - 'health': amount health, taken only below upTo (default the player's maxHealth). - 'armor': amount armour up to upTo (default maxArmor), absorbing absorb of damage (keeps the old rate when 0). - 'ammo': amount of ammo. - 'weapon': weapon, with amount of its ammunition. - 'key': the key key. - 'backpack': doubles every ammunition maximum and gives amount of each type. - 'power': the power power for duration seconds ('invulnerable', 'berserk', 'radsuit', 'invisible', 'light', 'map', or the game's own). - 'treasure': points only.
  • amount?: number — How much.
  • upTo?: number — Health and armour: the most it fills to.
  • absorb?: number — Armour: the share of damage it takes, 0 to 1.
  • ammo?: string — Ammo: the type.
  • weapon?: string — Weapon: its id.
  • key?: string — Key: its name.
  • power?: string — Power: its name.
  • duration?: number — Power: seconds it lasts; 0 for the rest of the level. Default 30.
  • score?: number — Points; default 0.
  • counts?: boolean — Counts toward the tally's items share. Default false.
  • sound?: string — A sound to play when picked up.

ShooterPropDef

interface ShooterPropDef

A kind of prop: a thing on the map that stands in the way and can be shot, like a barrel that bursts or a crate that breaks. Hitscan pellets, projectiles, splash and other props' bursts damage it.

  • id: string — Unique id, unlike any item's or enemy's; the map places it by this name.
  • hp?: number — Hit points, above 0; default none: it cannot be broken (a statue, a stack of girders).
  • radius?: number — Radius in units, 0.05 to 4; default 0.4.
  • height?: number — Height in units, 0.05 to 20; default 1. A body that gets on top stands on it.
  • solid?: boolean — Bodies cannot pass through it and shots stop at it; default true. A prop that is not solid can still be shot while it has hit points.
  • burst?: PropBurst — What it does when broken: bursts after a delay with splash damage and knockback. Default none.
  • drops?: string[] — Item ids it leaves when broken.
  • score?: number — Points to the player for breaking it; default 0.
  • sound?: string — A sound by name as it breaks.

StyleDef

interface StyleDef

Points for killing with style (the modern preset): kills in the air and just after a dash count more, and kills close together chain.

  • kill?: number — Points for a kill; default 100.
  • air?: number — Multiplier for a kill while in the air; default 2.
  • dash?: number — Multiplier for a kill within half a second of a dash; default 1.5.
  • chain?: number — Seconds in which kills chain; default 2.
  • prop?: number — Multiplier for a kill by a prop the player set off (a barrel's burst); default 1.5.
  • decay?: number — How fast the style meter (0 to 100) drains, per second; default 8.