<!-- https://minecraftdocs.dev/systems/rendering/ — this page as markdown. The book's index: https://minecraftdocs.dev/llms.txt; the whole book in one file: https://minecraftdocs.dev/llms-full.txt -->

# XI · Rendering

> Verified against **Minecraft 26.3** · Part XI · One thread, a hundred-odd times a second, turning a world nobody can see into a picture — and two layers of machinery underneath that never touch the world at all.

**The renderer is not allowed to look at the world.** A frame is one call to
[`Minecraft.renderFrame`](the-frame), on the same thread that ticked the
world a moment earlier, and it runs twice over: once to *copy* the live game
into a pile of value objects, and once to draw those objects with the live
game held at arm's length. Everything in this part is either that wall, or
something feeding it, or something on the far side of it working from a copy.
And the claim the part makes is that **nothing you see on screen is the
world; it is a copy of the world, and every seam a player notices is two
copies disagreeing**. A mob pins in place under `/tick freeze` while the item
in your hand keeps swaying, because each was copied at a partial tick of its own. A
chest's lid stops and the chest in your hand does not, for the same reason
one step further out. And terrain fills in outward as you fly because the
copy that decides what is *visible* can only reach as far as the copies that
already exist — which is the same disagreement again, now between the world
and the meshes that stand in for it.

Besides the renderer's own per-tick half, three things escape the frame, and
each of them is a page: particles are stepped from the [*tick*](particles),
most sections are meshed on [a background pool](section-meshing), and the atlases are built by [a resource
reload](models-and-atlases) and animated before each frame.

It is also the largest thing on the client. `client/renderer`,
`client/model`, `client/particle`, `com/mojang/blaze3d` and
`com/mojang/renderpearl` together come to
**1,291 files and 98,283 lines** — counted the way [the atlas](../../maps/README) counts a part, leaving out the hatched packages — against 358 files and 48,834 lines for `net/minecraft/server` counted the same way. `net/minecraft/server` has a little over a quarter as many files as the client's renderer, and about half its lines.

## The shape of the part

Part XI is **a substrate under a pipeline**. Two of its pages — the window
and Blaze3D — are what the renderer stands on: neither has a trace through
the world, and Blaze3D is cited far more than it cites. The rest is a
pipeline. [The frame](the-frame) opens the part ahead of the substrate it
stands on, because it is the shortest way to see the whole shape at once and
because a reader who has watched one frame end to end has a reason to care
what a `GpuDevice` is.

```mermaid
flowchart TD
    FRAME["1 · The frame"]
    subgraph SUB["the substrate"]
        WIN["2 · The window"]
        B3D["3 · Blaze3D"]
    end
    subgraph PIPE["the pipeline"]
        VIS["4 · Visibility and the frame graph"]
        MESH["5 · Section meshing"]
        MOD["6 · Models and atlases"]
        ENT["7 · Entity rendering"]
        BEN["8 · Block-entity rendering"]
        SKY["9 · Lightmap, fog and sky"]
        PART["10 · Particles"]
        POST["11 · Post-processing"]
        VIS --> MESH --> MOD --> ENT --> BEN --> SKY --> PART --> POST
    end
    FRAME --> SUB --> PIPE
```

*The part as a substrate and a pipeline, numbered to the watch order, the
frame first: an arrow is the next lecture, which is not the order a frame runs
in.*

