# 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**:

```ts
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
- **[Rich Media: p5.js & three.js](../concepts/rich-media-p5-three.md)** · **[Building a 3D Scene](./building-a-scene.md)** ·
  **[The Floor](../concepts/the-floor.md)**
