Skip to content

portwatcher/vue-godot

Repository files navigation

Vue Godot

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)
  }
}

demo

How It Works

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 (createRenderer from @vue/runtime-core) that maps Vue operations to Godot node tree operations: createElementClassDB.instantiate(), insertadd_child(), patchPropel.set() / signal connect(), etc.
  • @vue-godot/cli — A CLI tool (vue-godot) for vue-godot projects. Currently supports generating Vue GlobalComponents type 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), with godot as an external. The Godot scene (.tscn) attaches this script to a Control node.
  • In the Godot editor, GodotJS runs dist/app.js. The _ready() method calls createApp(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).

Repository Structure

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

Getting Started

Prerequisites

Note: GodotJS 1.0.0-2 has a scene codegen bug where SceneTSDCodeGen.make_path doesn't strip res:// from scene paths, producing ERROR: Could not create directory: './typings/res:/'. This was fixed on the main branch (method renamed to make_scene_path with res:// 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 → search GodotJS and set codegen/generate_scene_dts to false.

Install & Build

npm install
npm run build          # builds all packages + apps via Turborepo

Run an example

Open the GodotJS editor and open any app's project.godot, for example apps/v-on/project.godot. Press F5 to run the scene.

Development Workflow

1. Open the Godot project

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.tsgodot8.gen.d.ts, godot.mix.d.ts, etc.).

2. Generate Vue component types

cd apps/v-model
npm run gen:types

This 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).

3. Write Vue components

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. via v-on)
  • All standard Vue features work: ref(), computed(), watch(), v-if, v-for, template refs, etc.

4. Write the entry point

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).

5. Build

npm run build          # from repo root — builds everything
# or
cd apps/v-model && npm run build   # build a single app

Vite compiles vue/src/main.ts into dist/app.js (CJS format, godot external). The Godot scene references this file.

6. Run in Godot

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.

Iteration loop

Edit .vue / .ts  →  npm run build  →  F5 in Godot  →  see changes

Creating a New App

  1. Copy an existing app directory (e.g. apps/v-model) to apps/<your-app>
  2. Update package.json name field
  3. Update project.godot project name
  4. Open apps/<your-app>/project.godot in the GodotJS editor to generate fresh typings
  5. Run npm run gen:types to generate Vue component types
  6. Edit vue/src/ with your components
  7. npm run build and press F5 in Godot

Packages

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/cli

vue-godot <command> [options]

create / integrate

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 --html

gen-types

Generate 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

About

bridging Vue.js and Godot Engine for game UI and cross platform applications

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages