Skip to main content

Overview

The Editor Store is a Zustand-based state management solution that powers the G3Engine editor. It manages the scene graph, object transformations, editor modes, and history (undo/redo) functionality.

Types

ObjectType

type ObjectType = 'box' | 'sphere' | 'cylinder' | 'plane' | 'cone' | 'torus' | 'pointLight' | 'directionalLight' | 'ambientLight' | 'camera'

Vec3

interface Vec3 {
    x: number;
    y: number;
    z: number;
}

MaterialProps

interface MaterialProps {
    color: string;
    roughness: number;
    metalness: number;
    emissive?: string;
    emissiveIntensity?: number;
    opacity?: number;
    transparent?: boolean;
}

SceneObject

interface SceneObject {
    id: string;
    name: string;
    type: ObjectType;
    position: Vec3;
    rotation: Vec3;
    scale: Vec3;
    material: MaterialProps;
    visible: boolean;
    lightIntensity?: number;
    lightColor?: string;
}

TransformMode

type TransformMode = 'translate' | 'rotate' | 'scale'

Store Hook

useEditorStore

const useEditorStore = create<EditorState>((set, get) => ({...}))
The main store hook that provides access to the editor state and actions.

State Properties

objects
SceneObject[]
Array of all scene objects in the current scene
selectedObjectId
string | null
ID of the currently selected object, or null if no selection
isPlaying
boolean
Whether the scene is in play mode
transformMode
TransformMode
Current transform gizmo mode: ‘translate’, ‘rotate’, or ‘scale’
web3Enabled
boolean
Whether Web3 features are enabled in the editor
history
HistoryEntry[]
Array of history snapshots for undo/redo functionality
historyIndex
number
Current position in the history array

Object CRUD Actions

addObject

addObject(type: ObjectType): void
Adds a new object to the scene with default properties.
type
ObjectType
required
The type of object to create
Example:
import { useEditorStore } from '@/store/editorStore';

const { addObject } = useEditorStore();
addObject('box'); // Adds a new cube to the scene

removeObject

removeObject(id: string): void
Removes an object from the scene by its ID.
id
string
required
The ID of the object to remove
Example:
const { removeObject } = useEditorStore();
removeObject('obj-123');

duplicateObject

duplicateObject(id: string): void
Creates a copy of an existing object, offset by 1 unit on the X axis.
id
string
required
The ID of the object to duplicate
Example:
const { duplicateObject } = useEditorStore();
duplicateObject('obj-123'); // Creates "Object Copy" at position + 1 on X

selectObject

selectObject(id: string | null): void
Selects an object in the scene or clears selection if null.
id
string | null
required
The ID of the object to select, or null to clear selection
Example:
const { selectObject } = useEditorStore();
selectObject('obj-123');
selectObject(null); // Clear selection

Transform Actions

updateTransform

updateTransform(id: string, field: 'position' | 'rotation' | 'scale', value: Vec3): void
Updates the position, rotation, or scale of an object.
id
string
required
The ID of the object to transform
field
'position' | 'rotation' | 'scale'
required
The transform property to update
value
Vec3
required
The new transform value
Example:
const { updateTransform } = useEditorStore();
updateTransform('obj-123', 'position', { x: 0, y: 2, z: 0 });

updateMaterial

updateMaterial(id: string, material: Partial<MaterialProps>): void
Updates material properties of an object.
id
string
required
The ID of the object
material
Partial<MaterialProps>
required
Partial material properties to merge
Example:
const { updateMaterial } = useEditorStore();
updateMaterial('obj-123', { color: '#ff0000', metalness: 0.8 });

setTransformMode

setTransformMode(mode: TransformMode): void
Sets the active transform gizmo mode.
mode
TransformMode
required
The transform mode to activate
Example:
const { setTransformMode } = useEditorStore();
setTransformMode('rotate');

renameObject

renameObject(id: string, name: string): void
Renames an object in the scene.
id
string
required
The ID of the object to rename
name
string
required
The new name for the object
Example:
const { renameObject } = useEditorStore();
renameObject('obj-123', 'Hero Character');

Editor Actions

togglePlay

togglePlay(): void
Toggles between edit mode and play mode. Clears selection when entering play mode. Example:
const { togglePlay, isPlaying } = useEditorStore();
togglePlay(); // Switches to play mode

toggleWeb3

toggleWeb3(): void
Toggles Web3 integration features on/off. Example:
const { toggleWeb3, web3Enabled } = useEditorStore();
toggleWeb3();

History Actions

pushHistory

pushHistory(): void
Manually creates a snapshot of the current scene state for undo/redo. Example:
const { pushHistory } = useEditorStore();
pushHistory(); // Saves current state

undo

undo(): void
Reverts to the previous state in history. Example:
const { undo } = useEditorStore();
undo();

redo

redo(): void
Reapplies the next state in history after an undo. Example:
const { redo } = useEditorStore();
redo();

Serialization Actions

exportScene

exportScene(): string
Exports the current scene to a JSON string.
return
string
JSON string containing scene version and objects array
Example:
const { exportScene } = useEditorStore();
const json = exportScene();
console.log(json);
// {"version": 1, "objects": [...]}

importScene

importScene(json: string): void
Imports a scene from JSON, replacing the current scene.
json
string
required
JSON string containing scene data with version and objects array
Example:
const { importScene } = useEditorStore();
const sceneData = '{"version": 1, "objects": [...]}';
importScene(sceneData);

Usage Patterns

Reading State

function SceneHierarchy() {
  const objects = useEditorStore((state) => state.objects);
  const selectedId = useEditorStore((state) => state.selectedObjectId);
  
  return (
    <div>
      {objects.map(obj => (
        <div key={obj.id} className={obj.id === selectedId ? 'selected' : ''}>
          {obj.name}
        </div>
      ))}
    </div>
  );
}

Calling Actions

function AddObjectButton() {
  const addObject = useEditorStore((state) => state.addObject);
  
  return (
    <button onClick={() => addObject('sphere')}>
      Add Sphere
    </button>
  );
}

Complete CRUD Example

function ObjectEditor() {
  const { objects, selectedObjectId, selectObject, updateTransform, removeObject } = useEditorStore();
  
  const selectedObject = objects.find(obj => obj.id === selectedObjectId);
  
  if (!selectedObject) return null;
  
  return (
    <div>
      <h3>{selectedObject.name}</h3>
      <input 
        type="number" 
        value={selectedObject.position.y}
        onChange={(e) => updateTransform(
          selectedObject.id, 
          'position', 
          { ...selectedObject.position, y: parseFloat(e.target.value) }
        )}
      />
      <button onClick={() => removeObject(selectedObject.id)}>Delete</button>
    </div>
  );
}

Build docs developers (and LLMs) love