# Your First App

> **The one idea that matters:** a ChainRender app *is* a component compiled to bytes, registered on-chain, and
> rendered by an `eth_call` — the component IS the app. Do **not** fetch data with viem and hand-render it in React
> with ChainRender only printing a hash on the side; that is a conventional Web3 dashboard, not a ChainRender app.
> See **[Building Correctly](../concepts/building-correctly.md)**.



Build, grade, and understand a real component end-to-end.

## 1. Compose

```ts
import { compose } from "@chainrender/client";

const app = compose.box([
  compose.heading("My First On-Chain App"),
  compose.text("This UI lives entirely on-chain."),
  compose.button("Do it", { variant: "primary", action: { to: "0x…", sig: "act(uint256)", args: "$n" } }),
]);
```

You composed from the **vocabulary** — a closed set of primitives. You literally cannot express anything outside
it, which is what makes the next step meaningful.

## 2. Compile — get your app's identity

```ts
import { compileComponent } from "@chainrender/client";
const built = compileComponent(app);
console.log(built.hash); // 0x… — this IS your app, forever
```

The hash is content-addressed: it's the `keccak256` of your app's exact bytes. Change anything and the hash
changes. See **[Content Addressing](../concepts/content-addressing.md)**.

## 3. Grade — know your trust level before deploying

```ts
import { grade } from "@chainrender/client";
const g = grade(app);
console.log(g.letter, g.word); // "A" "Trustless"
```

Your app is grade A because it's fully on-chain with no external dependencies. If you'd added an off-chain image,
you'd see it drop to C — with an itemized reason. This grade equals what the chain computes (drift-locked). See
**[The Trust Grade](../concepts/trust-grade.md)**.

## 4. Register — pay gas once

Register the bytes to the `ComponentRegistry` (one transaction). After that, anyone renders your app for free,
forever, from any RPC.

## 5. Render — free, reproducible

```ts
import { renderComponent } from "@chainrender/client/runtime";
const html = await renderComponent({ rpc, router }, built.hash );
```

## What you learned

- Composition is constrained (safe by construction).
- The hash is the identity (immutable, verifiable).
- The grade discloses trust (honest, itemized).
- Rendering is a free, reproducible `eth_call`.

**Next:** **[Bind Live On-Chain Data](../guides/bind-data.md)** to make it show real chain state.
