Files
ichni_Creator_Studio/docs/superpowers/specs/2026-06-10-ichni-nodescript-web-design.md
TRADER_FOER c99c10fd37 NodeScript Web 设计规格
将 Unity 内节点编辑器拆分为独立的 Web 应用 (Vue 3 + Vue Flow),
Unity 端精简为执行引擎,通过 localhost:515 WebSocket 通信。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 01:20:02 +08:00

10 KiB
Raw Blame History

Ichni NodeScript Web — 独立节点编辑器设计

概述

将 Unity 内的 NodeScript 编辑器整体迁移到 Web,重新用 Vue 3 + TypeScript 实现。Unity 端精简为只负责执行和执行结果返回,通过 localhost:515 WebSocket 与 Web 前端通信。

引用项目:

架构总览

┌──────────────────────────────────┐     WebSocket (JSON-RPC)     ┌──────────────────────┐
│  IchniNodeScriptWeb/             │  ◄────────────────────────►  │  Unity Editor        │
│                                  │  ws://localhost:515          │                      │
│  ┌───────────┐  ┌──────────────┐ │                              │  ┌────────────────┐  │
│  │ Vue Flow  │  │  NodeEngine  │ │                              │  │ WS Server 515  │  │
│  │ 编辑器画布 │  │  (TypeScript)│ │                              │  ├────────────────┤  │
│  ├───────────┤  ├──────────────┤ │                              │  │ ExecutionSvc   │  │
│  │ 属性面板   │  │ 纯节点执行    │ │                              │  ├────────────────┤  │
│  ├───────────┤  ├──────────────┤ │                              │  │ GameElementSvc │  │
│  │ 节点面板   │  │ 图编辑逻辑    │ │                              │  └────────────────┘  │
│  ├───────────┤  ├──────────────┤ │                              │                      │
│  │ WS 通信   │  │ 保存/加载    │ │                              │  删掉了所有 UI 代码   │
│  └───────────┘  └──────────────┘ │                              │                      │
└──────────────────────────────────┘                              └──────────────────────┘

技术栈

技术
构建 Vite
框架 Vue 3 (Composition API)
语言 TypeScript严格模式
状态管理 Pinia
节点编辑器 Vue Flow (@vue-flow/core)
WebSocket 原生 WebSocket API + JSON-RPC 2.0
Unity WS System.Net.WebSockets (内置,无需三方库)

系统架构

核心节点系统

后端执行引擎的类型系统TypeScript

  • Node — 节点基类,含 inputs/outputs 连接器、status、loop()
  • Input/Output — 连接器name, dataType, color, value
  • LoopResult — loop() 返回值Complete / Hang / Repeat / Wait
  • NodeEngine — 调度器triggerTable + runtimeTable参考现有 NodeManager.RunCycle
  • UnityBridgeNode — 特殊基类loop() 时将 inputs 打包发送至 Unity等待返回后填 outputs

两种节点类型

纯节点 (PureNode) Unity 桥接节点
执行位置 Web 浏览器内 Unity 进程
执行方式 同步 JS 运算 WS 请求 → 等待 → 回调
等待策略 立即 Complete Hang 直到收到回复
例子 NodeMath, NodeBranch, NodeForLoop, NodeConst, NodeSplit NodeGameElement, NodeSetTransform

Vue Flow 集成

Vue Flow 概念 对应实现
Node 自定义 Vue Flow Node渲染标题栏 + Handle (输入/输出插槽) + 参数 UI
Edge 连线onConnect 回调中做类型兼容检查 + 环检测
Handle Input/Output 端口,颜色根据 dataType 变化
Minimap Vue Flow 内置小地图
Controls 缩放/平移控件

组件设计

组件 职责
NodeEditor.vue 主画布 (Vue Flow)、工具栏、快捷键
NodePalette.vue 节点创建面板(搜索 + 分类,参考 Blueprint 弹窗)
PropertyPanel.vue 侧边属性面板(选中节点后显示参数编辑)
StatusBar.vue 底部栏WS 连接状态、执行状态、节点数
WebSocketService.ts WS 连接管理 + JSON-RPC 请求/响应匹配
editorStore.ts Pinia store图状态、选中、撤销历史

节点分类

纯 Web 节点(~20 个TypeScript 实现)

分类 节点
入口 NodeStart
数学 NodeMath (+-*/)
插值 NodeLerp
比较 NodeCompare (== != > < >= <=)
向量拆分 NodeSplit
向量合并 NodeCombine
常量 NodeConst (6 种类型统一)
分支 NodeBranch
循环 NodeForLoop, NodeForEach
数据 NodeSelect (二选一), NodeSet (赋值)
变量 NodeVariable, NodeList, NodeListAdd, NodeListGet
调试 NodeLog

Unity 桥接节点(~5 个)

节点 功能 WS 方法
NodeGameElement 复制/粘贴 GameElement execute_nodes
NodeGetTransform 读取位置/旋转/缩放 query_gameelement
NodeSetTransform 写入位置/旋转/缩放 modify_gameelement
NodeChildByIndex 按索引取子元素 query_gameelement
NodeChildCount 取子元素数量 query_gameelement

