⚠️ Alpha · testnets only. ChainRender is in active alpha and deployed on testnets only — Ethereum Sepolia, the Robinhood Chain Testnet, and the Circle Arc Testnet — not on any mainnet. Contracts, addresses, and APIs may change. Do not use with real funds or production assets.
Guides

Example: On-Chain Tetris (rich media)

A complete, playable Tetris — the game code and the p5.js library live on-chain (content-addressed), and the play runs client-side over an on-chain poster floor. It's a real example of ChainRender's rich-media capability, and an honest one about where the trust boundary sits.

What "on-chain" means here (honest)

ChainRender is deliberately declarative and analyzable — there is no arbitrary-code escape hatch, which is what makes trust-grading possible. A real-time arcade game (60fps, keyboard input, mutable state) inherently runs client-side. So Tetris is built as a rich-media enhancement over an on-chain floor:

  • On-chain: the p5.js library (in the DependencyRegistry, by content hash) + the Tetris sketch (as a SourceStore entry) + the seed. Nothing is fetched from a CDN or server at play time in production.
  • Client-side: the actual play (the game loop, input, rendering) runs in the viewer, over an on-chain poster floor that shows "Tetris" on any client, even without p5.
  • Grade ⚙️ (enhancement over a Grade-A floor) — not "fully on-chain trustless." The code is on-chain; the play is a client enhancement. That distinction is stated honestly, per ChainRender's core value that marketing never exceeds what the code guarantees.

If you wanted a trustless Tetris (Grade A), that's a different design: move-by-move, each move a transaction, the board validated in a contract — turn-based, not arcade. This example is the playable one.

Determinism from the seed

The piece sequence derives from the on-chain seed (a bytes32) via a seeded PRNG — so the same seed always produces the same game. Two players with the same seed get the same pieces (useful for fair competitions or verifiable runs).

How it's wired

It's a standard ChainRender p5 scene binding:

import { encodeSceneBinding } from "@chainrender/client";

const tetris = encodeSceneBinding({
  kind: "p5",
  libHash: "0x…",     // DependencyRegistry content hash of the on-chain p5 library
  seed:    "0x…",     // bytes32 — the deterministic piece sequence
  entry:   "tetris",  // SourceStore id of the on-chain sketch (or inlined source)
});
// bind it to an image node with a poster floor; the viewer loads the lib + sketch and runs it, fail-closed.

The viewer reads the binding, loads the library and sketch from chain, and runs the sketch sandboxed over the poster floor — failing closed to the poster if p5 can't run.

Controls

← → move · ↑ rotate · ↓ soft drop · space hard drop · P pause · R restart.

Why this is a good example

It demonstrates the honest rich-media pattern end to end: real, fun, interactive content, stored on-chain, presented through ChainRender, with the trust boundary stated plainly (⚙️ enhancement over an on-chain floor). It's the template for any p5/three interactive piece — a generative-art minter, a physics toy, a data visualization you can drag.

Related