A small simple project that bridges Vue.js and Godot.
This project is for:
- Write game UI using Vue.js
- Write cross platform applications using Vue.js with Godot as the runtime
This project is far from production ready. follow me on @juryxiong for updates.
<template>
<HBoxContainer>
<Button :text="'Click me'" @pressed="handleClick"></Button>
<Label :text="count"></Label>
</HBoxContainer>
</template>
<script setup lang="ts">
// Test.vue
import { ref } from 'vue'
const count = ref(1)
const handleClick = () => {
count.value = count.value + 1
}
</script>// main.ts
import { createApp } from '@vue-godot/runtime-tscn'
import { Control } from 'godot'
import Test from './Test.vue'
export default class App extends Control {
_ready() {
const app = createApp(Test)
app.mount(this)
}
}vue-godot is a custom Vue renderer that targets Godot's scene tree instead of the DOM. The key pieces:
@vue-godot/runtime-tscn— A Vue custom renderer (createRendererfrom@vue/runtime-core) that maps Vue operations to Godot node tree operations:createElement→ClassDB.instantiate(),insert→add_child(),patchProp→el.set()/ signalconnect(), etc.@vue-godot/cli— A CLI tool (vue-godot) for vue-godot projects. Currently supports generating VueGlobalComponentstype augmentation from GodotJS typings so Volar provides autocomplete and type checking for Godot nodes in Vue templates.- Vite builds the Vue app as a CJS library (
dist/app.js), withgodotas an external. The Godot scene (.tscn) attaches this script to aControlnode. - In the Godot editor, GodotJS runs
dist/app.js. The_ready()method callscreateApp(Root).mount(this), and Vue takes over the subtree.
Upper-cased tags in templates (e.g. <HBoxContainer>, <Label>) are treated as custom elements and resolved at runtime via ClassDB.instantiate(tag).
vue-godot/
├── packages/
│ ├── runtime-tscn/ # Vue custom renderer for Godot
│ └── cli/ # CLI tool: vue-godot gen-types, scaffolding, etc.
├── apps/
│ ├── v-model/ # Example: two-way binding with TextEdit
│ ├── v-on/ # Example: event handling with @pressed
│ └── template-ref/ # Example: template refs
└── turbo.json # Turborepo config
Each app has the following layout:
apps/<name>/
├── project.godot # Godot project file
├── app.tscn # Main scene — attaches dist/app.js to a Control node
├── typings/ # GodotJS-generated type declarations (godot*.gen.d.ts)
│ └── godot.vue-components.gen.d.ts # Generated by @vue-godot/cli
├── vue/
│ ├── vite.config.ts # Vite config — builds vue/src/main.ts → dist/app.js
│ ├── tsconfig.json # Vue/Volar tsconfig (separate from Godot root tsconfig)
│ └── src/
│ ├── main.ts # Entry: createApp(Root).mount(this)
│ ├── *.vue # Vue SFC components
│ └── env.d.ts # *.vue module declaration for TypeScript
├── tsconfig.json # Godot root tsconfig (excludes vue/)
├── dist/ # Build output (loaded by Godot at runtime)
└── package.json
- Node.js >= 18
- GodotJS editor — download from https://github.com/ialex32x/GodotJS-Build/releases
Note: GodotJS 1.0.0-2 has a scene codegen bug where
SceneTSDCodeGen.make_pathdoesn't stripres://from scene paths, producingERROR: Could not create directory: './typings/res:/'. This was fixed on the main branch (method renamed tomake_scene_pathwithres://stripping) but no Godot 4.4 build includes the fix yet. The errors are harmless and don't affect runtime. To suppress them, go to Editor → Editor Settings → searchGodotJSand setcodegen/generate_scene_dtstofalse.
npm install
npm run build # builds all packages + apps via TurborepoOpen the GodotJS editor and open any app's project.godot, for example apps/v-on/project.godot. Press F5 to run the scene.
Open one of the example apps (e.g. apps/v-model/project.godot) in the GodotJS editor. On first open, GodotJS auto-generates TypeScript declarations for all engine classes into the typings/ directory (godot0.gen.d.ts … godot8.gen.d.ts, godot.mix.d.ts, etc.).
cd apps/v-model
npm run gen:typesThis runs vue-godot gen-types, which reads the Godot typings and produces typings/godot.vue-components.gen.d.ts — a GlobalComponents augmentation that gives Volar full autocomplete and type checking for Godot node tags in .vue templates.
Re-run this whenever Godot typings are regenerated (e.g. after a Godot version upgrade).
Edit .vue files under vue/src/. Use Godot node class names as tags directly in templates:
<template>
<HBoxContainer>
<TextEdit :text="text"></TextEdit>
<Label :text="text"></Label>
</HBoxContainer>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const text = ref('')
</script>- Props map to Godot node properties (
:text,:visible,:size, etc.) - Events map to Godot signals (
@pressed,@text_changed, etc. viav-on) - All standard Vue features work:
ref(),computed(),watch(),v-if,v-for, template refs, etc.
vue/src/main.ts is the entry point. It creates a Vue app and mounts it onto a Godot Control node:
import { createApp } from '@vue-godot/runtime-tscn'
import { Control } from 'godot'
import Test from './Test.vue'
export default class App extends Control {
_ready() {
const app = createApp(Test)
app.mount(this)
}
}This class is attached to a Control node in the Godot scene (.tscn file).
npm run build # from repo root — builds everything
# or
cd apps/v-model && npm run build # build a single appVite compiles vue/src/main.ts into dist/app.js (CJS format, godot external). The Godot scene references this file.
Press F5 in the GodotJS editor. Godot loads dist/app.js, the _ready() method fires, and Vue renders its component tree into the Godot scene.
Edit .vue / .ts → npm run build → F5 in Godot → see changes
- Copy an existing app directory (e.g.
apps/v-model) toapps/<your-app> - Update
package.jsonname field - Update
project.godotproject name - Open
apps/<your-app>/project.godotin the GodotJS editor to generate fresh typings - Run
npm run gen:typesto generate Vue component types - Edit
vue/src/with your components npm run buildand press F5 in Godot
| Package | Description |
|---|---|
@vue-godot/runtime-tscn |
Vue custom renderer for Godot scene tree |
@vue-godot/html |
HTML-like Vue components built on Godot nodes |
@vue-godot/cli |
CLI tool for vue-godot projects |
vue-godot <command> [options]Both create (new project) and integrate (existing Godot project) accept a --html flag that configures @vue-godot/html automatically — setting up the Vite compiler config and plugin registration so lowercase HTML tags (<div>, <img>, etc.) work as Godot-backed components with zero renaming.
vue-godot create my-app --html
vue-godot integrate --htmlGenerate Vue GlobalComponents type augmentation from GodotJS typings.
vue-godot gen-types [--typings <dir>] [--out <file>] [--ancestor <class>] [--vue-src <dir>]| Option | Default | Description |
|---|---|---|
--typings |
./typings |
Directory containing godot*.gen.d.ts files |
--out |
<typings>/godot.vue-components.gen.d.ts |
Output file path |
--ancestor |
Control |
Base class — only descendants are included |
--vue-src |
./vue/src |
Vue source dir — generates env.d.ts shim there |
