---
title: "Images — image"
---

> Documentation Index
> Fetch the complete documentation index at: https://aesthetic-docs.pages.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Images — image

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.

```lua
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.

```lua
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.

Source: https://aesthetic-docs.pages.dev/image/index.md
