Phaser AE

Physics workshop levels

Free packv3.0.0-12DPhysics

Physics levels as JSON: items, prefabs, materials and links laid out as data, loaded into a Box2D world of their own and painted as blueprints. A level made in an editor and one written by hand as data play the same way.

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

Released October 19, 2026 · updated October 20, 2026

Physics workshop levels: 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

physicsWorkshop

function physicsWorkshop(): Pack<{ physicsWorkshop: PhysicsWorkshopApi }>

The physics-workshop pack: physics levels as JSON (the Design Desk's workshop format), loaded into their own Box2D world and painted as blueprints.

Helpers

cleanPhysicsLevel

function cleanPhysicsLevel(value: unknown): PhysicsLevel

Total, bounded and idempotent. Deterministic IDs on migration, never random IDs on read.

createPhysicsLevel

async function createPhysicsLevel(input: unknown, module?: string): Promise<PhysicsLevelRuntime>

Load JSON into Phaser AE' Box2D, with prefabs, joints and materials. No generated game code.

expandPhysicsLevel

function expandPhysicsLevel(input: unknown): PhysicsAssembly

Expand prefabs before simulation. The editor and games use exactly this expansion.

paintPhysicsAssembly

function paintPhysicsAssembly(ctx: CanvasRenderingContext2D, assembly: PhysicsAssembly, selected?: string): void

Blueprint outlines shared by the editor, thumbnails and host games.

paintPhysicsPiece

function paintPhysicsPiece(ctx:CanvasRenderingContext2D,p:PhysicsPiecePose,selected=false):void

Outline one piece in blueprint style at its pose, with an inner mesh, a fixed-piece cross and its label; selected highlights it.

PART_SIZE

const PART_SIZE: Record<PhysicsPart, [number, number]>

Default [width, height] in world pixels for each part kind.

PHYSICS_MATERIALS

const PHYSICS_MATERIALS: readonly ["wood", "rubber", "ice", "steel"]

Material presets; each sets a piece's default density, friction and restitution.

PHYSICS_PARTS

const PHYSICS_PARTS: readonly ["box", "rectangle", "circle", "triangle", "capsule", "polygon", "l-section", "t-section", "oval", "star", "heart", "cross", "custom", "crate", "plank", "ball", "ramp", "domino", "bumper", "anchor", "buggy", "pendulum", "seesaw", "bridge", "ragdoll"]

Physics workshop format. Pure JSON, world pixels, clockwise degrees, +y down. This file is also copied verbatim into the Design Desk. No browser dependencies.

physicsPiece

function physicsPiece(kind: PhysicsPart, id: string, x: number, y: number, grid = 16): PhysicsItem

Make a palette piece; callers supply the ID at the moment of creation.

physicsPolygon

function physicsPolygon(width:number,height:number,sides:number):{x:number;y:number}[]

Convex polygon vertices normalized to the exact requested footprint.

physicsShapePoints

function physicsShapePoints(kind:PhysicsPart,sides=6):PhysicsPoint[]

Ready-made concave silhouettes and normalized regular shapes.

physicsStarter

function physicsStarter(kind: 'dominoes' | 'buggy' | 'playground' | 'blank' = 'playground'): PhysicsLevel

Authored starter levels, all in the same format as an export.

simplifyPhysicsPoints

function simplifyPhysicsPoints(input:readonly PhysicsPoint[],max=64,tolerance=.006):PhysicsPoint[]

Ramer-Douglas-Peucker reduction plus an even cap for authored/traced outlines.

Constants

physicsNumber

const physicsNumber = (v: unknown, fallback: number, low: number, high: number): number=> …

Coerce v to a number clamped to [low, high]; fallback when it is not a finite number (null and the empty string count as missing). Never throws.

Types

PhysicsAssembly

interface PhysicsAssembly

A level expanded into simulation pieces and the joints between them.

  • pieces: PhysicsPiecePose[] — Every piece, in item order; a prefab such as a buggy or ragdoll contributes several.
  • joints: { a: string; b: string; kind: 'rope' | 'spring' | 'hinge' | 'wheel'; }[] — Joints by piece id; wheel is the suspended wheel joint a buggy uses, the others are the level's link kinds.

PhysicsBounds

interface PhysicsBounds

Which edges of the level rectangle get an invisible wall; all false by default.

  • left: boolean — Wall along the left edge (x = 0).
  • right: boolean — Wall along the right edge (x = level width).
  • top: boolean — Wall along the top edge (y = 0).
  • bottom: boolean — Wall along the bottom edge (y = level height).

PhysicsItem

interface PhysicsItem

One authored item of a level: a part with a pose, a material and its physics tuning.

  • id: string — Unique id within the level, at most 80 characters; links refer to it. A missing id becomes piece-<index>.
  • name: string — Label painted above the item, at most 80 characters; empty for none.
  • kind: PhysicsPart — Which part this is; an unknown kind becomes box.
  • x: number — Centre x in world pixels, within +/-1,000,000; default 400.
  • y: number — Centre y in world pixels (+y down), within +/-1,000,000; default 200.
  • width: number — Width in world pixels, 1 to 100000; default the kind's width in PART_SIZE.
  • height: number — Height in world pixels, 1 to 100000; default the kind's height in PART_SIZE.
  • angle: number — Rotation in degrees, clockwise on screen, -360 to 360; default 0.
  • material: PhysicsMaterial — Material preset that supplies the default density, friction and restitution; default wood.
  • fixed: boolean — Whether the item is static (never moves). Default true for ramp, anchor and bumper, false otherwise.
  • flipX: boolean — Mirror a ramp left to right; default false.
  • cornerRadius: number — Rounding of a box's corners in world pixels, 0 to just under half the smaller side; default 0.
  • sides: number — Sides of a regular polygon, 3 to 8; default 6.
  • points: PhysicsPoint[] — Outline as fractions of width and height from the centre; three or more make a custom (possibly concave) shape, at most 64 kept. Preset kinds such as star and heart fill it in.
  • mass: number — Exact total mass in kilograms, shared across a prefab's pieces by area; 0 (default) takes the mass from density. Up to 100000.
  • density: number — Mass per unit area, 0.001 to 1000; default from the material.
  • friction: number — Surface friction, 0 to 10; default from the material.
  • restitution: number — Bounciness, 0 (a beanbag) to 2; default from the material.
  • linearDamping: number — Linear damping (air resistance), 0 to 100; default 0.
  • angularDamping: number — Angular damping, 0 to 100; default 0.05.
  • gravityScale: number — Multiplier on the level's gravity for this item, -10 to 10; default 1.
  • fixedRotation: boolean — Lock the item's rotation; default false.
  • sensor: boolean — Report overlaps without stopping anything; default false.
  • bullet: boolean — Continuous collision, so a fast item cannot tunnel through a thin wall; default true.

PhysicsLevel

interface PhysicsLevel

A whole authored physics level: the JSON the workshop exports and createPhysicsLevel loads.

  • format: 'phaser-ae.physics2d' — File format tag; always phaser-ae.physics2d.
  • version: 1 — File format version; always 1.
  • name: string — Title, at most 100 characters; default Untitled experiment.
  • width: number — Level width in world pixels, 16 to 1,000,000; default 1600.
  • height: number — Level height in world pixels, 16 to 1,000,000; default 896.
  • gravity: number — Gravity in world pixels per second squared, +y down, -1800 to 1800; default 900.
  • grid: number — Editor snap size in world pixels, 1 to 512; default 16.
  • bounds: PhysicsBounds — Which edges of the level rectangle are walled.
  • items: PhysicsItem[] — The items, at most 250.
  • links: PhysicsLink[] — The joints between items, at most 250; a link to an unknown item is dropped.

PhysicsLevelRuntime

interface PhysicsLevelRuntime extends PhysicsAssembly

A loaded configuration. Call step at 1/120s, draw the pieces, and dispose on exit.

  • world: Box2dWorld — The live Box2D world; destroyed by dispose.
  • bodies: Map<string, Body2d> — The body of each piece, by piece id.
  • step(dt: number, drive?: number): void — Advance the simulation by dt seconds (clamped to 0 to 1/30); drive, -1 to 1 (default 0), spins every wheel piece. Does nothing after dispose.
  • dispose(): void — Destroy the world and clear bodies; safe to call twice.
interface PhysicsLink

A joint between two items of a level.

  • id: string — Unique link id, at most 80 characters; a missing id becomes link-<index>.
  • kind: 'rope' | 'spring' | 'hinge' — rope keeps the items a fixed distance apart, spring is a soft rope, hinge pins them at their midpoint.
  • a: string — Id of the first item (or prefab piece) joined.
  • b: string — Id of the second item (or prefab piece) joined; must differ from a.

PhysicsMaterial

type PhysicsMaterial = typeof PHYSICS_MATERIALS[number]

The name of a material preset: wood, rubber, ice or steel.

PhysicsPart

type PhysicsPart = typeof PHYSICS_PARTS[number]

One kind of part: a primitive shape, a ready-made outline, or a prefab such as buggy that expands into several pieces.

PhysicsPiecePose

interface PhysicsPiecePose extends PoseTarget

A drawable piece of a prefab, posed by the engine's actual Box2D world.

  • id: string — Unique piece id: the item's id for its first piece, <item id>/<n> for the others of a prefab.
  • owner: string — Id of the level item this piece was expanded from.
  • label?: string — The item's name; set on its first piece only.
  • shape: 'box' | 'circle' | 'ramp' | 'capsule' | 'polygon' | 'custom' — Collision and paint shape; ramp is a right triangle, custom uses points.
  • material: PhysicsMaterial — Material preset that supplies the default density, friction and bounce.
  • fixed: boolean — Whether the piece is static.
  • flipX?: boolean — Mirror a ramp left to right.
  • accent?: string — Role of the piece: wheel, buggy, doll or face inside a prefab, else the item's kind; it selects extra tuning such as wheel grip and bumper bounce.
  • cornerRadius?: number — Rounding of a box's corners in world pixels.
  • sides?: number — Sides of a regular polygon, 3 to 8.
  • points?: PhysicsPoint[] — Outline of a custom shape as fractions of width and height from the centre.
  • mass?: number — This piece's share of the item's exact mass in kilograms; unset to take the mass from density.

PhysicsPoint

interface PhysicsPoint

One point of a custom outline, as fractions of the item's size from its centre.

  • x: number — Fraction of the item's width from its centre: -0.5 is the left edge, 0.5 the right.
  • y: number — Fraction of the item's height from its centre: -0.5 is the top edge, 0.5 the bottom.

PhysicsWorkshopApi

type PhysicsWorkshopApi = typeof level & typeof paint

game.physicsWorkshop: the level format, its loader and its painter.