Skip to main content

Overview

The Scene Serializer provides utilities for exporting and importing G3Engine scenes to and from JSON format. It includes metadata tracking and downloadable file generation.

Types

SceneExport

interface SceneExport {
    version: number;
    exportedAt: string;
    objects: SceneObject[];
    metadata: {
        objectCount: number;
        hasLights: boolean;
        hasWeb3: boolean;
    };
}
Represents a complete scene export with version control and metadata.

Functions

exportScene

function exportScene(objects: SceneObject[], web3Enabled: boolean): SceneExport
Exports the current scene state to a serializable JSON format with metadata.
objects
SceneObject[]
required
Array of scene objects to export
web3Enabled
boolean
required
Whether Web3 features are enabled in the scene
return
SceneExport
Complete scene export object with version, timestamp, objects, and metadata
Example:
import { exportScene } from '@/lib/sceneSerializer';
import { useEditorStore } from '@/store/editorStore';

function SaveScene() {
  const { objects, web3Enabled } = useEditorStore();
  
  const handleExport = () => {
    const sceneData = exportScene(objects, web3Enabled);
    console.log(sceneData);
    // {
    //   version: 1,
    //   exportedAt: "2026-03-04T12:00:00.000Z",
    //   objects: [...],
    //   metadata: {
    //     objectCount: 5,
    //     hasLights: true,
    //     hasWeb3: false
    //   }
    // }
  };
  
  return <button onClick={handleExport}>Export Scene</button>;
}

importScene

function importScene(json: string): SceneObject[] | null
Imports a scene from JSON string and returns the objects array.
json
string
required
JSON string containing the scene export data
return
SceneObject[] | null
Array of scene objects if successful, null if parsing fails or data is invalid
Example:
import { importScene } from '@/lib/sceneSerializer';

function LoadScene() {
  const handleImport = (jsonString: string) => {
    const objects = importScene(jsonString);
    
    if (objects) {
      console.log(`Loaded ${objects.length} objects`);
      // Update your store with the objects
    } else {
      console.error('Failed to import scene');
    }
  };
  
  return (
    <input 
      type="file" 
      onChange={(e) => {
        const file = e.target.files?.[0];
        if (file) {
          file.text().then(handleImport);
        }
      }}
    />
  );
}

downloadSceneAsJSON

function downloadSceneAsJSON(objects: SceneObject[], web3Enabled: boolean): void
Exports the scene and triggers a browser download as a JSON file.
objects
SceneObject[]
required
Array of scene objects to export
web3Enabled
boolean
required
Whether Web3 features are enabled in the scene
Example:
import { downloadSceneAsJSON } from '@/lib/sceneSerializer';
import { useEditorStore } from '@/store/editorStore';

function DownloadButton() {
  const { objects, web3Enabled } = useEditorStore();
  
  return (
    <button onClick={() => downloadSceneAsJSON(objects, web3Enabled)}>
      Download Scene
    </button>
  );
}
This will download a file named game-scene-{timestamp}.json with the complete scene data.

Usage Patterns

Complete Save/Load Workflow

import { exportScene, importScene, downloadSceneAsJSON } from '@/lib/sceneSerializer';
import { useEditorStore } from '@/store/editorStore';

function SceneManager() {
  const { objects, web3Enabled } = useEditorStore();
  const { importScene: updateStore } = useEditorStore();
  
  // Save to localStorage
  const saveToLocalStorage = () => {
    const sceneData = exportScene(objects, web3Enabled);
    localStorage.setItem('savedScene', JSON.stringify(sceneData));
  };
  
  // Load from localStorage
  const loadFromLocalStorage = () => {
    const json = localStorage.getItem('savedScene');
    if (json) {
      const objects = importScene(json);
      if (objects) {
        updateStore(json); // Use the store's importScene
      }
    }
  };
  
  // Download as file
  const handleDownload = () => {
    downloadSceneAsJSON(objects, web3Enabled);
  };
  
  return (
    <div>
      <button onClick={saveToLocalStorage}>Save</button>
      <button onClick={loadFromLocalStorage}>Load</button>
      <button onClick={handleDownload}>Download</button>
    </div>
  );
}

File Upload Handler

import { importScene } from '@/lib/sceneSerializer';
import { useEditorStore } from '@/store/editorStore';

function SceneUploader() {
  const { importScene: updateStore } = useEditorStore();
  
  const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;
    
    try {
      const text = await file.text();
      const objects = importScene(text);
      
      if (objects) {
        updateStore(text);
        console.log(`Successfully imported ${objects.length} objects`);
      } else {
        alert('Invalid scene file');
      }
    } catch (error) {
      console.error('Failed to read file:', error);
      alert('Failed to read scene file');
    }
  };
  
  return (
    <input 
      type="file" 
      accept=".json"
      onChange={handleFileUpload}
    />
  );
}

Inspecting Scene Metadata

import { exportScene } from '@/lib/sceneSerializer';
import { useEditorStore } from '@/store/editorStore';

function SceneInfo() {
  const { objects, web3Enabled } = useEditorStore();
  const sceneData = exportScene(objects, web3Enabled);
  
  return (
    <div>
      <p>Version: {sceneData.version}</p>
      <p>Exported: {new Date(sceneData.exportedAt).toLocaleString()}</p>
      <p>Objects: {sceneData.metadata.objectCount}</p>
      <p>Has Lights: {sceneData.metadata.hasLights ? 'Yes' : 'No'}</p>
      <p>Web3 Enabled: {sceneData.metadata.hasWeb3 ? 'Yes' : 'No'}</p>
    </div>
  );
}

Scene Export Format

The exported JSON follows this structure:
{
  "version": 1,
  "exportedAt": "2026-03-04T12:00:00.000Z",
  "objects": [
    {
      "id": "abc-123",
      "name": "Cube 1",
      "type": "box",
      "position": { "x": 0, "y": 0.5, "z": 0 },
      "rotation": { "x": 0, "y": 0, "z": 0 },
      "scale": { "x": 1, "y": 1, "z": 1 },
      "material": {
        "color": "#6366f1",
        "roughness": 0.4,
        "metalness": 0.1
      },
      "visible": true
    }
  ],
  "metadata": {
    "objectCount": 1,
    "hasLights": false,
    "hasWeb3": false
  }
}

Build docs developers (and LLMs) love