Repository navigation
API Model Appearances
Lua API / Model appearances
Add appearance to a block, item, or entity declaration to configure its model presentation. Gameplay properties, collision, and selection use their existing fields.
local appearance = {
model = "mymod:item/robot", texture = "mymod:item/robot",
display = {
gui = { scale = 0.8, rotation = { x = 0, y = 15, z = 0 } },
held = { position = { x = 0, y = 2, z = 0 } }
}
}| Field | Meaning |
|---|---|
model |
Required model reference, registered key, or relative geometry path. |
texture |
Texture reference/key/path for the default material slot. |
material |
Settings for the default slot; its texture can come from appearance.texture. |
materials |
Table of explicit material settings indexed by exported material_instance name. Every used slot must be bound. |
position |
Model-unit offset {x,y,z}, default zero. |
rotation |
Degrees {x,y,z}, default zero. |
scale |
Nonnegative uniform number (0–1024) or {x,y,z} factors; default 1. |
display |
Optional transforms for gui, held, ground, block, and entity; each accepts position, rotation, and scale. |
animation |
{asset=animationRefOrKeyOrPath, clip=exactName, speed=1}; speed is 0–100. Entity instances can select another clip at runtime. |
onPose |
Function receiving a pose context; {action=function(ctx) ... end} is also accepted. |
mode |
"auto" (default) or "dynamic"; forces per-instance block presentation when dynamic. |
layers |
Up to seven additional model appearance tables. Layers require their own model/material bindings and can have their own clips/callbacks. They inherit the outer appearance transform. Nested layer lists are unsupported. |
Base transforms apply before the context-specific transform. In block context the origin is at the block's bottom center; 16 model units equal one block. Inventory, held, and dropped contexts have default display transforms, adjustable through display.
Set render.variants[metadata].appearance to a complete appearance table. Omit it to inherit the top-level appearance, or set it to false to use ordinary block textures or an item icon. Without either appearance, ordinary rendering applies. Variant appearances replace the default; nested fields are not merged. Reuse Lua tables for shared definitions.
local idle = { model = "mymod:block/machine", texture = "mymod:block/machine_idle" }
local running = {
model = "mymod:block/machine", texture = "mymod:block/machine_active",
animation = { asset = "mymod:block/machine", clip = "animation.machine.running" }
}
-- Fields inside a block or item declaration:
local visuals = {
appearance = idle,
render = { variants = {
[1] = { appearance = running },
[2] = { appearance = false }
} }
}Keys are block metadata 0–15 or item damage/metadata 0–32767. The selected model applies in world, inventory, held, and dropped contexts as appropriate. Texture/icon/color fields outside appearance apply to ordinary rendering; model materials use their own textures and tint.
The Facing Stair Display uses four metadata appearances to rotate one model.
If the default appearance or any variant has a model clip animation, onPose, dynamic layer, or mode="dynamic", every state of that block type renders dynamically, including states using ordinary textures. Otherwise, all states use static chunk rendering. Animated textures change material pixels without making the geometry dynamic. Static model materials require opaque/cutout blending and opacity 1; use dynamic mode for transparent models. Dynamic block appearances currently draw within 64 blocks of the camera.
render.preset, render.bounds, and ordinary texture variants remain available for states without a model. Appearance models use their own geometry and transforms. Set collision, selection, opaque, normalCube, and light blocking through the existing block fields; appearances do not change gameplay properties or add world tile entities.
Light blocking is a separate gameplay property. Set the block's lightOpacity=0 for
an open model that should let world light pass through; changing its model or material
does not automatically change light blocking.
local appearance = {
model = "mymod:item/robot", texture = "mymod:item/robot",
layers = {
{
model = "mymod:item/robot", texture = "mymod/textures/robot_glow.png",
material = { blend = "additive", lighting = "unlit", opacity = 0.6 }
}
}
}| Field | Supported values / default |
|---|---|
texture |
Texture reference/key/path; required unless the default slot uses appearance.texture. |
blend |
"opaque", "cutout" (default), "alpha", or "additive". Cutout uses alpha threshold 0.1. |
lighting |
"world" (default) or "unlit". Unlit appearance does not emit world light. |
cull |
Hide back faces when true; default false. Zero-thickness planes keep their separately exported front/back faces directional. |
tint |
Integer RGB color 0x000000–0xFFFFFF; default white. |
opacity |
0–1; default 1. |
uv |
{u=0,v=0,scaleU=1,scaleV=1} in normalized texture coordinates; values within ±10,000. |
Solid/cutout layers render before transparent layers. Transparent layers follow declaration/material order; overlapping transparent geometry can show ordering artifacts. Prefer cutout for sharp transparent edges and additive for simple glow overlays.
For a block using this layered appearance, add mode="dynamic" to the outer table.
onPose(ctx) runs after the automatic clip and receives:
| Value | Meaning |
|---|---|
ctx.pose |
Pose operations; expires when this callback returns. |
ctx.state.ageTicks |
Interpolated time: holder age for held items, dropped-item age for ground items, world time for blocks/GUI, or zero in a GUI without a world. |
ctx.state.display |
"gui", "held", "ground", "block", or "entity". |
ctx.state.metadata |
Block metadata or item damage/metadata. |
ctx.state.x/y/z |
World position, or zero in GUI context. |
State is copied presentation input. Mutating its table cannot change gameplay. Use the provided time; callback frequency depends on rendering and visibility. Every evaluation starts at rest, then applies the automatic clip, then calls Lua. A callback error disables that callback and reports the owning script. A rendering error suspends that appearance until an asset refresh.
The Clockwork Bird model item combines an exported clip with onPose. The Animated Machine adds state variants, material slots, and a glow layer.
Appearance declarations require the BetaMoon Java agent. Asset declarations and pose inspection are available independently of rendering. Appearance changes support hot reload, including static-to-dynamic and dynamic-to-static changes. Reload rebuilds visual data without replacing placed blocks or changing metadata, Lua tile data, or inventories. Other declaration changes follow the existing reload rules.
betamoon.assets:refresh() updates compatible models, clips, and textures. Block visuals update after refresh. Model replacements must preserve bundled part/locator names and cannot introduce unbound material slots. Animation replacements retain bundled clip names and cannot add new bone requirements to those clips. Geometry and clips used together are validated together; incompatible combinations try their bundled files together. If replacements remain unusable, the previous complete appearance stays active. Warnings explain when a consumer needs grouped fallback; an individual asset's source inspection describes that asset's selection.
- Installation
- Install scripts
- Getting started
- VS Code and LuaLS
- Examples
- Reload and compatibility
- Troubleshooting
- Changelog
Scripts and shared values
- Script lifecycle
- Packaged Lua mods
- Modules
- References and stacks
- Queries
- Overrides
- Minecraft constants
- Chat and positions
- Structured data
- Script configuration
- Particles
Blocks and items
- Multiblocks
- Blocks
- Block state and placement
- Block shapes and rendering
- Block callbacks
- Block ticks and redstone
- Items
- Fluids
- Item callbacks
- Tools and armor
- Materials
- Textures
Entities
- Entities
- Entity access and movement
- Entity lifecycle and data
- Entity health and loot
- Entity inventories and relationships
- Projectiles and pickups
- Entity presentation and sounds
- Living entities and AI
- Entity parts and sensors
Assets and audio
- Assets
- Models and animations
- Built-in Minecraft models
- Model appearances
- Blockbench workflow
- Audio
- Texture-pack overrides
Events and world actions
World generation
World systems
Inventories and screens
Recipes