Glyph wave

Uses natiny.font.get_glyph metrics and natiny.render.text_ex to position, rotate, and color each glyph independently around its own center. The outlined rectangles show the glyph bounds relative to the baseline.


    
main.lua
local natiny = require("natiny")

natiny.backend.init()

local win = natiny.window.create("Glyph wave", 900, 600)
natiny.window.set_scale_mode(win, natiny.window.SCALE_MODE_STRETCH)

local res  = natiny.resource.load("data/common/fonts/roboto.ttf")
local font = natiny.font.create(res, 72)
local small = natiny.font.create(res, 18)

local WORD = "natiny"
local BG     = {  21 / 255,  30 / 255,  44 / 255 } -- #151E2C
local OBJECT = { 169 / 255, 179 / 255, 197 / 255 } -- #A9B3C5
local LIGHT_TEXT = { 243 / 255, 245 / 255, 250 / 255 } -- #F3F5FA

local ascent = natiny.font.get_ascent(font)
local time = 0

local function rainbow(phase)
    return 0.55 + 0.45 * math.sin(phase),
           0.55 + 0.45 * math.sin(phase + 2.09),
           0.55 + 0.45 * math.sin(phase + 4.19)
end

natiny.backend.loop(function(dt)
    natiny.window.bind(win, function()
        time = time + dt

        local width = 0
        for _, code in utf8.codes(WORD) do
            width = width + natiny.font.get_glyph(font, code)
        end

        natiny.render.clear(BG[1], BG[2], BG[3], 1)

        local pen, index = (900 - width) / 2, 0
        local baseline = 320

        natiny.render.set_color(OBJECT[1], OBJECT[2], OBJECT[3], 1)
        natiny.render.line(60, baseline, 840, baseline, 1)

        for _, code in utf8.codes(WORD) do
            local advance, gx, gy, gw, gh = natiny.font.get_glyph(font, code)
            local phase = time * 3 - index * 0.6
            local bob = math.sin(phase) * 34
            local tilt = math.sin(phase) * 14

            natiny.render.set_color(OBJECT[1], OBJECT[2], OBJECT[3], 1)
            natiny.render.rectangle_outline(pen + gx, baseline + gy + bob, gw, gh, 3)

            natiny.render.set_color(rainbow(phase))
            natiny.render.text_ex(font, pen + gx + gw / 2, baseline + gy + gh / 2 + bob,
                      utf8.char(code),
                      gx + gw / 2, ascent + gy + gh / 2, tilt)

            pen = pen + advance
            index = index + 1
        end

        natiny.render.set_color(LIGHT_TEXT[1], LIGHT_TEXT[2], LIGHT_TEXT[3], 1)
        natiny.render.text(small, 60, 500,
               "each box is what get_glyph returns: the picture, relative to the pen")
    end)
end)

natiny.backend.shutdown()