{"id":18980348,"url":"https://github.com/calico-games/react-native-godot","last_synced_at":"2025-10-19T11:02:35.716Z","repository":{"id":260197787,"uuid":"809899682","full_name":"calico-games/react-native-godot","owner":"calico-games","description":"Bring Godot to React Native 🔮. Create immersive 3D experiences or interactive games directly within React Native.","archived":false,"fork":false,"pushed_at":"2024-12-12T15:40:24.000Z","size":38722,"stargazers_count":205,"open_issues_count":3,"forks_count":3,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-04T03:16:11.331Z","etag":null,"topics":["3d","android","gltf","godot","godot-engine","godotengine","ios","metal","opengl","react-native","react-native-godot","rendering","vulkan"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/calico-games.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-03T17:00:20.000Z","updated_at":"2025-04-02T07:06:46.000Z","dependencies_parsed_at":"2025-01-17T16:20:36.755Z","dependency_job_id":null,"html_url":"https://github.com/calico-games/react-native-godot","commit_stats":{"total_commits":22,"total_committers":1,"mean_commits":22.0,"dds":0.0,"last_synced_commit":"7212561ff03d88976d9bfb7b47f13d071718f819"},"previous_names":["calico-games/react-native-godot"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calico-games%2Freact-native-godot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calico-games%2Freact-native-godot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calico-games%2Freact-native-godot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calico-games%2Freact-native-godot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/calico-games","download_url":"https://codeload.github.com/calico-games/react-native-godot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248641759,"owners_count":21138262,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["3d","android","gltf","godot","godot-engine","godotengine","ios","metal","opengl","react-native","react-native-godot","rendering","vulkan"],"created_at":"2024-11-08T16:06:33.892Z","updated_at":"2025-10-19T11:02:35.706Z","avatar_url":"https://github.com/calico-games.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cpicture\u003e\n  \u003cimg alt=\"react-native-godot\" src=\"./static/banner.png\" /\u003e\n\u003c/picture\u003e\n\n\u003cbr /\u003e\n\n# React Native Godot\n\nBring **Godot** to **React Native** 🔮. Create immersive 3D experiences or interactive games directly within React Native.\n\n[![npm version](https://img.shields.io/npm/v/react-native-godot.svg?style=flat)](https://www.npmjs.com/package/react-native-godot)\n[![godot engine](https://img.shields.io/badge/Godot-4.4.1-blue)](https://godotengine.org/download)\n\n## Table of Contents\n\n- [Screenshots](#screenshots)\n- [Features](#features)\n- [Device Support](#device-support)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [API Reference](#api-reference)\n  - [GodotView Component](#godot-view)\n  - [Godot Variants](#godot-variants)\n  - [Runtime GDScript \u0026 Node Creation](#runtime-gdscript-node-creation)\n  - [Scene Node Access](#scene-node-access)\n  - [React Native ↔ Godot Communication](#react-native-godot-communication)\n- [Project Setup](#project-setup)\n  - [Importing Godot Projects](#importing-godot-projects)\n  - [Metro Configuration](#metro-configuration)\n- [Limitations \u0026 Known Issues](#limitations-known-issues)\n- [Contributing](#contributing)\n- [License](#license)\n\n## \u003ca id=\"screenshots\"\u003e\u003c/a\u003eScreenshots 📸\n\n[\u003cimg src=\"screenshots/screenshot1.jpeg\" alt=\"Multiple Cubes demo\" align=\"center\" width=\"150\" hspace=\"2\" vspace=\"10\"\u003e](screenshots/screenshot1.jpeg)\n[\u003cimg src=\"screenshots/screenshot2.jpeg\" alt=\"Earth demo\" align=\"center\" width=\"150\" hspace=\"2\" vspace=\"10\"\u003e](screenshots/screenshot2.jpeg)\n\n## \u003ca id=\"features\"\u003e\u003c/a\u003eFeatures 🚀\n\n- 🏎️ **Native C++ JSI performance** - Direct JavaScript to native bindings\n- 🔥 **GPU-accelerated rendering** - Metal (iOS) and OpenGL/Vulkan support\n- ✅ **Full React Native compatibility** - Supports old and new architecture\n- 🎮 **Complete Godot integration** - Access all Godot variants and features\n- 🧙‍♂️ **Runtime GDScript compilation** - Create and execute scripts dynamically\n- 📦 **Easy project import** - Simple workflow to bring Godot projects to RN\n- 🔄 **Bidirectional communication** - React Native ↔ Godot messaging\n\n## \u003ca id=\"device-support\"\u003e\u003c/a\u003eDevice Support 📱\n\niOS support is implemented, full Android support is coming soon.\n\n| Platform         | Supported |\n| ---------------- | --------- |\n| iOS Device       | ✅        |\n| iOS Simulator    | ❌        |\n| Android Device   | 🚧        |\n| Android Emulator | 🚧        |\n\n## \u003ca id=\"requirements\"\u003e\u003c/a\u003eRequirements 🥸\n\n- Godot 4.4.1 ([https://godotengine.org/](https://godotengine.org/))\n- React Native 0.70+\n- iOS 12.0+ / Android API 21+\n\n## \u003ca id=\"installation\"\u003e\u003c/a\u003eInstallation 🚀\n\n```bash\nnpm install react-native-godot\n# or\nyarn add react-native-godot\n```\n\n## \u003ca id=\"quick-start\"\u003e\u003c/a\u003eQuick Start 👇\n\n### 1. Setup GodotProvider\n\nWrap your app with `GodotProvider` to initialize Godot properly:\n\n```tsx\n// App.tsx\nimport React from 'react';\nimport { GodotProvider } from 'react-native-godot';\nimport MyGameScreen from './MyGameScreen';\n\nexport default function App() {\n  return (\n    \u003cGodotProvider\u003e\n      \u003cMyGameScreen /\u003e\n    \u003c/GodotProvider\u003e\n  );\n}\n```\n\n### 2. Create your game component\n\n```tsx\n// MyGameScreen.tsx\nimport React, { useEffect, useState } from 'react';\nimport { GodotView, useGodot, useGodotRef } from 'react-native-godot';\n\nconst MyGameScreen = () =\u003e {\n  const godotRef = useGodotRef();\n  const { Vector3, Vector2 } = useGodot();\n  const [isGodotReady, setIsGodotReady] = useState(false);\n\n  useEffect(() =\u003e {\n    // Start Godot rendering (call once in your app)\n    GodotView.startDrawing();\n\n    return () =\u003e {\n      // Stop Godot rendering when component unmounts\n      GodotView.stopDrawing();\n    };\n  }, []);\n\n  useEffect(() =\u003e {\n    if (!isGodotReady || !godotRef.current) {\n      return;\n    }\n\n    // Use Godot variants\n    const position = Vector3(1, 2, 3);\n    console.log('Position Y:', position.y);\n\n    // Get nodes from your scene\n    const playerNode = godotRef.current.getRoot()?.getNode('Player');\n    playerNode?.call('jump', 10);\n\n    // Send data to Godot\n    godotRef.current.emitMessage({\n      type: 'player_spawn',\n      position: position,\n      health: 100\n    });\n\n  }, [isGodotReady]);\n\n  return (\n    \u003cGodotView\n      ref={godotRef}\n      style={{ flex: 1 }}\n      source={require('./assets/game.pck')}\n      scene=\"res://main.tscn\"\n      onReady={() =\u003e setIsGodotReady(true)}\n      onMessage={(instance, message) =\u003e {\n        console.log('Message from Godot:', message);\n      }}\n    /\u003e\n  );\n};\n\nexport default MyGameScreen;\n```\n\n## \u003ca id=\"api-reference\"\u003e\u003c/a\u003eAPI Reference\n\n### \u003ca id=\"godot-view\"\u003e\u003c/a\u003eGodotView Component\n\nThe 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.\n\n#### Props\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `source` | `string \\| ImageSourcePropType` | Path to your .pck file |\n| `scene` | `string` | Scene path (e.g., \"res://main.tscn\") |\n| `style` | `StyleProp\u003cViewStyle\u003e` | React Native style object |\n| `onReady` | `(instance: GodotViewRef) =\u003e void` | Called when Godot is ready |\n| `onMessage` | `(instance: GodotViewRef, message: any) =\u003e void` | Called when receiving messages from Godot |\n\n#### Instance Methods (via ref)\n\n| Method | Description |\n|--------|-------------|\n| `getRoot(): Node` | Get the root node of the loaded scene |\n| `emitMessage(message: any): void` | Send a message to Godot scripts |\n| `pause(): void` | Pause the Godot instance |\n| `resume(): void` | Resume the Godot instance |\n| `isReady(): boolean` | Check if Godot is ready |\n\n#### Static Methods\n\n| Method | Description |\n|--------|-------------|\n| `GodotView.startDrawing(): void` | Start Godot rendering engine (call once per app) |\n| `GodotView.stopDrawing(): void` | Stop Godot rendering engine |\n\n**Single GodotView Example:**\n```tsx\nconst MyGame = () =\u003e {\n  const godotRef = useGodotRef();\n\n  useEffect(() =\u003e {\n    // Start rendering when app launches\n    GodotView.startDrawing();\n    return () =\u003e GodotView.stopDrawing();\n  }, []);\n\n  return (\n    \u003cGodotView\n      ref={godotRef}\n      source={require('./game.pck')}\n      scene=\"res://main.tscn\"\n      onReady={(instance) =\u003e {\n        console.log('Godot ready!');\n        instance.emitMessage({ type: 'game_start' });\n      }}\n      onMessage={(instance, message) =\u003e {\n        console.log('From Godot:', message);\n      }}\n    /\u003e\n  );\n};\n```\n\n**Multiple GodotView Example:**\n```tsx\nconst MultiSceneApp = () =\u003e {\n  const gameRef = useGodotRef();\n  const uiRef = useGodotRef();\n  const minimapRef = useGodotRef();\n\n  useEffect(() =\u003e {\n    // Start rendering once for all GodotView instances\n    GodotView.startDrawing();\n    return () =\u003e GodotView.stopDrawing();\n  }, []);\n\n  return (\n    \u003cView style={{ flex: 1 }}\u003e\n      {/* Main game view */}\n      \u003cGodotView\n        ref={gameRef}\n        source={require('./game.pck')}\n        scene=\"res://game_world.tscn\"\n        style={{ flex: 1 }}\n      /\u003e\n      \n      {/* UI overlay */}\n      \u003cGodotView\n        ref={uiRef}\n        source={require('./ui.pck')}\n        scene=\"res://hud.tscn\"\n        style={{ \n          position: 'absolute',\n          top: 0,\n          left: 0,\n          width: '100%',\n          height: 100 \n        }}\n      /\u003e\n      \n      {/* Minimap */}\n      \u003cGodotView\n        ref={minimapRef}\n        source={require('./game.pck')}\n        scene=\"res://minimap.tscn\"\n        style={{ \n          position: 'absolute',\n          top: 20,\n          right: 20,\n          width: 150,\n          height: 150 \n        }}\n      /\u003e\n    \u003c/View\u003e\n  );\n};\n```\n\n**💡 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.\n\n**Example: Controlling individual scenes:**\n```tsx\n// Pause the minimap when not needed\nminimapRef.current?.pause();\n\n// Resume it later\nminimapRef.current?.resume();\n\n// Pause game but keep UI active\ngameRef.current?.pause();\n// UI continues running for menus, etc.\n```\n\n### \u003ca id=\"godot-variants\"\u003e\u003c/a\u003eGodot Variants 🍭\n\nAll Godot variant types are available with full method and property support:\n\n**Available Types:**\n`AABB | Basis | Color | Plane | Projection | Quaternion | Rect2 | Rect2i | Transform2D | Transform3D | Vector2 | Vector2i | Vector3 | Vector3i | Vector4 | Vector4i`\n\n**Usage:**\n\n```tsx\nconst { Vector3, Color, Transform3D } = useGodot();\n\n// Create variants\nconst position = Vector3(1, 2, 3);\nconst color = Color(1, 0, 0, 1); // Red\nconst transform = Transform3D();\n\n// Use methods and properties\nconsole.log('Distance:', position.length());\nconsole.log('Normalized:', position.normalized());\nconsole.log('Red component:', color.r);\n```\n\nComplete documentation: [Godot Variant Types](https://docs.godotengine.org/en/stable/classes/index.html#variant-types)\n\n### \u003ca id=\"runtime-gdscript-node-creation\"\u003e\u003c/a\u003eRuntime GDScript \u0026 Node Creation 🧙‍♂️\n\nCreate and compile GDScript at runtime, then attach to dynamically created nodes:\n\n```tsx\nconst { Script, Node } = useGodot();\n\n// Create and compile a script\nconst script = Script();\nconst success = script.setSourceCode(`\nextends Node\n\n@onready var health = 100\n\nfunc _ready():\n    print(\"Dynamic script loaded!\")\n\nfunc take_damage(amount: int) -\u003e int:\n    health -= amount\n    return health\n\nfunc heal(amount: int):\n    health += amount\n    print(\"Healed for \", amount, \" HP\")\n`);\n\nif (success) {\n  // Create node and attach script\n  const dynamicNode = Node();\n  dynamicNode.setScript(script);\n  dynamicNode.setName(\"DynamicPlayer\");\n  \n  // Add to scene\n  godotRef.current?.getRoot()?.addChild(dynamicNode);\n  \n  // Call script methods\n  const remainingHealth = dynamicNode.call(\"take_damage\", 25);\n  console.log('Health remaining:', remainingHealth);\n  \n  // Alternative syntax with TypeScript casting\n  (dynamicNode as any).heal(10);\n}\n```\n\n#### Script API\n\n| Method | Description |\n|--------|-------------|\n| `Script()` | Create a new empty script |\n| `setSourceCode(source: string): boolean` | Set and compile GDScript source code |\n\n#### Node API\n\n| Method | Description |\n|--------|-------------|\n| `Node()` | Create a new empty node |\n| `getNode(path: string): Node \\| null` | Get child node by path |\n| `getParent(): Node \\| null` | Get parent node |\n| `getChildren(): Node[]` | Get all child nodes |\n| `getChildCount(): number` | Get number of child nodes |\n| `addChild(child: Node)` | Add a child node |\n| `setName(name: string)` | Set the node's name |\n| `setScript(script: Script)` | Attach a script to the node |\n| `call(method: string, ...args: any[]): any` | Call a method defined in the attached script |\n\n**💡 Tip:** For better TypeScript ergonomics, you can call script methods directly using `(node as any).methodName(args)` instead of `node.call(\"methodName\", args)`.\n\n### \u003ca id=\"scene-node-access\"\u003e\u003c/a\u003eScene Node Access 🎯\n\nAccess and interact with nodes from your loaded Godot scenes:\n\n```tsx\nuseEffect(() =\u003e {\n  if (!isGodotReady || !godotRef.current) return;\n\n  // Get the root node\n  const root = godotRef.current.getRoot();\n  \n  // Navigate the scene tree\n  const player = root?.getNode('Player');\n  const ui = root?.getNode('UI/HealthBar');\n  \n  // Access node hierarchy\n  const parent = player?.getParent();\n  const children = player?.getChildren();\n  const siblingCount = parent?.getChildCount();\n  \n  // Call methods defined in the node's GDScript\n  player?.call('set_health', 100);\n  ui?.call('update_display', 100, 100);\n  \n  // Alternative direct method calls\n  (player as any)?.jump(15);\n  (ui as any)?.show_damage_effect();\n  \n}, [isGodotReady]);\n```\n\n### \u003ca id=\"react-native-godot-communication\"\u003e\u003c/a\u003eReact Native ↔ Godot Communication 📡\n\n#### React Native → Godot\n\nSend messages from React Native to your Godot scripts:\n\n```tsx\n// Send structured data to Godot\ngodotRef.current?.emitMessage({\n  type: 'player_action',\n  action: 'attack',\n  target: 'enemy_1',\n  position: Vector3(10, 0, 5),\n  damage: 50\n});\n```\n\n#### Godot → React Native\n\nReceive messages in React Native from Godot scripts:\n\n```tsx\n\u003cGodotView\n  onMessage={(instance, message) =\u003e {\n    console.log('Received from Godot:', message);\n    \n    // Handle different message types\n    switch (message.type) {\n      case 'game_over':\n        showGameOverScreen(message.score);\n        break;\n      case 'level_complete':\n        advanceToNextLevel();\n        break;\n      case 'item_collected':\n        updateInventory(message.item);\n        break;\n    }\n  }}\n/\u003e\n```\n\n#### Godot Script Implementation\n\n```gdscript\nextends Node\n\n@onready var rn_singleton = Engine.get_singleton(\"ReactNative\")\n\nfunc _ready():\n    if rn_singleton:\n        # Listen for messages from React Native\n        rn_singleton.on_message(_on_react_native_message)\n\nfunc _on_react_native_message(message: Dictionary):\n    print(\"Message from React Native: \", message)\n    \n    match message.type:\n        \"player_action\":\n            handle_player_action(message)\n        \"game_state_change\":\n            update_game_state(message.state)\n\nfunc send_to_react_native(data: Dictionary):\n    if rn_singleton:\n        rn_singleton.emit_message(data)\n\nfunc _on_enemy_defeated():\n    send_to_react_native({\n        \"type\": \"enemy_defeated\",\n        \"enemy_id\": \"goblin_1\",\n        \"exp_gained\": 50\n    })\n```\n\n## \u003ca id=\"project-setup\"\u003e\u003c/a\u003eProject Setup\n\n### \u003ca id=\"importing-godot-projects\"\u003e\u003c/a\u003eImporting Godot Projects 📥\n\nTo use your existing Godot project in React Native:\n\n1. **Add export preset configuration**\n\n  Create `export_presets.cfg` in your Godot project directory:\n\n  ```ini\n  [preset.0]\n\n  name=\"main\"\n  platform=\"iOS\"\n  runnable=true\n  advanced_options=false\n  dedicated_server=false\n  custom_features=\"\"\n  export_filter=\"\"\n  include_filter=\"project.godot\"\n  exclude_filter=\"\"\n  export_path=\"\"\n  encryption_include_filters=\"\"\n  encryption_exclude_filters=\"\"\n  encrypt_pck=false\n  encrypt_directory=false\n  script_export_mode=2\n\n  [preset.0.options]\n\n  export/distribution_type=1\n  binary_format/architecture=\"universal\"\n  binary_format/embed_pck=false\n  custom_template/debug=\"\"\n  custom_template/release=\"\"\n  debug/export_console_wrapper=0\n  display/high_res=true\n  ```\n\n2. **Generate PCK file**\n\n  Run the provided script (modify path for your OS):\n\n  ```bash\n  ./gen-pck PROJECT_FOLDER_PATH\n  ```\n\n3. **Add to React Native project**\n\n  Move the generated `.pck` file to your React Native `assets` folder.\n\n4. **Include project.godot in iOS**\n\n  Add your `project.godot` file to your Xcode project bundle.\n\n### \u003ca id=\"metro-configuration\"\u003e\u003c/a\u003eMetro Configuration 🚇\n\nAdd PCK file support to your `metro.config.js`:\n\n```js\nconst config = getDefaultConfig(__dirname);\n\n// Add pck files as assets\nconfig.resolver.assetExts.push('pck');\n\nmodule.exports = config;\n```\n\n## \u003ca id=\"limitations-known-issues\"\u003e\u003c/a\u003eLimitations \u0026 Known Issues 🚧\n\n### Texture Import Settings\n\nWhen importing textures or 3D models, avoid using `VRAM Compressed` format as it may not export properly in PCK files.\n\n[\u003cimg src=\"screenshots/screenshot3.png\" alt=\"VRAM Compressed\" align=\"center\" width=\"200\" hspace=\"2\" vspace=\"10\"\u003e](screenshots/screenshot3.png)\n\n### PCK Asset Swapping\n\nCurrently, 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.\n\n### Platform Support\n\n- iOS Simulator is not supported due to architecture differences\n- Android support is in development\n\n## \u003ca id=\"contributing\"\u003e\u003c/a\u003eContributing 🤝\n\nWe welcome contributions! The core development happens in a private repository, but if you'd like to contribute:\n\n1. Open an issue to discuss your idea\n2. Contact us at `team@calico.games` for access to the private repo\n3. Experience with Godot Engine, C++, and React Native is preferred\n4. Knowledge of [Bazel](https://github.com/bazelbuild/bazel) is a plus\n\n## \u003ca id=\"license\"\u003e\u003c/a\u003eLicense 👨‍⚖️\n\n**Copyright Calico Games 2024. All rights reserved.**\n\nThis library is released under a **Custom License**:\n\n- **✅ Free for non-commercial use** - Personal, educational, or open-source projects\n- **💼 Commercial use requires license** - Companies/individuals with \u003e$50,000 annual revenue need a commercial license\n- **❌ No redistribution** - Cannot be redistributed, repackaged, or resold\n\nWe support the Godot Foundation by sharing revenue from commercial licenses.\n\nFor commercial licensing: `team@calico.games`\n\n---\n\n## \u003ca id=\"credits\"\u003e\u003c/a\u003eCredits 🙏\n\n- Special thanks to the [Godot Engine](https://github.com/godotengine/godot) contributors\n- Huge appreciation to [Migeran](https://github.com/migeran) for their invaluable help\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalico-games%2Freact-native-godot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalico-games%2Freact-native-godot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalico-games%2Freact-native-godot/lists"}