Docs · Drawing & paint

Drawing & paint

on render is where a script draws its own overlay — a HUD, markers, a progress bar — over the game view. It is a new event, a sibling of on start / on loop / on stop, and it comes with a family of paint* commands: shapes and text, but also outlined text (paintTextOutlined — readable over the game with no backing panel), paintRing (the round progress dial), and colour helpers — blendColours("red", "green", hpPercent) is the classic health-colour trick. This page is how it works; the commands themselves are in the reference below.

How on render works

  • It is pumped on the launcher's own frame cadence — about 30 times a second — while the loop is idling between passes.
  • It runs on the script's own thread, so it can read the script's vars with no threading worries. The bot work stays in on loop; the drawing goes in on render.
  • Drawing is double-buffered: each on render pass builds a complete frame that is swapped in atomically, so it never flickers. You do not need to call paintClear — just draw your whole HUD every pass. The overlay clears itself when the script stops.

Draw-only

on render may only draw. You cannot wait or wait until, call any acting / blocking command (interact, walkTo, bank*, drop*, …), become another state, or return a value. The checker rejects these in the block, and the engine refuses them at runtime even if reached through a helper fun — so a bot can never act from its paint hook. Reads are fine: level, invCount, nearestNpc, all the math / string / list commands, and every paint* command.

The smallest possible HUD

The bot work goes in on loop; the drawing goes in on render, redrawn every frame.

script "Mini HUD" author "you" version "1.0" description "the smallest paint example" category "Demo" every 600
on loop { return 600 }
on render {
    paintText(8, 20, "botting", "lime")
}

Colours, coordinates & numbers

Colours

A name, or a hex string. A bad colour falls back to the house colour rather than erroring.

Names: red green lime blue cyan aqua yellow gold orange magenta pink purple white black gray/grey teal brown navy silver.

Hex: "#rrggbb", plus two more digits "#rrggbbaa" for transparency (alpha) — e.g. "#0b0f14cc" is a dark panel at ~80% opacity.

Coordinates

Game-view pixels. (0,0) is the top-left of the game view; x grows right, y grows down. Text sits on its baseline at the point you give.

Numbers to text

paintText wants a string, so wrap an int with commas(n)commas(1234) gives "1,234". (numberIn is the reverse: string → int.)

Worked examples

A full HUD — panel, title, runtime, counter, progress bar, markers
# The bot work goes in 'on loop'. The drawing goes in 'on render', pumped
# every frame so the readout stays smooth even while the loop sleeps.
script      "Paint Render Demo"
author      "mark"
version     "1.0"
description "A live HUD drawn from on render while on loop does the work"
category    "Demo"
every       600

var started = 0
var loops   = 0

on start { started = nowMillis() }

on loop {
    loops = loops + 1
    return 600
}

on render {
    paintFill(6, 6, 168, 92, "#0b0f14cc")
    paintBox(6, 6, 168, 92, "teal")
    paintTextSized(16, 28, "PAINT DEMO", "gold", 15)
    paintText(16, 50, "runtime:")
    paintText(92, 50, formatDuration(elapsedSince(started)), "white")
    paintText(16, 66, "loops:")
    paintText(92, 66, commas(loops), "lime")
    paintProgress(16, 76, 148, 12, wrap(loops, 0, 101), "green")
    paintDot(120, 130, "red")
    paintCircle(120, 130, 18, "yellow")
}
A paint helper — you may call a draw-only fun from on render
script "HUD Helper" author "you" version "1.0" description "drawing split into a fun" category "Demo" every 600
var kills = 0
on loop { kills = kills + 1 return 600 }
fun drawHud() {
    paintFill(4, 4, 130, 40, "#000000aa")
    paintText(12, 22, "kills:")
    paintText(70, 22, commas(kills), "lime")
}
on render { drawHud() }

The paint commands · group paint

blendColours returns string
blendColours(from: string, to: string, percent: int) -> string

The colour part way between two others — feed it a health percent and get red at 0, green at 100, amber in the middle.

ParameterTypeWhat it does
fromrequired string the colour at 0
torequired string the colour at 100
percentrequired int how far from one to the other, 0 to 100
Example
paintText(8, 20, "hp", blendColours("red", "green", 75))
darken returns string
darken(colour: string, percent: int) -> string

The colour moved toward black by a percentage — the shadow of a colour you already use.

ParameterTypeWhat it does
colourrequired string the colour to start from
percentrequired int how far toward black, 0 to 100
Example
paintText(8, 20, "deep", darken("teal", 40))
lighten returns string
lighten(colour: string, percent: int) -> string

