diff --git a/docs/components/MUDTable.module.css b/docs/components/MUDTable.module.css
new file mode 100644
index 0000000000..becc677b84
--- /dev/null
+++ b/docs/components/MUDTable.module.css
@@ -0,0 +1,25 @@
+.table {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
+ background-color: hsl(var(--nextra-primary-hue) 100% 66%/0.1);
+ margin-top: 1em;
+ text-align: center;
+}
+
+.table th,
+.table td {
+ padding: 1em 1.5em;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.2);
+}
+
+.table th {
+ color: white;
+ background: hsl(var(--nextra-primary-hue) 100% 45%/0.5);
+}
+.table thead th {
+ background: hsl(var(--nextra-primary-hue) 100% 45%/0.75);
+}
+
+.table tbody tr:hover th,
+.table tbody tr:hover td {
+ backdrop-filter: brightness(1.5);
+}
diff --git a/docs/components/MUDTable.tsx b/docs/components/MUDTable.tsx
new file mode 100644
index 0000000000..cd3ee923ca
--- /dev/null
+++ b/docs/components/MUDTable.tsx
@@ -0,0 +1,10 @@
+import React, { ReactNode } from "react";
+import styles from "./MUDTable.module.css";
+
+type Props = {
+ children: ReactNode;
+};
+
+export function MUDTable({ children }: Props) {
+ return
;
+}
diff --git a/docs/next.config.mjs b/docs/next.config.mjs
index 752d004fde..eb8c7b2092 100644
--- a/docs/next.config.mjs
+++ b/docs/next.config.mjs
@@ -216,6 +216,11 @@ export default withNextra({
destination: "/config",
permanent: false,
},
+ {
+ source: "/guides/extending-world",
+ destination: "/guides/extending-a-world",
+ permanent: false,
+ },
];
},
});
diff --git a/docs/pages/guides/_meta.js b/docs/pages/guides/_meta.js
index 797a65eaba..22f31cb216 100644
--- a/docs/pages/guides/_meta.js
+++ b/docs/pages/guides/_meta.js
@@ -1,5 +1,6 @@
export default {
+ "replicating-onchain-state": "Replicating onchain state",
"hello-world": "Hello World",
- "extending-world": "Extending World",
+ "extending-a-world": "Extending a World",
emojimon: "Emojimon",
};
diff --git a/docs/pages/guides/extending-world.mdx b/docs/pages/guides/extending-a-world.mdx
similarity index 99%
rename from docs/pages/guides/extending-world.mdx
rename to docs/pages/guides/extending-a-world.mdx
index 920b284553..0f529ba70e 100644
--- a/docs/pages/guides/extending-world.mdx
+++ b/docs/pages/guides/extending-a-world.mdx
@@ -1,6 +1,6 @@
import { CollapseCode } from "../../components/CollapseCode";
-# Extending World
+# Extending a World
On this page you learn how to modify a `World` that is already deployed to the blockchain.
If you want to learn how to modify a `World` before it is deployed, [see the hello world page](./hello-world).
diff --git a/docs/pages/guides/hello-world.mdx b/docs/pages/guides/hello-world.mdx
index 90f0538251..9df7b03fc2 100644
--- a/docs/pages/guides/hello-world.mdx
+++ b/docs/pages/guides/hello-world.mdx
@@ -1,7 +1,7 @@
# Hello World
On this page you learn how to modify a `World` before it is deployed to the blockchain.
-If you want to learn how to modify a `World` that is already deployed, [see the extending world page](./extending-world).
+If you want to learn how to modify a `World` that is already deployed, see the [Extending a World](./extending-a-world) guide.
The examples on this page use [the vanilla template](../templates/typescript/vanilla).
[See this page for installation instructions](../templates/typescript/getting-started).
diff --git a/docs/pages/guides/replicating-onchain-state.mdx b/docs/pages/guides/replicating-onchain-state.mdx
index 3c48d2dc5c..7288cb075f 100644
--- a/docs/pages/guides/replicating-onchain-state.mdx
+++ b/docs/pages/guides/replicating-onchain-state.mdx
@@ -1,10 +1,10 @@
-# Replicating onchain state from MUD Store events
+# Replicating onchain state
This guide walks through how you might recreate onchain state from MUD's Store events. We use this pattern in our sync stack to hydrate a client or indexer from blockchain logs fetched from an RPC.
## Store: MUD's onchain storage
-Before we get started, it's helpful to understand [how MUD stores its data on chain](/store/introduction). MUD introduces [a few new concepts](/store/tables): tables, records, key tuples, and fields.
+Before we get started, it's helpful to understand [how MUD stores its data on chain](/store/introduction). MUD introduces [a few new concepts](/store/data-model): tables, records, key tuples, and fields.
You can think of tables like a native Solidity `mapping`, where its keys and values are [encoded in a standardized way](/store/encoding) to 1) more easily replicate and represent data offchain, like in relational databases, and 2) require less onchain storage and gas than native Solidity.
diff --git a/docs/pages/store/_meta.js b/docs/pages/store/_meta.js
index 69d1233847..109874c16f 100644
--- a/docs/pages/store/_meta.js
+++ b/docs/pages/store/_meta.js
@@ -1,9 +1,9 @@
export default {
introduction: "Introduction",
+ "data-model": "Data model",
tables: "Tables",
- "table-libraries": "Table Libraries",
+ "table-libraries": "Table libraries",
encoding: "Encoding",
- "store-hooks": "Store Hooks",
+ "store-hooks": "Store hooks",
reference: "Reference",
- "table-intro": { display: "hidden" }, // imported
};
diff --git a/docs/pages/store/data-model.mdx b/docs/pages/store/data-model.mdx
new file mode 100644
index 0000000000..2e2b422718
--- /dev/null
+++ b/docs/pages/store/data-model.mdx
@@ -0,0 +1,138 @@
+import { CollapseCode } from "../../components/CollapseCode";
+import { MUDTable } from "../../components/MUDTable";
+
+# How MUD models data
+
+The MUD framework helps you to model your onchain state in a way that enables building applications with familiar tooling, like relational databases.
+
+In your MUD config, you define data as a set of tables. Like relational databases, these tables have “columns” by way of two MUD concepts: a key schema and a value schema. Each one has a set of fields that map to Solidity types.
+
+## Defining tables
+
+Let's say we're making a game where players can move around a map. The definition for a `Position` table might look something like:
+
+
+
+```tsx filename="mud.config.ts" {3-11} showLineNumbers
+export default mudConfig({
+ tables: {
+ Position: {
+ keySchema: {
+ player: "address",
+ },
+ valueSchema: {
+ x: "int32",
+ y: "int32",
+ },
+ },
+ },
+});
+```
+
+
+
+Translating the table definition above would look like this in a relational database:
+
+
+
+
+ player |
+ x |
+ y |
+
+
+
+
+ 0x1234 |
+ -5 |
+ 1 |
+
+
+ 0x5678 |
+ 3 |
+ 6 |
+
+
+
+
+Because `player` in part of the key schema, we would have a unique/primary key constraint on `player`.
+
+Let's add another table for terrain at a given position on the map. MUD allows for multiple keys in the key schema and, like databases, we call these composite keys.
+
+
+
+```tsx filename="mud.config.ts" {12-20} showLineNumbers
+export default mudConfig({
+ tables: {
+ Position: {
+ keySchema: {
+ player: "address",
+ },
+ valueSchema: {
+ x: "int32",
+ y: "int32",
+ },
+ },
+ Terrain: {
+ keySchema: {
+ x: "int32",
+ y: "int32",
+ },
+ valueSchema: {
+ terrainType: "string",
+ },
+ },
+ },
+});
+```
+
+
+
+Similarly, the relational database representation of that table would look like:
+
+
+
+
+ x |
+ y |
+ terrainType |
+
+
+
+
+ -1 |
+ 0 |
+ grass |
+
+
+ 0 |
+ 1 |
+ tree |
+
+
+ 1 |
+ 0 |
+ grass |
+
+
+
+
+Because we have a composite key of `x` and `y`, we would have a unique/primary key constraint on the tuple of `(x, y)`.
+
+## Tables on chain
+
+Solidity and the EVM have much more limited data structures, so how can we express a relational database onchain? MUD takes the concept of tables and does a few things with them:
+
+- [encodes each table record as a key/value pair](./encoding) before storing onchain
+- [emits an event for each mutation](/guides/replicating-onchain-state)
+- [provides a typed Solidity libraries](./table-libraries) to abstract this away
+
+## Field types
+
+Key schema fields can use all of Solidity's static-length primitive types like `uint256`, `address`, `bool`.
+
+Value schema fields can use all of Solidity's static-length primitive types, arrays of those static-length primitive types, as well as and `string` and `bytes`.
+
+Enums and user types are also supported and automatically map down to their Solidity primitive types.
+
+More complex types like structs, `string[]`, and `bytes[]` are not yet supported. We'll cover the reasons why in our encoding/decoding guide.
diff --git a/docs/pages/store/introduction.mdx b/docs/pages/store/introduction.mdx
index 56145e3cb6..efad032186 100644
--- a/docs/pages/store/introduction.mdx
+++ b/docs/pages/store/introduction.mdx
@@ -1,14 +1,13 @@
-import TableIntro from "./table-intro.mdx";
-
# Introduction
`Store` is an alternative to Solidity's storage engine.
-It enforces a data model that can be mapped directly to a relational database, enables [automatic indexing](../services/indexer) by emitting events on each storage operation, and [packs data more tightly](./encoding) than Solidity's storage engine.
+It enforces a data model that can be mapped directly to a relational database, enables [automatic indexing](../services/indexer) by emitting a common set of events for each mutation, and [packs data more tightly](./encoding) than native Solidity.
It also allows external contract storage to be read onchain without being limited by existing `view` functions and [without a new opcode](https://eips.ethereum.org/EIPS/eip-2330).
## Data model
-
+Each piece of data in `Store` is stored as a _record_ in a _table_.
+You can think of tables in two ways, either [as a relational database](./how-mud-models-data) or [as a key-value store](./tables).
## Reading and writing data
@@ -43,4 +42,4 @@ This allows advanced use cases like the [`World` protocol](../world/introduction
## Automatic indexing
`Store` automatically emits events on every write operation, including when a new table is registered in the `Store` at runtime.
-These events allow [automatic indexers](../services/indexer) to replicate the onchain state of each table in each `Store` contract in a relational database for offchain use, without the need for custom integrations.
+These events allow [automatic indexers](../services/indexer) to [replicate the onchain state](/guides/replicating-onchain-state) of each table in each `Store` contract in a relational database for offchain use, without the need for custom integrations.
diff --git a/docs/pages/store/table-intro.mdx b/docs/pages/store/table-intro.mdx
deleted file mode 100644
index 25a780b070..0000000000
--- a/docs/pages/store/table-intro.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
-Each piece of data in `Store` is stored as a _record_ in a _table_.
-You can think of tables in two ways, either as a relational database or as a key-value store.
-
-- Each table is identified by a unique `ResourceId tableId`.
-- Each record in a table is identified by a unique `bytes32[] keyTuple`.
- You can think of the key tuple as a composite key in a relational database, or as a nested mapping in a key-value store.
-- Each table has a `ValueSchema` that defines the types of data stored in the table.
- You can think of the value schema as the column types in a table in a relational database, or the type of structs stored in a key-value store.
diff --git a/docs/pages/store/tables.mdx b/docs/pages/store/tables.mdx
index d9f294d029..70db84ccf9 100644
--- a/docs/pages/store/tables.mdx
+++ b/docs/pages/store/tables.mdx
@@ -1,13 +1,19 @@
import { Callout } from "nextra/components";
-import TableIntro from "./table-intro.mdx";
# Tables
-
+Each piece of data in `Store` is stored as a _record_ in a _table_.
+You can think of tables in two ways, either [as a relational database](./how-mud-models-data) or as a key-value store.
+
+- Each table is identified by a unique `ResourceId tableId`.
+- Each record in a table is identified by a unique `bytes32[] keyTuple`.
+ You can think of the key tuple as a composite key in a relational database, or as a nested mapping in a key-value store.
+- Each table has a `ValueSchema` that defines the types of data stored in the table.
+ You can think of the value schema as the column types in a table in a relational database, or the type of structs stored in a key-value store.
Tables are registered in the `Store` contract at runtime.
When a table is registered, its ID, key and value types, as well as key and field names are stored in the internal `Tables` table.
-This emits an event that can be used by [offchain indexers](../services/indexer) to start replicating the state of the new table.
+This emits an event that can be used by [offchain indexers](../services/indexer) to start [replicating the state](/guides/replicating-onchain-state) of the new table.
The recommended way of reading from tables and writing to tables is via the [typed table libraries](./table-libraries).
However, it is also possible to use the low-level [`IStore` (external)](./reference/store) or [`StoreCore` (internal)](./reference/store-core) API directly.
@@ -18,7 +24,7 @@ There are two types of tables in `Store`: _Onchain tables_ and _offchain tables_
We often omit the prefix from onchain tables and just call them tables.
As the name suggests, **onchain tables** store their state onchain, in the `Store` contract.
-In addition, an event is emitted on every write operation, to allow [offchain indexers](../services/indexer) to replicate the onchain state.
+In addition, an event is emitted on every write operation, to allow [offchain indexers](../services/indexer) to [replicate the onchain state](/guides/replicating-onchain-state).
**Offchain tables** on the other hand don't store any state onchain, but only emit the events for [offchain indexers](../services/indexer).
This makes them suitable for use cases where data doesn't need to be retrieved onchain, but should still be synchronized from the `Store` contract to [offchain indexers](../services/indexer).
@@ -120,7 +126,7 @@ FieldLayout fieldLayout = FieldLayoutLib.encode({
### Manually register a table
-Registering a table is a prerequisite for writing to the table, and allows [offchain indexers](../services/indexer) to replicate the onchain state.
+Registering a table is a prerequisite for writing to the table, and allows [offchain indexers](../services/indexer) to [replicate the onchain state](/guides/replicating-onchain-state).
```solidity
import { IStore } from "@latticexyz/store/src/IStore.sol";
diff --git a/docs/pages/world/function-selectors.mdx b/docs/pages/world/function-selectors.mdx
index 8adb954fa5..9dc757e91c 100644
--- a/docs/pages/world/function-selectors.mdx
+++ b/docs/pages/world/function-selectors.mdx
@@ -21,7 +21,7 @@ This function takes two parameters:
This value encodes both the namespace and the name of the `System`.
- [The signature (name and parameter types)](https://docs.soliditylang.org/en/v0.8.22/abi-spec.html#function-selector) of the function within the `System`.
-For example, in the [Extending World guide](/guides/extending-world#deploy-to-the-blockchain) we create a namespace called `messaging`, within it a `System` called `message`, and that `System` includes a function called `incrementMessage`.
+For example, in the [Extending a World](/guides/extending-a-world#deploy-to-the-blockchain) guide we create a namespace called `messaging`, within it a `System` called `message`, and that `System` includes a function called `incrementMessage`.
This is the code we use to register the `System` and the function selector:
diff --git a/docs/pages/world/introduction.mdx b/docs/pages/world/introduction.mdx
index 0a8ae81feb..c07e975d9b 100644
--- a/docs/pages/world/introduction.mdx
+++ b/docs/pages/world/introduction.mdx
@@ -14,7 +14,7 @@ To prevent systems from being registered in the root namespace, the root namespa
`Systems` in a `World` are comparable to [`Facets` in the `Diamond` pattern](https://eips.ethereum.org/EIPS/eip-2535) in many ways.
The big difference is permissionless extensions.
-Anybody can claim an unused [namespace](/world/namespaces-access-control), and put into it tables and `System` contracts to [extend the world](/guides/extending-world).
+Anybody can claim an unused [namespace](/world/namespaces-access-control), and put into it tables and `System` contracts to [extend the world](/guides/extending-a-world).
![overall illustration](./world-intro.svg)
diff --git a/docs/tsconfig.json b/docs/tsconfig.json
index f96e49f43e..6c4ba7b499 100644
--- a/docs/tsconfig.json
+++ b/docs/tsconfig.json
@@ -1,11 +1,7 @@
{
"compilerOptions": {
- "target": "es5",
- "lib": [
- "dom",
- "dom.iterable",
- "esnext"
- ],
+ "target": "es2020",
+ "lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
@@ -25,14 +21,6 @@
],
"strictNullChecks": true
},
- "include": [
- "next-env.d.ts",
- "**/*.ts",
- "**/*.tsx",
- "pages/_meta.js",
- ".next/types/**/*.ts"
- ],
- "exclude": [
- "node_modules"
- ]
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "pages/_meta.js", ".next/types/**/*.ts"],
+ "exclude": ["node_modules"]
}