Skip to content

📋 Configuration Schema Reference

Complete TypeScript reference for ExperienceConfig - the main configuration object for WebXR Gallery experiences.


Table of Contents


ExperienceConfig

Root configuration object for an entire experience.

interface ExperienceConfig {
  experience: ExperienceMetadata;
  stages: ExperienceStage[];
  navigation?: NavigationConfig;
}

ExperienceMetadata

interface ExperienceMetadata {
  title: string;              // Experience name
  description?: string;       // Brief description
  author?: string;            // Creator name
  thumbnailUrl?: string;      // Preview image URL
  createdAt?: string;         // ISO 8601 timestamp
  updatedAt?: string;         // ISO 8601 timestamp
}

Example:

{
  "experience": {
    "title": "Museum Virtual Tour",
    "description": "Explore our collection in 360°",
    "author": "Jane Doe",
    "thumbnailUrl": "https://cdn.com/thumb.jpg",
    "createdAt": "2025-12-02T10:00:00Z",
    "updatedAt": "2025-12-02T15:30:00Z"
  }
}


ExperienceStage

A single stage (scene) in the experience.

interface ExperienceStage {
  id: string;                     // Unique identifier
  name: string;                   // Display name
  skybox?: SkyboxConfig;          // 360° background
  models?: ModelConfig[];         // 3D models
  planes?: PlaneConfig[];         // 2D planes (images/videos)
  lights?: LightConfig[];         // Scene lighting
  hotspots?: HotspotConfig[];     // Interactive hotspots
  audioUrl?: string;              // Background audio
  audioVolume?: number;           // 0-1, default 1
  audioLoop?: boolean;            // Loop audio, default true
  location?: GeoCoordinates;      // Geographic position
  initialCameraTarget?: Vector3Config;  // Where camera looks (first stage only)
}

Vector3Config

interface Vector3Config {
  x: number;  // X coordinate
  y: number;  // Y coordinate
  z: number;  // Z coordinate
}

GeoCoordinates

interface GeoCoordinates {
  lat: number;  // Latitude (-90 to 90)
  lng: number;  // Longitude (-180 to 180)
}

Example:

{
  "id": "lobby",
  "name": "Main Lobby",
  "skybox": {
    "type": "video",
    "url": "https://cdn.com/lobby.mp4",
    "autoplay": true
  },
  "hotspots": [
    {
      "id": "info-desk",
      "type": "info",
      "position": { "x": 0, "y": 0, "z": 100 },
      "infoTitle": "Welcome",
      "infoBody": "Welcome to our museum!"
    }
  ],
  "audioUrl": "https://cdn.com/ambient.mp3",
  "audioVolume": 0.5,
  "location": {
    "lat": 40.7128,
    "lng": -74.0060
  },
  "initialCameraTarget": { "x": 0, "y": 0, "z": 100 }
}


SkyboxConfig

360° background configuration.

interface SkyboxConfig {
  type: 'video' | 'image' | 'color';
  url?: string;                   // Media URL (required for video/image)
  hlsUrl?: string;                // HLS manifest URL (.m3u8) for streaming
  thumbnailUrl?: string;          // Preview image (video only)
  color?: string;                 // Hex color (type='color')
  autoplay?: boolean;             // Video: auto-play, default true
  loop?: boolean;                 // Video: loop, default true
  rotation?: number;              // Rotation in degrees, default 0

  // Multi-variant support (advanced)
  variants?: {
    desktop?: TextureVariant;
    mobile?: TextureVariant;
    tablet?: TextureVariant;
    vr?: TextureVariant;
    fallback: TextureVariant;     // Required
  };
}

TextureVariant

interface TextureVariant {
  url: string;
  format: 'ktx2-uastc' | 'ktx2-etc1s' | 'jpg' | 'png';
  resolution?: string;            // e.g., "4096x2048"
  quality?: number;               // ETC1S quality (1-255)
  fileSize?: number;              // Bytes
}

Examples:

Video Skybox:

{
  "type": "video",
  "url": "https://cdn.com/tour.mp4",
  "hlsUrl": "https://stream.mux.com/abc123.m3u8",
  "thumbnailUrl": "https://cdn.com/tour-thumb.jpg",
  "autoplay": true,
  "loop": true,
  "rotation": 90
}

Image Skybox:

{
  "type": "image",
  "url": "https://cdn.com/pano.jpg",
  "rotation": 180
}

Color Skybox:

{
  "type": "color",
  "color": "#87CEEB"
}

Multi-Variant (Advanced):

{
  "type": "image",
  "variants": {
    "desktop": {
      "url": "https://cdn.com/pano-4k.ktx2",
      "format": "ktx2-uastc",
      "resolution": "4096x2048"
    },
    "mobile": {
      "url": "https://cdn.com/pano-2k.ktx2",
      "format": "ktx2-etc1s",
      "resolution": "2048x1024",
      "quality": 128
    },
    "fallback": {
      "url": "https://cdn.com/pano.jpg",
      "format": "jpg"
    }
  }
}