WebSocket 协议

传输

  • 协议:纯 WebSocket (ws://localhost:515)
  • 格式JSON 文本帧
  • 风格JSON-RPC 2.0

消息格式

请求 (Web → Unity):

{
  "jsonrpc": "2.0",
  "id": "req_001",
  "method": "execute_nodes",
  "params": { ... }
}

响应 (Unity → Web):

{
  "jsonrpc": "2.0",
  "id": "req_001",
  "result": { ... }
}

API 方法

方法 方向 说明
execute_nodes Web→Unity 批量执行 Unity 节点,传入 inputs+params返回 outputs
query_gameelement Web→Unity 查询 GameElement 属性transform/children 等)
modify_gameelement Web→Unity 修改 GameElement 属性
get_type_registry Web→Unity 获取 Unity 端注册的桥接节点类型列表

连接生命周期

  1. Web 打开页面 → 自动 ws://localhost:515 连接
  2. 连接成功 → 发送 get_type_registry 获取 Unity 节点类型
  3. 连接断开 → Web 显示 "Unity 未连接",禁用运行按钮,可继续编辑
  4. 自动重连(每 3 秒尝试)
  5. Unity 退出 → Web 仍可编辑

Unity 端架构

删除的代码

  • NodeObject.cs (MonoBehaviour 节点 UI)
  • ConnectorSlot.cs (连接点交互)
  • NodeUIBuilder.cs (UI 控件构建)
  • NodeManager 中的 UI 交互:拖线/右键菜单/选中/复制粘贴
  • 文件 Save / Load
  • 节点列表管理 (allNodes)

保留的代码

  • NodeCore.cs核心类型NodeBase, Input/Output, InputAny/OutputAny, 生命周期)
  • NodeCompoment.cs 中部分节点NodeGameElement, NodeGetTransform, NodeSetTransform, NodeChildByIndex, NodeChildCount
  • NodeManager.RunCycle() + RunGraph() — 执行调度
  • ComputeLValues — 内部拓扑排序
  • 类型检查 / 环检测

新增的代码

  • NodeWebSocketServer.cs — HttpListener + WebSocket 服务端 (port 515)
  • JsonRpcHandler.cs — 消息解包和分发
  • NodeExecutionService.cs — 接收图 → 反序列化 → 构建 NodeBase → 执行 → 返回结果
  • GameElementQueryService.cs — 查询/修改 GameElement 属性

执行流程Web 发图 → Unity 执行)

  1. Web 用户点击"运行"
  2. Web 收集所有 Unity 节点的 inputs + params
  3. WS 发送 execute_nodes { nodes: [...] }
  4. Unity 接收 → 反序列化 GraphData → 重建 NodeBase → 设置连接 → RunGraph()
  5. 收集每个节点的 outputs → WS 返回结果
  6. Web 填入对应节点 outputs → 继续执行剩余纯节点

序列化

JSON 文件格式,保存在 IchniNodeScriptWeb/saves/ 下:

{
  "version": "1.0",
  "entryNode": "start",
  "nodes": [
    { "id": "n_1", "type": "NodeStart", "position": { "x": -400, "y": 0 }, "params": {} }
  ],
  "edges": [
    { "from": "n_1", "fromPort": "exec", "to": "n_2", "toPort": "exec" }
  ]
}

每个节点 params 包含节点特定参数(类型选择、数值等),端口连接信息在 edges 数组中。

项目文件结构

IchniNodeScriptWeb/
├── package.json
├── vite.config.ts
├── tsconfig.json
├── index.html
├── src/
│   ├── main.ts
│   ├── App.vue
│   ├── components/
│   │   ├── NodeEditor.vue         # Vue Flow 主画布
│   │   ├── NodePalette.vue        # 节点创建面板
│   │   ├── PropertyPanel.vue      # 属性编辑面板
│   │   └── StatusBar.vue          # 底部状态栏
│   ├── nodes/
│   │   ├── engine/
│   │   │   ├── types.ts           # 核心类型定义
│   │   │   ├── NodeEngine.ts      # 执行引擎
│   │   │   └── UnityBridgeNode.ts # 桥接节点基类
│   │   ├── math/MathNode.ts
│   │   ├── control/BranchNode.ts, ForLoopNode.ts, ForEachNode.ts
│   │   ├── data/ConstNode.ts, VariableNode.ts, SelectNode.ts, SetNode.ts
│   │   ├── vector/SplitNode.ts, CombineNode.ts
│   │   ├── logic/CompareNode.ts, LerpNode.ts
│   │   ├── debug/LogNode.ts
│   │   └── unity/
│   │       ├── GameElementNode.ts
│   │       ├── GetTransformNode.ts
│   │       ├── SetTransformNode.ts
│   │       ├── ChildByIndexNode.ts
│   │       └── ChildCountNode.ts
│   ├── services/
│   │   ├── WebSocketService.ts    # WS 连接 + JSON-RPC
│   │   └── GraphSerializer.ts     # 保存/加载 JSON
│   └── stores/
│       └── editorStore.ts         # Pinia 状态
├── saves/                         # 图的 JSON 文件
└── public/