feat: add render graph driven renderer architecture

Amp-Thread-ID: https://ampcode.com/threads/T-019f9d91-77c1-7206-a60f-ed6554ce92ab

Co-authored-by: Heaust Azure <heaust.azure@gmail.com>
This commit is contained in:
Amp
2026-07-27 02:53:44 +00:00
co-authored by heaust
parent 8a8369706b
commit d4e8634f67
290 changed files with 48804 additions and 1995 deletions
+23
View File
@@ -0,0 +1,23 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>FxNode controls</title>
<style>
html,
body {
margin: 0;
background: #111;
}
canvas {
display: block;
width: 1200px;
height: 640px;
}
</style>
</head>
<body>
<canvas id="controls"></canvas>
<script type="module" src="./main.ts"></script>
</body>
</html>
@@ -0,0 +1,293 @@
{
"graphId": "control-test",
"catalogVersion": 4,
"nodes": [
{
"id": "color",
"typeId": "fxnode.shader.color",
"typeVersion": 1,
"known": true,
"position": {
"x": 300,
"y": 200
},
"size": {
"x": 151,
"y": 100
},
"label": "Color",
"parameters": {
"color": {
"kind": "color",
"value": [
0.8,
0.8,
0.8,
1
]
}
},
"sockets": [
{
"id": "color:color",
"key": "color",
"label": "Color",
"direction": "output",
"dataType": "color",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
}
],
"muted": false,
"collapsed": false,
"extensions": {}
},
{
"id": "group",
"typeId": "fxnode.common.group-input",
"typeVersion": 1,
"known": true,
"position": {
"x": -100,
"y": -100
},
"size": {
"x": 257,
"y": 100
},
"label": "Group Input",
"parameters": {
"interfaceName": {
"kind": "string",
"value": "Socket"
}
},
"sockets": [
{
"id": "group:output",
"key": "output",
"label": "Interface",
"direction": "output",
"dataType": "any",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
}
],
"muted": false,
"collapsed": false,
"extensions": {}
},
{
"id": "math",
"typeId": "fxnode.shader.math",
"typeVersion": 1,
"known": true,
"position": {
"x": -250,
"y": 200
},
"size": {
"x": 192,
"y": 148
},
"label": "Math",
"parameters": {
"operation": {
"kind": "string",
"value": "add"
},
"clamp": {
"kind": "boolean",
"value": false
}
},
"sockets": [
{
"id": "math:a",
"key": "a",
"label": "A",
"direction": "input",
"dataType": "float",
"accepts": [
"float",
"any"
],
"maxIncomingLinks": 1,
"visible": true,
"defaultValue": {
"kind": "number",
"value": 0
}
},
{
"id": "math:b",
"key": "b",
"label": "B",
"direction": "input",
"dataType": "float",
"accepts": [
"float",
"any"
],
"maxIncomingLinks": 1,
"visible": true,
"defaultValue": {
"kind": "number",
"value": 0
}
},
{
"id": "math:value",
"key": "value",
"label": "Value",
"direction": "output",
"dataType": "float",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
}
],
"muted": false,
"collapsed": false,
"extensions": {}
},
{
"id": "value",
"typeId": "fxnode.shader.value",
"typeVersion": 1,
"known": true,
"position": {
"x": -500,
"y": 200
},
"size": {
"x": 151,
"y": 100
},
"label": "Value",
"parameters": {
"value": {
"kind": "number",
"value": 0
}
},
"sockets": [
{
"id": "value:value",
"key": "value",
"label": "Value",
"direction": "output",
"dataType": "float",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
}
],
"muted": false,
"collapsed": false,
"extensions": {}
},
{
"id": "vector",
"typeId": "fxnode.shader.vector-math",
"typeVersion": 1,
"known": true,
"position": {
"x": 20,
"y": 200
},
"size": {
"x": 340,
"y": 148
},
"label": "Vector Math",
"parameters": {
"operation": {
"kind": "string",
"value": "add"
}
},
"sockets": [
{
"id": "vector:a",
"key": "a",
"label": "A",
"direction": "input",
"dataType": "vector",
"accepts": [
"vector",
"any"
],
"maxIncomingLinks": 1,
"visible": true,
"defaultValue": {
"kind": "vector",
"value": [
0,
0,
0
]
}
},
{
"id": "vector:b",
"key": "b",
"label": "B",
"direction": "input",
"dataType": "vector",
"accepts": [
"vector",
"any"
],
"maxIncomingLinks": 1,
"visible": true,
"defaultValue": {
"kind": "vector",
"value": [
0,
0,
0
]
}
},
{
"id": "vector:vector",
"key": "vector",
"label": "Vector",
"direction": "output",
"dataType": "vector",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
},
{
"id": "vector:value",
"key": "value",
"label": "Value",
"direction": "output",
"dataType": "float",
"accepts": [],
"maxIncomingLinks": 0,
"visible": true
}
],
"muted": false,
"collapsed": false,
"extensions": {}
}
],
"links": [
{
"id": "value-math",
"fromNodeId": "value",
"fromSocketId": "value:value",
"toNodeId": "math",
"toSocketId": "math:a",
"muted": false,
"extensions": {}
}
],
"metadata": {}
}
+30
View File
@@ -0,0 +1,30 @@
import { createApplicationFxNode, type ApplicationFxNode } from "../application-browser.js";
import type { FxNodeView } from "@lib/index.js";
import { prepareFxNodeBrowserHost } from "../../shared/browser-host.js";
import initialLayout from "./initialLayout.json" with { type: "json" };
const canvas = document.querySelector<HTMLCanvasElement>("#controls");
if (!canvas) throw new Error("Control test canvas missing");
const host = prepareFxNodeBrowserHost({ canvas });
const handle: { root: ApplicationFxNode | null; view: FxNodeView | null; ready: Promise<void> } = {
root: null,
view: null,
ready: Promise.resolve(),
};
window.controlTest = handle;
handle.ready = (async () => {
let root: ApplicationFxNode | undefined, view: FxNodeView | undefined;
try {
root = await createApplicationFxNode();
await root.setState(initialLayout);
view = await root.attachView({ canvas, viewport: host.initialViewport });
handle.root = root;
handle.view = view;
host.attach(root, view);
await view.whenRendered();
} catch (error) {
host.destroy();
await view?.detach();
root?.destroy();
throw error;
}
})();