The Render Pipeline
What actually happens when an app renders, start to finish.
The path
renderHash(hash)
→ the registry reads the app's bytes (stored on-chain via SSTORE2)
→ the interpreter walks the byte-encoded component tree
→ for each node: emit its HTML/SVG from the closed vocabulary
→ for each data slot: call the bound resolver (a view call) and inline the result (escaped)
→ for each image slot: resolve on-chain media (or fall back to a poster floor)
→ return the assembled HTML string
Every step is a view — no state changes, no gas, fully reproducible.
Key properties
- Deterministic. The same hash always yields the same output. This is what content addressing guarantees.
- Fail-closed. A reverting resolver, a missing source, a gas-bomb, or an unknown node never breaks the render — it degrades to an honest fallback ("unavailable", an axes-only chart, a poster image). An app can't be made to render a lie by a failing dependency.
- Escaped by construction. Any value a resolver returns is re-escaped before it enters the output — a resolver can never inject markup. Safety isn't a runtime check you might forget; it's structural.
- Paginated when large. Big outputs (an atlas, a long table) support chunked reads that concatenate byte-identically to the whole — so even large apps stay within call limits.
Two render entry points
renderHash(hash)— the plain render; baked defaults.renderHashWithContext(hash, ctx)— the same app with a presentation context (theme, palette, chart dimensions) applied at render time. Same app, same hash, different appearance — zero gas, no redeploy. See Presentation & Theming.
Related
- Resolvers & Data Binding — where live data comes from.
- The Trust Grade — how the pipeline's dependencies are graded.