{"id":20731866,"url":"https://github.com/thirdweb-example/phaser-platformer","last_synced_at":"2025-06-17T00:38:25.911Z","repository":{"id":107808490,"uuid":"588656951","full_name":"thirdweb-example/phaser-platformer","owner":"thirdweb-example","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-12T00:28:22.000Z","size":266,"stargazers_count":4,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T18:21:57.531Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thirdweb-example.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2023-01-13T16:58:19.000Z","updated_at":"2024-09-14T18:02:35.000Z","dependencies_parsed_at":"2023-03-13T14:32:23.815Z","dependency_job_id":null,"html_url":"https://github.com/thirdweb-example/phaser-platformer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fphaser-platformer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fphaser-platformer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fphaser-platformer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thirdweb-example%2Fphaser-platformer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thirdweb-example","download_url":"https://codeload.github.com/thirdweb-example/phaser-platformer/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254142216,"owners_count":22021481,"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":[],"created_at":"2024-11-17T05:16:54.290Z","updated_at":"2025-05-14T12:31:01.729Z","avatar_url":"https://github.com/thirdweb-example.png","language":"TypeScript","funding_links":[],"categories":["NextJS"],"sub_categories":["Phaser"],"readme":"\u003e [!Important]  \n\u003e This repository is referencing the `mumbai` chain.\n\u003e \n\u003e `Mumbai` [is deprecated since 08/04/2024](https://blog.thirdweb.com/deprecation-of-mumbai-testnet/), meaning the code in this repository will no longer work out of the box.\n\u003e\n\u003e You can still use this repository, however you will have to switch any references to `mumbai` to another chain.\n\n# Phaser platformer game\n\n## Introduction\n\nIn this guide, we will utilize signature-based minting of NFTs to create a browser game with Phaser framework, where each user mints and their game score as a NFT based on how fast the player finish the game.\n\nBy the end, we'll have an NFT collection as scoreboard of all players.\n\n**Check out the Demo here**: https://with-phaser-platformer.vercel.app/\n\n## Tools:\n\n- [**thirdweb React SDK**](https://docs.thirdweb.com/react): to enable users to connect and disconnect their wallets to our website, using [useMetamask](https://docs.thirdweb.com/react/react.usemetamask) \u0026 [useDisconnect](https://docs.thirdweb.com/react/react.usedisconnect), and prompt them to approve transactions with MetaMask. We'll also use the helpful hooks such as [useNFTs](https://docs.thirdweb.com/react/react.usenfts) to easily fetch data from the smart contract.\n- [**thirdweb NFT Collection**](https://portal.thirdweb.com/contracts/nft-collection): to create an ERC721 NFT Collection that our community can mint NFTs into.\n- [**thirdweb TypeScript SDK**](https://docs.thirdweb.com/typescript): to connect to our NFT Collection Smart contract via React hooks such as [useNFTCollection](https://docs.thirdweb.com/react/react.usenftcollection), mint new NFTs with [signature based minting](https://docs.thirdweb.com/typescript/sdk.nftcollection.signature).\n- [**Next JS API Routes**](https://nextjs.org/docs/api-routes/introduction): For us to securely generate signatures on the server-side, on behalf of our wallet, using our wallet's private key.\n\n## Using This Repo\n\n- Create a project using this example by running:\n\n```bash\nnpx thirdweb create --template phaser-platformer\n```\n\n- Create your own NFT Collection via the thirdweb dashboard (follow the steps in **Setting Up The NFT Collection** of this doc if you need more help)\n\n- Create an environment variable in a `.env.local` file with your private key, in the form `PRIVATE_KEY=xxx`, similarly to the `.env.example` file provided.\n\n- Add the `NEXT_PUBLIC_NFT_COLLECTION_ADDRESS` environment variable to your `.env.local` file too, in the form `NEXT_PUBLIC_NFT_COLLECTION_ADDRESS=xxx`, similarly to the `.env.example` file provided.\n\n## What is Signature Based Minting?\n\nNFT Collections come in different shapes, sizes, and rules.\n\nOn one end of the spectrum, an NFT collection can be a set amount of NFTs, and they're all made by one wallet, once they're all claimed/minted, no more NFTs are ever minted in the collection. A popular example of this is the [Bored Ape Yacht Club Collection](https://boredapeyachtclub.com/#/).\n\nOn the other end of the spectrum, an NFT collection could also start out with no NFTs! NFTs in _this_ collection could be created by anyone, at any time, and the NFTs could look completely different. This type of collection is a bit less well-known, but demonstrates that NFT collections can be totally different!\n\nSignature-based minting enables a use case that is somewhere between these two ends of the spectrum. What if you didn't want **EVERYONE** to be able to mint an NFT into your collection, or you only wanted specific types of NFTs to be minted?\n\nSignature-based minting allows you to specify exactly what NFTs you allow to be minted into your NFT collection, by generating a signature for an NFT. This signature can be used by a wallet address that you specify to mint that NFT.\n\nIn this guide, we'll grant users signatures to mint NFTs into our collection.\n\nIn the end, we'll have a scoreboard collection that contains NFTs with players name with their respective score.\n\nLet's get into it!\n\n## Setting Up The NFT Collection\n\nTo create an NFT collection, we can use the thirdweb dashboard and create a fully customizable NFT collection in just a few clicks.\n\nHead to https://thirdweb.com/dashboard and create a new contract on the Polygon Mumbai network. Click **Create NFTs and Tokens** \u003e **NFT Collection**.\n\nGive your collection a name and click **Deploy now**!\n\nNice! Now we have an NFT collection. Let's set up a project and see how we can start minting some NFTs using the thirdweb SDK.\n\n## Setting Up The Project\n\nTo get started, we have a ready-made template that includes all the code you need to work with Thirdweb, TypeScript and Next JS available here https://github.com/thirdweb-example/next-typescript-starter\n\nOur application is wrapped in a Thirdweb Provider so that we can access Thirdweb anywhere in our application:\n\n```tsx\nimport { ChainId, ThirdwebProvider } from \"@thirdweb-dev/react\";\n\n// This is the chainId your dApp will work on.\nconst activeChainId = ChainId.Mumbai;\n\nfunction MyApp({ Component, pageProps }: AppProps) {\n  return (\n    \u003cThirdwebProvider desiredChainId={activeChainId}\u003e\n      \u003cComponent {...pageProps} /\u003e\n    \u003c/ThirdwebProvider\u003e\n  );\n}\n```\n\n## Connecting User's Wallets\n\nIn `EndingScene.tsx` We're using the ethers with [thirdweb SDK](https://portal.thirdweb.com/typescript/sdk.thirdwebsdk.fromsigner) so our user can connect their wallet to our website.\n\n```tsx\nimport { ThirdwebSDK } from \"@thirdweb-dev/sdk\";\nimport { ethers } from \"ethers\";\n\n  // Connect Metamask\n  const provider = new ethers.providers.Web3Provider(\n    window.ethereum as any,\n    \"any\"\n  );\n  await provider.send(\"eth_requestAccounts\", []);\n  const signer = provider.getSigner(); // Grab the current user's address\n  const address = await signer.getAddress(); \n\n  // Fetch the NFT collection from thirdweb via it's contract address.\n  const sdk = ThirdwebSDK.fromSigner(signer);\n\n```\n\n## Loading \u0026 Displaying NFTs\n\nFor our community collection, each NFT is minted by a different user. We're using another thirdweb hook called `useNFTCollection` to connect to our smart contract and load all of the NFT's in our collection.\n\n```tsx\n// Fetch the NFT collection from thirdweb via it's contract address.\nconst nftCollection = useNFTCollection(\n  // Replace this with your NFT Collection contract address\n  process.env.NEXT_PUBLIC_NFT_COLLECTION_ADDRESS\n);\n```\n\nOnce we've loaded them from the smart contract, we can display each NFT to the user.\n\nWe'll be using the React SDK's `useNFTs` to fetch all of the NFTs in our collection.\n\n**Fetch All NFTS**:\n\n```tsx\nconst { data: nfts, isLoading: loadingNfts } = useNFTs(nftCollection);\n```\n\nNow we've got the NFT's loaded, we can display them to the user!\n\nWe'll let you decide how best to display your NFTs, but if you're looking for an example, check out the [index.tsx file](./pages/index.tsx) to see how we did it.\n\nWe can also see who is the owner of each nft with `.owner`, and the `metadata.name` and `metadata.description` inside of each NFT!\n\n## Creating NFTs with Signature Based Minting\n\nThe way that our signature-based minting process works is in 3 steps:\n\n![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1650958559249/S8mlZIQZm.png)\n\n1. The connected wallet calls a [Next JS API Route](https://nextjs.org/docs/api-routes/introduction) with three parameters, `authorAddress`, `nftName`, and `imagePath` inside the request body.\n\n2. The API route runs some checks on the server-side to see if this user and the NFT they are requesting to mint is eligible or not. If the request _is_ eligible, it generates a signature to mint an NFT with a specific set of characteristics.\n\n3. Once the API function is done processing, it sends the client/user a signature. The user can call `mint` with this signature to create an NFT with the conditions provided from our server.\n\nThe main benefit here is that we have made an environment where us (the owner of the smart contract) can decide what the user can mint into our collection, all programmatically.\n\n## API Route\n\nTo create an API Route, you'll need to create a file in the `/pages/api` directory of your project.\n\nOn the server-side API route, we can:\n\n- Run a few checks to see if the requested NFT meets our criteria\n- Generate a signature to mint the NFT if it does.\n- Send the signature back to the client/user if the NFT is eligible.\n\n**De-structure the arguments we passed in out of the request body**:\n\n```tsx\nconst { authorAddress, nftName, imagePath } = JSON.parse(req.body);\n```\n\n**Initialize the Thirdweb SDK on the server-side**\n\n```tsx\n// Initialize the Thirdweb SDK on the serverside\nconst sdk = ThirdwebSDK.fromPrivateKey(\n  // Your wallet private key (read it in from .env.local file)\n  process.env.PRIVATE_KEY as string,\n  \"mumbai\"\n);\n```\n\n**Load the NFT Collection via it's contract address using the SDK**\n\n```tsx\nconst nftCollection = sdk.getNFTCollection(\n  // Replace this with your NFT Collection contract address\n  \"0x000000000000000000000000000000000000000\"\n);\n```\n\n**Example Check - Check that this wallet doesn't already own an NFT in this collection**\n\n```tsx\nconst hasMinted = (await nftCollection.balanceOf(authorAddress)).gt(0);\nif (hasMinted) {\n  res.status(400).json({ error: \"Already minted\" });\n  return;\n}\n```\n\n**When we are satisfied with the NFT conditions, we can generate a signature to mint the NFT**\n\n```tsx\n// This is to generate the page number based on how many pages have been minted already\nconst pageNumber = (await nftCollection.totalSupply()).add(1);\n\n// If all the checks pass, begin generating the signature...\n// Generate the signature for the page NFT\nconst signedPayload = await nftCollection.signature.generate({\n  to: playerAddress,\n  metadata: {\n    name: username as string,\n    image:\n      \"ipfs://QmZvVNpnnbwsPzVhRoRSuT4T3DFV6wiwzBdXmJAdgGk6UP/platformer.png\" as string,\n    description: `${username} finished the game in ${recordSeconds} seconds`,\n    properties: {\n      time: recordSeconds,\n      // Add any properties you want to store on the NFT\n    },\n  },\n});\n```\n\n**Return the signature to the client**\n\n```tsx\n// Return back the signedPayload to the client.\nres.status(200).json({\n  signedPayload: JSON.parse(JSON.stringify(signedPayload)),\n});\n```\n\nIf at any point this process fails or the request is not valid, we send back an error response instead of the generated signature.\n\n```tsx\nres.status(500).json({ error: `Server error ${e}` });\n```\n\n## Making the API Request on the client\n\nWith our API route available, we make `fetch` requests to this API, and securely run that code on the server-side.\n\n**Call the API route on the client**\n\n```tsx\n// Make a request to /api/server\nconst signedPayloadReq = await fetch(`/api/server`, {\n  method: \"POST\",\n  body: JSON.stringify({\n    authorAddress: address, // Address of the current user\n    nftName: nftName,\n    imagePath: url,\n  }),\n});\n\n// Grab the JSON from the response\nconst json = await signedPayloadReq.json();\n```\n\n**Read the signature from the response**\n\n```tsx\nconst signedPayload = json.signedPayload;\n```\n\n**Mint the NFT with the signature**\n\n```tsx\n// Now we can call signature.mint and pass in the signed payload that we received from the server.\nconst nft = await nftCollection?.signature.mint(signedPayload);\n```\n\n## Credits:\n\nhttps://phaser.io/learn\n\n---\n\n## Join our Discord!\n\nFor any questions, suggestions, join our discord at [https://discord.gg/thirdweb](https://discord.gg/thirdweb).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fphaser-platformer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthirdweb-example%2Fphaser-platformer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthirdweb-example%2Fphaser-platformer/lists"}