Skip to content

Using Assets (.glb, textures, audio) ​

Ship models, textures and sounds inside your mod. The host serves them versioned and immutable-cached; the SDK loads them with one hook.

Layout ​

my-mod/
  vibelands-mod.json
  client/index.jsx
  assets/                 ← anything in here ships with the mod
    chest.glb
    sparkle.png
    chime.ogg

The hosted sandbox builder bundles assets/ into the signed mod artifact (budget: 25 MB total) and the host serves it at /mods/<id>/<version>/assets/... for hosted releases. Versioned URLs mean hard immutable caching with zero stale-asset bugs after updates.

Loading ​

jsx
import {
  useModGltf,         // .glb / .gltf - suspends while loading
  useModTexture,      // images - suspends
  useModAudioBuffer,  // decoded via the HOST audio context - null until ready
  useModAssetUrl,     // escape hatch: just the resolved URL string
} from '@vibelands/mod-sdk/client';

export function ChestModel({ position }) {
  const gltf = useModGltf('chest.glb');
  return <primitive object={gltf.scene.clone()} position={position} />;
}

Loaders cache per URL - and the URL embeds your version, so caches roll over cleanly on release.

Audio: always ride the master bus ​

useModAudioBuffer decodes with the host's AudioContext so playback can route through the master gain - that's what makes your sounds correctly muffle underwater and inside interiors. Requires the audio permission.

jsx
import { useModAudio, useModAudioBuffer } from '@vibelands/mod-sdk/client';

export function useChime() {
  const audio = useModAudio();                 // needs "permissions": ["audio"]
  const buffer = useModAudioBuffer('chime.ogg');

  return () => {
    const ctx = audio.getAudioContext();
    if (!ctx || !buffer || !audio.isAudioEnabled()) return;
    const source = ctx.createBufferSource();
    source.buffer = buffer;
    source.connect(audio.getMasterGain());        // ← the important line
    source.start();
  };
}

WARNING

Never new Audio(url) or build your own AudioContext - that audio escapes interior/underwater filtering and the user's volume settings.

Practical limits ​

AspectRule
Total assets/ size≤ 25 MB per mod (check and the hosted build enforce it)
Formats.glb (preferred over .gltf+bin), compressed textures, .ogg audio
Draco/KTX2not provided by the host - ship uncompressed glb or embed your own decoder
Pathsrelative inside assets/, no .. traversal (the host 404s it anyway)
Disposalloader caches live for the session; prefer .clone() when mounting the same GLTF many times

Tier A + assets example: a picnic table at spawn ​

jsx
import { defineModClient, useModGltf, useTerrainSampler } from '@vibelands/mod-sdk/client';

function PicnicLayer() {
  const gltf = useModGltf('picnic-table.glb');
  const getGroundHeight = useTerrainSampler();
  const x = 8, z = -6;
  return <primitive object={gltf.scene} position={[x, getGroundHeight(x, z), z]} name="picnic-table" />;
}

export default defineModClient({ WorldLayer: PicnicLayer });

VibeLands Creator · Runtime API v2