# WorldGraph Node Editor A standalone visual node editor for the WorldGraph procedural generation system, built with Dear ImGui and imnodes. Every node displays a live 64×64 preview of its output, ShaderGraph-style. ## Building & Running ```bash make world-editor ``` This configures, builds, and launches the editor in one step. --- ## Interface ### Layout | Area | Description | |---|---| | Left sidebar | Preview settings, World Output status, help | | Main canvas | Node graph — pan with middle-mouse, zoom with scroll | ### Adding Nodes Right-click anywhere on the empty canvas to open the node menu, grouped by category. The node spawns at the click position. ### Connecting Nodes Drag from an **output pin** (right side of a node) to an **input pin** (left side). Dragging in either direction works. Connecting to an already-wired input replaces the existing connection. Cycles are rejected automatically. ### Disconnecting Click an existing link to select it, then press **Delete**. Or drag a new connection onto the same input slot to replace it. ### Deleting Nodes Select one or more nodes and press **Delete**. The **World Output** node cannot be deleted. ### Keyboard Shortcuts | Key | Action | |---|---| | `Ctrl+S` | Save | | `Ctrl+O` | Open | | `Delete` | Delete selected nodes or links | --- ## World Output Node The **World Output** node (blue title bar) is the fixed endpoint of the graph. It is always present and cannot be moved off-canvas or deleted. Each input slot represents one **generation pass**. Passes execute in order — pass 1 can read the tile output of pass 0 via `QueryTile`, `QueryRange`, and `QueryDistance` nodes. - **Connect a pass:** drag any node's output pin into a `Pass N` slot. - **Add a pass slot:** click `+ Pass` inside the node. - **Remove the last pass slot:** click `- Pass`. The World Output preview shows the result of running `GenerateChunk()` with all connected passes over a 64×64 tile region starting at the preview origin. Each pixel equals one world tile. --- ## Per-Node Previews Every node in the graph renders its own 64×64 preview by evaluating the subgraph rooted at that node across a grid of world coordinates. | Output type | Preview color | |---|---| | `Float` | Grayscale, clamped to `[0, 1]` | | `Bool` | White (true) / black (false) | | `Int` (tile ID) | Hashed to a distinct hue; tile 0 (AIR) = near-black | **Scale** in the sidebar controls how many world units one pixel represents in per-node previews. This lets you zoom in on high-frequency noise or zoom out to see large-scale structure. > Query nodes (`QueryTile`, `QueryRange`, `QueryDistance`) always preview as blank in the per-node view because no previous-pass data is available at that stage. They work correctly in the World Output preview when used in a later pass. --- ## Preview Settings (Sidebar) | Setting | Effect | |---|---| | **Origin X / Y** | World-space top-left corner of all previews | | **Scale** | World units per pixel (per-node previews only; World Output is always 1 tile/pixel) | | **Seed** | World seed passed to every `EvalContext` | --- ## Node Types ### Source | Node | Output | Description | |---|---|---| | `Constant` | Float | Fixed float value (drag to edit) | | `TileID` | Int | Fixed tile ID integer (drag to edit) | | `PositionX` | Int | World X coordinate of the current cell | | `PositionY` | Int | World Y coordinate of the current cell | ### Math `Add`, `Subtract`, `Multiply`, `Divide`, `Modulo`, `Sin`, `Cos` ### Compare `Less`, `Greater`, `LessEqual`, `GreaterEqual`, `Equal` — all output `Bool` ### Logic `And`, `Or`, `Not` ### Control | Node | Inputs | Description | |---|---|---| | `Branch` | condition (Bool), true, false | Passes through whichever branch the condition selects | ### Query (previous pass) These nodes read from the previous generation pass. They have no input pins — their parameters are edited inline by dragging. | Node | Output | Parameters | |---|---|---| | `QueryTile` | Bool | `offsetX`, `offsetY`, `expectedID` — true if prev-pass tile at offset equals ID | | `QueryRange` | Int | `minX..maxX`, `minY..maxY`, `tileID` — count of matching tiles in rectangle | | `QueryDistance` | Int | `tileID`, `maxDistance` — Chebyshev distance to nearest matching tile | --- ## File Format Graphs are saved as `.wge` JSON files containing both the graph data and editor layout: ```json { "graph": { ... }, "editor": { "nodePositions": { "1": [x, y], "__worldOutput": [x, y] }, "worldOutputPasses": [3, 7], "seed": 0, "previewOriginX": 0, "previewOriginY": 0, "previewScale": 1.0 } } ``` `worldOutputPasses` is an array of graph node IDs, one per pass slot (`0` = empty slot).