The colour moved toward white by a percentage — for a hover or a highlight tint of a colour you already use.

ParameterTypeWhat it does
colourrequired string the colour to start from
percentrequired int how far toward white, 0 to 100
Example
paintText(8, 20, "soft", lighten("teal", 40))
paintArc
paintArc(x: int, y: int, radius: int, startDeg: int, sweepDeg: int, colour: string)

Part of a circle's edge — a curve from a start angle through a sweep, for dials and markers a full circle would overdo.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
radiusrequired int how far the curve sits from the centre
startDegrequired int where the curve begins: 0 is three o'clock, 90 is noon
sweepDegrequired int how far it runs, in degrees, anticlockwise when positive
colourrequired string a colour name or hex string
Example
paintArc(160, 120, 20, 90, 180, "cyan")
paintArrow
paintArrow(x1: int, y1: int, x2: int, y2: int, colour: string)

A line with an arrowhead at its end — from here to there, with a direction.

ParameterTypeWhat it does
x1required int start x in pixels
y1required int start y in pixels
x2required int end x in pixels — where the head points
y2required int end y in pixels
colourrequired string a colour name or hex string
Example
paintArrow(20, 20, 120, 90, "yellow")
paintBox
paintBox(x: int, y: int, width: int, height: int, colour: string)

Draws the outline of a rectangle, for framing a readout or ringing a spot on the game.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
colourrequired string a colour name or hex string
Example
paintBox(4, 4, 140, 70, "green")
paintChart
paintChart(x: int, y: int, width: int, height: int, values: list<int>, colour: string)

A line chart of a whole series in one call: the values are scaled to fill the box, smallest at the bottom, and drawn as a connected line — feed it runningTotals or a tally history. A flat series draws a level line.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide the chart is in pixels
heightrequired int how tall the chart is in pixels
valuesrequired list<int> the series to draw, two values or more
colourrequired string a colour name or hex string
Example
paintChart(6, 100, 160, 40, runningTotals(range(1, 9)), "cyan")
paintCircle
paintCircle(x: int, y: int, radius: int, colour: string)

Draws the outline of a circle around a point, for ringing a target on the game.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
radiusrequired int how far the ring reaches from the centre, in pixels
colourrequired string a colour name or hex string
Example
paintCircle(160, 120, 24, "red")
paintClear
paintClear()

Wipes this script's paint, ready for a fresh pass. Call it at the top of the loop, then draw the current numbers underneath.

Example
paintClear()
paintCrosshair
paintCrosshair(x: int, y: int, size: int, colour: string)

A crosshair centred on a point — four arms and a gap in the middle, for marking exactly where a click would land.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
sizerequired int how far each arm reaches, in pixels
colourrequired string a colour name or hex string
Example
paintCrosshair(160, 120, 10, "red")
paintDisc
paintDisc(x: int, y: int, radius: int, colour: string)

Draws a filled circle centred on a point, a bigger, bolder marker than a dot.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
radiusrequired int how far the disc reaches from the centre, in pixels
colourrequired string a colour name or hex string
Example
paintDisc(160, 120, 6, "lime")
paintDot
paintDot(x: int, y: int, colour: string)

Marks a spot with a small filled dot, for showing where something is.

ParameterTypeWhat it does
xrequired int pixels from the left edge of the game
yrequired int pixels down from the top of the game
colourrequired string a colour name or hex string like "#33dd55"
Example
paintDot(120, 84, "red")
paintFill
paintFill(x: int, y: int, width: int, height: int, colour: string)

Fills a solid rectangle. Use a see-through colour like "#00000088" as a backing panel so text reads over a busy game.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
colourrequired string a colour name or hex string, add two hex digits for see-through
Example
paintFill(4, 4, 140, 70, "#00000088")
paintGradient
paintGradient(x: int, y: int, width: int, height: int, from: string, to: string)

A rectangle filled with a smooth top-to-bottom blend between two colours — a panel with some depth to it.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
fromrequired string the colour at the top
torequired string the colour at the bottom
Example
paintGradient(4, 4, 150, 80, "#123a5a", "#0b0f14")
paintGradientAcross
paintGradientAcross(x: int, y: int, width: int, height: int, from: string, to: string)

A rectangle filled with a smooth left-to-right blend between two colours — the sideways partner of paintGradient.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
fromrequired string the colour at the left
torequired string the colour at the right
Example
paintGradientAcross(4, 90, 150, 12, "red", "green")
paintLine
paintLine(x1: int, y1: int, x2: int, y2: int, colour: string)

Draws a straight line between two points, for pointing from here to there on the game.

