Block Texture Configuration
Configure block sprite sheets, positional variation, animation, auto-tiling, and fluid fill levels.
Block textures are the most involved texture format in the game: beyond simple sprite animation, they support random positional variants (e.g. a few slightly different grass tiles), animated block-states (e.g. a glow rock that changes appearance), auto-tiling against neighboring blocks (e.g. dirt/grass edges), and fluid fill-level variants. The block itself must already be registered in Block Configuration — texture loading looks it up by name and fails if it isn’t found.
File Location
Config file:
mods/<your-mod>/assets/textures/blocks/blocks.yaml
Texture images go in the same folder:
mods/<your-mod>/assets/textures/blocks/<name>.png
The file name must match the name field exactly (case-sensitive), with spaces kept as spaces in the file name.
Minimal Example
textures:
- name: my_block
sprites:
- name: my_block
frame-count: 1
variation-count: 1
This registers the texture for my_block (a block that must already exist in block-config.yaml) from my_block.png, as a single, non-animated, non-tiled 16×16px tile.
Full Field Reference
textures:
- name: my_block # Required. Must match a name already registered in block-config.yaml
texture-override: Creation:dirt # Optional. Redirect this entry's pixels onto another block (see below)
tiled: false # Optional. Auto-tile against neighboring blocks (see below). Default: false
fluid-variations: 0 # Optional. Number of fill-level variants for a fluid block. Default: 0
animation-phase-jitter: false # Optional. Desync animation timing per-position. Default: false
tiles-with: # Optional. Other block names this block tiles seamlessly with
- other_block
sprites: # Required. One or more variation entries (see below)
- name: my_block # Required. Variation name
frame-count: 1 # Required. Animation frames in this variation
variation-count: 1 # Required. Number of random positional sub-variants
frame-time-ms: 100 # Optional. Milliseconds per frame. Default: 100
block-state: 0 # Optional. Block-state index this variation maps to. Default: 0
loop: true # Optional. Loop the animation? Default: true
frame-durations-ms: # Optional. Per-frame timing override (see below)
- 100
| Field | Required | Description |
|---|---|---|
name | Yes | Must match a name already registered in block-config.yaml. |
texture-override | No | Full name of another block whose stored texture data this entry replaces, guarded by a variant-count check. See Overrides. |
override | No | Full name of another block this entry’s texture is bound to instead of name — an unguarded overwrite. See Overrides. Prefer texture-override. |
tiled | No | Enables auto-tiling (see Auto-Tiling). Default: false. |
fluid-variations | No | Number of fill-level frames for a fluid block (see Fluids). Default: 0. |
animation-phase-jitter | No | If true, each placed instance of this block animates on its own deterministic phase offset instead of all instances staying in lockstep. Default: false. |
tiles-with | No | Other block names (this mod’s or another’s) this block tiles seamlessly against. Tiling must be declared on both sides to take effect. |
sprites | Yes | One or more variation entries. At least one required. |
sprites[].name | Yes | Variation name (informational; not currently used to key anything at render time). |
sprites[].frame-count | Yes | Number of animation frames in this variation. 1 for a non-animated block. |
sprites[].variation-count | Yes | Number of random positional sub-variants sharing this animation (e.g. two slightly different-looking dirt tiles). Each placed instance of the block picks one at random. |
sprites[].frame-time-ms | No | Milliseconds per frame for uniform timing. Default: 100. |
sprites[].block-state | No | Which block-state this variation is used for (see Block States). Default: 0. |
sprites[].loop | No | true (default) repeats continuously; false plays a single pass after the block enters this state, then holds the last frame. The same loop boolean the UI button/icon animations use. |
sprites[].frame-durations-ms | No | Per-frame timing override. See Per-Frame Timing. |
Sprite Sheet Format (Non-Tiled)
For a non-tiled block, the sprite sheet is a grid of 16×16px tiles:
- Columns — frames, read left to right,
frame-countwide. - Rows — positional sub-variants, stacked top to bottom,
variation-counttall, in the order variations are declared.
A block with multiple sprites entries stacks each entry’s variation-count rows beneath the previous entry’s, in declaration order — e.g. red_glass (three variation-count: 1 entries, one per block-state) is three single rows stacked directly on top of each other, one per block-state.
Positional Variants
variation-count gives a block several random-looking sub-variants without needing separate block-states or scripting — each time the block is placed, one row is picked at random. This is how DIRT, GRASS, and snowy_grass get slight visual variety:
- name: grass
tiled: true
sprites:
- name: grass
frame-count: 1
variation-count: 2
tiles-with:
- dirt
- snowy_grass
Block States
A single block entry can define multiple sprites, each tagged with a different block-state index. This lets a block change its entire appearance (including its own animation) based on state, driven from Lua/script logic rather than being a fixed animation:
- name: glow_rock
animation-phase-jitter: true
sprites:
- name: glow_rock
frame-count: 3
variation-count: 1
block-state: 0
frame-durations-ms:
- count: 2
duration-ms: 450
- count: 1
duration-ms: 2000
- name: glow_rock_state_1
frame-count: 3
variation-count: 1
frame-time-ms: 300
block-state: 1
- name: glow_rock_state_2
frame-count: 3
variation-count: 1
frame-time-ms: 250
block-state: 2
loop: false
Each block-state value keys its own independent animation timing and frame count.
Per-Frame Timing
Same flat/batch frame-durations-ms format as Mob Texture Configuration, applied per-variation. If the total entries (after expanding batches) don’t equal frame-count exactly, the override is ignored and frame-time-ms is used for all frames instead.
Auto-Tiling
Setting tiled: true makes a block automatically pick a different edge/corner sprite based on which neighboring blocks it’s touching, so blocks like dirt and grass blend into each other without hard seams. The texture for a tiled block is a fixed-layout auto-tile atlas (multiple 16×16px tiles per frame, covering the corner/edge/interior combinations), rather than a single flat tile per frame.
Getting this pixel layout exactly right by hand is error-prone — the safest way to build a new tiled block texture is to start from an existing shipped tiled block’s PNG (e.g. DIRT.png, GRASS.png, snowy_grass.png, or the animated anim_dirt.png/water_8.png) as a template and edit the art in place, rather than constructing the tile layout from scratch.
Two blocks only tile seamlessly against each other if both list the other under tiles-with — it’s not automatic in one direction:
- name: dirt
tiled: true
sprites:
- name: dirt
frame-count: 1
variation-count: 2
tiles-with:
- grass
- snowy_grass
- stone
- anim_dirt
A block’s own id is always implicitly included in its own tile-friend set, so identical adjacent blocks always tile together without needing to self-reference.
Animated tiled blocks (like anim_dirt) work the same way — the auto-tile atlas is simply repeated once per animation frame.
Fluids
fluid-variations gives a fluid block a number of fill-level frames (e.g. a water block rendered fuller or emptier depending on how much fluid occupies that cell), combined with tiled: true for edge blending against solid ground:
- name: water
fluid-variations: 8
tiled: true
tiles-with:
- dirt
- stone
- grass
sprites:
- name: water_8
frame-count: 2
variation-count: 1
frame-time-ms: 500
Overrides
texture-override redirects this entry’s loaded pixel data and animation data onto another already-registered block’s texture slot, instead of the block named by name. This is how a mod can restyle an existing block (from any mod) without touching that block’s own files:
- name: my_dirt_reskin
texture-override: Creation:dirt
sprites:
- name: my_dirt_reskin
frame-count: 1
variation-count: 2
nameis still required (it locates your replacement PNG in your mod’s folder).- The target block (
texture-override’s value) must already have texture data loaded with at least as many positional variants as your replacement — if your replacement has fewer, the override is skipped. tiled,tiles-with,fluid-variations, and allspritesfields on this entry describe your replacement texture, not the original block’s.
There is also a lower-level override key. Where texture-override keeps this entry bound to its own name block and additionally stamps your pixels onto the target, override rebinds the whole entry to the target block: your PNG (still located by name) is written straight into the named block’s texture slot unconditionally — there is no variant-count guard, so it applies even when your replacement has fewer positional variants than the target (which can leave the target’s extra variants pointing at stale pixels). The override value must be an already-registered block, or the entry is skipped. Prefer texture-override for restyling another block; reach for override only when you specifically want the unguarded overwrite.
Complete Example
Based on the real shipped block textures:
textures:
- name: dirt
tiled: true
sprites:
- name: dirt
frame-count: 1
variation-count: 2
tiles-with:
- grass
- snowy_grass
- stone
- anim_dirt
- name: glow_rock
animation-phase-jitter: true
sprites:
- name: glow_rock
frame-count: 3
variation-count: 1
block-state: 0
frame-durations-ms:
- count: 2
duration-ms: 450
- count: 1
duration-ms: 2000
- name: glow_rock_state_1
frame-count: 3
variation-count: 1
frame-time-ms: 300
block-state: 1
- name: glow_rock_state_2
frame-count: 3
variation-count: 1
frame-time-ms: 250
block-state: 2
loop: false
- name: water
fluid-variations: 8
tiled: true
tiles-with:
- dirt
- stone
- grass
sprites:
- name: water_8
frame-count: 2
variation-count: 1
frame-time-ms: 500