Image
ImageRenderable loads PNG, JPEG, WebP, GIF, or encoded bytes into a native image and renders it with Kitty graphics, Sixel, or a Unicode block fallback.
Renderable API
import { ImageRenderable, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const image = new ImageRenderable(renderer, {
id: "cover",
source: "./cover.webp",
width: 40,
height: 15,
fit: "cover",
protocol: "auto",
onError: console.error,
})
renderer.root.add(image)
await image.loadPromise
source accepts a path, file:/HTTP(S)/blob:/data: URL, URL, Blob, Response, Uint8Array, or ArrayBuffer. Format detection uses the encoded bytes. See Native images for formats, decoding, pixel access, and limits.
React
import { createCliRenderer } from "@opentui/core"
import { createRoot } from "@opentui/react"
const renderer = await createCliRenderer()
createRoot(renderer).render(
<image source="./cover.webp" fit="cover" protocol="auto" style={{ width: 40, height: 15 }} />,
)
Solid
import { createCliRenderer } from "@opentui/core"
import { render } from "@opentui/solid"
const renderer = await createCliRenderer()
await render(
() => <image source="./cover.webp" fit="cover" protocol="auto" style={{ width: 40, height: 15 }} />,
renderer,
)
The source, callbacks, fit, and protocol props can be updated after construction. Replacing source keeps the current image visible until the replacement succeeds, cancels obsolete loading, and disposes stale native images. Setting source to undefined clears it; clearing fit or protocol restores "fit" or "auto".
Sizing
fit |
Behavior |
|---|---|
fit |
Contain and center the full image; preserve aspect (default) |
cover |
Fill the renderable, preserve aspect ratio, and center-crop |
fill |
Fill the renderable and allow stretching |
Sizing uses terminal pixel resolution when available and a 2:1 cell-height fallback otherwise. During startup and resize, Sixel images temporarily use blocks until current pixel geometry arrives.
Rendering protocol
protocol |
Behavior |
|---|---|
auto |
Global override, then Kitty, then Sixel, then Unicode blocks |
kitty |
Force Kitty graphics |
sixel |
Force Sixel; falls back to blocks without terminal pixel resolution |
blocks |
Portable Unicode quadrant-block rendering |
With global and per-image protocols set to auto, tmux uses blocks. Explicit Kitty, or Sixel with pixel resolution, uses tmux passthrough.
Overlapping images must use the same effective protocol. Layering and alpha composition across different effective protocols are not supported; leave overlapping images on auto or give them the same explicit protocol. Non-overlapping images may use different protocols.
Kitty preserves image alpha, Sixel treats alpha below 128 as transparent, and blocks blend sampled alpha. Placement opacity scales Kitty and block alpha; Sixel dims toward cell backgrounds. Direct, unbuffered fills, text, and box borders cover images at whole-cell granularity without blending.
Use OPENTUI_IMAGE_PROTOCOL=auto|kitty|sixel|blocks to set the global default. OPENTUI_GRAPHICS=false disables Kitty and Sixel detection. See Environment variables.
Split-footer scrollback snapshots follow the same protocol resolution as live images: Kitty placement, Sixel with detected pixel geometry, or Unicode quadrant blocks. Snapshots containing mixed effective protocols, overlapping images, or covered Sixel image cells use blocks. Native scrollback placement starts once the footer is pinned and the image rectangle is addressable. Await loadPromise before rendering an image into a ScrollbackSurface; see Writing to scrollback.
resolveImageRenderProtocol(requested, capabilities, hasResolution) exposes the same protocol-resolution policy for code that needs it without constructing a renderable.
Options and state
| Member | Type | Description |
|---|---|---|
source |
ImageSource |
Image source; optional |
fit |
"fit" | "cover" | "fill" |
Destination sizing |
protocol |
"auto" | "kitty" | "sixel" | "blocks" |
Requested rendering protocol |
onLoad |
(image: NativeImage) => void |
Called after the current source loads |
onError |
(error: unknown) => void |
Called when the current source fails |
image |
NativeImage | null |
Currently displayed renderable-owned image |
loading |
boolean |
Whether the current source is loading |
loadError |
unknown |
Current load error, otherwise null |
loadPromise |
Promise<void> | null |
Settles after the current load attempt |
effectiveProtocol |
kitty | sixel | blocks |
Current resolved protocol; may change with capabilities or size |
cellAspectRatio |
number |
Physical or fallback cell aspect ratio |
getFittedSize(...) |
(width, height, cellAspect?, sourceWidth?, sourceHeight?) |
Resolve destination cells; omitted overrides use current values |
The renderable owns image and the NativeImage passed to onLoad; do not dispose or transfer them. Current-source failures set loadError, call onError, and resolve loadPromise. Superseded, cleared, or destroyed loads resolve without callbacks. Exceptions from either callback reject after state settles. Successful replacement, clearing, and destruction release owned images; failed replacement keeps the current image.