The arrows in that figure are **the order to watch in**, which is not the
order a frame runs in. Visibility hands section meshing the sections to
compile, and a frame's terrain is drawn from meshes an earlier frame made, so
the fourth and fifth lectures feed each other. Inside a frame the order is
different — the sky pass is declared before the main one, the
lightmap is built before the world is drawn at all, and [one of the five post
chains runs as passes of the world's own graph while the other four build one
and throw it away](post-processing#two-doors-into-the-gpu-and-one-of-them-is-deprecated).

## Before you start

[The client loop](../client/the-client-loop) from Part X, and not
optionally: it is the page that says *when* a frame happens and how many
ticks ran before it, and this part begins exactly where that page's *frame*
zone opens. It is one of the two longest pages in Part X, so budget for it.

[The resource system](../foundations/resource-system) from Part II before
[models and atlases](models-and-atlases), which is a reload listener and
leans on the barrier semantics taught there rather than restating them.

[Environment attributes and timelines](../world/environment-attributes-and-timelines)
from Part IV before [lightmap, fog and sky](lightmap-fog-and-sky). Part IV
owns that system; Part XI is one of its client-side consumers and does not
re-teach it.

[The client level](../client/the-client-level), for what the thing being drawn is — a `Level` with its authority removed — and for the two
ways `LevelExtractor` is reached, pushed and pulled.

## Watch in this order

1. [The frame](the-frame) — one method, two halves, and a wall between
   them. Fifteen profiler zones, six clocks disagreeing on purpose, and a failed
   surface acquisition that costs you the picture but not the work.
2. [The window](the-window) — the substrate nothing else admits to
   needing. A retry loop that settles the graphics backend before the window
   exists, nineteen kinds of window event and the six the game is never told
   about, and `NativeImage`, the seam between a file and a texture.
3. [Blaze3D](blaze3d) — the game's own graphics API, and the part's
   vocabulary page. Four validating façades over two real backends, one of
   which is Vulkan and is the larger of the two.
4. [Visibility and the frame graph](visibility-and-the-frame-graph) — what
   the frame decides to draw, and in what order. A reachability walk whose
   asymmetry — uncompiled sections stop it, empty ones do not — is why
   terrain reveals itself outward.
5. [Section meshing](section-meshing) — where the triangles came from. A
   block is placed, a halo of positions goes dirty, the sections it touches are
   rebuilt from a snapshot — by default inline for your own block, on a worker
   for the server's —
   and the new mesh swaps in all at once.
6. [Models and atlases](models-and-atlases) — the reload pipeline behind
   block, item and particle quads. Twelve atlases stitched in parallel, one barrier, and a
   quad whose chunk layer is read out of its sprite's pixels.
7. [Entity rendering](entity-rendering) — every entity in the world, in
   four stages, none of which is called *render*. The zombie
   is animated at least twice per frame.
8. [Block-entity rendering](block-entity-rendering) — the same four
   stages with three differences that show. A chest's block model is empty,
   a block entity is never frustum-tested on its own, and
   the chest in your hand is drawn by a different renderer at a different
   partial tick.
9. [Lightmap, fog and sky](lightmap-fog-and-sky) — what colour all of it
   is. One question asked by four of the five renderers, most of which no
   longer know what time it is.
10. [Particles](particles) — the part's policy page: three distance rules
    for a particle or a level event, enforced in three places and three readers of one setting who disagree
    about what its values mean, with a break puff that answers to almost
    none of them.
11. [Post-processing](post-processing) — the closer. Five JSON-declared
    shader chains, which is how the pause-menu blur and the creeper
    spectator shader turn out to be the same machine — and a resource pack
   can rewrite all five and add its own.

Four and five are a pair — one journey seen from its two ends — and so are
seven and eight, the second of which is written as the differences from the
first. One to three can be watched in order or in the order one, three, two;
the window is the page a viewer is most likely to skip and least likely to
regret.

## Where the part stops

What draws *over* the world rather than in it — screens, the HUD, the render
tree they record into and the text inside them — is Part X, from [the GUI
render tree](../client/the-gui-render-tree) onward; what the server chose
to tell this client is Part IX. The packages themselves cross the boundary in
both directions: the GUI's render states and the debug renderers under `client/renderer`
count against Part XI while being Part X's subjects, and `client/resources/model`
counts against Part X while being the subject of [models and
atlases](models-and-atlases).

Everything else left out is the families — one class per mob model, one per
renderer, one per particle, one file per GL or Vulkan call site — which is
why **41% of the part's lines are named on no page in the book**, the second-highest
figure in the book after Part V's. Teaching each family's shape and declining its
instances leaves a great many lines untouched, and that is the trade, made on
purpose.

## Reference this part uses

[Submit phases and feature renderers](../../reference/submit-phases) is
the catalogue behind [entity rendering](entity-rendering) and
[block-entity rendering](block-entity-rendering): the fifteen phases a
submitted feature can land in, and the twelve renderers that write the
vertices. [The threads](../../reference/threads) for the two that matter
here — the Render thread most of the part runs on, and the background pool that
meshes sections — and [diagram lanes](../../reference/lanes) for the
abbreviations the figures use. [Naming drift](../../reference/naming-drift)
is worth having open throughout: the world-facing half of the
old `LevelRenderer` is now `LevelExtractor`, and many of the names a 1.21-era
reader reaches for moved with it. [The
glossary](../../reference/glossary) for *extract*, *render state*, *frame
graph*, *partial tick*, *atlas*, *special model renderer* and *built-in block
model*.

---

*Rules: names, never code · how the system works, not how the code reads ·
newest version only · every backticked name passes `tools/verify_names.py`.*
