Skip to content

@aosengine/assets-placeholder ​

Classes ​

ColliderFormatError ​

A collider buffer that could not be read.

The message always says what was expected and what was found, because the only realistic way to hit it is to hand the parser the wrong file.

Extends ​

  • Error

Constructors ​

Constructor ​
ts
new ColliderFormatError(message): ColliderFormatError;

Build a collider format error.

Parameters ​
ParameterTypeDescription
messagestringWhat is wrong with the buffer.
Returns ​

ColliderFormatError

Overrides ​
ts
Error.constructor

Interfaces ​

ArenaBounds ​

The axis-aligned box the playable arena occupies.

Example ​

ts
import type { ArenaBounds } from '@aosengine/assets-placeholder';
import { arenaSpawns } from '@aosengine/assets-placeholder';

const bounds: ArenaBounds = arenaSpawns.bounds;
console.log(bounds.max[0] - bounds.min[0]); // 24 — the floor is 24 m across

Properties ​

max ​
ts
readonly max: readonly [number, number, number];

Maximum corner [x, y, z] in metres.

min ​
ts
readonly min: readonly [number, number, number];

Minimum corner [x, y, z] in metres.


ArenaSpawns ​

The shape of assets/arena.spawns.json.

Example ​

ts
import type { ArenaSpawns } from '@aosengine/assets-placeholder';
import { arenaSpawns } from '@aosengine/assets-placeholder';

const spawns: ArenaSpawns = arenaSpawns;
console.log(spawns.units, spawns.up); // 'metres' '+Y'

Properties ​

bounds ​
ts
readonly bounds: ArenaBounds;

The playable volume: floor, walls and everything between them.

enemies ​
ts
readonly enemies: readonly SpawnPoint[];

Six enemy spawn points, spread around the perimeter.

generatedBy ​
ts
readonly generatedBy: string;

Which script produced the file.

pickups ​
ts
readonly pickups: readonly SpawnPoint[];

Three pickup positions, floating a metre above the floor.

player ​
ts
readonly player: SpawnPoint;

Where the player starts, facing the centre.

units ​
ts
readonly units: "metres";

Length unit every coordinate is in.

up ​
ts
readonly up: "+Y";

Which axis points up.

yawConvention ​
ts
readonly yawConvention: string;

How to read the yaw fields.


ColliderMesh ​

A triangle mesh: flat positions plus flat triangle indices.

Properties ​

indices ​
ts
readonly indices: Uint32Array;

Triangle indices into positions. Length is a multiple of three.

positions ​
ts
readonly positions: Float32Array;

Vertex positions in metres, flattened x y z. Length is 3 * vertexCount.


ParseColliderOptions ​

Options for parseCollider.

Properties ​

validate? ​
ts
readonly optional validate?: boolean;

Walk the index array and reject an index that points past the last vertex.

The scan is O(indexCount) on the asset-loading path, and it catches exactly one thing: a corrupt or mis-generated file. That is a development concern, so it defaults to import.meta.env.DEV — true under vite dev, false in a production build — and to true wherever there is no import.meta.env at all (Node, vitest, a plain bundler), so the safe answer is the one you get by saying nothing.

Turning it off does not make a bad index safe: Jolt reads the array itself. It moves the check to the place that already has to do it.


PlaceholderManifest ​

The shape of assets/assets.json.

Example ​

ts
import type { PlaceholderManifest } from '@aosengine/assets-placeholder';
import { placeholderManifest } from '@aosengine/assets-placeholder';

const manifest: PlaceholderManifest = placeholderManifest;
console.log(manifest.version); // 1

Properties ​

assets ​
ts
readonly assets: readonly AssetEntry[];

Every placeholder asset, in load order.

version ​
ts
readonly version: 1;

Manifest schema version.


SpawnPoint ​

A place to put something, with the direction it should face.

Example ​

ts
import type { SpawnPoint } from '@aosengine/assets-placeholder';
import { arenaSpawns } from '@aosengine/assets-placeholder';

const spawn: SpawnPoint = arenaSpawns.player;
console.log(spawn.position[1]); // 0 — feet on the floor

Properties ​

position ​
ts
readonly position: readonly [number, number, number];

World position [x, y, z] in metres, Y-up, origin at the floor centre.

yaw ​
ts
readonly yaw: number;

Yaw in radians about +Y; 0 looks down -Z, like three's rotation.y.

Type Aliases ​

PlaceholderAssetEntry ​

ts
type PlaceholderAssetEntry = AssetEntry;

One entry of placeholderManifest: an @aosengine/assetsAssetEntry, under a name that says where it came from.

Example ​

ts
import type { PlaceholderAssetEntry } from '@aosengine/assets-placeholder';
import { placeholderManifest } from '@aosengine/assets-placeholder';

const sfx: readonly PlaceholderAssetEntry[] = placeholderManifest.assets.filter(
  (a) => a.tags?.includes('sfx') ?? false,
);
console.log(sfx.length); // 4

PlaceholderCollider ​

ts
type PlaceholderCollider = AssetCollider;

A static collision proxy, as the manifest declares it.

This is @aosengine/assets's own AssetCollider, not a copy of it: the pack's entries go straight into parseManifest, so a second declaration of the same shape could only ever drift from the one that is validated.

Example ​

ts
import type { PlaceholderCollider } from '@aosengine/assets-placeholder';

const collider: PlaceholderCollider = {
  shape: 'mesh',
  src: 'arena.collider.bin',
  layer: 'static',
};
console.log(collider.src); // 'arena.collider.bin'

