UI 9-Slice Demo
apps/ui_nineslice_demo shows the retained UI drawing a textured 9-slice panel driven entirely from
data (engine PLM-139 / PLM-140, ADR 0038). Two panels of very different sizes reference the same image
by path, and a sidecar next to that image marks it nine_slice with a 24px border — so both frames keep the
same crisp corners while their edges and centers stretch to fit.
What it demonstrates
Section titled “What it demonstrates”- Image by path — each frame is a
type = "panel"withimage = "textures/panel.png"(a mounted PNG), not a bare integertexturehandle. The engine resolves the path to a texture on the first render, through the PhysicsFS sandbox. - A
.ui.componentsidecar —textures/panel.png.ui.componentsits next to the PNG and carries the slicing metadata (nine_slice = true,border = [24, 24, 24, 24]), authored once with the asset. Both.uielements pick it up automatically just by referencing the image. - 9-slice scaling — a small frame (160×120) and a large frame (500×400) share that one image. The four corners stay their fixed pixel size; the edges stretch on one axis and the center stretches both. Compare the two frames: the rounded corners are identical, only the middle grows.
The document
Section titled “The document”The layout lives in apps/ui_nineslice_demo/ui/main.ui: a full-window background panel plus two child
panels — frameSmall and frameLarge — that each set image = "textures/panel.png". Neither .ui
element repeats the border; the sidecar supplies it. See the
Ui API for the full field reference.
# textures/panel.png.ui.component — slicing authored once, with the image.nine_slice = trueborder = [24, 24, 24, 24] # L, R, T, B in texture pixels
# ui/main.ui — both frames reference the same PNG by path.[[element]]id = "frameSmall"type = "panel"parent = "bg"image = "textures/panel.png"
[[element]]id = "frameLarge"type = "panel"parent = "bg"image = "textures/panel.png"The script
Section titled “The script”import "engine" for Engine, Logger, Window, Ui
class Game { construct new() { _doc = null }
init() { _doc = Ui.load("ui/main.ui") if (_doc == null) Logger.error("failed to load ui/main.ui") }
draw() { if (_doc != null) Ui.render(_doc, 0, 0, Window.getWidth(), Window.getHeight()) }
quit() {}}The demo auto-captures ui_nineslice_demo.png after ~1.5 s so the render can be verified headlessly.
See the Ui API for the image field, 9-slice scaling, and the
.ui.component sidecar, and the UI Demo for the retained-UI basics.