Skip to content

Building Systems for Nexus Engine ​

A "System" in Nexus Engine is a standalone, decoupled feature (e.g., Pathfinding, Player Controllers, Phone UI) that users can purchase or install and drop into their 3D worlds.

System Anatomy ​

A complete system consists of two parts:

  1. The Runtime Component: A standard React component (2D or 3D via @react-three/fiber) that executes the actual game logic.
  2. The Editor Plugin Schema: A configuration object that tells the Visual Editor how to render the properties panel, spawn helpers, and handle configuration.

1. The Runtime Component ​

Runtime components receive position, rotation, scale, and all custom properties defined in your Editor schema as standard React props.

tsx
import React from 'react';
import { useGLTF } from '@react-three/drei';
import * as THREE from 'three';

export function MySystemRuntime({ position, rotation, speed, modelUrl }) {
  const { scene } = useGLTF(modelUrl);
  
  // Apply position to the scene if needed
  React.useEffect(() => {
    scene.position.set(position[0], position[1], position[2]);
  }, [position]);

  return <primitive object={scene} />;
}

2. The Editor Schema ​

The schema object must implement the EditorPlugin interface from @neural-workspace/nexus-engine-core.

tsx
import { EditorPlugin } from '@neural-workspace/nexus-engine-core';

export const MySystemPlugin: EditorPlugin = {
  id: "my-system",
  name: "My Awesome System",
  category: "Systems",
  is3D: true, // True if the system renders inside the <Canvas>
  iconSvg: '<svg>...</svg>', // Raw SVG string for the sidebar
  
  // Optional: A URL to a 3D model used ONLY as a visual placeholder in the editor
  viewportHelperModel: "/models/optimized/placeholder.glb",
  
  // Optional: A custom React component for complex Editor viewport visualization 
  // (e.g., drawing grids, rings, or bounds). This overrides `viewportHelperModel`.
  CustomViewportHelper: ({ node, onChange }) => {
    // Render custom visualizers using standard Drei/Three tools
    return <mesh><boxGeometry/></mesh>;
  },

  // Optional: A custom React component for the right sidebar properties panel.
  // This allows complex UIs (like behavior graphs or script editors) beyond simple schemas.
  CustomInspector: ({ node, onChange }) => {
    // You can access built-in Editor UI components from window.NexusEnv.EditorUI!
    const { BehaviorScriptEditor } = (window as any).NexusEnv.EditorUI;
    return (
      <BehaviorScriptEditor 
        script={node.properties.script || []} 
        onChange={(newScript) => onChange({ script: newScript })} 
      />
    );
  },

  defaultProps: {
    speed: 5,
    modelUrl: '/models/optimized/default.glb',
    script: []
  },
  
  properties: [
    { id: 'speed', label: 'Speed', type: 'number', min: 1, max: 10, default: 5 },
    { id: 'modelUrl', label: 'Model', type: 'string', default: '/models/optimized/default.glb' },
    // You can also use built-in complex property types directly in the schema:
    { id: 'script', label: 'Bot Script', type: 'behavior_script', options: ['move', 'wait', 'turn'] }
  ]
};

Distributing Systems ​

Systems can be bundled into standalone ECMAScript modules (ESM) and served remotely.

To build systems for distribution, we use esbuild with a custom globalsPlugin that maps bare specifiers (like react, three) to window.NexusEnv. This ensures that dynamically loaded systems share the same React instance as the host engine.

See apps/backend/buildPlugins.js for the exact build pipeline.