render
The render module draws shapes on top of the game and converts world coordinates to screen coordinates. This page covers shapes and the screen; state stacks, fonts and images are described on separate pages.
General rules#
- Only inside the
renderevent. Drawing functions work only while therenderevent is being dispatched. Outside it you get the errorthis function may only be called inside the 'render' event.screen_size,world_to_screen,offscreen,camera_angles, font and image loading andmeasure_textwork without the event. - A rectangle is given as
(pos, size): the secondvector2is the size, the bottom-right corner =pos + size. - Rounding
roundingis a number (one radius for all corners) or a table{tl, tr, br, bl}(top-left, top-right, bottom-right, bottom-left). If not passed, corners are square. - Arc angles.
startis the start angle in degrees (default 0),pctis the fraction of a full circle (1 — full circle, 0.5 — half; default 1). - Optional arguments count only with the exact type: a string with a number cannot be passed instead of a number.
nilmeans "not passed".
color(255, 0, 0)without alpha is invisible: alpha defaults to 0. Writecolor(255, 0, 0, 255).
render.screen_size()#
Screen size in pixels. Also works outside the render event.
Returns: vector2 — width and height.
local font = render.load_font("Verdana", 14, "outline")
events.render:set(function()
local center = render.screen_size() / 2
render.text(center, color(255, 255, 255, 255), font, "c", "+")
end)
render.world_to_screen(pos: vector)#
Converts a world point to a screen point. The result is rounded to whole pixels.
| Parameter | Type | Description |
|---|---|---|
pos |
vector |
world point |
Returns: vector2 or nil if the point cannot be projected (for example, it is behind the camera).
events.render:set(function()
for _, pawn in ipairs(entity.pawns(true)) do
local p = render.world_to_screen(pawn:origin())
if p then
render.circle(p, color(255, 60, 60, 255), 4) -- dot at the enemy's feet
end
end
end)
render.offscreen(pos: vector, t?: number)#
Projects a world point for an arrow indicator at the screen edge. If the point is visible on screen, its screen position is returned. If the point is beyond the screen edge or behind the camera, a point on a circle around the screen center, in the direction of the target, is returned.
| Parameter | Type | Description |
|---|---|---|
pos |
vector |
world point |
t |
number |
circle radius as a fraction of half the smaller screen side: 0 — center, 1 — edge. Clamped to [0, 1]; default 1 |
Example: on a 3440×1440 screen half the smaller side is 720 px, so with t = 0.25 the point is placed 180 px from the center.
Returns: vector, number, boolean:
- the screen point (
vector,zis always 0); - the direction angle to the point in degrees (0 if the point is visible);
trueif the point is beyond the screen edge;falseif it is visible.
Also works outside the render event. If the screen size is not available, the error is offscreen: screen size unavailable.
-- A marker dot for every enemy beyond the screen edge
events.render:set(function()
for _, pawn in ipairs(entity.pawns(true)) do
local p, ang, off = render.offscreen(pawn:origin(), 0.8)
if off then
render.circle(vector2(p.x, p.y), color(255, 60, 60, 255), 5)
end
end
end)
render.camera_angles()#
Angles of the main game camera.
Returns: angle — a copy of the camera angles.
local font = render.load_font("Verdana", 14, "outline")
events.render:set(function()
local a = render.camera_angles()
render.text(vector2(20, 60), color(255, 255, 255, 255), font, nil, string.format("pitch %.1f yaw %.1f", a.x, a.y))
end)
render.line(a: vector2, b: vector2, col: color, thickness?: number)#
Draws a line segment.
| Parameter | Type | Description |
|---|---|---|
a |
vector2 |
start |
b |
vector2 |
end |
col |
color |
color |
thickness |
number |
thickness, default 1 |
Returns: nothing.
-- A line from the bottom center of the screen to each enemy
events.render:set(function()
local s = render.screen_size()
local from = vector2(s.x / 2, s.y)
for _, pawn in ipairs(entity.pawns(true)) do
local p = render.world_to_screen(pawn:origin())
if p then
render.line(from, p, color(255, 200, 0, 180), 1)
end
end
end)
render.bezier(p1: vector2, p2: vector2, p3: vector2, p4: vector2, col: color, thickness: number, segments?: number)#
Draws a cubic Bezier curve from p1 to p4 with control points p2 and p3.
| Parameter | Type | Description |
|---|---|---|
p1 … p4 |
vector2 |
start, two control points, end |
col |
color |
color; nothing is drawn with alpha 0 |
thickness |
number |
thickness (required) |
segments |
number |
number of segments; default 0 — chosen automatically |
Returns: nothing.
events.render:set(function()
render.bezier(vector2(40, 300), vector2(90, 240), vector2(140, 360), vector2(190, 300), color(0, 200, 255, 255), 2)
end)
render.rect(pos: vector2, size: vector2, col: color, rounding?: number|table)#
Draws a filled rectangle.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
col |
color |
fill color |
rounding |
number or table |
corner rounding |
Returns: nothing.
events.render:set(function()
render.rect(vector2(20, 100), vector2(160, 40), color(20, 20, 20, 200), 6)
end)
render.rect_outline(pos: vector2, size: vector2, col: color, thickness?: number, rounding?: number|table)#
Draws a rectangle outline.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
col |
color |
color |
thickness |
number |
thickness, default 1 |
rounding |
number or table |
corner rounding |
Returns: nothing.
events.render:set(function()
-- only the top corners are rounded
render.rect_outline(vector2(20, 100), vector2(160, 40), color(255, 255, 255, 255), 1, { 6, 6, 0, 0 })
end)
render.rect_shadow(pos: vector2, size: vector2, col: color, rounding?: number|table, blur?: number, offset?: vector2)#
Draws a soft rectangle shadow.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
col |
color |
shadow color |
rounding |
number or table |
corner rounding |
blur |
number |
blur, default 0 |
offset |
vector2 |
shadow offset, default (0, 0) |
Returns: nothing.
events.render:set(function()
local pos, size = vector2(20, 160), vector2(160, 40)
render.rect_shadow(pos, size, color(0, 0, 0, 200), 6, 12, vector2(0, 2))
render.rect(pos, size, color(30, 30, 30, 255), 6)
end)
render.rect_gradient(pos: vector2, size: vector2, c1: color, c2: color, c3: color, c4: color, rounding?: number|table)#
Draws a rectangle with a corner gradient.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
c1 |
color |
top-left corner |
c2 |
color |
top-right corner |
c3 |
color |
bottom-left corner |
c4 |
color |
bottom-right corner |
rounding |
number or table |
corner rounding |
Returns: nothing.
events.render:set(function()
local a, b = color(255, 80, 80, 255), color(80, 80, 255, 255)
-- horizontal gradient: red on the left, blue on the right
render.rect_gradient(vector2(20, 220), vector2(160, 8), a, b, a, b, 4)
end)
render.rect_glow(pos: vector2, size: vector2, col: color, rounding?: number|table)#
Draws a glowing accent bar. Only the top-left radius is taken from the rounding.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
col |
color |
glow color |
rounding |
number or table |
rounding |
Returns: nothing.
events.render:set(function()
render.rect_glow(vector2(20, 240), vector2(4, 40), color(120, 160, 255, 255), 8)
end)
render.rect_window(pos: vector2, size: vector2, rounding?: number|table)#
Draws a window background in the menu style (with background blur and a shadow). The top-left radius is taken from the rounding.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
rounding |
number or table |
rounding |
Returns: nothing.
- The call removes an active
render.push_blur.
local font = render.load_font("Verdana", 14)
events.render:set(function()
render.rect_window(vector2(20, 300), vector2(180, 50), 10)
render.text(vector2(110, 325), color(255, 255, 255, 255), font, "c", "Script window")
end)
render.rect_window_shadow(pos: vector2, size: vector2, rounding?: number|table)#
Draws only the window shadow in the menu style. The top-left radius is applied to all corners.
| Parameter | Type | Description |
|---|---|---|
pos |
vector2 |
top-left corner |
size |
vector2 |
size |
rounding |
number or table |
rounding |
Returns: nothing.
events.render:set(function()
render.rect_window_shadow(vector2(220, 300), vector2(120, 50), 8)
render.rect(vector2(220, 300), vector2(120, 50), color(25, 25, 25, 255), 8)
end)
render.circle(center: vector2, col: color, radius: number, start?: number, pct?: number)#
Draws a filled circle or sector. Nothing is drawn with alpha 0 or radius <= 0.
| Parameter | Type | Description |
|---|---|---|
center |
vector2 |
center |
col |
color |
color |
radius |
number |
radius |
start |
number |
start angle, degrees; default 0 |
pct |
number |
circle fraction; default 1 |
Returns: nothing.
events.render:set(function()
render.circle(vector2(60, 400), color(255, 0, 255, 255), 16, 0, 0.75) -- three quarters
end)
render.circle_outline(center: vector2, col: color, radius: number, start?: number, pct?: number, thickness?: number)#
Draws a circle or an arc as an outline.
| Parameter | Type | Description |
|---|---|---|
center |
vector2 |
center |
col |
color |
color |
radius |
number |
radius |
start |
number |
start angle, degrees; default 0 |
pct |
number |
circle fraction; default 1 |
thickness |
number |
thickness, default 1 |
Returns: nothing.
-- Health indicator as an arc around the crosshair
events.render:set(function()
local me = entity.local_pawn()
if not me or not me:is_alive() then return end
local center = render.screen_size() / 2
render.circle_outline(center, color(80, 255, 120, 255), 24, -90, me:health() / 100, 2)
end)
render.circle_gradient(center: vector2, edge: color, inner: color, radius: number, softness?: number, start?: number, pct?: number)#
Draws a circle with a radial gradient from the center to the edge.
| Parameter | Type | Description |
|---|---|---|
center |
vector2 |
center |
edge |
color |
edge color |
inner |
color |
center color |
radius |
number |
radius |
softness |
number |
fraction of the radius taken by the transition from the edge color to the center color; default 1 — a smooth gradient |
start |
number |
start angle, degrees; default 0 |
pct |
number |
circle fraction; default 1 |
- Small
softnessvalues (for example, 0.1) give a solid circle of theinnercolor with a thin transition toedgeat the rim. - Values of 0.5 and above give a smooth gradient. Values above 1 work like 1.
Returns: nothing.
events.render:set(function()
-- smooth gradient
render.circle_gradient(vector2(120, 400), color(255, 0, 0, 0), color(255, 0, 0, 255), 20)
-- solid circle with a soft rim
render.circle_gradient(vector2(180, 400), color(255, 0, 0, 0), color(255, 0, 0, 255), 20, 0.1)
end)
render.circle_shadow(center: vector2, col: color, radius: number, blur: number, start?: number, pct?: number, offset?: vector2)#
Draws a soft circle shadow.
| Parameter | Type | Description |
|---|---|---|
center |
vector2 |
center |
col |
color |
shadow color |
radius |
number |
radius |
blur |
number |
blur (required) |
start |
number |
start angle, degrees; default 0 |
pct |
number |
circle fraction; default 1 |
offset |
vector2 |
offset, default (0, 0) |
Returns: nothing.
events.render:set(function()
local c = vector2(180, 400)
render.circle_shadow(c, color(0, 0, 0, 255), 14, 10)
render.circle(c, color(240, 240, 240, 255), 14)
end)
render.circle_blur(center: vector2, alpha: number, radius: number, start?: number, pct?: number)#
Draws a circle of blurred background.
| Parameter | Type | Description |
|---|---|---|
center |
vector2 |
center |
alpha |
number |
blur opacity, 0–1 |
radius |
number |
radius |
start |
number |
start angle, degrees; default 0 |
pct |
number |
circle fraction; default 1 |
Returns: nothing.
events.render:set(function()
render.circle_blur(vector2(240, 400), 1, 28)
end)
render.triangle(a: vector2, b: vector2, c: vector2, col: color)#
Draws a filled triangle.
| Parameter | Type | Description |
|---|---|---|
a, b, c |
vector2 |
vertices |
col |
color |
color |
Returns: nothing.
-- A pointer arrow above the screen center
events.render:set(function()
local c = render.screen_size() / 2
render.triangle(vector2(c.x, c.y - 40), vector2(c.x + 8, c.y - 52), vector2(c.x - 8, c.y - 52), color(255, 255, 255, 255))
end)
render.triangle_outline(a: vector2, b: vector2, c: vector2, col: color, thickness?: number)#
Draws a triangle outline.
| Parameter | Type | Description |
|---|---|---|
a, b, c |
vector2 |
vertices |
col |
color |
color |
thickness |
number |
thickness, default 1 |
Returns: nothing.
events.render:set(function()
render.triangle_outline(vector2(300, 380), vector2(320, 410), vector2(280, 410), color(255, 255, 255, 255), 1.5)
end)
render.poly(points: table, col: color)#
Draws a convex filled polygon.
| Parameter | Type | Description |
|---|---|---|
points |
table |
array of vertices {vector2, ...} |
col |
color |
color |
Returns: nothing.
events.render:set(function()
render.poly({ vector2(340, 380), vector2(360, 390), vector2(350, 410), vector2(330, 400) }, color(0, 128, 255, 255))
end)
render.polyline(points: table, col: color, closed: boolean, thickness: number)#
Draws a polyline.
| Parameter | Type | Description |
|---|---|---|
points |
table |
array of points {vector2, ...} |
col |
color |
color |
closed |
boolean |
close the polyline (required) |
thickness |
number |
thickness (required) |
Returns: nothing.
-- FPS graph for the last 60 frames
local history = {}
events.render:set(function()
table.insert(history, 1 / math.max(globals.absoluteframetime, 0.001))
if #history > 60 then table.remove(history, 1) end
local pts = {}
for i, fps in ipairs(history) do
pts[i] = vector2(20 + i * 3, 500 - math.min(fps, 300) / 3)
end
if #pts > 1 then
render.polyline(pts, color(0, 255, 120, 255), false, 1)
end
end)
render.poly_gradient(anchor: vector2|nil, points: table, edge: color, center: color, extent?: number)#
Draws a polygon with a gradient from the edge to the center.
| Parameter | Type | Description |
|---|---|---|
anchor |
vector2 or nil |
gradient center point; nil — the average of all vertices is used as the center |
points |
table |
array of vertices {vector2, ...} |
edge |
color |
edge color |
center |
color |
center color |
extent |
number |
gradient extent, default 1 |
Returns: nothing.
events.render:set(function()
local pts = { vector2(400, 380), vector2(480, 380), vector2(480, 440), vector2(400, 440) }
render.poly_gradient(vector2(440, 410), pts, color(0, 255, 0, 0), color(0, 255, 0, 255), 0.6)
end)
render.poly_shadow(points: table, col: color, thickness: number, offset: vector2)#
Draws a polygon shadow. All arguments are required.
| Parameter | Type | Description |
|---|---|---|
points |
table |
array of vertices {vector2, ...} |
col |
color |
shadow color |
thickness |
number |
shadow width |
offset |
vector2 |
shadow offset |
Returns: nothing.
events.render:set(function()
local pts = { vector2(500, 380), vector2(580, 380), vector2(540, 440) }
render.poly_shadow(pts, color(0, 0, 0, 255), 20, vector2(4, 4))
render.poly(pts, color(200, 200, 200, 255))
end)