playableintelligence/game-creatorMIT1 file

Worldlabs

Generate photorealistic 3D worlds and environments with the World Labs Marble API — Gaussian Splat scenes from text prompts or reference images. Use when the user says "generate a 3D world", "create an environment", "make a 3D scene", or "use World Labs". Requires WLT_API_KEY environment variable.

Specification
Skill ID
playableintelligence/game-creator/worldlabs
Publisher
playableintelligence
Repository
game-creator
Installs
0
Files
1
License
MIT
Requires
Requires WLT_API_KEY environment variable and internet access for World Labs API calls.
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

playableintelligence/game-creator/worldlabsInstalls these files
  • SKILL.md

What this skill tells the agent

World Labs — 3D World/Environment Generation

Generate photorealistic 3D environments from text prompts or images using the World Labs Marble API. Outputs Gaussian Splat scenes (SPZ) rendered via SparkJS in Three.js, plus collider meshes (GLB) for physics.

When to Use

  • Environment/level generation — create entire 3D worlds (rooms, landscapes, buildings) from reference images or text
  • Complementary to Meshy AI — Meshy generates individual models/characters; World Labs generates the environments they exist in
  • Photorealistic scenes — Gaussian Splats produce photorealistic quality vs mesh-based environments

Input Priority

Image-first — always prefer image input over text:

  1. Image mode (default) — if the user has a reference image, concept art, screenshot, or photo, use --mode image. This produces the most faithful results because the AI can match the exact visual style, layout, lighting, and mood.
  2. Text mode (fallback) — only use --mode text when no reference image is available. The API auto-expands short prompts into rich scene descriptions, but results are less predictable than image-driven generation.

When the game-creator pipeline runs, ask the user for a reference image first:

I can generate a photorealistic 3D environment for your game using World Labs. Do you have a reference image (photo, concept art, screenshot) for the environment? - Yes → provide the file path or URL - No → I'll generate from a text description instead

Tech Stack

ComponentTechnology
APIWorld Labs Marble API (https://api.worldlabs.ai/marble/v1)
AuthWLT-Api-Key header
Output: VisualGaussian Splat (.spz) — 100k, 500k, full resolution tiers
Output: PhysicsCollider mesh (.glb) — for collision detection
Output: SkyboxPanorama image (.jpg/.png)
Browser RendererSparkJS 2.x (@sparkjsdev/spark) — SparkRenderer + SplatMesh, Three.js compatible
CLI Scriptscripts/worldlabs-generate.mjs (zero dependencies)

Environment Variable

Before prompting the user, check if the key already exists: test -f .env && grep -q '^WORLDLABS_API_KEY=.' .env && echo "found" If found, export it with set -a; . .env; set +a and skip the prompt.

If not set, ask the user:

I'll generate a photorealistic 3D environment with World Labs. You can get a free API key: 1. Sign up at https://platform.worldlabs.ai 2. Go to API Keys 3. Create a new key Paste your key below like: WORLDLABS_API_KEY=your-key-here (It will be saved to .env and redacted from this conversation automatically.) Or type "skip" to use basic geometry instead.

CLI Script Usage

# Text to 3D world
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
  --mode text --prompt "a medieval tavern with wooden beams and a roaring fireplace" \
  --output public/assets/worlds/ --slug tavern

# Image to 3D world (local file or URL)
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
  --mode image --image ./reference-photo.jpg \
  --output public/assets/worlds/ --slug my-world

# Check generation status
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
  --mode status --operation-id <op-id>

# Download assets from existing world
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs \
  --mode get --world-id <id> --output public/assets/worlds/ --slug my-world

# List your worlds
WORLDLABS_API_KEY=<key> node scripts/worldlabs-generate.mjs --mode list

Output Files

public/assets/worlds/
  tavern.spz              # Gaussian Splat (full resolution)
  tavern-500k.spz         # Gaussian Splat (500k, medium quality)
  tavern-100k.spz         # Gaussian Splat (100k, lightweight/mobile)
  tavern-collider.glb     # Collider mesh for physics (GLB)
  tavern-pano.jpg         # Panorama image (skybox)
  tavern.meta.json        # Metadata: world ID, prompt, timestamps, asset URLs

Integration with Three.js Games

Tested & working — see examples/worldlabs-arcade/ for a complete runnable demo.

Install SparkJS 2.0

npm install @sparkjsdev/spark@^2.0.0

Package: @sparkjsdev/spark — high-performance Gaussian Splat renderer for Three.js. Pin to ^2.0.0; the 0.x line has a different API (no SparkRenderer) and will not match the snippets below. Supports SPZ, PLY, SOGS, KSPLAT, SPLAT formats (auto-detected by extension).

Three.js peer version: Spark 2.0 declares three@^0.180.0 as its peer dependency. Three treats every 0.x minor as potentially breaking, so three@^0.181 or newer triggers an ERESOLVE peer-dep error on npm install. Pin three to ^0.180.0 in your project's package.json — this is what the threejs-3d template and the worldlabs-arcade example both use.

No bundler? Use the CDN importmap instead of npm:

<script type="importmap">{
  "imports": {
    "three": "https://cdnjs.cloudflare.com/ajax/libs/three.js/0.180.0/three.module.js",
    "@sparkjsdev/spark": "https://sparkjs.dev/releases/spark/2.0.0/spark.module.js"
  }
}</script>

WebGLRenderer config: Create it with antialias: false. Spark's splat shader provides its own anti-aliasing, and enabling MSAA on top wastes GPU for no visual gain:

const renderer = new THREE.WebGLRenderer({ antialias: false });

Constants.js — World Configuration

export const WORLD = {
  splatPath: 'assets/worlds/tavern-500k.spz',   // 500k is a good desktop default
  colliderPath: 'assets/worlds/tavern-collider.glb',
  panoPath: 'assets/worlds/tavern-pano.png',
  scale: 1,
  position: { x: 0, y: 0, z: 0 },
};

WorldLoader.js — Load Gaussian Splat + Collider

Spark 2.0 introduces SparkRenderer — a scene-level object that hooks into Three.js's render pipeline and controls splat quality, sorting, and LOD. You instantiate it once, add it to the scene, then add SplatMesh instances as normal Three.js objects. The WebGLRenderer's render() call handles everything transparently.

import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { SparkRenderer, SplatMesh } from '@sparkjsdev/spark';
import { WORLD } from '../core/Constants.js';

let _colliderMesh = null;
let _splatMesh = null;

export async function loadWorld(scene, renderer, camera) {
  // 0. SparkRenderer — quality + LOD controls for splat rendering.
  //    Must be added to the scene BEFORE any SplatMesh. One per scene.
  const spark = new SparkRenderer({
    renderer,
    maxPixelRadius: 512,   // bigger max → sharper close-up splats
    sortRadial: true,      // eliminates black-bar artifacts on camera rotation
    enableLod: true,       // auto-reduce splat count at distance
    lodSplatScale: 1.0,    // >1.0 = more splats (higher quality), <1.0 = fewer
  });
  scene.add(spark);

  const promises = [];

  // 1. Gaussian Splat via SparkJS — SplatMesh works like any Three.js object.
  //    `splat.initialized` is a Promise that resolves once the file is parsed
  //    and GPU buffers are uploaded.
  if (WORLD.splatPath) {
    promises.push((async () => {
      const splat = new SplatMesh({ url: WORLD.splatPath });
      splat.scale.setScalar(WORLD.scale);
      splat.position.set(WORLD.position.x, WORLD.position.y, WORLD.position.z);
      scene.add(splat);
      if (splat.initialized) await splat.initialized;
      _splatMesh = splat;
    })());
  }

  // 2. Collider mesh (GLB) — invisible, for physics raycasting only
  if (WORLD.colliderPath) {
    promises.push((async () => {
      const loader = new GLTFLoader();
      const gltf = await loader.loadAsync(WORLD.colliderPath);
      _colliderMesh = gltf.scene;
      _colliderMesh.visible = false;
      _colliderMesh.scale.setScalar(WORLD.scale);
      _colliderMesh.position.set(WORLD.position.x, WORLD.position.y, WORLD.position.z);

Use this skill in a project

Open any RiverX project, search the Skills panel for playableintelligence/game-creator/worldlabs, and install it in one click.

Use this skill