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.jsonsrc/level.json
Steps
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.tsmaps those onto the files insidegameable/placeholder. Anything else is resolved againstbaseUrl, solevels/foundry.spz(the filepublic/levels/foundry.spz) loads there.A world baked in
examples/splat-bakehas a.light.bin: add"bakedLighting": "levels/foundry.light.bin"to the entry. Then drop the arena'senvironmentLightinginsrc/main.ts, or it is lit twice.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 —
parseCollideringameable/placeholderdocuments the format, andsrc/main.tsis where it is turned into a static body.Say which place the level plays in, and move the placements.
placeis the manifest id of the world; everypositionis in metres, Y-up, withyawin degrees about+Y(0faces+Z). A level actor's name is how the sandbox's edit mode finds it, so name what people will move.diff// src/level.json { "format": 1, + "place": "env.arena", "actors": [ { "name": "playerStart", - "position": [0, 1.15, 9], + "position": [-17, 1.15, 0], + "yaw": 90, "class": "PlayerStart", "tags": ["arena"] }, { "name": "guide", - "position": [2.5, 1.05, 4], + "position": [12, 1.05, -6], "yaw": -26.562, "class": "Npc",The level is loaded before
init, so adding or removing an entry changes how many things exist. Nothing else needs to know. A game with several places keeps one level file per place: switch levels at runtime.
Verify
sh
npm testThe template's tests read placements from src/level.json through tests/level.ts, so a moved start moves the test with it. Then:
sh
npm run devWalk 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
- Assets and the manifest
- Load a splat environment
- Use the placeholder assets
packages/splat/README.md— gameable/splat