Variables ​

arenaSpawns ​

ts
const arenaSpawns: ArenaSpawns;

A typed, ready-to-use copy of assets/arena.spawns.json.

Spawn points are not assets — there is no manifest type for "a list of coordinates" and inventing one would be a schema change — so they ship as a plain export. A unit test asserts this object and the JSON never drift apart, and that every point sits inside ArenaSpawns.bounds.

Example ​

ts
import { arenaSpawns } from '@aosengine/assets-placeholder';

const { position, yaw } = arenaSpawns.player;
console.log(position, yaw); // [0, 0, 9] 0
console.log(arenaSpawns.enemies.length); // 6

PACKAGE ​

ts
const PACKAGE: "@aosengine/assets-placeholder";

Package identity marker.

Example ​

ts
import { PACKAGE } from '@aosengine/assets-placeholder';

console.log(PACKAGE); // '@aosengine/assets-placeholder'

PLACEHOLDER_ASSETS_BASE ​

ts
const PLACEHOLDER_ASSETS_BASE: string;

Absolute URL of the directory holding the packaged assets, with a trailing slash.

Use it as a manifest baseUrl. It resolves against this module, so it is correct from src/ under the development condition, from dist/ in a published install, and from whatever path a bundler emits.

Example ​

ts
import { PLACEHOLDER_ASSETS_BASE } from '@aosengine/assets-placeholder';

console.log(PLACEHOLDER_ASSETS_BASE.endsWith('/assets/')); // true

placeholderManifest ​

ts
const placeholderManifest: PlaceholderManifest;

A typed, ready-to-parse copy of assets/assets.json.

It has no baseUrl, so merge PLACEHOLDER_ASSETS_BASE in when you feed it to parseManifest, or point loadManifest at the JSON file itself and let it default the base to the file's own directory. A unit test asserts this object and the JSON never drift apart.

face.idle is deliberately absent: docs/schemas/assets.schema.json fixes type to splat | gltf | character | audio, an ARKit clip is none of those, and extending the schema is out of scope for a placeholder pack. Reach it with placeholderAssetUrl('face_idle.arkit.json') instead.

Example ​

ts
import { parseManifest } from '@aosengine/assets';
import { placeholderManifest, PLACEHOLDER_ASSETS_BASE } from '@aosengine/assets-placeholder';

const manifest = parseManifest(placeholderManifest, { baseUrl: PLACEHOLDER_ASSETS_BASE });
console.log(manifest.assets.map((a) => a.id)); // ['env.arena', 'sfx.shot', ...]

Functions ​

encodeCollider() ​

ts
function encodeCollider(positions, indices): ArrayBuffer;

Write an arena.collider.bin buffer.

The exact inverse of parseCollider: parseCollider(encodeCollider(p, i)) returns p and i unchanged, up to f32 rounding of the positions.

Parameters ​

ParameterTypeDescription
positionsArrayLike<number>Vertex positions in metres, flattened x y z.
indicesArrayLike<number>Triangle indices into positions.

Returns ​

ArrayBuffer

The encoded file, ready to write to disk.

Throws ​

When positions is not a whole number of vertices, indices is not a whole number of triangles, or an index is out of range.

Example ​

ts
import { encodeCollider, parseCollider } from '@aosengine/assets-placeholder';

// A single 1 m triangle on the floor.
const file = encodeCollider([0, 0, 0, 1, 0, 0, 0, 0, 1], [0, 1, 2]);
console.log(file.byteLength); // 8 + 9 * 4 + 3 * 4 = 56
console.log(parseCollider(file).indices.length); // 3

parseCollider() ​

ts
function parseCollider(buffer, options?): ColliderMesh;

Read an arena.collider.bin buffer.

The header is always validated — counts and total length — so a mesh that parses has the right number of bytes in it. The per-index range scan is the one part that costs time proportional to the file, so it follows ParseColliderOptions.validate.

Parameters ​

ParameterTypeDescription
bufferArrayBuffer | ArrayBufferView<ArrayBufferLike>The file contents, as an ArrayBuffer or any view over one.
optionsParseColliderOptionsSee ParseColliderOptions.

Returns ​

ColliderMesh

The vertex positions and triangle indices, as views over buffer.

Throws ​

When the buffer is truncated, the index count is not a multiple of three, or (when validating) an index is out of range.

Example ​

ts
import { parseCollider, placeholderAssetUrl } from '@aosengine/assets-placeholder';

const bytes = await (await fetch(placeholderAssetUrl('arena.collider.bin'))).arrayBuffer();
const { positions, indices } = parseCollider(bytes);
console.log(positions.length / 3, indices.length / 3); // 98 142

placeholderAssetUrl() ​

ts
function placeholderAssetUrl(file): string;

The absolute URL of one packaged file.

This is the escape hatch for the two files that cannot live in the manifest — arena.spawns.json and face_idle.arkit.json — and for tooling that wants the bytes directly. Game logic must not call it: assets are addressed by id (AGENTS.md rule 3), and the ids are in placeholderManifest.

Parameters ​

ParameterTypeDescription
filestringA file name inside assets/, for example arena.spz.

Returns ​

string

The absolute URL of that file.

Example ​

ts
import { placeholderAssetUrl } from '@aosengine/assets-placeholder';

const url = placeholderAssetUrl('face_idle.arkit.json');
console.log(url.endsWith('/assets/face_idle.arkit.json')); // true