HotspotConfig

Interactive 3D hotspots.

interface HotspotConfig {
  id: string;                     // Unique ID
  position: Vector3Config;        // 3D position
  type: 'info' | 'audio' | 'both' | 'navigation';

  // Visual customization
  color?: string;                 // Hex color, default "#4A90E2"
  size?: number;                  // Radius in meters
  opacity?: number;               // 0-1, default 0.9
  label?: string;                 // Text label
  customIconUrl?: string;         // Custom PNG icon URL

  // Portal-specific (navigation type)
  targetStageId?: string;         // Which stage to navigate to
  portalEffectStyle?: PortalEffectStyle;
  portalRestSize?: number;        // Scale at rest
  portalHoverSize?: number;       // Scale on hover
  portalColor?: string;           // Hex color
  initialViewDirection?: Vector3Config;  // Camera look direction

  // Info content (info/both types)
  infoTitle?: string;
  infoBody?: string;
  infoImageUrl?: string;
  infoImageAspectRatio?: number;  // Width/height
  infoVideoUrl?: string;
  infoLinks?: InfoLink[];

  // Audio (audio/both types)
  audioUrl?: string;
  audioLoop?: boolean;            // Default true
  audioVolume?: number;           // 0-1, default 1
  audioSpatial?: boolean;         // 3D spatial audio, default true
  audioRolloffFactor?: number;    // Distance attenuation, default 1
  audioMaxDistance?: number;      // Max audible distance, default 100
}

PortalEffectStyle

type PortalEffectStyle =
  | 'liquid'      // Flowing liquid metal
  | 'shimmer'     // Shimmering particles
  | 'warp'        // Space-time warp
  | 'minimal';    // Simple glow
interface InfoLink {
  label: string;     // Link text
  url: string;       // URL
  icon?: string;     // Icon name
}

Examples:

Info Hotspot:

{
  "id": "artwork-1",
  "type": "info",
  "position": { "x": 50, "y": 10, "z": 80 },
  "color": "#FFD700",
  "label": "Starry Night",
  "infoTitle": "The Starry Night",
  "infoBody": "Vincent van Gogh, 1889...",
  "infoImageUrl": "https://cdn.com/starry-night.jpg",
  "infoLinks": [
    {
      "label": "Learn More",
      "url": "https://en.wikipedia.org/wiki/The_Starry_Night",
      "icon": "external"
    }
  ]
}

Audio Hotspot:

{
  "id": "ambient-1",
  "type": "audio",
  "position": { "x": 0, "y": 50, "z": 100 },
  "audioUrl": "https://cdn.com/birds.mp3",
  "audioSpatial": true,
  "audioRolloffFactor": 2,
  "audioMaxDistance": 50
}

Navigation Portal:

{
  "id": "portal-gallery-2",
  "type": "navigation",
  "position": { "x": 0, "y": 0, "z": -100 },
  "targetStageId": "gallery-2",
  "portalEffectStyle": "liquid",
  "portalColor": "#4A90E2",
  "portalRestSize": 1.0,
  "portalHoverSize": 1.2,
  "initialViewDirection": { "x": 0, "y": 0, "z": 1 }
}


Geographic navigation system.

interface NavigationConfig {
  type: 'floorplan' | 'map' | 'none';
  showMinimap?: boolean;          // Show corner minimap, default true
  markers: NavigationMarker[];

  // Map-specific
  mapConfig?: {
    tileLayer?: string;           // 'streets' | 'satellite' | 'outdoors' | 'dark'
    initialZoom?: number;         // Default 15
    maxZoom?: number;             // Default 18
    minZoom?: number;             // Default 10
  };

  // Floor plan-specific
  floorPlan?: FloorPlanConfig;    // Single floor
  floorPlans?: FloorPlanConfig[]; // Multi-floor

  // Legacy (deprecated)
  displayMode?: 'minimap' | 'fullscreen' | 'both' | 'none';
  minimapPosition?: 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
  minimapSize?: 'small' | 'medium' | 'large';
}
interface NavigationMarker {
  stageId: string;                // Which stage?
  label?: string;                 // Display name

  // Geographic (maps)
  geoPosition?: GeoCoordinates;

  // Floor plan
  floorPlanPosition?: FloorPlanPosition;

  // Visual
  icon?: 'default' | 'star' | 'info' | 'camera' | 'video' | 'audio';
  customIconUrl?: string;
  color?: string;

  // Metadata
  placeName?: string;             // From geocoding
}

FloorPlanPosition

interface FloorPlanPosition {
  x: number;  // 0-1 (0=left, 1=right)
  y: number;  // 0-1 (0=top, 1=bottom)
}

