Skip to main content

Overview

The Script Compiler transforms visual Blueprint node graphs (React Flow) into executable game scripts. It traverses event-action connections and generates compiled actions that can be consumed by the Three.js game loop.

Types

CompiledAction

interface CompiledAction {
    eventType: string;
    eventLabel: string;
    actionType: string;
    actionLabel: string;
    params: Record<string, unknown>;
}
Represents a single compiled event-action pair from the Blueprint graph.

CompiledScript

interface CompiledScript {
    actions: CompiledAction[];
}
Contains all compiled actions for a Blueprint script.

Functions

compileGraph

function compileGraph(nodes: Node[], edges: Edge[]): CompiledScript
Traverses a React Flow graph and produces an array of compiled actions that can be consumed by the game loop. Each compiled action pairs an EventNode with an ActionNode or Web3Node based on the edges connecting them.
nodes
Node[]
required
Array of React Flow nodes from the Blueprint editor
edges
Edge[]
required
Array of React Flow edges connecting the nodes
return
CompiledScript
Compiled script containing all event-action pairs
Event Types Recognized:
  • keyPress - Detected from labels containing “key” or “wasd”
  • click - Detected from labels containing “click”
  • start - Detected from labels containing “start”
  • update - Detected from labels containing “update” or “tick”
  • walletConnect - Detected from labels containing “wallet” or “connect”
  • chain - For chained actions (action→action or action→web3)
  • custom - All other event types
Action Types Recognized:
  • moveCharacter - Labels containing “move”
  • toggleVisibility - Labels containing “hide” or “show”
  • playAnimation - Labels containing “play” and “anim”
  • playSound - Labels containing “play” and “sound”
  • rotateObject - Labels containing “rotate”
  • mintNFT - Web3 nodes with “mint”
  • transferToken - Web3 nodes with “transfer” or “send”
  • nftGate - Web3 nodes with “gate” or “require”
  • web3Custom - Other Web3 nodes
  • customAction - All other action types
Example:
import { compileGraph } from '@/lib/scriptCompiler';
import { Node, Edge } from '@xyflow/react';

const nodes: Node[] = [
  { id: '1', type: 'eventNode', data: { label: 'On Key Press (WASD)' }, position: { x: 0, y: 0 } },
  { id: '2', type: 'actionNode', data: { label: 'Move Character' }, position: { x: 200, y: 0 } },
];

const edges: Edge[] = [
  { id: 'e1-2', source: '1', target: '2' },
];

const script = compileGraph(nodes, edges);
console.log(script);
// {
//   actions: [
//     {
//       eventType: 'keyPress',
//       eventLabel: 'On Key Press (WASD)',
//       actionType: 'moveCharacter',
//       actionLabel: 'Move Character',
//       params: {}
//     }
//   ]
// }

generateCallbacks

function generateCallbacks(script: CompiledScript): (() => void)[]
Takes compiled actions and generates executable callback registrations that can be consumed by a Three.js game loop.
script
CompiledScript
required
The compiled script from compileGraph
return
(() => void)[]
Array of executable callback functions
Example:
import { compileGraph, generateCallbacks } from '@/lib/scriptCompiler';

const script = compileGraph(nodes, edges);
const callbacks = generateCallbacks(script);

// Register callbacks in game loop
callbacks.forEach(cb => cb());
// Console output: [GameLoop] Event: keyPress (On Key Press (WASD)) → Action: moveCharacter (Move Character)

serializeScript

function serializeScript(script: CompiledScript): string
Serializes a compiled script to JSON for storage or export.
script
CompiledScript
required
The compiled script to serialize
return
string
Pretty-printed JSON string of the script
Example:
import { compileGraph, serializeScript } from '@/lib/scriptCompiler';

const script = compileGraph(nodes, edges);
const json = serializeScript(script);

localStorage.setItem('gameScript', json);

Usage Patterns

Blueprint Editor Integration

import { compileGraph } from '@/lib/scriptCompiler';
import { useReactFlow } from '@xyflow/react';

function BlueprintCompiler() {
  const { getNodes, getEdges } = useReactFlow();
  
  const handleCompile = () => {
    const nodes = getNodes();
    const edges = getEdges();
    const script = compileGraph(nodes, edges);
    
    console.log(`Compiled ${script.actions.length} actions`);
    return script;
  };
  
  return (
    <button onClick={handleCompile}>
      Compile Blueprint
    </button>
  );
}

Web3 Blueprint Example

import { compileGraph } from '@/lib/scriptCompiler';

const web3Nodes = [
  { id: '1', type: 'eventNode', data: { label: 'On Wallet Connect' }, position: { x: 0, y: 0 } },
  { id: '2', type: 'web3Node', data: { label: '🚀 Mint NFT' }, position: { x: 200, y: 0 } },
];

const web3Edges = [
  { id: 'e1-2', source: '1', target: '2' },
];

const script = compileGraph(web3Nodes, web3Edges);
// {
//   actions: [
//     {
//       eventType: 'walletConnect',
//       eventLabel: 'On Wallet Connect',
//       actionType: 'mintNFT',
//       actionLabel: '🚀 Mint NFT',
//       params: {}
//     }
//   ]
// }

Chained Actions

import { compileGraph } from '@/lib/scriptCompiler';

const chainedNodes = [
  { id: '1', type: 'eventNode', data: { label: 'On Click' }, position: { x: 0, y: 0 } },
  { id: '2', type: 'actionNode', data: { label: 'Play Sound' }, position: { x: 200, y: 0 } },
  { id: '3', type: 'actionNode', data: { label: 'Show Object' }, position: { x: 400, y: 0 } },
];

const chainedEdges = [
  { id: 'e1-2', source: '1', target: '2' },
  { id: 'e2-3', source: '2', target: '3' }, // Action chaining
];

const script = compileGraph(chainedNodes, chainedEdges);
// Creates two actions:
// 1. click → playSound
// 2. chain → toggleVisibility (triggered after playSound)

Game Loop Integration

import { compileGraph, generateCallbacks } from '@/lib/scriptCompiler';
import { useEffect } from 'react';

function GameRuntime({ nodes, edges }: { nodes: Node[], edges: Edge[] }) {
  useEffect(() => {
    // Compile the Blueprint graph
    const script = compileGraph(nodes, edges);
    const callbacks = generateCallbacks(script);
    
    // Register callbacks with game engine
    callbacks.forEach((callback, index) => {
      const action = script.actions[index];
      
      // Example: Register keypress handler
      if (action.eventType === 'keyPress') {
        window.addEventListener('keydown', callback);
      }
      
      // Example: Register click handler
      if (action.eventType === 'click') {
        canvas.addEventListener('click', callback);
      }
    });
    
    return () => {
      // Cleanup listeners
    };
  }, [nodes, edges]);
  
  return <canvas />;
}

Save and Load Scripts

import { compileGraph, serializeScript } from '@/lib/scriptCompiler';

function ScriptManager() {
  const saveScript = (nodes: Node[], edges: Edge[]) => {
    const script = compileGraph(nodes, edges);
    const json = serializeScript(script);
    localStorage.setItem('compiledScript', json);
  };
  
  const loadScript = (): CompiledScript | null => {
    const json = localStorage.getItem('compiledScript');
    if (!json) return null;
    
    try {
      return JSON.parse(json) as CompiledScript;
    } catch {
      return null;
    }
  };
  
  return { saveScript, loadScript };
}

Build docs developers (and LLMs) love