Skip to content

Draw ​

2D and 3D drawing primitives. Drawing only works inside frame callbacks (on_tick); calling these from event callbacks does nothing.

Colors ​

Colors are IM_COL32 packed uint32 in 0xAABBGGRR format (alpha in the high byte, red in the low byte).

lua
local WHITE  = 0xFFFFFFFF
local RED    = 0xFF0000FF  -- red in the low byte, FF alpha
local GREEN  = 0xFF00FF00
local BLUE   = 0xFFFF0000
local YELLOW = 0xFF00FFFF

Use draw.color to build colors from RGBA components without hand-packing:

lua
local muted = draw.color(180, 180, 180)        -- alpha defaults to 255
local fade  = draw.color(255, 255, 255, 80)

Byte order gotcha

This format is ABGR, not ARGB. 0xFFFF0000 is solid blue, not red, most other engines and CSS use 0xAARRGGBB. If you're copying a hex color from elsewhere, the red and blue channels need to swap. draw.color(r, g, b, a) builds the right uint32 without the mental gymnastics.

2D primitives ​

FunctionDescription
draw.line(x1, y1, x2, y2, color, [thickness])Line between two points
draw.rect(x1, y1, x2, y2, color, [thickness])Outlined rectangle
draw.rect_filled(x1, y1, x2, y2, color)Filled rectangle
draw.circle(x, y, radius, color, [thickness])Outlined circle
draw.circle_filled(x, y, radius, color)Filled circle

Text ​

Text functions accept an optional font name OR scale parameter. Pass a string for a font name, or a number for scale on the default font.

FunctionDescription
draw.text(x, y, text, color, [font_or_size], [size])Text with shadow
draw.text_raw(x, y, text, color, [font_or_size], [size])Text without shadow
draw.text3d(pos, text, color, [font_or_size], [size])Text anchored to a world position (vec3)
lua
draw.text(100, 100, "Hello", 0xFFFFFFFF)              -- default font, scale 1.0
draw.text(100, 120, "Hello", 0xFFFFFFFF, 1.5)          -- default font, scale 1.5
draw.text(100, 140, "Hello", 0xFFFFFFFF, "hud")        -- custom font, scale 1.0
draw.text(100, 160, "Hello", 0xFFFFFFFF, "hud", 1.5)   -- custom font, scale 1.5

All text functions return nothing.

Fonts ​

Scripts can use custom fonts. Either pre-load fonts via fonts.lua or let users pick from system fonts via the font picker setting.

FunctionReturnsDescription
draw.set_font(name)-Set the per-script default font for subsequent draw.text calls. Pass nil or "" to reset to the overlay default
draw.get_font()stringCurrent per-script default font name
draw.get_fonts()tableArray of all loaded custom font names

Font state is per-script. Calling draw.set_font("Arial") in Script A doesn't affect Script B.

If the font name isn't loaded yet, draw.set_font triggers dynamic loading. The engine searches in this order:

  1. %APPDATA%/TsukiProject/Deadlock/fonts/
  2. C:\ProgramData\TsukiProject\Deadlock\fonts\
  3. C:\Windows\Fonts\

The first frame may render with the default font while the atlas rebuilds.

fonts.lua (optional pre-loading) ​

Pre-load fonts at specific sizes into the atlas at startup. Drop a fonts.lua next to your scripts. Not required; the font picker dynamically loads system fonts on demand.

lua
-- %APPDATA%/TsukiProject/Deadlock/scripts/fonts.lua
return {
    hud   = { file = "roboto.ttf",   size = 16 },
    small = { file = "consolas.ttf", size = 10 },
    big   = { file = "inter.ttf",    size = 24 },
}

.ttf and .otf files go in %APPDATA%/TsukiProject/Deadlock/fonts/. The keys (hud, small, etc.) become the names you pass to draw.set_font.

Font priority ​

Highest precedence wins:

  1. Explicit font passed to draw.text(..., font_name)
  2. Per-script default set via draw.set_font(name)
  3. Overlay default font

3D primitives ​

3D primitives are reprojected per frame.

FunctionDescription
draw.line3d(p1, p2, color, [thickness])Line between two vec3 points
draw.circle3d(center, radius, color, [thickness])Outlined circle in world space
draw.circle3d_filled(center, radius, color)Filled circle in world space
draw.box3d(center, width, depth, height, color, [thickness])Axis-aligned box centered at center (vec3) with dimensions in world units along X (width), Y (depth), and Z (height)
draw.sphere3d(center, radius, color, [segments])Wireframe sphere

Projection and screen size ​

FunctionReturnsDescription
draw.world_to_screen(vec3)vec2 | nilPixel position as a vec2 with .x and .y, or nil if behind the camera
draw.screen_size()vec2Screen dimensions as vec2 with .x (width) and .y (height)

world_to_screen is also available as camera.world_to_screen. Same function.

Example ​

lua
local WHITE = 0xFFFFFFFF
local RED   = 0xFF3232FF

function on_tick()
    for _, p in ipairs(get_players()) do
        if p:is_enemy() and p:is_alive() then
            local box = p:screen_box()
            if box then
                draw.rect(box.x, box.y, box.x + box.w, box.y + box.h, RED, 2)
                draw.text(box.x, box.y - 14, p:hero_name(), WHITE)
            end
        end
    end
end

Not affiliated with Valve Corporation.