A modular onchain game framework for Base.
Agents — human or AI — are first-class players.
contracts (Foundry) → server (Python) → client (TypeScript)
deploy in an afternoon add bots + sync add gasless intents
Each layer is independent. Use one, two, or all three.
Getting Started · Architecture · Contracts · Server · Client
Onchain game frameworks are either too heavy — MUD, Dojo require custom indexers, schema DSLs, and steep learning curves — or too thin — web2 servers with an NFT mint bolted on, no onchain logic, no composability.
Trellis sits between. Five contracts, a Python server, and a TypeScript client.
| Agents are first-class | ERC-721 entities that own assets and execute onchain via session keys. The contract doesn't know if a player is human or AI. |
| Progressive adoption | Start with just contracts. Add a server for bots and fast sync. Add the client SDK for gasless intents. Each layer is optional. |
| Onchain NPCs | NPCs with wallets, not server-side simulations. They own territory, trade resources, and persist whether your server is running or not. |
| One signature, zero gas | Players sign once per session. Server executes via session keys. Paymaster sponsors gas. No wallet popups during gameplay. |
┌──────────────────────────────────────────────────────────┐
│ TrellisWorld / TrellisAgentWorld │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ System Router (delegatecall dispatch) │ │
│ │ Session Key Registry + Budget Tracking │ │
│ │ ERC-7201 Namespaced Storage (Trellis + Game) │ │
│ │ ERC-721 Agents (optional) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ delegatecall (shared storage) │
│ │ │
│ ┌────────┬───────────┼───────────┬────────────┐ │
│ ▼ ▼ ▼ ▼ ▼ │
│ Your Your Your Your Your │
│ Mint Battle Reward Build Trade │
│ System System System System System │
│ │
│ Systems are yours. Trellis provides the dispatch. │
└────────────────────────┬─────────────────────────────────┘
│ events
┌──────────┼──────────┐
▼ ▼ ▼
SyncServer Client AgentRunner
(Python) (browser) (Python bots)
| MUD | Dojo | Trellis | |
|---|---|---|---|
| Assumption | All state onchain | All state onchain | Progressive layers |
| Language | Solidity + MUD DSL | Cairo | Solidity + Python + TypeScript |
| Chain | Any EVM | Starknet | Base |
| Infra required | Indexer, codegen, dev server | Katana, Torii | None — Foundry + viem |
| Contract weight | ~20 contracts | ~15 contracts | ~5 contracts |
| NPC/bot support | Not built-in | Not built-in | First-class |
| Learning curve | Steep (MUD-specific) | Steep (Cairo) | Low (standard tools) |
| Best for | Autonomous worlds | Starknet games | Agent-native games on Base |
forge install 0x-zer0/trellis-framework --no-gitAdd to remappings.txt:
@trellis/=lib/trellis-framework/packages/contracts/src/
contract BattleSystem is SystemBase {
function battle(uint256 attackerId, uint256 targetId) external onlyTrusted {
address caller = _trustedCaller();
uint256 agent = _trustedAgent();
// your game logic — shared storage via delegatecall
}
}forge script script/Deploy.s.sol --rpc-url $BASE_SEPOLIA_RPC --broadcastSee the full Getting Started guide for a complete walkthrough.
@trellis/contracts — Solidity
The onchain layer. System dispatch, session keys, lazy evaluation.
| Contract | Purpose |
|---|---|
TrellisWorld |
System router + execute() — for games without NFT agents |
TrellisAgentWorld |
Extends TrellisWorld + ERC-721 + session keys + budgets |
TrellisStorage |
ERC-7201 namespaced storage — zero collision with game state |
SystemBase |
Trusted caller context via transient storage (tstore/tload) |
KeeperMulticall |
Batch execution wrapper for keepers and bots |
LazyMath |
Rate × elapsed helpers for idle mechanics |
EntityLib |
Entity type + ID packing into uint256 |
Your game adds its own ERC-7201 storage namespace and system contracts. Trellis provides the dispatch.
trellis-server — Python
The offchain layer. Event indexing, WebSocket sync, bot runner, intent processing.
pip install trellis-serverserver = SyncServer(rpc_url=..., contract_address=..., abi=ABI, events={...})
runner = AgentRunner(decisions={"fighter": decide_fighter}, tick_interval=15)
server.embed(runner)
server.run(port=8765)Run sync and bots together or independently. Server docs →
@trellis/client — TypeScript
The browser layer. WebSocket state sync, intent sending, session key management.
npm install @trellis/clientconst sync = new SyncClient({ wsUrl: 'ws://localhost:8765' })
sync.on('stateChange', (state) => renderGame(state))No renderer opinions. Plug into React, Phaser, PixiJS, Three.js, or vanilla JS. Client docs →
| Guide | Description |
|---|---|
| Getting Started | Deploy a game in 30 minutes |
| Architecture | Progressive layers, storage model, system dispatch |
| Contracts | TrellisWorld, TrellisAgentWorld, SystemBase, storage |
| Server | SyncServer, AgentRunner, deployment modes |
| Client | SyncClient, IntentClient, SessionManager |
| Onchain NPCs | NPCs as real onchain entities with wallets |
| Session Keys | Patterns, budget/epoch mechanics, trade-offs |
| Gas Budget | Base L2 cost estimates per game type |
Contributions welcome. Please open an issue to discuss before submitting a PR.