Skip to content

Serialization

Save and restore world state as plain JSON. Version 1 stores voxels as a sparse map keyed by "x,y,z" strings for human readability and easy diffing. Tileset metadata is embedded so the loader can restore textures automatically.

ts
const vr = new VoxelRenderer({});

// Save
const json = vr.save();
localStorage.setItem("map", JSON.stringify(json));

// Load
const data = JSON.parse(localStorage.getItem("map")!) as VoxelWorldJSON;
await vr.load(data);

Types

ts
/** World-space coordinate encoded as a string key. */
type VoxelEntryKey = `${number},${number},${number}`;

interface VoxelEntryJSON {
  block: number;     // BlockDefinition.id
  transform: number; // packed rotation + flip byte
}

interface VoxelLayerJSON {
  id: string;
  name: string;
  visible: boolean;
  order: number;
  /** World-space translation of the layer.
   * Absent in files produced before layer offsets were introduced;
   * treated as {x:0,y:0,z:0} on load.
   **/
  offset?: { x: number; y: number; z: number };
  voxels: Record<VoxelEntryKey, VoxelEntryJSON>;
}

/**
 * Voxel keys are always world-space coordinates (layer offset included).
 * Files produced before layer offsets were introduced carry no `offset` field
 * and are loaded as if offset is {0,0,0} — identical to the previous behaviour.
 */

/**
 * Flat key/value bag for custom object properties.
 * Only primitive scalars (string, number, boolean) survive the round-trip.
 */
type VoxelObjectProperties = Record<string, string | number | boolean>;

/**
 * A single named object placed in the world (spawn point, trigger zone, …).
 * Coordinates are in voxel/tile space; floats are allowed for sub-tile precision.
 * `y` is 0 for maps imported from a flat 2-D source.
 */
interface VoxelObjectJSON {
  id: string;
  name: string;
  /** Optional semantic type tag (e.g. "SpawnPoint", "Trigger"). */
  type?: string;
  x: number;
  y: number;
  z: number;
  width?: number;
  height?: number;
  rotation?: number;
  visible: boolean;
  properties?: VoxelObjectProperties;
}

/** A named layer that holds placed objects rather than voxel data. */
interface VoxelObjectLayerJSON {
  id: string;
  name: string;
  visible: boolean;
  order: number;
  objects: VoxelObjectJSON[];
}

interface VoxelWorldJSON {
  version: 1;
  chunkSize: number;
  tilesets: TilesetDefinition[];
  layers: VoxelLayerJSON[];
  /** Block definitions embedded by converters (e.g. TiledConverter).
   * Auto-registered on load.
   **/
  blocks?: BlockDefinition[];
  /**
   * Named object layers (spawn points, triggers, etc.).
   * Present in converter output and in files saved after object layers
   * were added at runtime via VoxelRenderer.addObjectLayer().
   */
  objectLayers?: VoxelObjectLayerJSON[];
}

VoxelSerializer

Low-level serialiser. Most users should prefer the higher-level VoxelRenderer.save() / VoxelRenderer.load(), which also handle material invalidation and chunk rebuilds.

serialize(world: VoxelWorld, tilesetManager: TilesetManager): VoxelWorldJSON

Converts the world and tileset metadata to a plain JSON-serialisable object.

deserialize(data: VoxelWorldJSON, world: VoxelWorld): void

Clears world and restores it from a snapshot. Voxel layers and object layers are both restored. Throws if data.version !== 1.