https://github.com/calico-games/react-native-godot
Bring Godot to React Native 🔮. Create immersive 3D experiences or interactive games directly within React Native.
https://github.com/calico-games/react-native-godot
3d android gltf godot godot-engine godotengine ios metal opengl react-native react-native-godot rendering vulkan
Last synced: 2 months ago
JSON representation
Bring Godot to React Native 🔮. Create immersive 3D experiences or interactive games directly within React Native.
- Host: GitHub
- URL: https://github.com/calico-games/react-native-godot
- Owner: calico-games
- Created: 2024-06-03T17:00:20.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-12T15:40:24.000Z (about 1 year ago)
- Last Synced: 2025-04-04T03:16:11.331Z (9 months ago)
- Topics: 3d, android, gltf, godot, godot-engine, godotengine, ios, metal, opengl, react-native, react-native-godot, rendering, vulkan
- Language: TypeScript
- Homepage:
- Size: 36.9 MB
- Stars: 205
- Watchers: 6
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README

# React Native Godot
Bring **Godot** to **React Native** 🔮. Create immersive 3D experiences or interactive games directly within React Native.
[](https://www.npmjs.com/package/react-native-godot)
[](https://godotengine.org/download)
## Table of Contents
- [Screenshots](#screenshots)
- [Features](#features)
- [Device Support](#device-support)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [API Reference](#api-reference)
- [GodotView Component](#godot-view)
- [Godot Variants](#godot-variants)
- [Runtime GDScript & Node Creation](#runtime-gdscript-node-creation)
- [Scene Node Access](#scene-node-access)
- [React Native ↔ Godot Communication](#react-native-godot-communication)
- [Project Setup](#project-setup)
- [Importing Godot Projects](#importing-godot-projects)
- [Metro Configuration](#metro-configuration)
- [Limitations & Known Issues](#limitations-known-issues)
- [Contributing](#contributing)
- [License](#license)
[
](screenshots/screenshot1.jpeg)
[
](screenshots/screenshot2.jpeg)
- 🏎️ **Native C++ JSI performance** - Direct JavaScript to native bindings
- 🔥 **GPU-accelerated rendering** - Metal (iOS) and OpenGL/Vulkan support
- ✅ **Full React Native compatibility** - Supports old and new architecture
- 🎮 **Complete Godot integration** - Access all Godot variants and features
- 🧙♂️ **Runtime GDScript compilation** - Create and execute scripts dynamically
- 📦 **Easy project import** - Simple workflow to bring Godot projects to RN
- 🔄 **Bidirectional communication** - React Native ↔ Godot messaging
iOS support is implemented, full Android support is coming soon.
| Platform | Supported |
| ---------------- | --------- |
| iOS Device | ✅ |
| iOS Simulator | ❌ |
| Android Device | 🚧 |
| Android Emulator | 🚧 |
- Godot 4.4.1 ([https://godotengine.org/](https://godotengine.org/))
- React Native 0.70+
- iOS 12.0+ / Android API 21+
```bash
npm install react-native-godot
# or
yarn add react-native-godot
```
### 1. Setup GodotProvider
Wrap your app with `GodotProvider` to initialize Godot properly:
```tsx
// App.tsx
import React from 'react';
import { GodotProvider } from 'react-native-godot';
import MyGameScreen from './MyGameScreen';
export default function App() {
return (
);
}
```
### 2. Create your game component
```tsx
// MyGameScreen.tsx
import React, { useEffect, useState } from 'react';
import { GodotView, useGodot, useGodotRef } from 'react-native-godot';
const MyGameScreen = () => {
const godotRef = useGodotRef();
const { Vector3, Vector2 } = useGodot();
const [isGodotReady, setIsGodotReady] = useState(false);
useEffect(() => {
// Start Godot rendering (call once in your app)
GodotView.startDrawing();
return () => {
// Stop Godot rendering when component unmounts
GodotView.stopDrawing();
};
}, []);
useEffect(() => {
if (!isGodotReady || !godotRef.current) {
return;
}
// Use Godot variants
const position = Vector3(1, 2, 3);
console.log('Position Y:', position.y);
// Get nodes from your scene
const playerNode = godotRef.current.getRoot()?.getNode('Player');
playerNode?.call('jump', 10);
// Send data to Godot
godotRef.current.emitMessage({
type: 'player_spawn',
position: position,
health: 100
});
}, [isGodotReady]);
return (
setIsGodotReady(true)}
onMessage={(instance, message) => {
console.log('Message from Godot:', message);
}}
/>
);
};
export default MyGameScreen;
```
The main component for embedding Godot scenes in React Native. You can use multiple `GodotView` components on the same screen - each will render a different scene but they all share the same Godot engine instance.
#### Props
| Prop | Type | Description |
|------|------|-------------|
| `source` | `string \| ImageSourcePropType` | Path to your .pck file |
| `scene` | `string` | Scene path (e.g., "res://main.tscn") |
| `style` | `StyleProp` | React Native style object |
| `onReady` | `(instance: GodotViewRef) => void` | Called when Godot is ready |
| `onMessage` | `(instance: GodotViewRef, message: any) => void` | Called when receiving messages from Godot |
#### Instance Methods (via ref)
| Method | Description |
|--------|-------------|
| `getRoot(): Node` | Get the root node of the loaded scene |
| `emitMessage(message: any): void` | Send a message to Godot scripts |
| `pause(): void` | Pause the Godot instance |
| `resume(): void` | Resume the Godot instance |
| `isReady(): boolean` | Check if Godot is ready |
#### Static Methods
| Method | Description |
|--------|-------------|
| `GodotView.startDrawing(): void` | Start Godot rendering engine (call once per app) |
| `GodotView.stopDrawing(): void` | Stop Godot rendering engine |
**Single GodotView Example:**
```tsx
const MyGame = () => {
const godotRef = useGodotRef();
useEffect(() => {
// Start rendering when app launches
GodotView.startDrawing();
return () => GodotView.stopDrawing();
}, []);
return (
{
console.log('Godot ready!');
instance.emitMessage({ type: 'game_start' });
}}
onMessage={(instance, message) => {
console.log('From Godot:', message);
}}
/>
);
};
```
**Multiple GodotView Example:**
```tsx
const MultiSceneApp = () => {
const gameRef = useGodotRef();
const uiRef = useGodotRef();
const minimapRef = useGodotRef();
useEffect(() => {
// Start rendering once for all GodotView instances
GodotView.startDrawing();
return () => GodotView.stopDrawing();
}, []);
return (
{/* Main game view */}
{/* UI overlay */}
{/* Minimap */}
);
};
```
**💡 Note:** All `GodotView` instances share the same Godot engine, so you only need to call `GodotView.startDrawing()` once per app, regardless of how many views you have. Use `pause()` and `resume()` on individual view instances to control which scenes are actively rendering.
**Example: Controlling individual scenes:**
```tsx
// Pause the minimap when not needed
minimapRef.current?.pause();
// Resume it later
minimapRef.current?.resume();
// Pause game but keep UI active
gameRef.current?.pause();
// UI continues running for menus, etc.
```
All Godot variant types are available with full method and property support:
**Available Types:**
`AABB | Basis | Color | Plane | Projection | Quaternion | Rect2 | Rect2i | Transform2D | Transform3D | Vector2 | Vector2i | Vector3 | Vector3i | Vector4 | Vector4i`
**Usage:**
```tsx
const { Vector3, Color, Transform3D } = useGodot();
// Create variants
const position = Vector3(1, 2, 3);
const color = Color(1, 0, 0, 1); // Red
const transform = Transform3D();
// Use methods and properties
console.log('Distance:', position.length());
console.log('Normalized:', position.normalized());
console.log('Red component:', color.r);
```
Complete documentation: [Godot Variant Types](https://docs.godotengine.org/en/stable/classes/index.html#variant-types)
### Runtime GDScript & Node Creation 🧙♂️
Create and compile GDScript at runtime, then attach to dynamically created nodes:
```tsx
const { Script, Node } = useGodot();
// Create and compile a script
const script = Script();
const success = script.setSourceCode(`
extends Node
@onready var health = 100
func _ready():
print("Dynamic script loaded!")
func take_damage(amount: int) -> int:
health -= amount
return health
func heal(amount: int):
health += amount
print("Healed for ", amount, " HP")
`);
if (success) {
// Create node and attach script
const dynamicNode = Node();
dynamicNode.setScript(script);
dynamicNode.setName("DynamicPlayer");
// Add to scene
godotRef.current?.getRoot()?.addChild(dynamicNode);
// Call script methods
const remainingHealth = dynamicNode.call("take_damage", 25);
console.log('Health remaining:', remainingHealth);
// Alternative syntax with TypeScript casting
(dynamicNode as any).heal(10);
}
```
#### Script API
| Method | Description |
|--------|-------------|
| `Script()` | Create a new empty script |
| `setSourceCode(source: string): boolean` | Set and compile GDScript source code |
#### Node API
| Method | Description |
|--------|-------------|
| `Node()` | Create a new empty node |
| `getNode(path: string): Node \| null` | Get child node by path |
| `getParent(): Node \| null` | Get parent node |
| `getChildren(): Node[]` | Get all child nodes |
| `getChildCount(): number` | Get number of child nodes |
| `addChild(child: Node)` | Add a child node |
| `setName(name: string)` | Set the node's name |
| `setScript(script: Script)` | Attach a script to the node |
| `call(method: string, ...args: any[]): any` | Call a method defined in the attached script |
**💡 Tip:** For better TypeScript ergonomics, you can call script methods directly using `(node as any).methodName(args)` instead of `node.call("methodName", args)`.
Access and interact with nodes from your loaded Godot scenes:
```tsx
useEffect(() => {
if (!isGodotReady || !godotRef.current) return;
// Get the root node
const root = godotRef.current.getRoot();
// Navigate the scene tree
const player = root?.getNode('Player');
const ui = root?.getNode('UI/HealthBar');
// Access node hierarchy
const parent = player?.getParent();
const children = player?.getChildren();
const siblingCount = parent?.getChildCount();
// Call methods defined in the node's GDScript
player?.call('set_health', 100);
ui?.call('update_display', 100, 100);
// Alternative direct method calls
(player as any)?.jump(15);
(ui as any)?.show_damage_effect();
}, [isGodotReady]);
```
### React Native ↔ Godot Communication 📡
#### React Native → Godot
Send messages from React Native to your Godot scripts:
```tsx
// Send structured data to Godot
godotRef.current?.emitMessage({
type: 'player_action',
action: 'attack',
target: 'enemy_1',
position: Vector3(10, 0, 5),
damage: 50
});
```
#### Godot → React Native
Receive messages in React Native from Godot scripts:
```tsx
{
console.log('Received from Godot:', message);
// Handle different message types
switch (message.type) {
case 'game_over':
showGameOverScreen(message.score);
break;
case 'level_complete':
advanceToNextLevel();
break;
case 'item_collected':
updateInventory(message.item);
break;
}
}}
/>
```
#### Godot Script Implementation
```gdscript
extends Node
@onready var rn_singleton = Engine.get_singleton("ReactNative")
func _ready():
if rn_singleton:
# Listen for messages from React Native
rn_singleton.on_message(_on_react_native_message)
func _on_react_native_message(message: Dictionary):
print("Message from React Native: ", message)
match message.type:
"player_action":
handle_player_action(message)
"game_state_change":
update_game_state(message.state)
func send_to_react_native(data: Dictionary):
if rn_singleton:
rn_singleton.emit_message(data)
func _on_enemy_defeated():
send_to_react_native({
"type": "enemy_defeated",
"enemy_id": "goblin_1",
"exp_gained": 50
})
```
### Importing Godot Projects 📥
To use your existing Godot project in React Native:
1. **Add export preset configuration**
Create `export_presets.cfg` in your Godot project directory:
```ini
[preset.0]
name="main"
platform="iOS"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter=""
include_filter="project.godot"
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
export/distribution_type=1
binary_format/architecture="universal"
binary_format/embed_pck=false
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=0
display/high_res=true
```
2. **Generate PCK file**
Run the provided script (modify path for your OS):
```bash
./gen-pck PROJECT_FOLDER_PATH
```
3. **Add to React Native project**
Move the generated `.pck` file to your React Native `assets` folder.
4. **Include project.godot in iOS**
Add your `project.godot` file to your Xcode project bundle.
Add PCK file support to your `metro.config.js`:
```js
const config = getDefaultConfig(__dirname);
// Add pck files as assets
config.resolver.assetExts.push('pck');
module.exports = config;
```
## Limitations & Known Issues 🚧
### Texture Import Settings
When importing textures or 3D models, avoid using `VRAM Compressed` format as it may not export properly in PCK files.
[
](screenshots/screenshot3.png)
### PCK Asset Swapping
Currently, you cannot swap PCK assets at runtime. You need to restart the app to load a new PCK file. This appears to be a Godot engine limitation that we're investigating.
### Platform Support
- iOS Simulator is not supported due to architecture differences
- Android support is in development
We welcome contributions! The core development happens in a private repository, but if you'd like to contribute:
1. Open an issue to discuss your idea
2. Contact us at `team@calico.games` for access to the private repo
3. Experience with Godot Engine, C++, and React Native is preferred
4. Knowledge of [Bazel](https://github.com/bazelbuild/bazel) is a plus
**Copyright Calico Games 2024. All rights reserved.**
This library is released under a **Custom License**:
- **✅ Free for non-commercial use** - Personal, educational, or open-source projects
- **💼 Commercial use requires license** - Companies/individuals with >$50,000 annual revenue need a commercial license
- **❌ No redistribution** - Cannot be redistributed, repackaged, or resold
We support the Godot Foundation by sharing revenue from commercial licenses.
For commercial licensing: `team@calico.games`
---
- Special thanks to the [Godot Engine](https://github.com/godotengine/godot) contributors
- Huge appreciation to [Migeran](https://github.com/migeran) for their invaluable help