From a45e6e6478e1a14e696b2be50ea0e93617b4690a Mon Sep 17 00:00:00 2001 From: 0xpolarzero <0xpolarzero@gmail.com> Date: Tue, 13 May 2025 19:29:02 +0200 Subject: [PATCH 01/41] init: mud package --- bundler-packages/mud/.depcheckrc | 4 ++ bundler-packages/mud/.gitignore | 50 +++++++++++++++++ bundler-packages/mud/CHANGELOG.md | 0 bundler-packages/mud/LICENSE | 22 ++++++++ bundler-packages/mud/README.md | 3 ++ bundler-packages/mud/biome.json | 77 +++++++++++++++++++++++++++ bundler-packages/mud/package.json | 76 ++++++++++++++++++++++++++ bundler-packages/mud/tsconfig.json | 10 ++++ bundler-packages/mud/tsup.config.ts | 5 ++ bundler-packages/mud/typedoc.json | 7 +++ bundler-packages/mud/vitest.config.ts | 19 +++++++ pnpm-lock.yaml | 77 +++++++++++++++++++++++---- 12 files changed, 340 insertions(+), 10 deletions(-) create mode 100644 bundler-packages/mud/.depcheckrc create mode 100644 bundler-packages/mud/.gitignore create mode 100644 bundler-packages/mud/CHANGELOG.md create mode 100644 bundler-packages/mud/LICENSE create mode 100644 bundler-packages/mud/README.md create mode 100644 bundler-packages/mud/biome.json create mode 100644 bundler-packages/mud/package.json create mode 100644 bundler-packages/mud/tsconfig.json create mode 100644 bundler-packages/mud/tsup.config.ts create mode 100644 bundler-packages/mud/typedoc.json create mode 100644 bundler-packages/mud/vitest.config.ts diff --git a/bundler-packages/mud/.depcheckrc b/bundler-packages/mud/.depcheckrc new file mode 100644 index 0000000000..daf381d93e --- /dev/null +++ b/bundler-packages/mud/.depcheckrc @@ -0,0 +1,4 @@ +ignores: [ + "@tevm/config" +] +skip-missing: true diff --git a/bundler-packages/mud/.gitignore b/bundler-packages/mud/.gitignore new file mode 100644 index 0000000000..f788c233f1 --- /dev/null +++ b/bundler-packages/mud/.gitignore @@ -0,0 +1,50 @@ +.env + +cache +forge-artifacts +broadcast +types + +# compiled output +dist +packages/*/dist +tmp +/out-tsc +**/tsconfig.tsbuildinfo + +# dependencies +node_modules + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +**/lcov.info + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db + +# My personal files +.zshrc diff --git a/bundler-packages/mud/CHANGELOG.md b/bundler-packages/mud/CHANGELOG.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/bundler-packages/mud/LICENSE b/bundler-packages/mud/LICENSE new file mode 100644 index 0000000000..b5a4fa7a69 --- /dev/null +++ b/bundler-packages/mud/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright 2020-2022 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/bundler-packages/mud/README.md b/bundler-packages/mud/README.md new file mode 100644 index 0000000000..a063ef45a3 --- /dev/null +++ b/bundler-packages/mud/README.md @@ -0,0 +1,3 @@ +# @tevm/mud + +MUD plugin for optimistic updates with Tevm diff --git a/bundler-packages/mud/biome.json b/bundler-packages/mud/biome.json new file mode 100644 index 0000000000..5fece99d72 --- /dev/null +++ b/bundler-packages/mud/biome.json @@ -0,0 +1,77 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "organizeImports": { + "enabled": true + }, + "files": { + "ignore": [ + ".nx", + "node_modules", + "package.json", + "**/package.json", + "**/coverage", + "**/node_modules", + "**/dist", + "**/types", + "**/artifacts", + "**/lib", + "**/fixtures", + "**/.next", + "**/.vitepress/cache", + "**/.vitepress/dist", + "scaffold-tevm", + "docs/**/*", + "tevm/**/*", + "bundler/**/*", + ".vscode", + ".changeset", + ".devcontainer", + "examples/svelte-ethers/.svelte-kit", + "examples/next", + "bundler-packages/cli", + "experimental/viem-effect", + "bundler-packages/config/src/fixtures", + "bundler-packages/cli/fixtures" + ] + }, + "formatter": { + "enabled": true, + "formatWithErrors": false, + "indentStyle": "tab", + "indentWidth": 2, + "lineWidth": 120 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "style": { + "useImportType": "off" + }, + "performance": { + "noDelete": "off", + "noAccumulatingSpread": "off" + }, + "complexity": { + "noForEach": "off", + "noBannedTypes": "off", + "useLiteralKeys": "off" + }, + "suspicious": { + "noExplicitAny": "off", + "noGlobalAssign": "off", + "noArrayIndexKey": "off", + "noConfusingVoidType": "off", + "noAssignInExpressions": "off", + "noRedeclare": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "trailingCommas": "all", + "semicolons": "asNeeded" + } + } +} diff --git a/bundler-packages/mud/package.json b/bundler-packages/mud/package.json new file mode 100644 index 0000000000..db885d180e --- /dev/null +++ b/bundler-packages/mud/package.json @@ -0,0 +1,76 @@ +{ + "name": "@tevm/mud", + "version": "1.0.0-next.142", + "private": false, + "description": "MUD plugin for optimistic updates with Tevm", + "keywords": [ + "solidity", + "mud", + "typescript", + "web3", + "blockchain" + ], + "repository": { + "type": "git", + "url": "https://github.com/evmts/tevm-monorepo.git", + "directory": "bundler-packages/mud" + }, + "license": "MIT", + "contributors": [ + "Will Cory " + ], + "sideEffects": false, + "type": "module", + "exports": { + "./package.json": "./package.json", + ".": { + "import": { + "types": "./types/src/index.d.ts", + "default": "./dist/index.js" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } + } + }, + "main": "dist/index.cjs", + "module": "dist/index.js", + "types": "types/src/index.d.ts", + "files": [ + "dist", + "types", + "src" + ], + "scripts": { + "//lint:package": "bunx publint --strict && attw --pack", + "//test": "vitest --coverage", + "//test:coverage": "vitest run --coverage", + "//test:run": "vitest run", + "//test:ui": "vitest --ui", + "all": "pnpm i && bun run build && bun run lint && bun run lint:check && bun run format:check && bun run format && bun run test:coverage && bun run generate:docs", + "build": "nx run-many --targets=build:dist,build:types --projects=@tevm/whatsabi ", + "build:dist": "tsup", + "build:types": "tsup --dts-only && tsc --emitDeclarationOnly --declaration", + "clean": "rm -rf node_modules && rm -rf artifacts && rm -rf dist && rm -rf cache", + "format": "biome format . --write", + "format:check": "biome format .", + "generate:docs": "typedoc", + "lint": "biome check . --write --unsafe", + "lint:check": "biome check . --verbose", + "lint:deps": "bunx depcheck" + }, + "dependencies": { + "@tevm/config": "workspace:^" + }, + "devDependencies": { + "@tevm/tsconfig": "workspace:^", + "@tevm/tsupconfig": "workspace:^" + }, + "peerDependencies": { + "viem": "^2.21.1" + }, + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/bundler-packages/mud/tsconfig.json b/bundler-packages/mud/tsconfig.json new file mode 100644 index 0000000000..108f4fb0f2 --- /dev/null +++ b/bundler-packages/mud/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@tevm/tsconfig/base.json", + "compilerOptions": { + "outDir": "types", + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true + }, + "include": ["src", "src/**/*.json", "package.json"] +} diff --git a/bundler-packages/mud/tsup.config.ts b/bundler-packages/mud/tsup.config.ts new file mode 100644 index 0000000000..c7b10dcf8f --- /dev/null +++ b/bundler-packages/mud/tsup.config.ts @@ -0,0 +1,5 @@ +import { createTsUpOptions } from '@tevm/tsupconfig' +export default createTsUpOptions({ + entry: ['src/index.ts'], + target: 'node', +}) diff --git a/bundler-packages/mud/typedoc.json b/bundler-packages/mud/typedoc.json new file mode 100644 index 0000000000..93f5d67354 --- /dev/null +++ b/bundler-packages/mud/typedoc.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "out": "./docs", + "entryPoints": ["./src/index.ts"], + "plugin": ["typedoc-plugin-markdown"], + "gitRevision": "main" +} diff --git a/bundler-packages/mud/vitest.config.ts b/bundler-packages/mud/vitest.config.ts new file mode 100644 index 0000000000..71039368f6 --- /dev/null +++ b/bundler-packages/mud/vitest.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vitest/config' + +// https://vitest.dev/config/ - for docs +export default defineConfig({ + test: { + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + environment: 'node', + coverage: { + reporter: ['text', 'json-summary', 'json'], + thresholds: { + autoUpdate: true, + lines: 0, + functions: 0, + branches: 0, + statements: 0, + }, + }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 855c83fd69..b164d9bb7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -310,6 +310,22 @@ importers: specifier: workspace:^ version: link:../../configs/tsupconfig + bundler-packages/mud: + dependencies: + '@tevm/config': + specifier: workspace:^ + version: link:../config + viem: + specifier: ^2.21.1 + version: 2.29.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.3) + devDependencies: + '@tevm/tsconfig': + specifier: workspace:^ + version: link:../../configs/tsconfig + '@tevm/tsupconfig': + specifier: workspace:^ + version: link:../../configs/tsupconfig + bundler-packages/resolutions: dependencies: '@tevm/tsconfig': @@ -2274,7 +2290,7 @@ importers: version: 2.29.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.3) vitest: specifier: ^3.1.3 - version: 3.1.3(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.1.2)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1) + version: 3.1.3(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.1.2(vitest@3.1.2))(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1) test/bench: dependencies: @@ -8439,7 +8455,6 @@ packages: bun@1.2.5: resolution: {integrity: sha512-fbQLt+DPiGUrPKdmsHRRT7cQAlfjdxPVFvLZrsUPmKiTdv+pU50ypdx9yRJluknSbyaZchFVV7Lx2KXikXKX2Q==} - cpu: [arm64, x64, aarch64] os: [darwin, linux, win32] hasBin: true @@ -21025,7 +21040,7 @@ snapshots: '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.22.9 - viem: 2.23.11(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) + viem: 2.29.2(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2) transitivePeerDependencies: - bufferutil - typescript @@ -21035,7 +21050,7 @@ snapshots: '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.3)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.22.9 - viem: 2.23.11(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.3) + viem: 2.29.2(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.3) transitivePeerDependencies: - bufferutil - typescript @@ -22255,6 +22270,14 @@ snapshots: chai: 5.2.0 tinyrainbow: 2.0.0 + '@vitest/mocker@3.0.8(vite@6.3.4(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))': + dependencies: + '@vitest/spy': 3.0.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + vite: 6.3.4(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1) + '@vitest/mocker@3.0.8(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1))': dependencies: '@vitest/spy': 3.0.8 @@ -22372,7 +22395,7 @@ snapshots: sirv: 3.0.1 tinyglobby: 0.2.12 tinyrainbow: 2.0.0 - vitest: 3.0.8(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.0.8)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1) + vitest: 3.0.8(@types/debug@4.1.12)(@types/node@22.13.10)(@vitest/ui@3.0.8)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1) '@vitest/ui@3.1.2(vitest@3.1.2)': dependencies: @@ -25525,7 +25548,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-webpack@0.13.10(eslint-plugin-import@2.31.0)(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)): + eslint-import-resolver-webpack@0.13.10(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)): dependencies: debug: 3.2.7 enhanced-resolve: 0.9.1 @@ -25549,7 +25572,7 @@ snapshots: '@typescript-eslint/parser': 7.18.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-webpack: 0.13.10(eslint-plugin-import@2.31.0)(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)) + eslint-import-resolver-webpack: 0.13.10(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)) transitivePeerDependencies: - supports-color @@ -32944,6 +32967,40 @@ snapshots: - utf-8-validate - zod + viem@2.29.2(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.2): + dependencies: + '@noble/curves': 1.8.2 + '@noble/hashes': 1.7.2 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.8.2)(zod@3.24.2) + isows: 1.0.6(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.9(typescript@5.8.2)(zod@3.24.2) + ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + + viem@2.29.2(bufferutil@4.0.9)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.24.3): + dependencies: + '@noble/curves': 1.8.2 + '@noble/hashes': 1.7.2 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.8.2)(zod@3.24.3) + isows: 1.0.6(ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.9(typescript@5.8.2)(zod@3.24.3) + ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + viem@2.29.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.24.2): dependencies: '@noble/curves': 1.8.2 @@ -33193,7 +33250,7 @@ snapshots: vitest@3.0.8(@types/debug@4.1.12)(@types/node@22.13.10)(@vitest/ui@3.0.8)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1)) + '@vitest/mocker': 3.0.8(vite@6.3.4(@types/node@22.13.10)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1)) '@vitest/pretty-format': 3.0.8 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -33351,7 +33408,7 @@ snapshots: - tsx - yaml - vitest@3.1.3(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.1.2)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1): + vitest@3.1.3(@types/debug@4.1.12)(@types/node@22.15.3)(@vitest/ui@3.1.2(vitest@3.1.2))(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1): dependencies: '@vitest/expect': 3.1.3 '@vitest/mocker': 3.1.3(vite@6.3.4(@types/node@22.15.3)(jiti@2.4.2)(lightningcss@1.29.3)(terser@5.39.0)(tsx@4.19.3)(yaml@2.7.1)) @@ -34002,7 +34059,7 @@ snapshots: eslint-config-xo: 0.45.0(eslint@8.57.1) eslint-config-xo-typescript: 5.0.0(@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2))(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2) eslint-formatter-pretty: 6.0.1 - eslint-import-resolver-webpack: 0.13.10(eslint-plugin-import@2.31.0)(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)) + eslint-import-resolver-webpack: 0.13.10(eslint-plugin-import@2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1))(webpack@5.98.0(@swc/core@1.11.9(@swc/helpers@0.5.15))(esbuild@0.25.3)) eslint-plugin-ava: 14.0.0(eslint@8.57.1) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.1) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@7.18.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-webpack@0.13.10)(eslint@8.57.1) From 2270b508b5ef83db6f1ccb8cb0b33a1afd386b6e Mon Sep 17 00:00:00 2001 From: 0xpolarzero <0xpolarzero@gmail.com> Date: Tue, 13 May 2025 19:30:53 +0200 Subject: [PATCH 02/41] init: mud react example --- .../mud/examples/react-ecs/.eslintrc | 10 + .../mud/examples/react-ecs/.gitattributes | 3 + .../mud/examples/react-ecs/.gitignore | 16 + .../react-ecs/.vscode/extensions.json | 3 + .../examples/react-ecs/.vscode/settings.json | 3 + .../mud/examples/react-ecs/mprocs.yaml | 21 + .../mud/examples/react-ecs/package.json | 32 + .../react-ecs/packages/client/.eslintrc | 7 + .../react-ecs/packages/client/.gitignore | 1 + .../react-ecs/packages/client/index.html | 12 + .../react-ecs/packages/client/package.json | 44 + .../packages/client/postcss.config.cjs | 6 + .../react-ecs/packages/client/src/App.tsx | 74 + .../packages/client/src/Providers.tsx | 29 + .../react-ecs/packages/client/src/common.ts | 27 + .../packages/client/src/game/GameMap.tsx | 112 + .../client/src/game/useKeyboardMovement.ts | 26 + .../react-ecs/packages/client/src/index.tsx | 19 + .../packages/client/src/mud/Explorer.tsx | 32 + .../packages/client/src/mud/Synced.tsx | 14 + .../react-ecs/packages/client/src/mud/recs.ts | 6 + .../packages/client/src/mud/useSyncStatus.ts | 17 + .../client/src/mud/useWorldContract.ts | 44 + .../packages/client/src/ui/AsyncButton.tsx | 41 + .../packages/client/src/ui/ErrorFallback.tsx | 58 + .../client/src/ui/icons/ArrowDownIcon.tsx | 22 + .../packages/client/src/ui/icons/MUDIcon.tsx | 25 + .../packages/client/src/wagmiConfig.ts | 49 + .../packages/client/tailwind.config.ts | 10 + .../react-ecs/packages/client/tsconfig.json | 11 + .../react-ecs/packages/client/vite.config.ts | 12 + .../react-ecs/packages/contracts/.gitignore | 13 + .../react-ecs/packages/contracts/.prettierrc | 8 + .../packages/contracts/.solhint.json | 12 + .../react-ecs/packages/contracts/foundry.toml | 29 + .../packages/contracts/mud.config.ts | 18 + .../contracts/out/IWorld.sol/IWorld.abi.json | 2039 +++ .../react-ecs/packages/contracts/package.json | 35 + .../packages/contracts/remappings.txt | 3 + .../contracts/script/PostDeploy.s.sol | 25 + .../packages/contracts/src/Entity.sol | 20 + .../packages/contracts/src/MoveSystem.sol | 30 + .../packages/contracts/src/SpawnSystem.sol | 18 + .../packages/contracts/src/codegen/common.sol | 11 + .../packages/contracts/src/codegen/index.sol | 8 + .../src/codegen/tables/EntityCount.sol | 187 + .../contracts/src/codegen/tables/Owner.sol | 202 + .../contracts/src/codegen/tables/Position.sol | 321 + .../src/codegen/world/IMoveSystem.sol | 16 + .../src/codegen/world/ISpawnSystem.sol | 15 + .../contracts/src/codegen/world/IWorld.sol | 17 + .../packages/contracts/src/createEntity.sol | 11 + .../packages/contracts/test/MoveTest.t.sol | 39 + .../packages/contracts/test/WorldTest.t.sol | 16 + .../packages/contracts/tsconfig.json | 3 + .../react-ecs/packages/contracts/worlds.json | 5 + .../packages/contracts/worlds.json.d.ts | 2 + .../mud/examples/react-ecs/pnpm-lock.yaml | 14040 ++++++++++++++++ .../examples/react-ecs/pnpm-workspace.yaml | 2 + .../mud/examples/react-ecs/tsconfig.json | 3 + 60 files changed, 17934 insertions(+) create mode 100644 bundler-packages/mud/examples/react-ecs/.eslintrc create mode 100644 bundler-packages/mud/examples/react-ecs/.gitattributes create mode 100644 bundler-packages/mud/examples/react-ecs/.gitignore create mode 100644 bundler-packages/mud/examples/react-ecs/.vscode/extensions.json create mode 100644 bundler-packages/mud/examples/react-ecs/.vscode/settings.json create mode 100644 bundler-packages/mud/examples/react-ecs/mprocs.yaml create mode 100644 bundler-packages/mud/examples/react-ecs/package.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/.eslintrc create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/.gitignore create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/index.html create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/package.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/postcss.config.cjs create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/App.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/Providers.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/common.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/game/GameMap.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/game/useKeyboardMovement.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/index.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/mud/Explorer.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/mud/Synced.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/mud/recs.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/mud/useSyncStatus.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/mud/useWorldContract.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/ui/AsyncButton.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/ui/ErrorFallback.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/ui/icons/ArrowDownIcon.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/ui/icons/MUDIcon.tsx create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/src/wagmiConfig.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/tailwind.config.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/tsconfig.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/client/vite.config.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/.gitignore create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/.prettierrc create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/.solhint.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/foundry.toml create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/mud.config.ts create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/out/IWorld.sol/IWorld.abi.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/package.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/remappings.txt create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/script/PostDeploy.s.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/Entity.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/MoveSystem.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/SpawnSystem.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/common.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/index.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/tables/EntityCount.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/tables/Owner.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/tables/Position.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/world/IMoveSystem.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/world/ISpawnSystem.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/codegen/world/IWorld.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/src/createEntity.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/test/MoveTest.t.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/test/WorldTest.t.sol create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/tsconfig.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/worlds.json create mode 100644 bundler-packages/mud/examples/react-ecs/packages/contracts/worlds.json.d.ts create mode 100644 bundler-packages/mud/examples/react-ecs/pnpm-lock.yaml create mode 100644 bundler-packages/mud/examples/react-ecs/pnpm-workspace.yaml create mode 100644 bundler-packages/mud/examples/react-ecs/tsconfig.json diff --git a/bundler-packages/mud/examples/react-ecs/.eslintrc b/bundler-packages/mud/examples/react-ecs/.eslintrc new file mode 100644 index 0000000000..79bd6ef23f --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/.eslintrc @@ -0,0 +1,10 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ] +} diff --git a/bundler-packages/mud/examples/react-ecs/.gitattributes b/bundler-packages/mud/examples/react-ecs/.gitattributes new file mode 100644 index 0000000000..9c70dc52f0 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/.gitattributes @@ -0,0 +1,3 @@ +# suppress diffs for generated files +**/pnpm-lock.yaml linguist-generated=true +**/codegen/**/*.sol linguist-generated=true diff --git a/bundler-packages/mud/examples/react-ecs/.gitignore b/bundler-packages/mud/examples/react-ecs/.gitignore new file mode 100644 index 0000000000..b05d373f12 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/.gitignore @@ -0,0 +1,16 @@ +.DS_Store +logs +*.log + +node_modules + +.env.* + +# foundry +cache +broadcast +out/* +!out/IWorld.sol +out/IWorld.sol/* +!out/IWorld.sol/IWorld.abi.json +!out/IWorld.sol/IWorld.abi.d.json.ts diff --git a/bundler-packages/mud/examples/react-ecs/.vscode/extensions.json b/bundler-packages/mud/examples/react-ecs/.vscode/extensions.json new file mode 100644 index 0000000000..f015de2761 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["NomicFoundation.hardhat-solidity", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] +} diff --git a/bundler-packages/mud/examples/react-ecs/.vscode/settings.json b/bundler-packages/mud/examples/react-ecs/.vscode/settings.json new file mode 100644 index 0000000000..25fa6215fd --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/bundler-packages/mud/examples/react-ecs/mprocs.yaml b/bundler-packages/mud/examples/react-ecs/mprocs.yaml new file mode 100644 index 0000000000..d3d02c2118 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/mprocs.yaml @@ -0,0 +1,21 @@ +scrollback: 10000 +procs: + client: + cwd: packages/client + shell: pnpm run dev + contracts: + cwd: packages/contracts + shell: pnpm mud dev-contracts --rpc http://127.0.0.1:8545 + deploy-prereqs: + cwd: packages/contracts + shell: pnpm entrykit-deploy + env: + DEBUG: "mud:*" + # Anvil default account (0x70997970C51812dc3A010C7d01b50e0d17dc79C8) + PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + anvil: + cwd: packages/contracts + shell: anvil --block-time 2 + explorer: + cwd: packages/contracts + shell: pnpm explorer diff --git a/bundler-packages/mud/examples/react-ecs/package.json b/bundler-packages/mud/examples/react-ecs/package.json new file mode 100644 index 0000000000..c1c663d871 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/package.json @@ -0,0 +1,32 @@ +{ + "name": "mud-template-react", + "private": true, + "scripts": { + "build": "pnpm recursive run build", + "dev": "mprocs", + "dev:client": "pnpm --filter 'client' run dev", + "dev:contracts": "pnpm --filter 'contracts' dev", + "foundry:up": "curl -L https://foundry.paradigm.xyz | bash && bash $HOME/.foundry/bin/foundryup", + "mud:up": "pnpm mud set-version --tag main && pnpm install", + "prepare": "(forge --version || pnpm foundry:up)", + "test": "pnpm recursive run test" + }, + "devDependencies": { + "@latticexyz/cli": "2.2.21", + "@latticexyz/common": "2.2.21", + "@latticexyz/explorer": "2.2.21", + "@latticexyz/store-indexer": "2.2.21", + "@types/debug": "4.1.7", + "@types/node": "^20", + "@typescript-eslint/eslint-plugin": "7.1.1", + "@typescript-eslint/parser": "7.1.1", + "eslint": "8.57.0", + "mprocs": "^0.7.1", + "shx": "^0.3.4", + "typescript": "5.4.2" + }, + "engines": { + "node": "^20", + "pnpm": "^9" + } +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/.eslintrc b/bundler-packages/mud/examples/react-ecs/packages/client/.eslintrc new file mode 100644 index 0000000000..930af95967 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/.eslintrc @@ -0,0 +1,7 @@ +{ + "extends": ["../../.eslintrc", "plugin:react/recommended", "plugin:react-hooks/recommended"], + "plugins": ["react", "react-hooks"], + "rules": { + "react/react-in-jsx-scope": "off" + } +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/.gitignore b/bundler-packages/mud/examples/react-ecs/packages/client/.gitignore new file mode 100644 index 0000000000..1521c8b765 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/.gitignore @@ -0,0 +1 @@ +dist diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/index.html b/bundler-packages/mud/examples/react-ecs/packages/client/index.html new file mode 100644 index 0000000000..ccf1b76fb2 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/index.html @@ -0,0 +1,12 @@ + + + + + + a MUD app + + +
+ + + diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/package.json b/bundler-packages/mud/examples/react-ecs/packages/client/package.json new file mode 100644 index 0000000000..02d7a101aa --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/package.json @@ -0,0 +1,44 @@ +{ + "name": "client", + "version": "0.0.0", + "private": true, + "license": "MIT", + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite", + "preview": "vite preview", + "test": "tsc --noEmit" + }, + "dependencies": { + "@latticexyz/common": "2.2.21", + "@latticexyz/entrykit": "2.2.21", + "@latticexyz/explorer": "2.2.21", + "@latticexyz/react": "2.2.21", + "@latticexyz/recs": "2.2.21", + "@latticexyz/schema-type": "2.2.21", + "@latticexyz/store-sync": "2.2.21", + "@latticexyz/utils": "2.2.21", + "@latticexyz/world": "2.2.21", + "@tanstack/react-query": "^5.63.0", + "contracts": "workspace:*", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-error-boundary": "5.0.0", + "tailwind-merge": "^2.6.0", + "viem": "2.23.2", + "wagmi": "2.12.11" + }, + "devDependencies": { + "@types/react": "18.2.22", + "@types/react-dom": "18.2.7", + "@vitejs/plugin-react": "^4.3.4", + "autoprefixer": "^10.4.20", + "eslint-plugin-react": "7.31.11", + "eslint-plugin-react-hooks": "4.6.0", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.17", + "vite": "^6.0.7", + "vite-plugin-mud": "2.2.21" + } +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/postcss.config.cjs b/bundler-packages/mud/examples/react-ecs/packages/client/postcss.config.cjs new file mode 100644 index 0000000000..12a703d900 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/postcss.config.cjs @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/App.tsx b/bundler-packages/mud/examples/react-ecs/packages/client/src/App.tsx new file mode 100644 index 0000000000..0d4237aadc --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/App.tsx @@ -0,0 +1,74 @@ +import { AccountButton } from "@latticexyz/entrykit/internal"; +import { Direction, Entity } from "./common"; +import mudConfig from "contracts/mud.config"; +import { useMemo } from "react"; +import { GameMap } from "./game/GameMap"; +import { useWorldContract } from "./mud/useWorldContract"; +import { Synced } from "./mud/Synced"; +import { useSync } from "@latticexyz/store-sync/react"; +import { components } from "./mud/recs"; +import { useEntityQuery } from "@latticexyz/react"; +import { Has, getComponentValueStrict } from "@latticexyz/recs"; +import { Address } from "viem"; + +export function App() { + const playerEntities = useEntityQuery([Has(components.Owner), Has(components.Position)]); + const players = useMemo( + () => + playerEntities.map((entity) => { + const owner = getComponentValueStrict(components.Owner, entity); + const position = getComponentValueStrict(components.Position, entity); + return { + entity: entity as Entity, + owner: owner.owner as Address, + x: position.x, + y: position.y, + }; + }), + [playerEntities], + ); + + const sync = useSync(); + const worldContract = useWorldContract(); + + const onMove = useMemo( + () => + sync.data && worldContract + ? async (entity: Entity, direction: Direction) => { + const tx = await worldContract.write.app__move([entity, mudConfig.enums.Direction.indexOf(direction)]); + await sync.data.waitForTransaction(tx); + } + : undefined, + [sync.data, worldContract], + ); + + const onSpawn = useMemo( + () => + sync.data && worldContract + ? async () => { + const tx = await worldContract.write.app__spawn(); + await sync.data.waitForTransaction(tx); + } + : undefined, + [sync.data, worldContract], + ); + + return ( + <> +
+ ( +
+ {message} ({percentage.toFixed(1)}%)… +
+ )} + > + +
+
+
+ +
+ + ); +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/Providers.tsx b/bundler-packages/mud/examples/react-ecs/packages/client/src/Providers.tsx new file mode 100644 index 0000000000..80ac80df1e --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/Providers.tsx @@ -0,0 +1,29 @@ +import { WagmiProvider } from "wagmi"; +import { QueryClientProvider, QueryClient } from "@tanstack/react-query"; +import { ReactNode } from "react"; +import { SyncProvider } from "@latticexyz/store-sync/react"; +import { defineConfig, EntryKitProvider } from "@latticexyz/entrykit/internal"; +import { wagmiConfig } from "./wagmiConfig"; +import { chainId, getWorldAddress, startBlock } from "./common"; +import { syncAdapter } from "./mud/recs"; + +const queryClient = new QueryClient(); + +export type Props = { + children: ReactNode; +}; + +export function Providers({ children }: Props) { + const worldAddress = getWorldAddress(); + return ( + + + + + {children} + + + + + ); +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/common.ts b/bundler-packages/mud/examples/react-ecs/packages/client/src/common.ts new file mode 100644 index 0000000000..47c55e7817 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/common.ts @@ -0,0 +1,27 @@ +import mudConfig from "contracts/mud.config"; +import { chains } from "./wagmiConfig"; +import { Chain, Hex } from "viem"; + +export const chainId = import.meta.env.CHAIN_ID; +export const worldAddress = import.meta.env.WORLD_ADDRESS; +export const startBlock = BigInt(import.meta.env.START_BLOCK ?? 0n); + +export const url = new URL(window.location.href); + +export type Entity = Hex; +export type Direction = (typeof mudConfig.enums.Direction)[number]; + +export function getWorldAddress() { + if (!worldAddress) { + throw new Error("No world address configured. Is the world still deploying?"); + } + return worldAddress; +} + +export function getChain(): Chain { + const chain = chains.find((c) => c.id === chainId); + if (!chain) { + throw new Error(`No chain configured for chain ID ${chainId}.`); + } + return chain; +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/game/GameMap.tsx b/bundler-packages/mud/examples/react-ecs/packages/client/src/game/GameMap.tsx new file mode 100644 index 0000000000..139a8c9b3a --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/game/GameMap.tsx @@ -0,0 +1,112 @@ +import { serialize, useAccount } from "wagmi"; +import { useKeyboardMovement } from "./useKeyboardMovement"; +import { Address, Hex, hexToBigInt, keccak256 } from "viem"; +import { ArrowDownIcon } from "../ui/icons/ArrowDownIcon"; +import { twMerge } from "tailwind-merge"; +import { Direction, Entity } from "../common"; +import mudConfig from "contracts/mud.config"; +import { AsyncButton } from "../ui/AsyncButton"; +import { useAccountModal } from "@latticexyz/entrykit/internal"; +import { useMemo } from "react"; + +export type Props = { + readonly players?: { + readonly entity: Entity; + readonly owner: Address; + readonly x: number; + readonly y: number; + }[]; + readonly onMove?: (entity: Entity, direction: Direction) => Promise; + readonly onSpawn?: () => Promise; +}; + +const size = 40; +const scale = 100 / size; + +function getColorAngle(seed: Hex) { + return Number(hexToBigInt(keccak256(seed)) % 360n); +} + +const rotateClassName = { + North: "rotate-0", + East: "rotate-90", + South: "rotate-180", + West: "-rotate-90", +} as const satisfies Record; + +export function GameMap({ players = [], onMove, onSpawn }: Props) { + const { openAccountModal } = useAccountModal(); + const { address: userAddress } = useAccount(); + + const currentPlayer = players.find((player) => player.owner.toLowerCase() === userAddress?.toLowerCase()); + + useKeyboardMovement( + useMemo( + () => (onMove && currentPlayer ? (direction: Direction) => onMove(currentPlayer.entity, direction) : undefined), + [currentPlayer, onMove], + ), + ); + + return ( +
+
+ {currentPlayer && onMove + ? mudConfig.enums.Direction.map((direction) => ( + + )) + : null} + + {players.map((player) => ( +
+ {player === currentPlayer ?
: null} +
+ ))} + + {!currentPlayer ? ( + onSpawn ? ( +
+ onSpawn()} + > + Spawning… + +
+ ) : ( +
+ +
+ ) + ) : null} +
+
+ ); +} diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/game/useKeyboardMovement.ts b/bundler-packages/mud/examples/react-ecs/packages/client/src/game/useKeyboardMovement.ts new file mode 100644 index 0000000000..7e9074290f --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/game/useKeyboardMovement.ts @@ -0,0 +1,26 @@ +import { useEffect } from "react"; +import { Direction } from "../common"; + +const keys = new Map([ + ["ArrowUp", "North"], + ["ArrowRight", "East"], + ["ArrowDown", "South"], + ["ArrowLeft", "West"], +]); + +export const useKeyboardMovement = (move: undefined | ((direction: Direction) => void)) => { + useEffect(() => { + if (!move) return; + + const listener = (event: KeyboardEvent) => { + const direction = keys.get(event.key); + if (direction == null) return; + + event.preventDefault(); + move(direction); + }; + + window.addEventListener("keydown", listener); + return () => window.removeEventListener("keydown", listener); + }, [move]); +}; diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/index.tsx b/bundler-packages/mud/examples/react-ecs/packages/client/src/index.tsx new file mode 100644 index 0000000000..995e6ec9fd --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/index.tsx @@ -0,0 +1,19 @@ +import "tailwindcss/tailwind.css"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { Providers } from "./Providers"; +import { App } from "./App"; +import { Explorer } from "./mud/Explorer"; +import { ErrorBoundary } from "react-error-boundary"; +import { ErrorFallback } from "./ui/ErrorFallback"; + +createRoot(document.getElementById("react-root")!).render( + + + + + + + + , +); diff --git a/bundler-packages/mud/examples/react-ecs/packages/client/src/mud/Explorer.tsx b/bundler-packages/mud/examples/react-ecs/packages/client/src/mud/Explorer.tsx new file mode 100644 index 0000000000..fe59d58c57 --- /dev/null +++ b/bundler-packages/mud/examples/react-ecs/packages/client/src/mud/Explorer.tsx @@ -0,0 +1,32 @@ +import { useState } from "react"; +import { getChain, getWorldAddress } from "../common"; +import { MUDIcon } from "../ui/icons/MUDIcon"; + +export function Explorer() { + const [open, setOpen] = useState(false); + + const chain = getChain(); + const worldAddress = getWorldAddress(); + + const explorerUrl = chain.blockExplorers?.worldsExplorer?.url; + if (!explorerUrl) return null; + + return ( +
+ + {open ?