Skip to content

Change the level

Goal

The game renders your own gaussian-splat environment, collides with your own collision mesh, and spawns the player, the enemies and the pickups where you want them.

Files you will edit

  • src/assets.json
  • src/arena.ts

Steps

  1. Point the manifest at your world. Drop the files in public/ — Vite copies that directory verbatim — and give them ids. The id is the contract; game code never sees a path.

    diff
    // src/assets.json
     {
       "version": 1,
       "baseUrl": "/",
       "assets": [
         {
           "id": "env.arena",
           "type": "splat",
    -      "src": "@placeholder/arena.spz",
    +      "src": "/levels/foundry.spz",
           "tags": ["world"],
    -      "collider": { "shape": "mesh", "src": "@placeholder/arena.collider.bin", "layer": "static" }
    +      "collider": { "shape": "mesh", "src": "/levels/foundry.collider.bin", "layer": "static" }
         },

    @placeholder/... is a template convention: src/main.ts maps those onto the files inside @aosengine/assets-placeholder. Anything else is resolved against baseUrl, so /levels/foundry.spz means public/levels/foundry.spz.

    SPZ loads about four times faster than PLY; prefer it. The collider is a separate baked triangle mesh, because a splat has no geometry a solver can use — parseCollider in @aosengine/assets-placeholder documents the format, and src/main.ts is where it is turned into a static body.

  2. Move the spawn points. Every position is on the floor, in metres, Y-up, with yaw in radians about +Y (0 looks down -Z); the prefab's own half-height is added when it spawns.

    diff
    // src/arena.ts
     export const arenaSpawns: ArenaSpawns = {
    -  bounds: { min: [-12, 0, -12], max: [12, 3, 12] },
    -  player: { position: [0, 0, 9], yaw: 0 },
    +  bounds: { min: [-20, 0, -14], max: [20, 6, 14] },
    +  player: { position: [-17, 0, 0], yaw: 1.5708 },
       enemies: [
    -    { position: [-9.5, 0, -9.5], yaw: -2.3562 },
    +    { position: [12, 0, -6], yaw: 3.1416 },
    +    { position: [12, 0, 6], yaw: 3.1416 },
    +    { position: [0, 0, 0], yaw: 3.1416 },
       ],
       pickups: [
    -    { position: [0, 1, 0], yaw: 0 },
    +    { position: [-4, 1, 8], yaw: 0 },
       ],
     };

    The loops in src/game.ts's init walk these lists, so adding or removing an entry changes how many things exist. Nothing else needs to know.

Verify

sh
npm test

The template ships one test asserting that src/arena.ts matches the placeholder pack's own spawn table; delete it once the level is yours, and replace it with one that matters — that every spawn point is inside bounds, for example. Then:

sh
npm run dev

Walk to each spawn point. You should land on the floor rather than falling through it or standing in the air: if you fall, the collider and the splat disagree about where the floor is, and the collider is what to fix.

See also