ParameterTypeWhat it does
x1required int start x in pixels
y1required int start y in pixels
x2required int end x in pixels
y2required int end y in pixels
colourrequired string a colour name or hex string
Example
paintLine(0, 0, 120, 90, "cyan")
paintLines
paintLines(xs: list<int>, ys: list<int>, colour: string)

Connected lines through every point in the two lists — a route, a sparkline, a shape of your own. The lists must be the same size, two points or more.

ParameterTypeWhat it does
xsrequired list<int> the x of each point, in order
ysrequired list<int> the y of each point, matching xs one for one
colourrequired string a colour name or hex string
Example
paintLines(range(0, 5), repeated(50, 5), "cyan")
paintPie
paintPie(x: int, y: int, radius: int, startDeg: int, sweepDeg: int, colour: string)

A filled slice of a circle — the pie-chart wedge, from a start angle through a sweep.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
radiusrequired int how far the slice reaches from the centre
startDegrequired int where the slice begins: 0 is three o'clock, 90 is noon
sweepDegrequired int how far it runs, in degrees, anticlockwise when positive
colourrequired string a colour name or hex string
Example
paintPie(160, 120, 20, 90, 120, "#ffd40088")
paintPolygon
paintPolygon(xs: list<int>, ys: list<int>, colour: string)

A closed outline through every corner in the two lists — paintLines with the last point joined back to the first.

ParameterTypeWhat it does
xsrequired list<int> the x of each corner, in order
ysrequired list<int> the y of each corner, matching xs one for one
colourrequired string a colour name or hex string
Example
paintPolygon(range(0, 3), repeated(40, 3), "yellow")
paintPolygonFill
paintPolygonFill(xs: list<int>, ys: list<int>, colour: string)

A filled shape over every corner in the two lists — the solid partner of paintPolygon.

ParameterTypeWhat it does
xsrequired list<int> the x of each corner, in order
ysrequired list<int> the y of each corner, matching xs one for one
colourrequired string a colour name or hex string
Example
paintPolygonFill(range(0, 3), repeated(40, 3), "#ffd40066")
paintProgress
paintProgress(x: int, y: int, width: int, height: int, percent: int, colour: string)

Draws a progress bar: a dark track, a coloured fill for the percentage and a light frame. Feed it a level's progress or a trip count.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide the whole bar is in pixels
heightrequired int how tall the bar is in pixels
percentrequired int how full, 0 to 100
colourrequired string the colour of the filled part
Example
paintProgress(4, 90, 140, 12, 65, "green")
paintRing
paintRing(x: int, y: int, radius: int, percent: int, colour: string)

A circular progress dial: a dark ring with a coloured sweep from twelve o'clock — paintProgress, rounded up.

ParameterTypeWhat it does
xrequired int centre x in pixels
yrequired int centre y in pixels
radiusrequired int how far the ring sits from the centre
percentrequired int how full, 0 to 100
colourrequired string the colour of the filled sweep
Example
paintRing(160, 120, 16, 75, "green")
paintRoundBox
paintRoundBox(x: int, y: int, width: int, height: int, arc: int, colour: string)

The outline of a rectangle with rounded corners — the softer frame for a readout panel.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
arcrequired int how rounded the corners are, in pixels
colourrequired string a colour name or hex string
Example
paintRoundBox(4, 4, 150, 80, 12, "teal")
paintRoundFill
paintRoundFill(x: int, y: int, width: int, height: int, arc: int, colour: string)

A filled rectangle with rounded corners — the modern backing panel, especially in a see-through colour.

ParameterTypeWhat it does
xrequired int left edge in pixels
yrequired int top edge in pixels
widthrequired int how wide in pixels
heightrequired int how tall in pixels
arcrequired int how rounded the corners are, in pixels
colourrequired string a colour name or hex string; see-through with 8 hex digits
Example
paintRoundFill(4, 4, 150, 80, 12, "#0b0f14cc")
paintText
paintText(x: int, y: int, text: string)paintText(x: int, y: int, text: string, colour: string)

Draws text at a spot in the default colour. Positions are pixels on the game view.

Draws text at a spot in a colour you choose. Positions are pixels on the game view and the point is the text's baseline.

ParameterTypeWhat it does
xrequired int pixels from the left edge of the game
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string like "#ffd400"
Example
paintText(8, 20, "botting")
paintText(8, 40, "xp/hr: 32000", "yellow")
paintTextCentered
paintTextCentered(x: int, y: int, text: string, colour: string)

Draws text centred on a point rather than starting there — for a heading over a panel, give it the panel's middle.

