OriginBlueprint is a desktop-first visual blueprint editor built with Go, Wails v2, Vue 3, TypeScript, and Rete.js v2. It is designed to edit legacy .vgf blueprints while also supporting native .obp graph files and .obpf function blueprint files.
- Edit node graphs with pan, zoom, box selection, copy/paste, undo/redo, node groups, alignment, and connection cutting.
- Open and preserve legacy
.vgffiles, including unknown legacy nodes and edges where possible. - Save native
.obpgraph documents and.obpffunction blueprint files. - Load custom node definitions from JSON files under
nodes/. - Browse a workspace folder, open blueprints from the file tree, reveal files in Explorer/Finder, and refresh the node library.
- Validate graph structure, missing ports, type mismatches, missing entry nodes, unreachable execution flow, and possible execution cycles.
- Export selected nodes or the whole graph as a PNG image.
- Switch UI language between English and Chinese.
| File | Purpose |
|---|---|
.vgf |
Legacy blueprint JSON. The editor can migrate and preserve legacy content. |
.obp |
Native OriginBlueprint graph document. |
.obpf |
Native function blueprint document. |
originblueprint.project |
Workspace-level editor settings such as layout sizes, language, and UI preferences. |
nodes/**/*.json |
Node definition files loaded into the module library. |
Desktop development:
wails devFrontend-only development:
cd frontend
npm install
npm run devBuild and verify:
go test ./...
cd frontend
npm run test:layout
npm run buildBuild the desktop executable:
wails buildA small project is included at examples/sample-project/.
Open that folder with File > Open Workspace Folder to try:
- Loading a workspace-level
originblueprint.project. - Opening a native
.obpgraph. - Opening a function
.obpfgraph. - Discovering a new-style custom node JSON file under
nodes/.
- Open the application.
- Use File > Open Workspace to select a project directory.
- Open
.vgf,.obp, or.obpffiles from the file browser. - Drag nodes from the module library into the canvas.
- Connect compatible ports. Execution ports represent control flow; data ports carry typed values.
- Use the variables panel to create variables and variable groups.
- Use Test to validate the graph.
- Save with
Ctrl+S, or use Save As to choose a new file.
Useful shortcuts:
| Shortcut | Action |
|---|---|
Ctrl+S |
Save current graph |
Ctrl+Shift+S |
Save As |
Ctrl+A |
Select all |
Ctrl+D |
Deselect all |
Ctrl+C / Ctrl+X / Ctrl+V |
Copy, cut, paste |
Ctrl+Z / Ctrl+Y |
Undo, redo |
Ctrl+G |
Create a group, or ungroup when a group is selected |
Ctrl+Shift+Q |
Reveal the current or selected blueprint file in the system file manager |
Ctrl+Alt+R |
Export selected nodes as PNG |
Ctrl+Shift+R |
Export the whole graph as PNG |
A typical workspace can look like this:
ProjectRoot/
originblueprint.project
nodes/
MyGameplayNodes.json
combat/
DamageNodes.json
blueprints/
battle.vgf
skill.obp
functions/
calculate_damage.obpf
Rules:
- Open the workspace root folder, not an individual blueprint file, when you want file browser, node library, and project settings support.
- Put custom node JSON files anywhere under
nodes/. The loader scans recursively. - Keep blueprint files in any folder you prefer. The file browser shows
.vgf,.obp, and.obpffiles. originblueprint.projectbelongs to the workspace root. It stores editor preferences for that project.- Avoid editing generated build output. Treat
frontend/dist/and packaged app output as disposable.
Use the current explicit node-definition format for new nodes. It uses stable node IDs and named port keys, which are easier to maintain than legacy numeric port IDs.
Legacy node JSON can still be imported for compatibility, but new documentation and new projects should use the format below.
{
"id": "origin.example.clamp-integer",
"title": "Clamp Integer",
"category": "Math",
"subtitle": "Clamp a value between min and max.",
"inputs": [
{ "key": "value", "label": "Value", "type": "data", "data_type": "Integer", "defaultValue": 0 },
{ "key": "min", "label": "Min", "type": "data", "data_type": "Integer", "defaultValue": 0 },
{ "key": "max", "label": "Max", "type": "data", "data_type": "Integer", "defaultValue": 100 }
],
"outputs": [
{ "key": "result", "label": "Result", "type": "data", "data_type": "Integer" }
]
}Field notes:
id: Stable node type ID. Do not rename it after users save graphs with this node.title: Display name in the module library and node header.category: Module library category.subtitle: Optional description shown as secondary text.inputs/outputs: Port definitions.key: Stable port key used by graph documents and runtime validation.label: Port display text.type: Useexecfor execution-flow ports anddatafor value ports.data_type: Supported common values includeInteger,Float,Boolean,String,Array, andAny.defaultValue: Optional inline default value for input data ports.arrayItemType: Optional input item control type for array ports, usuallynumberorstring.
Guidelines:
- Keep
idstable after users start saving graphs with that node. - Use lowercase, descriptive port keys such as
exec,value,result,true, andfalse. - Use
execports only for control-flow order. - Use data ports for values and set
defaultValuewhen a user should be able to type a value directly on the node. - Adding a JSON node makes it visible and editable. It does not automatically implement runtime behavior in Go.
Some flow nodes need a + Item control that adds matching parameter rows and execution outputs. Use dynamicBranch for this pattern:
{
"id": "origin.flow.equal-switch-example",
"title": "Equal Switch",
"category": "Flow",
"inputs": [
{ "key": "exec", "label": "", "type": "exec" },
{ "key": "value", "label": "Value", "type": "data", "data_type": "Integer", "defaultValue": 0 },
{ "key": "cases", "label": "Cases", "type": "data", "data_type": "Array", "defaultValue": [], "arrayItemType": "number" }
],
"outputs": [
{ "key": "otherwise", "label": "Otherwise", "type": "exec" },
{ "key": "case1", "label": "", "type": "exec" },
{ "key": "case2", "label": "", "type": "exec" }
],
"dynamicBranch": {
"controlInput": "cases",
"defaultOutput": "otherwise",
"outputPrefix": "case",
"outputStartIndex": 1,
"maxBranches": 2
}
}The editor keeps persistent graph data in the GraphDocument contract defined in graph.go. Do not serialize Rete.js internals as a file format.
Important Go files:
| File | Responsibility |
|---|---|
graph.go |
GraphDocument, validation, stable built-in port definitions. |
legacy.go |
Legacy .vgf migration and export compatibility. |
node_schemas.go |
Loading nodes/**/*.json documents. |
execution.go |
Go runtime execution semantics. |
app.go |
Wails-facing file, workspace, project, image export, and platform services. |
When adding a runtime node:
- Add or update the JSON node definition under
nodes/. - If the node must validate as a known runtime node, add its stable port definition in
graph.go. - If it should execute in the Go runtime, implement its behavior in
execution.go. - If it must import/export old
.vgffiles, update the mapping rules inlegacy.goandfrontend/src/editor/runtimeNodeSchemas.ts. - Add focused Go tests for validation, migration, execution, or round-trip behavior.
Minimal execution flow:
GraphDocument JSON
-> Go validation / migration
-> executeGraph(...)
-> ExecutionEvent logs, results, variables, and node states
The frontend owns live canvas interaction. Go owns durable file compatibility, validation, migration, and execution rules.
The frontend can be built as a Vite web app, but the product is currently desktop-first.
Works in the browser build:
- Create and edit native graph documents.
- Open local
.obp,.obpf, or JSON files through the browser file picker. - Save native graph documents by downloading JSON.
- Load the static node library from
nodes/manifest.json. - Export graph images through browser download.
Desktop-only today:
- Native workspace directory scanning.
- Recent files and reveal-in-folder.
- Legacy
.vgfmigration and export through Go services. - Go-backed validation and runtime services.
- Native file dialogs and Wails window controls.
- Unknown legacy nodes and edges should be preserved instead of silently dropped.
.vgfround trips are compatibility-sensitive. Test representative legacy files when changing migration or export behavior.- New node IDs, port keys, and data types should be treated as stable once saved into graph documents.
- If a new node must be consumed by an old external parser, provide an explicit legacy export mapping.
- Architecture
- Node JSON format, Chinese
- Legacy compatibility, Chinese
- Blueprint change safety, Chinese
- Engine test matrix, Chinese
The repository includes a GitHub Actions workflow at .github/workflows/ci.yml. It runs:
go test ./...npm run test:layoutnpm run build
