Draw images as a paint fill, like a gradient: build a handle, pass it to
render.paint():image(handle, x, y, w, h), then draw any shape with that paint.
(x, y, w, h) maps the image in canvas space; the shape clips it.
local logo = image.url("https://http.cat/200.jpg") -- loads asynchronously
module:event("render_2d", function(render)
if not logo:ready() then return end
render.rect(8, 8, 96, 96, render.paint():image(logo, 8, 8, 96, 96), 12)
end)Loaders
| Loader | Image |
|---|---|
image.file(path) |
PNG/JPEG next to your scripts |
image.url(url) |
PNG/JPEG from the web |
image.identifier(id[, smooth]) |
Minecraft texture ("minecraft:textures/block/dirt.png"); nearest by default, smooth = true for linear |
image.head(source[, overlay]) |
Player head (face + hat); source is a player entity or name/uuid |
image.item(source) |
Item GUI render; source is an item handle or id string |
file and url load asynchronously; head/item bake on the GPU. A fresh handle may
draw nothing for a frame or two — guard with handle:ready() or skip empty frames.
Handles are cheap to build at top level and safe to reuse.
Handle methods
| Method | What it does |
|---|---|
handle:ready() |
true once the image can draw |
handle:width() |
Native pixel width (0 until ready) |
handle:height() |
Native pixel height (0 until ready) |
While an image is set, the paint’s color is ignored but its alpha still fades the
image — render.paint(0x80FFFFFF):image(...) draws at half opacity. tile (6th
argument, default "clamp") repeats the image outside its rectangle.
local head = image.head(target) -- player entity or name
local sword = image.item("minecraft:netherite_sword")
module:event("render_2d", function(render)
render.rect(8, 8, 32, 32, render.paint():image(head, 8, 8, 32, 32), 6)
render.rect(48, 8, 24, 24, render.paint():image(sword, 48, 8, 24, 24))
end)Transforms, clips and save_layer_alpha apply to image fills. Image-filled text works
the same as gradient-filled text — draws nothing until ready(), but still returns the
correct measured width.