DatumHuePlatform v0.0.24datumhue.com
Contents

Pixel art and sprites

Draw a small frame pixel by pixel, show it scaled up with hard edges, and animate sprites and tile maps cut from a sheet.

Draw a frame

image.new makes an image, a grid of pixels you draw into. Its origin is the top-left corner, and Y points down, as in most paint programs.

You do not draw on an image directly. You record commands into a picture, from image.picture, and Image:apply replays them onto the image in one pass, so a half-drawn frame never shows. Make the picture once; each frame, Picture:reset empties it, you record the new frame, and you apply it again.

This program draws a ball circling a 128 by 96 frame, shown four times larger:

frame.lualua
local color = datumhue.color
local W, H = 128, 96

local screen = datumhue.image.new({ width = W, height = H })
screen.filter = "nearest"
screen:mount({ width = W * 4, height = H * 4 })
local pic = datumhue.image.picture()

datumhue.on_update(function()
    local t = datumhue.time.now()
    local x = 64 + math.cos(t * 2) * 40
    local y = 48 + math.sin(t * 3) * 24
    pic:reset()
    pic:fill(color("#1d2b53"))
    pic:circfill(x, y, 8, color("#ff004d"))
    pic:print("hello", 46, 80, color("#fff1e8"))
    screen:apply(pic)
end)

In this example: datumhue.color datumhue.image.new Image.filter Image:mount datumhue.image.picture datumhue.on_update datumhue.time.now Picture:reset Picture:fill Picture:circfill Picture:print Image:apply

The picture's methods take positions as plain numbers in image pixels: Picture:circfill is a filled circle, Picture:rectfill a filled rectangle, Picture:line a line. Picture:camera and Picture:clip shift and limit everything drawn after them.

Keep pixels sharp

An image or canvas shown larger than its own size is smoothed by default, which blurs pixel art. Set Image.filter or DrawCanvas.filter to "nearest", as the program does, to keep every pixel a hard-edged square. Show the frame at a whole multiple of its size, here 4, so every pixel is the same size on screen.

Write text

Picture:print writes text in a bitmap font. The built-in font, from image.font, has 8 by 13 pixel characters. Picture:set_font switches to a font of your own: an atlas with one cell per character, from the space on. Picture:measure_text and Picture:wrap size and break text in the current font.

Animate sprites from a sheet

Image:atlas slices an image into a grid of equal cells, numbered from 0 along each row. Atlas:sprite makes a sprite of one cell, and DrawCanvas:sprite draws it on a draw canvas. To animate, assign DrawPrimitive.cell to show another cell of the same sheet.

A sprite drawn this way is a draw shape like any other: it takes a depth, joins groups, takes a physics body and a shader, and DrawCanvas:point_query finds it under the pointer.

Lay out a tile map

DrawCanvas:tilemap makes a grid on a canvas whose every cell shows one cell of an atlas, or nothing. TileMap:set places a tile. Rows count up from row 0 at the bottom, as Y does on a canvas.

This program paints a sheet of six cells, four frames of a coin and two ground tiles, then lays the ground and spins the coin above it:

sprites.lualua
local color = datumhue.color
local vec2 = datumhue.math.vec2
local vec3 = datumhue.math.vec3

-- Six 16x16 cells: four frames of a spinning coin, then a
-- grass tile and a dirt tile.
local sheet = datumhue.image.new({ width = 96, height = 16 })
local pic = datumhue.image.picture()
local widths = { 6, 4, 1, 4 }
for i = 0, 3 do
    local cx, w = i * 16 + 8, widths[i + 1]
    pic:ovalfill(cx - w, 2, cx + w, 13, color("#ffcc00"))
end
pic:rectfill(64, 0, 79, 15, color("#008751"))
pic:rectfill(64, 0, 79, 3, color("#00e436"))
pic:rectfill(80, 0, 95, 15, color("#ab5236"))
sheet:apply(pic)

local atlas = sheet:atlas({
    tile_size = vec2(16, 16),
    columns = 6,
    rows = 1,
})

local canvas = datumhue.draw.new({
    width = 128,
    height = 128,
    background = color("#1d2b53"),
})
canvas.filter = "nearest"
canvas:mount({ width = 384, height = 384 })

-- 8x8 tiles of 16 px cover the canvas. Row 0 is the bottom:
-- dirt, with grass above it.
local map = canvas:tilemap(atlas, { columns = 8, rows = 8 })
for x = 0, 7 do
    map:set(x, 0, 5)
    map:set(x, 1, 4)
end

-- The coin steps through cells 0 to 3, eight times a second.
local coin = canvas:sprite(atlas:sprite(0), { pos = vec3(0, 0, 1) })
datumhue.on_update(function()
    coin.cell = math.floor(datumhue.time.now() * 8) % 4
end)

In this example: datumhue.color datumhue.math.vec2 datumhue.math.vec3 datumhue.image.new datumhue.image.picture Picture:ovalfill Picture:rectfill Image:apply Image:atlas datumhue.draw.new DrawCanvas.filter DrawCanvas:mount DrawCanvas:tilemap TileMap:set DrawCanvas:sprite Atlas:sprite datumhue.on_update DrawPrimitive.cell datumhue.time.now

A sheet usually comes from a file: Bytes:image decodes a PNG, as in datumhue.package:dir():read("sheet.png"):image().

Combine images

Picture:blit copies a rectangle of another image, or of the same one, into the picture. Its blend mode decides how the copy meets the pixels already there: an additive blit brightens them for glows and lights, and a multiplying one darkens them for shadows.

See also

Reference used on this page: datumhue.color datumhue.image.new Image.filter Image:mount datumhue.image.picture datumhue.on_update datumhue.time.now Picture:reset Picture:fill Picture:circfill Picture:print Image:apply datumhue.math.vec2 datumhue.math.vec3 Picture:ovalfill Picture:rectfill Image:atlas datumhue.draw.new DrawCanvas.filter DrawCanvas:mount DrawCanvas:tilemap TileMap:set DrawCanvas:sprite Atlas:sprite DrawPrimitive.cell Picture:line Picture:camera Picture:clip datumhue.image.font Picture:set_font Picture:measure_text Picture:wrap DrawCanvas:point_query Bytes:image Package:dir Picture:blit

datumhue.com

(c) 2026 Shuusei AB. Quote excerpts of this manual, with attribution to DatumHue, in your own documentation, tutorials, course materials, reviews, and other writing or video. Republishing it in whole or in substantial part needs written permission: support@datumhue.com.

Victor Mono is licensed under the SIL Open Font License 1.1
Copyright (c) 2024, Rune Bjørnerås (https://github.com/rubjo)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Try

    ↑↓ selectEnter openTab filter

    Settings

    Theme
    Text
    Print

    Keyboard shortcuts

    / or Ctrl KSearch
    ↑ ↓ EnterPick a result
    TabNext result filter
    j kNext or previous entry
    [ ]Previous or next page
    yCopy a link to the current entry
    ?These shortcuts
    EscClose

    On this page