ParameterTypeWhat it does
xrequired int the centre of the text, in pixels
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
Example
paintTextCentered(90, 20, "MINING", "gold")
paintTextCenteredSized
paintTextCenteredSized(x: int, y: int, text: string, colour: string, size: int)

Draws sized text centred on a point — the heading command, one call for the middle of a panel at a size of your choosing.

ParameterTypeWhat it does
xrequired int the centre of the text, in pixels
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
sizerequired int the text height in pixels, roughly 6 to 96
Example
paintTextCenteredSized(90, 24, "MINING", "gold", 18)
paintTextOutlined
paintTextOutlined(x: int, y: int, text: string, colour: string)

Draws text with a dark outline behind it, so it stays readable over any part of the game without a backing panel.

ParameterTypeWhat it does
xrequired int pixels from the left edge of the game
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
Example
paintTextOutlined(8, 20, "no panel needed", "white")
paintTextOutlinedSized
paintTextOutlinedSized(x: int, y: int, text: string, colour: string, size: int)

Outlined text at a size of your choosing — a heading that reads over the game with no panel behind it.

ParameterTypeWhat it does
xrequired int pixels from the left edge of the game
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
sizerequired int the text height in pixels, roughly 6 to 96
Example
paintTextOutlinedSized(8, 30, "FISHING", "cyan", 18)
paintTextRight
paintTextRight(x: int, y: int, text: string, colour: string)

Draws text ending at a point rather than starting there — for a column of numbers that lines up on the right.

ParameterTypeWhat it does
xrequired int the RIGHT edge of the text, in pixels
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
Example
paintTextRight(160, 40, "32,000", "white")
paintTextSized
paintTextSized(x: int, y: int, text: string, colour: string, size: int)

Draws text at a spot in a colour and a size of your choosing, for a heading bigger than the normal readout.

ParameterTypeWhat it does
xrequired int pixels from the left edge of the game
yrequired int pixels down from the top, the text's baseline
textrequired string the words to draw
colourrequired string a colour name or hex string
sizerequired int the text height in pixels, roughly 6 to 96
Example
paintTextSized(8, 60, "MINING", "gold", 20)
paintTriangle
paintTriangle(x1: int, y1: int, x2: int, y2: int, x3: int, y3: int, colour: string)

The outline of a triangle over three corners — a pointer, a marker, a wedge.

ParameterTypeWhat it does
x1required int first corner x
y1required int first corner y
x2required int second corner x
y2required int second corner y
x3required int third corner x
y3required int third corner y
colourrequired string a colour name or hex string
Example
paintTriangle(10, 30, 30, 30, 20, 10, "lime")
paintTriangleFill
paintTriangleFill(x1: int, y1: int, x2: int, y2: int, x3: int, y3: int, colour: string)

A filled triangle over three corners — the solid partner of paintTriangle.

ParameterTypeWhat it does
x1required int first corner x
y1required int first corner y
x2required int second corner x
y2required int second corner y
x3required int third corner x
y3required int third corner y
colourrequired string a colour name or hex string
Example
paintTriangleFill(10, 30, 30, 30, 20, 10, "lime")
rgb returns string
rgb(red: int, green: int, blue: int) -> string

A colour built from red, green and blue parts, as the hex string every paint command takes. Parts outside 0-255 are clamped.

ParameterTypeWhat it does
redrequired int 0 to 255
greenrequired int 0 to 255
bluerequired int 0 to 255
Example
paintText(8, 20, "tinted", rgb(255, 120, 0))
rgba returns string
rgba(red: int, green: int, blue: int, alpha: int) -> string

A colour with transparency, as the hex string every paint command takes — rgb with a fourth part for how solid it is.

ParameterTypeWhat it does
redrequired int 0 to 255
greenrequired int 0 to 255
bluerequired int 0 to 255
alpharequired int 0 see-through to 255 solid
Example
paintFill(4, 4, 150, 80, rgba(0, 0, 0, 130))
textWidth returns int
textWidth(text: string) -> int

How wide a text would draw, in pixels, at the normal paint size — for sizing a panel to its contents before drawing either.

ParameterTypeWhat it does
textrequired string the words to measure
Example
paintFill(4, 4, textWidth("hello") + 16, 20, "#00000088")
textWidthSized returns int
textWidthSized(text: string, size: int) -> int

How wide a text would draw at a chosen size — the sized partner of textWidth.

ParameterTypeWhat it does
textrequired string the words to measure
sizerequired int the text height in pixels, roughly 6 to 96
Example
print(textWidthSized("MINING", 18))