{"id":14963972,"url":"https://github.com/expo/expo-phaser","last_synced_at":"2025-04-06T18:15:00.157Z","repository":{"id":29408761,"uuid":"121585941","full_name":"expo/expo-phaser","owner":"expo","description":"Use Phaser.js on mobile with Expo GL","archived":false,"fork":false,"pushed_at":"2023-02-27T17:31:53.000Z","size":12623,"stargazers_count":234,"open_issues_count":14,"forks_count":29,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-30T16:12:11.040Z","etag":null,"topics":["android","game","ios","phaser","react-native"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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}},"created_at":"2018-02-15T02:58:09.000Z","updated_at":"2025-03-19T10:02:16.000Z","dependencies_parsed_at":"2024-01-30T04:12:34.684Z","dependency_job_id":null,"html_url":"https://github.com/expo/expo-phaser","commit_stats":{"total_commits":47,"total_committers":3,"mean_commits":"15.666666666666666","dds":0.3829787234042553,"last_synced_commit":"0e23b24486c3a3d565bedd7c3e8aa1bd7927711e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-phaser","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-phaser/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-phaser/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/expo%2Fexpo-phaser/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/expo","download_url":"https://codeload.github.com/expo/expo-phaser/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247526764,"owners_count":20953143,"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":["android","game","ios","phaser","react-native"],"created_at":"2024-09-24T13:32:24.825Z","updated_at":"2025-04-06T18:15:00.136Z","avatar_url":"https://github.com/expo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![NPM](https://nodei.co/npm/expo-phaser.png)](https://nodei.co/npm/expo-phaser/)\n\n# expo-phaser\n\nTools for using Phaser-ce to build native 2D games in Expo 👾\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Functions](#functions)\n- [Example](#example)\n- [Demo](#demo)\n\n### Installation\n\n```bash\nyarn add expo-phaser\n```\n\n### Usage\n\nImport the library into your JavaScript file:\n\n```js\nimport ExpoPhaser from \"expo-phaser\";\n```\n\n## Functions\n\n### `ExpoPhaser.game({ context: WebGLRenderingContext, ...extras })`\n\nGiven a `context` from an\n[`Expo.GLView`](https://docs.expo.io/versions/latest/sdk/gl-view.html), return a\n[`Phaser.Game`](https://phaser.io/docs/2.6.2/Phaser.Game.html)\nthat draws into it.\n\n#### Props\n\n| Property    |         Type          | Description                                                                 |         Default Value         |\n| ----------- | :-------------------: | --------------------------------------------------------------------------- | :---------------------------: |\n| context     | WebGLRenderingContext | Required: context that the `Phaser.Game` will render to                     |            `null`             |\n| width       |        number?        | Optional: height of the `Phaser.Game`                                       | `context.drawingBufferWidth`  |\n| height      |        number?        | Optional: width of the `Phaser.Game`                                        | `context.drawingBufferHeight` |\n| title       |        string?        | Optional: title of the `Phaser.Game`                                        |     `\"expo-phaser-game\"`      |\n| preventLoop |       boolean?        | Optional: Prevents the app from calling `context.endFrameEXP()` every frame |            `false`            |\n\n#### Returns\n\n| Property |                              Type                              | Description                                      |\n| -------- | :------------------------------------------------------------: | ------------------------------------------------ |\n| game     | [`Phaser.Game`](https://phaser.io/docs/2.6.2/Phaser.Game.html) | The Phaser-ce game used for rendering game logic |\n\n## Example\n\n```js\nconst game = ExpoPhaser.game({ context });\n```\n\n## What does it do?\n\nUnder the hood, ExpoPhaser is maintaining global instances of a few libraries.\n\n- [Custom Phaser Pixi.js](https://github.com/photonstorm/phaser-ce/tree/master/src/pixi)\n- [Custom Phaser p2.js](https://github.com/photonstorm/phaser-ce/blob/master/build/custom/p2.js)\n- [Phaser-ce (Community Edition)](https://github.com/photonstorm/phaser-ce)\n\n```js\nwindow.PIXI = require(\"phaser-ce/build/custom/pixi\");\nwindow.p2 = require(\"phaser-ce/build/custom/p2\");\nwindow.Phaser = require(\"phaser-ce/build/phaser\");\n```\n\nOther libs can be included but are not required. For instance you can import the custom Creature lib the same way.\nWe also [override the `PIXI.WebGLRenderer.updateTexture`](https://github.com/expo/expo-phaser/tree/master/lib/Phaser.js) to make it compatible with Expo.\n\nFinally when a new instance of `Expo.Game` is created, we set the `document.readyState` to `'complete'` and save the global instance of `context`\n\n```js\nglobal.__context = context;\nglobal.document.readyState = \"complete\";\n```\n\nThen we create a standard render loop and call `context.endFrameEXP()` to flush the frame queue and render our context through `EXGL`.\n\n```js\nconst render = () =\u003e {\n  requestAnimationFrame(render);\n  context.endFrameEXP();\n};\n```\n\n## Example\n\nIt's important to note that you must preload all of your assets before starting the app, as the `Phaser.State.preload` method cannot be asynchronous.\nCreating a game in Expo is very simple with `ExpoPhaser`, we preload our assets, create a view, initialize our game, then add our assets.\n\n**We create an `Expo.GLView` to render our game to.**\n\n```jsx\nreturn (\n  \u003cExpo.GLView\n    style={{ flex: 1 }}\n    onContextCreate={context =\u003e startGame({ context })}\n  /\u003e\n);\n```\n\n**Then we create our `Phaser.Game` instance and assign it a playable state. We can then choose to start said state.**\n\n```js\nfunction startGame({ context }) {\n  const game = ExpoPhaser.game({ context });\n\n  game.state.add(\"Playable\", {\n    preload: function() {\n      /// This function cannot be async, preload all assets before getting here.\n      game.load.image(\n        \"man\",\n        Expo.Asset.fromModule(Assets[\"man.json\"]).localUri\n      );\n    },\n    create: function() {},\n    update: function() {}\n  });\n\n  game.state.start(\"Playable\");\n}\n```\n\n**Preloading**\n\nIn React Native all assets must be static resources, because of this we must create a reference to all the assets we may use, then download them and get their local URI.\nExpo has a convenient way of saving reference. We preload an `Expo.Asset` then if we create the same instance later we can simple call `asset.localUri`.\n\nIn a standard Phaser app we would load an asset like this:\n\n```js\ngame.load.image(\"man\", \"./assets/man.png\");\n```\n\nIn expo we would load it like this:\n\n```js\nconst preloadedExpoAsset = Expo.Asset.fromModule(require('./assets/man.png'))\nawait preloadedExpoAsset.downloadAsync();\n\n...\n\ngame.load.image('man', preloadedExpoAsset.localUri);\n```\n\n### All together\n\nThis example shows how to load an animated texture atlas and apply arcade physics to it.\n\n```js\nimport React from \"react\";\nimport Expo from \"expo\";\nimport ExpoPhaser from \"expo-phaser\";\n\nconst Assets = {\n  \"man.png\": require(\"./assets/man.png\"),\n  \"man.json\": require(\"./assets/man.json\")\n};\n\nexport default class App extends React.Component {\n  state = { loading: true };\n  async componentWillMount() {\n    const downloads = [];\n    for (let key of Object.keys(Assets)) {\n      const asset = Expo.Asset.fromModule(Assets[key]);\n      downloads.push(asset.downloadAsync());\n    }\n    await Promise.all(downloads);\n    this.setState({ loading: false });\n  }\n  render() {\n    if (this.state.loading) {\n      return \u003cExpo.AppLoading /\u003e;\n    }\n\n    return (\n      \u003cExpo.GLView\n        style={{ flex: 1 }}\n        onContextCreate={context =\u003e startGame({ context })}\n      /\u003e\n    );\n  }\n}\n\nfunction startGame({ context }) {\n  const game = ExpoPhaser.game({ context });\n\n  game.state.add(\"Playable\", {\n    preload: function() {\n      const atlas = Expo.Asset.fromModule(Assets[\"man.json\"]).localUri;\n      const texture = Expo.Asset.fromModule(Assets[\"man.png\"]).localUri;\n      game.load.atlasJSONHash(\"man\", texture, atlas);\n    },\n    create: function() {\n      game.stage.backgroundColor = \"#4488AA\";\n\n      game.physics.startSystem(Phaser.Physics.ARCADE);\n\n      //  Set the world (global) gravity\n      game.physics.arcade.gravity.y = 100;\n\n      const man = game.add.sprite(200, 200, \"man\");\n      game.physics.enable([man], Phaser.Physics.ARCADE);\n\n      //  Here we add a new animation called 'run'\n      //  We haven't specified any frames because it's using every frame in the texture atlas\n\n      man.animations.add(\"run\");\n      man.body.collideWorldBounds = true;\n      man.body.bounce.y = 0.8;\n      man.body.gravity.y = 200;\n\n      //  And this starts the animation playing by using its key (\"run\")\n      //  15 is the frame rate (15fps)\n      //  true means it will loop when it finishes\n      man.animations.play(\"run\", 15, true);\n    },\n    update: function() {}\n  });\n\n  game.state.start(\"Playable\");\n}\n```\n\n**note:** When working with `.json` asset inclusion, be sure to update the app.json file to handle `.json` appropriately.\n\n```\n\"packagerOpts\": {\n  \"assetExts\": [\n    \"json\"\n  ]\n},\n```\n\n## Demo\n\nWithin this repo is an [examples/basic](examples/basic) demo.\n\n\u003cp align=\"left\"\u003e\n  \u003cimg src=\"screenshots/screenshot1.png?raw=true\" width=\"440\" /\u003e\n  \u003cimg src=\"screenshots/screenshot2.png?raw=true\" width=\"440\" /\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpo%2Fexpo-phaser","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpo%2Fexpo-phaser","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpo%2Fexpo-phaser/lists"}