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.
Array of React Flow nodes from the Blueprint editor
Array of React Flow edges connecting the nodes
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.
The compiled script from compileGraph
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.
The compiled script to serialize
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 };
}