Skip to content

Commit 09846f2

Browse files
authored
feat(create-mud): new react-ecs template (#3485)
1 parent 227db4d commit 09846f2

61 files changed

Lines changed: 3462 additions & 517 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/hip-pugs-tease.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-mud": patch
3+
---
4+
5+
Updated React ECS template with EntryKit for wallet support and a cleaned up app structure.

templates/react-ecs/.gitignore

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1+
.DS_Store
2+
logs
3+
*.log
4+
15
node_modules
26

3-
# mud artifacts
4-
.mud
5-
# sqlite indexer data
6-
*.db
7-
*.db-journal
7+
.env.*
8+
9+
# foundry
10+
cache
11+
broadcast
12+
out/*
13+
!out/IWorld.sol
14+
out/IWorld.sol/*
15+
!out/IWorld.sol/IWorld.abi.json
16+
!out/IWorld.sol/IWorld.abi.d.json.ts

templates/react-ecs/mprocs.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
1+
scrollback: 10000
12
procs:
23
client:
34
cwd: packages/client
45
shell: pnpm run dev
56
contracts:
67
cwd: packages/contracts
78
shell: pnpm mud dev-contracts --rpc http://127.0.0.1:8545
9+
deploy-prereqs:
10+
cwd: packages/contracts
11+
shell: pnpm deploy-local-prereqs
12+
env:
13+
DEBUG: "mud:*"
14+
# Anvil default account (0x70997970C51812dc3A010C7d01b50e0d17dc79C8)
15+
PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"
816
anvil:
917
cwd: packages/contracts
10-
shell: anvil --base-fee 0 --block-time 2
18+
shell: anvil --block-time 2
1119
explorer:
1220
cwd: packages/contracts
1321
shell: pnpm explorer

templates/react-ecs/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "mud-template-react-ecs",
2+
"name": "mud-template-react",
33
"private": true,
44
"scripts": {
55
"build": "pnpm recursive run build",
@@ -17,7 +17,6 @@
1717
"@latticexyz/explorer": "link:../../packages/explorer",
1818
"@latticexyz/store-indexer": "link:../../packages/store-indexer",
1919
"@types/debug": "4.1.7",
20-
"@types/node": "^18",
2120
"@typescript-eslint/eslint-plugin": "7.1.1",
2221
"@typescript-eslint/parser": "7.1.1",
2322
"eslint": "8.57.0",
@@ -28,5 +27,12 @@
2827
"engines": {
2928
"node": "^18",
3029
"pnpm": "^8 || ^9"
30+
},
31+
"pnpm": {
32+
"overrides": {
33+
"@tanstack/react-query": "link:../../packages/entrykit/node_modules/@tanstack/react-query",
34+
"@types/react": "link:../../packages/entrykit/node_modules/@types/react",
35+
"wagmi": "link:../../packages/entrykit/node_modules/wagmi"
36+
}
3137
}
3238
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
node_modules
21
dist
3-
.DS_Store

templates/react-ecs/packages/client/index.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>a minimal MUD client</title>
6+
<title>a MUD app</title>
77
</head>
88
<body>
99
<div id="react-root"></div>

templates/react-ecs/packages/client/package.json

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,39 @@
66
"type": "module",
77
"scripts": {
88
"build": "vite build",
9-
"dev": "wait-port localhost:8545 && vite",
9+
"dev": "vite",
1010
"preview": "vite preview",
1111
"test": "tsc --noEmit"
1212
},
1313
"dependencies": {
1414
"@latticexyz/common": "link:../../../../packages/common",
15-
"@latticexyz/dev-tools": "link:../../../../packages/dev-tools",
15+
"@latticexyz/entrykit": "link:../../../../packages/entrykit",
16+
"@latticexyz/explorer": "link:../../../../packages/explorer",
1617
"@latticexyz/react": "link:../../../../packages/react",
1718
"@latticexyz/recs": "link:../../../../packages/recs",
1819
"@latticexyz/schema-type": "link:../../../../packages/schema-type",
1920
"@latticexyz/store-sync": "link:../../../../packages/store-sync",
2021
"@latticexyz/utils": "link:../../../../packages/utils",
2122
"@latticexyz/world": "link:../../../../packages/world",
23+
"@tanstack/react-query": "^5.63.0",
2224
"contracts": "workspace:*",
23-
"react": "^18.2.0",
24-
"react-dom": "^18.2.0",
25-
"rxjs": "7.5.5",
26-
"viem": "2.21.19"
25+
"react": "18.2.0",
26+
"react-dom": "18.2.0",
27+
"react-error-boundary": "5.0.0",
28+
"tailwind-merge": "^2.6.0",
29+
"viem": "2.21.19",
30+
"wagmi": "2.12.11"
2731
},
2832
"devDependencies": {
2933
"@types/react": "18.2.22",
3034
"@types/react-dom": "18.2.7",
31-
"@vitejs/plugin-react": "^3.1.0",
35+
"@vitejs/plugin-react": "^4.3.4",
36+
"autoprefixer": "^10.4.20",
3237
"eslint-plugin-react": "7.31.11",
3338
"eslint-plugin-react-hooks": "4.6.0",
34-
"vite": "^4.2.1",
35-
"wait-port": "^1.0.4"
39+
"postcss": "^8.4.49",
40+
"tailwindcss": "^3.4.17",
41+
"vite": "^6.0.7",
42+
"vite-plugin-mud": "link:../../../../packages/vite-plugin-mud"
3643
}
3744
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.exports = {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
};
Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,74 @@
1-
import { useComponentValue } from "@latticexyz/react";
2-
import { useMUD } from "./MUDContext";
3-
import { singletonEntity } from "@latticexyz/store-sync/recs";
1+
import { AccountButton } from "@latticexyz/entrykit/internal";
2+
import { Direction, Entity } from "./common";
3+
import mudConfig from "contracts/mud.config";
4+
import { useMemo } from "react";
5+
import { GameMap } from "./game/GameMap";
6+
import { useWorldContract } from "./mud/useWorldContract";
7+
import { Synced } from "./mud/Synced";
8+
import { useSync } from "@latticexyz/store-sync/react";
9+
import { components } from "./mud/recs";
10+
import { useEntityQuery } from "@latticexyz/react";
11+
import { Has, getComponentValueStrict } from "@latticexyz/recs";
12+
import { Address } from "viem";
413

5-
export const App = () => {
6-
const {
7-
components: { Counter },
8-
systemCalls: { increment },
9-
} = useMUD();
14+
export function App() {
15+
const playerEntities = useEntityQuery([Has(components.Owner), Has(components.Position)]);
16+
const players = useMemo(
17+
() =>
18+
playerEntities.map((entity) => {
19+
const owner = getComponentValueStrict(components.Owner, entity);
20+
const position = getComponentValueStrict(components.Position, entity);
21+
return {
22+
entity: entity as Entity,
23+
owner: owner.owner as Address,
24+
x: position.x,
25+
y: position.y,
26+
};
27+
}),
28+
[playerEntities],
29+
);
30+
31+
const sync = useSync();
32+
const worldContract = useWorldContract();
33+
34+
const onMove = useMemo(
35+
() =>
36+
sync.data && worldContract
37+
? async (entity: Entity, direction: Direction) => {
38+
const tx = await worldContract.write.app__move([entity, mudConfig.enums.Direction.indexOf(direction)]);
39+
await sync.data.waitForTransaction(tx);
40+
}
41+
: undefined,
42+
[sync.data, worldContract],
43+
);
1044

11-
const counter = useComponentValue(Counter, singletonEntity);
45+
const onSpawn = useMemo(
46+
() =>
47+
sync.data && worldContract
48+
? async () => {
49+
const tx = await worldContract.write.app__spawn();
50+
await sync.data.waitForTransaction(tx);
51+
}
52+
: undefined,
53+
[sync.data, worldContract],
54+
);
1255

1356
return (
1457
<>
15-
<div>
16-
Counter: <span>{counter?.value ?? "??"}</span>
58+
<div className="fixed inset-0 grid place-items-center p-4">
59+
<Synced
60+
fallback={({ message, percentage }) => (
61+
<div className="tabular-nums">
62+
{message} ({percentage.toFixed(1)}%)…
63+
</div>
64+
)}
65+
>
66+
<GameMap players={players} onMove={onMove} onSpawn={onSpawn} />
67+
</Synced>
68+
</div>
69+
<div className="fixed top-2 right-2">
70+
<AccountButton />
1771
</div>
18-
<button
19-
type="button"
20-
onClick={async (event) => {
21-
event.preventDefault();
22-
console.log("new counter value:", await increment());
23-
}}
24-
>
25-
Increment
26-
</button>
2772
</>
2873
);
29-
};
74+
}

templates/react-ecs/packages/client/src/MUDContext.tsx

Lines changed: 0 additions & 21 deletions
This file was deleted.

0 commit comments

Comments
 (0)