Skip to content

Host rooms

Stadiums

Pick a bundled stadium, load your own, and check stadium files before you use them.

Bundled stadiums

The package includes fourteen stadiums: Classic, Easy, Small, Big, Rounded, Big Easy, Big Rounded, Huge, Asphalt, Asphalt Arena, Courtyard, Meadow, Street Five and Training Green. Load one by name between matches:

JavaScript
await room.setDefaultStadium('Street Five');

A new room starts on a default arena. Call setDefaultStadium() after createRoom() to choose your first stadium.

Your own stadiums

Stadiums are text files, .ball2dstadium or JSON, that describe the pitch, goals, walls, discs and physics. Load one with setCustomStadium(), or pass its text as the stadium setting to start the room on it:

JavaScript
import { readFile } from 'node:fs/promises';

const futsal = await readFile(
  'stadiums/futsal.ball2dstadium',
  'utf8',
);
const room = await createRoom({
  apiKey,
  roomName: 'Futsal',
  stadium: futsal,
});

The stadium setting takes source text, not a name. For bundled stadiums, use setDefaultStadium().

Validate first

validateStadium() parses a stadium exactly as a room would, without opening one. Validate files when you accept them, such as in an upload handler or a build step, so a bad file never reaches a live room:

JavaScript
import { validateStadium } from 'ball2d/node';

try {
  const { name, warnings } = validateStadium(source);
  if (warnings.length)
    console.warn(`${name}:`, warnings.join('\n'));
} catch (error) {
  throw new Error(`Rejected stadium: ${error.message}`);
}

Stadiums can be up to 256 KB with 63 discs, 1,024 vertexes, 64 planes, 16 goals and 128 joints. Fields Ball2D doesn't use are reported as warnings, not errors.

Changing stadiums

Stadium changes apply only between matches. Loading a stadium returns the room to the lobby and resets the score. Score, time and kick-rate settings are kept, and a running recording is finished first.

Rotate stadiums

JavaScript
const rotation = ['Classic', 'Big', 'Street Five', 'Rounded'];
let next = 0;
room.onGameStop = async () => {
  next = (next + 1) % rotation.length;
  await room.setDefaultStadium(rotation[next]);
};