{"id":14981171,"url":"https://github.com/expo/expo-three","last_synced_at":"2025-05-15T04:04:24.302Z","repository":{"id":38805365,"uuid":"92997616","full_name":"expo/expo-three","owner":"expo","description":"Utilities for using THREE.js on Expo","archived":false,"fork":false,"pushed_at":"2024-07-31T16:36:08.000Z","size":104993,"stargazers_count":801,"open_issues_count":97,"forks_count":91,"subscribers_count":22,"default_branch":"master","last_synced_at":"2025-05-08T01:51:48.288Z","etag":null,"topics":["ar-session","arkit","expo","javascript","javascript-game","threejs"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/expo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-05-31T23:34:03.000Z","updated_at":"2025-05-06T14:08:15.000Z","dependencies_parsed_at":"2023-02-14T17:30:52.256Z","dependency_job_id":"b95f3565-b379-4357-94c0-d10cc1effe89","html_url":"https://github.com/expo/expo-three","commit_stats":{"total_commits":304,"total_committers":20,"mean_commits":15.2,"dds":"0.19736842105263153","last_synced_commit":"677571aef29cc1adba414d4675028b3fea175c23"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-three","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-three/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-three/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-three/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/expo","download_url":"https://codeload.github.com/expo/expo-three/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253625854,"owners_count":21938209,"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":["ar-session","arkit","expo","javascript","javascript-game","threejs"],"created_at":"2024-09-24T14:03:04.241Z","updated_at":"2025-05-15T04:04:24.243Z","avatar_url":"https://github.com/expo.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eWelcome to Expo \u0026 Three.JS 👋\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eTools for using three.js to create universal 3D experiences\u003c/b\u003e\n  |\n  \u003ca aria-label=\"Try Expo THREE in the browser with Expo Snack\" href=\"https://snack.expo.io/@bacon/three\"\u003e\n    \u003cb\u003eTry it in the browser!\u003c/b\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca aria-label=\"Well tested THREE.js Library\" href=\"https://github.com/expo/expo-three/actions\"\u003e\n    \u003cimg align=\"center\" alt=\"GitHub Actions status\" src=\"https://github.com/expo/expo-three/workflows/Check%20Universal%20Module/badge.svg\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003ca aria-label=\"Follow @expo on Twitter\" href=\"https://twitter.com/intent/follow?screen_name=expo\" target=\"_blank\"\u003e\n    \u003cimg  alt=\"Twitter: expo\" src=\"https://img.shields.io/twitter/follow/expo.svg?style=flat-square\u0026label=Follow%20%40expo\u0026logo=TWITTER\u0026logoColor=FFFFFF\u0026labelColor=00aced\u0026logoWidth=15\u0026color=lightgray\" target=\"_blank\" /\u003e\n  \u003c/a\u003e\n\n  \u003ca aria-label=\"Follow Expo on Medium\" href=\"https://blog.expo.io\"\u003e\n    \u003cimg align=\"right\" alt=\"Medium: exposition\" src=\"https://img.shields.io/badge/Learn%20more%20on%20our%20blog-lightgray.svg?style=flat-square\" target=\"_blank\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nThis package bridges [Three.js](https://threejs.org/) to [Expo GL](https://docs.expo.io/versions/latest/sdk/gl-view/) - a package which provides a WebGL interface for native OpenGL-ES in React. Largely this helps with abstracting the DOM parts away from Three.js.\n\n\u003e AR was moved to `expo-three-ar` in `expo-three@5.0.0`\n\n## Quick Start\n\nCreate a universal React project with `expo-three` setup:\n\n```sh\nnpx create-react-native-app -t with-three\n```\n\nFor a more declarative interface, you can use this package with [react-three-fiber](https://github.com/expo/examples/blob/master/with-react-three-fiber/README.md). You can bootstrap that with:\n\n```sh\nnpx create-react-native-app -t with-react-three-fiber\n```\n\n### Installation\n\n\u003e In `expo-three@5.0.0` and higher, Three.js is a **peer dependency**\n\n```bash\nyarn add three expo-three expo-gl\n```\n\n### Usage\n\nImport the library into your project file:\n\n```js\nimport { Renderer } from 'expo-three';\n```\n\nGet a global instance of `three.js` from `expo-three`:\n\n```js\nimport { THREE } from 'expo-three';\n```\n\n\u003e 🚨 You'll need to **use a physical device** as the iOS Simulators and Android emulators do not work well with Three.js + EXGL.\n\nDue to some issues with the **Metro bundler** you may need to manually define the global instance of Three.js. This is important because three.js doesn't fully use ECMAScript but rather mutates a single global instance of `THREE` with side-effects.\n\n```js\nglobal.THREE = global.THREE || THREE;\n```\n\n## Creating a Renderer\n\nGiven a `gl` from a [`GLView`](https://docs.expo.io/versions/latest/sdk/gl-view.html), return a\n[`THREE.WebGLRenderer`](https://threejs.org/docs/#api/renderers/WebGLRenderer)\nthat draws to it.\n\n```tsx\nimport * as React from 'react';\nimport { ExpoWebGLRenderingContext, GLView } from 'expo-gl';\nimport { Renderer } from 'expo-three';\n\nexport default function App() {\n  return (\n    \u003cGLView\n      style={{ flex: 1 }}\n      onContextCreate={(gl: ExpoWebGLRenderingContext) =\u003e {\n        // Create a WebGLRenderer without a DOM element\n        const renderer = new Renderer({ gl });\n        renderer.setSize(gl.drawingBufferWidth, gl.drawingBufferHeight);\n      }}\n    /\u003e\n  );\n}\n```\n\n### Loading assets\n\nThe Metro bundler cannot load arbitrary file types like (`.obj`, `.mtl`, `.dae`, etc..). In order to support them you must create a `./metro.config.js` in your project root, and add the file extensions you want to support.\n\n`metro.config.js`\n\n```js\nmodule.exports = {\n  resolver: {\n    assetExts: ['db', 'mp3', 'ttf', 'obj', 'png', 'jpg'],\n  },\n};\n```\n\nAll assets require a local URI to be loaded. You can resolve a local URI with `expo-asset`.\n\n```ts\nimport { Asset } from 'expo-asset';\n\n// Create an Asset from a local resource\nconst [{ localUri }] = await Asset.loadAsync(require('./image.png'));\n```\n\n### Loading a texture\n\nAfter you have an asset loaded, you can use it to create a Three.js Texture. `expo-three` provides a helper utility that can resolve the asset internally and make other modifications to support a wider variety of images:\n\n```ts\nimport { TextureLoader } from 'expo-three';\n\n// This texture will be immediately ready but it'll load asynchronously\nconst texture = new TextureLoader().load(require('./img.png'));\n```\n\nOptionally, you can create a texture from the local URI manually (this may not work for most image types):\n\n```ts\nimport { TextureLoader } from 'three';\nimport { Asset } from 'expo-asset';\n\n// Create an Asset from a resource\nconst [{ localUri }] = await Asset.loadAsync(require('./img.png'));\n\n// This texture will be immediately ready but it'll load asynchronously\nconst texture = new TextureLoader().load(localUri);\n```\n\n### Loading an obj model\n\nBe sure to add support for whatever model extension you wish to load to your `metro.config.js`, then you can load a model using the local URI:\n\n```ts\n// Import from jsm for smaller bundles and faster apps\nimport { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';\nimport { Asset } from 'expo-asset';\n\nconst [{ localUri }] = await Asset.loadAsync(require('./model.obj'));\n\nconst loader = new OBJLoader();\nloader.load(localUri, group =\u003e {\n  // Model loaded...\n});\n```\n\n### `ExpoTHREE.loadAsync()`\n\nA function that will asynchronously load files based on their extension.\n\n\u003e **Notice**: Remember to update your `metro.config.js` to bundle obscure file types!\n\n`metro.config.js`\n\n```js\nmodule.exports = {\n  resolver: {\n    assetExts: ['db', 'mp3', 'ttf', 'obj', 'png', 'jpg'],\n  },\n};\n```\n\n#### Props\n\n| Property      |           Type            | Description                                                      |\n| ------------- | :-----------------------: | ---------------------------------------------------------------- |\n| resource      |       PossibleAsset       | The asset that will be parsed asynchornously                     |\n| onProgress    |       (xhr) =\u003e void       | A function that is called with an xhr event                      |\n| assetProvider | () =\u003e Promise\u003cExpo.Asset\u003e | A function that is called whenever an unknown asset is requested |\n\n##### PossibleAsset Format\n\nexport type PossibleAsset = Expo.Asset | number | string | AssetFormat;\n\n```js\ntype PossibleAsset = number | string | Expo.Asset;\n```\n\n- `number`: Static file reference `require('./model.*')`\n- `Expo.Asset`: [Expo.Asset](https://docs.expo.io/versions/latest/sdk/asset.html)\n- `string`: A uri path to an asset\n\n#### Returns\n\nThis returns many different things, based on the input file.\nFor a more predictable return value you should use one of the more specific model loaders.\n\n#### Example\n\n```js\nconst texture = await ExpoTHREE.loadAsync(\n  'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png'\n);\n```\n\n## Loaders\n\n### loadAsync(assetReference, onProgress, onAssetRequested)\n\nA universal loader that can be used to load images, models, scenes, and animations.\nOptionally more specific loaders are provided with less complexity.\n\n```js\n// A THREE.Texture from a static resource.\nconst texture = await ExpoTHREE.loadAsync(require('./icon.png'));\nconst obj = await ExpoTHREE.loadAsync(\n  [require('./cartman.obj'), require('./cartman.mtl')],\n  null,\n  imageName =\u003e resources[imageName]\n);\nconst { scene } = await ExpoTHREE.loadAsync(\n  resources['./kenny.dae'],\n  onProgress,\n  resources\n);\n```\n\n### loadObjAsync({ asset, mtlAsset, materials, onAssetRequested, onMtlAssetRequested })\n\n\u003e 🚨 **Deprecated:** Load OBJ files manually with the JS module `three/examples/jsm/loaders/OBJLoader`\n\n#### Props\n\n- `asset`: a `obj` model reference that will be evaluated using `AssetUtils.resolveAsync`\n- `mtlAsset`: an optional prop that will be loaded using `loadMtlAsync()`\n- `onAssetRequested`: A callback that is used to evaluate urls found within the `asset` and optionally the `mtlAsset`. You can also just pass in a dictionary of key values if you know the assets required ahead of time.\n- `materials`: Optionally you can provide an array of materials returned from `loadMtlAsync()`\n- `onMtlAssetRequested`: If provided this will be used to request assets in `loadMtlAsync()`\n\nThis function is used as a more direct method to loading a `.obj` model.\nYou should use this function to debug when your model has a corrupted format.\n\n```js\nconst mesh = await loadObjAsync({ asset: 'https://www.members.com/chef.obj' });\n```\n\n### loadTextureAsync({ asset })\n\n\u003e 🚨 **Deprecated:** Load textures manually with the JS module from `three`\n\n#### Props\n\n- `asset`: an `Expo.Asset` that could be evaluated using `AssetUtils.resolveAsync` if `localUri` is missing or the asset hasn't been downloaded yet.\n\nThis function is used as a more direct method to loading an image into a texture.\nYou should use this function to debug when your image is using an odd extension like `.bmp`.\n\n```js\nconst texture = await loadTextureAsync({ asset: require('./image.png') });\n```\n\n### loadMtlAsync({ asset, onAssetRequested })\n\n\u003e 🚨 **Deprecated:** Load MTL files manually with the JS module `three/examples/jsm/loaders/MTLLoader`\n\n#### Props\n\n- `asset`: a `mtl` material reference that will be evaluated using `AssetUtils.resolveAsync`\n- `onAssetRequested`: A callback that is used to evaluate urls found within the `asset`, optionally you can just pass in a dictionary of key values if you know the assets required ahead of time.\n\n```js\nconst materials = await loadMtlAsync({\n  asset: require('chef.mtl'),\n  onAssetRequested: modelAssets,\n});\n```\n\n### loadDaeAsync({ asset, onAssetRequested, onProgress })\n\n\u003e 🚨 **Deprecated:** Load DAE files manually with the JS module `three/examples/jsm/loaders/ColladaLoader`\n\n#### Props\n\n- `asset`: a reference to a `dae` scene that will be evaluated using `AssetUtils.resolveAsync`\n- `onAssetRequested`: A callback that is used to evaluate urls found within the `asset`, optionally you can just pass in a dictionary of key values if you know the assets required ahead of time.\n- `onProgress`: An experimental callback used to track loading progress.\n\n```js\nconst { scene } = await loadDaeAsync({\n  asset: require('chef.dae'),\n  onAssetRequested: modelAssets,\n  onProgress: () =\u003e {},\n});\n```\n\n---\n\n## `ExpoTHREE.utils`\n\nThese are Three.js utilities that aren't required for using Three.js with Expo.\n\n### `ExpoTHREE.utils.alignMesh()`\n\n#### Props\n\n```js\ntype Axis = {\n  x?: number,\n  y?: number,\n  z?: number,\n};\n```\n\n| Property |    Type     | Description                       |\n| -------- | :---------: | --------------------------------- |\n| mesh     | \u0026THREE.Mesh | The mesh that will be manipulated |\n| axis     |    ?Axis    | Set the relative center axis      |\n\n#### Example\n\n```js\nExpoTHREE.utils.alignMesh(mesh, { x: 0.0, y: 0.5 });\n```\n\n---\n\n### `ExpoTHREE.utils.scaleLongestSideToSize()`\n\n#### Props\n\n| Property |    Type     | Description                                                  |\n| -------- | :---------: | ------------------------------------------------------------ |\n| mesh     | \u0026THREE.Mesh | The mesh that will be manipulated                            |\n| size     |   number    | The size that the longest side of the mesh will be scaled to |\n\n#### Example\n\n```js\nExpoTHREE.utils.scaleLongestSideToSize(mesh, 3.2);\n```\n\n---\n\n### `ExpoTHREE.utils.computeMeshNormals()`\n\nUsed for smoothing imported geometry, specifically when imported from `.obj` models.\n\n#### Props\n\n| Property |    Type     | Description                                       |\n| -------- | :---------: | ------------------------------------------------- |\n| mesh     | \u0026THREE.Mesh | The mutable (inout) mesh that will be manipulated |\n\n#### Example\n\n```js\nExpoTHREE.utils.computeMeshNormals(mesh);\n```\n\n---\n\n## THREE Extensions\n\n### `suppressMetroWarnings`\n\nA function that suppresses EXGL compatibility warnings and logs them instead. By default this is enabled on native because it can cause the Metro development server to slow down significantly.\nYou will need to import the `ExpoTHREE.THREE` global instance to use this. By\ndefault this function will be activated on import.\n\n- `shouldSuppress`: boolean\n\n```js\nimport { THREE } from 'expo-three';\nTHREE.suppressMetroWarnings();\n```\n\n---\n\n## Running the example app\n\nClone the repo and `cd expo-three` then run:\n\n```sh\nyarn\nyarn build\n# CMD+C to exit build watch mode\ncd example\nnpx expo prebuild\nnpx expo run:android # or npx expo run:ios\n```\n\n## ⛓ Links\n\nSomewhat out of date\n\n- [Loading Text](https://github.com/EvanBacon/expo-three-text)\n- [three.js docs](https://threejs.org/docs/)\n- [Random Demos](https://github.com/EvanBacon/expo-three-demo)\n- [Game: Expo Sunset Cyberspace](https://github.com/EvanBacon/Sunset-Cyberspace)\n- [Game: Crossy Road](https://github.com/EvanBacon/Expo-Crossy-Road)\n- [Game: Nitro Roll](https://github.com/EvanBacon/Expo-Nitro-Roll)\n- [Game: Pillar Valley](https://github.com/EvanBacon/Expo-Pillar-Valley)\n- [Voxel Terrain](https://github.com/EvanBacon/Expo-Voxel)\n\n## 🤝 Contributing\n\nContributions, issues and feature requests are welcome!\u003cbr /\u003eFeel free to check [issues page](https://github.com/Expo/expo-three/issues).\n\n## Show your support\n\nGive a ⭐️ if this project helped you!\n\n## 📝 License\n\nCopyright © 2019-2022 [650 Industries](https://expo.io/about).\u003cbr /\u003e\nThis project is [MIT](https://github.com/Expo/expo-three/blob/master/LICENSE) licensed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpo%2Fexpo-three","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpo%2Fexpo-three","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpo%2Fexpo-three/lists"}