Godot Wasm
Warning
This project is still in its infancy. Interfaces are liable to change with each release until v1.0.
A Godot extension allowing for loading and interacting with WebAssembly (Wasm) modules from GDScript via the Wasmer and Wasmtime WebAssembly runtimes.
Features
- Compile and instantiate WebAssembly modules
- Access exported Wasm functions and variables
- Write to and read from Wasm memory
- Wasmer and Wasmtime runtime support
- Install as Godot module or GDExtension addon
- Limited WASI support
- External (shared) Wasm memory support
Motivation
- Language Agnosticism. With dozens of supported languages, WebAssembly makes a versatile common build target. Create modules in Rust, Go, TypeScript, C++, etc. and seamlessly integrate them into your Godot project. A single Wasm module runs on multiple platforms and architectures e.g. Windows x86, Windows x64, macOS ARM, macOS x86, Linux, etc.
- Sandboxed Environment. WebAssembly operates within a sandboxed VM, allowing you to safely run modules from untrusted sources without jeopardizing your users' safety. This opens the door for zero-trust mods and plugins for your Godot project.
- Speed. WebAssembly runs incredibly fast at near-native speeds. Extensions become remarkably resource-efficient without the need to recompile the Godot engine. Mods can approach native speed regardless of source language. Compute-intensive operations can run orders of magnitude faster in Wasm than in GDScript.
Documentation
Please refer to the Godot Wasm wiki for guides, FAQs, class documentation, etc.
Quick Start
Godot Wasm can be used as a GDExtension/GDNative addon or Godot module. See the Installation wiki page for full instructions.
Using Godot Wasm involves the following. See the Usage wiki page for full instructions.
- Create a WebAssembly (Wasm) module using a language of your choice. See FAQ for more information. Alternatively, a simple test module can be used.
- Create a new Godot Wasm instance, read your Wasm module bytecode, and instantiate the Godot Wasm module. The following assumes a Wasm module that requires no imports.
var wasm = Wasm.new()
var file = FileAccess.open("res://my_module.wasm", FileAccess.READ)
var bytecode = file.get_buffer(file.get_length())
wasm.load(bytecode, {})
- The Wasm module is now instantiated and can be interacted with from GDScript. For example, an exported function may be invoked using via
wasm.function("my_function", [my_arg])
.
See the Usage wiki page for full instructions.
Known Issues
- A small subset of WASI bindings are provided to the Wasm module by default. These can be overridden by the imports supplied on module instantiation. The guest Wasm module has no access to the host machines filesystem, etc. Pros for this are simplicity and increased security. Cons include more work required to run Wasm modules created in ways that require a larger set of WASI bindings e.g. TinyGo (see relevant issue).
- Only
int
and float
return values are supported. While workarounds could be used, this limitation is because the only concrete types supported by Wasm are integers and floating point.
- Default empty
args
parameter for function(name, args)
is not supported in Godot 3.x using Godot Wasm as an addon e.g. via the Godot Asset Library. Default Array
parameters in GDNative seem to retain values between calls. Calling methods of this addon without expected arguments produces undefined behaviour. Default empty arguments are supported in Godot 4.x and Godot 3.x when using Godot Wasm as a module.
- Web/HTML5 export is not supported (see #15 and #18).
Relevant Discussion
There have been numerous discussions around modding/sandboxing support for Godot. Some of those are included below.
- Proposal: Implement a sandbox mode
- Issue: Add support for WebAssembly plugins and scripts
- Proposal: Add WASM (WASI) host support (including, but not limited to, the HTML5 target)
- Proposal: Add a method to disallow using all global classes in a particular GDScript
- Pull Request: Added globals disabled feature to GDScript class