FloorPlanConfig

interface FloorPlanConfig {
  floor?: number;                 // Floor number (1-indexed)
  name?: string;                  // Floor name
  imageUrl: string;               // Floor plan image
}

Examples:

Map Navigation:

{
  "type": "map",
  "showMinimap": true,
  "mapConfig": {
    "tileLayer": "streets",
    "initialZoom": 15
  },
  "markers": [
    {
      "stageId": "stage-1",
      "label": "Main Entrance",
      "geoPosition": { "lat": 40.7128, "lng": -74.0060 },
      "icon": "star",
      "color": "#FF0000"
    }
  ]
}

Floor Plan Navigation:

{
  "type": "floorplan",
  "showMinimap": true,
  "floorPlans": [
    {
      "floor": 1,
      "name": "Ground Floor",
      "imageUrl": "https://cdn.com/floor1.png"
    },
    {
      "floor": 2,
      "name": "Second Floor",
      "imageUrl": "https://cdn.com/floor2.png"
    }
  ],
  "markers": [
    {
      "stageId": "lobby",
      "label": "Main Lobby",
      "floorPlanPosition": { "x": 0.5, "y": 0.3 }
    }
  ]
}


ModelConfig

3D model configuration (glTF/GLB).

interface ModelConfig {
  id?: string;                    // Optional ID
  url: string;                    // Model URL
  position?: Vector3Config;       // Position, default {0,0,0}
  rotation?: Vector3Config;       // Rotation (radians), default {0,0,0}
  scale?: Vector3Config | number; // Scale, default 1
}

Example:

{
  "url": "https://cdn.com/sculpture.glb",
  "position": { "x": 0, "y": 0, "z": 50 },
  "rotation": { "x": 0, "y": 1.57, "z": 0 },
  "scale": 2.0
}


PlaneConfig

2D plane (image/video) in 3D space.

interface PlaneConfig {
  type: 'image' | 'video';
  url: string;
  hlsUrl?: string;                // HLS for video
  position?: Vector3Config;
  rotation?: Vector3Config;       // Radians
  scale?: { width: number; height: number };
  autoplay?: boolean;             // Video only
  loop?: boolean;                 // Video only
  muted?: boolean;                // Video only
}

Example:

{
  "type": "image",
  "url": "https://cdn.com/poster.jpg",
  "position": { "x": 0, "y": 20, "z": 80 },
  "rotation": { "x": 0, "y": 0, "z": 0 },
  "scale": { "width": 30, "height": 40 }
}


LightConfig

Scene lighting configuration.

interface LightConfig {
  type: 'hemispheric' | 'directional' | 'point' | 'spot';
  intensity?: number;             // 0-2, default 1
  diffuse?: string;               // Hex color, default "#FFFFFF"
  specular?: string;              // Hex color, default "#FFFFFF"

  // Hemispheric only
  groundColor?: string;

  // Directional/Hemispheric
  direction?: Vector3Config;

  // Point/Spot
  position?: Vector3Config;
  range?: number;

  // Spot only
  angle?: number;                 // Radians
  exponent?: number;              // 0-128
}

Examples:

Hemispheric Light:

{
  "type": "hemispheric",
  "intensity": 0.7,
  "diffuse": "#FFFFFF",
  "groundColor": "#444444",
  "direction": { "x": 0, "y": 1, "z": 0 }
}

Point Light:

{
  "type": "point",
  "position": { "x": 0, "y": 50, "z": 0 },
  "intensity": 1.5,
  "range": 100
}


Validation Rules

Required Fields

  • experience.title - Must not be empty
  • stages - Must have at least one stage
  • stage.id - Must be unique across all stages
  • stage.name - Must not be empty
  • hotspot.id - Must be unique within stage

Value Constraints

  • audioVolume: 0-1
  • opacity: 0-1
  • lat: -90 to 90
  • lng: -180 to 180
  • floorPlanPosition.x: 0-1
  • floorPlanPosition.y: 0-1
  • Colors: Must be valid hex (#RGB or #RRGGBB)

URL Validation

  • url fields must be valid HTTP/HTTPS URLs
  • For local development: http://localhost:* allowed
  • CORS headers must be configured for remote URLs

Migration Guides

v2.0 → v2.1

New Fields: - stage.initialCameraTarget - Camera orientation (first stage only) - hotspot.customIconUrl - Custom PNG icons - navigation.showMinimap - Simplified minimap control - marker.placeName - Auto-filled by geocoding

Deprecated Fields: - navigation.displayMode - Use showMinimap instead - navigation.minimapPosition - Now fixed at bottom-left - navigation.minimapSize - Now fixed at 100x100px

Breaking Changes: - None! All deprecated fields still work for backward compatibility.


Next Steps


Need help? Check the FAQ or open an issue.