neyuki 0.6.3

A small Lua-like scripting language implemented in Rust
local ui = require("@neyuki/ui")

-- Gradients, shadows, clipping, group opacity and backdrop blur. A gradient
-- "wallpaper" moves behind a frosted glass sidebar with a clipped,
-- scrolling list of 500 rows, a card with a shadow, and a cached canvas.
-- Scroll over the list, press Escape to quit.

local win = ui.open({ title = "Neyuki canvas", width = 640, height = 400 })
local scroll = 0
local t = 0

-- A card rendered once on a canvas and drawn every frame.
local badge = ui.canvas(120, 48, { scale = win:scale() })
badge:fillRect(0, 0, 120, 48, "#ff7a59", { radius = 24, gradient = { from = "#ff7a59", to = "#7a5cff", angle = 0 } })
badge:text(24, 12, "Canvas", { size = 20, color = "#ffffff" })

local star = ui.path()
for i = 0, 9 do
    local angle = math.rad(i * 36 - 90)
    local radius = 40
    if (i % 2 == 1) then radius = 18 end
    local x = 500 + math.cos(angle) * radius
    local y = 120 + math.sin(angle) * radius
    if (i == 0) then star:moveTo(x, y) else star:lineTo(x, y) end
end
star:close()

ui.run(function(events: {Event}, dt: number)
    for _, event in events do
        if (event.kind == "keydown" and event.key == "escape") then
            win:close()
            return
        elseif (event.kind == "scroll") then
            scroll = math.max(0, math.min(500 * 28 - 300, scroll - event.dy * 28))
        end
    end
    t += dt
    local w, h = win:size()

    -- Wallpaper: a slowly rotating gradient with a few shapes to blur.
    win:fillRect(0, 0, w, h, "#000000", {
        gradient = { from = "#1e3c72", to = "#e96443", angle = 30 + t * 20 },
    })
    win:circle(420 + math.sin(t) * 60, 120, 70, "#ffd166")
    win:circle(500, 280 + math.cos(t) * 40, 50, "#06d6a0")

    -- Frosted glass sidebar: blur the wallpaper, tint it, clip the rows.
    win:blurRegion(16, 16, 240, h - 32, 18, { radius = 16 })
    win:fillRect(16, 16, 240, h - 32, "#ffffff28", { radius = 16 })
    win:strokeRect(16, 16, 240, h - 32, "#ffffff50", { radius = 16 })
    win:pushClip(16, 16, 240, h - 32, { radius = 16 })
    local first = math.floor(scroll / 28)
    for i = first, first + 14 do
        if (i >= 0 and i < 500) then
            win:text(32, 28 + i * 28 - scroll, "Row " .. (i + 1), { size = 16, color = "#ffffff" })
        end
    end
    win:popClip()

    -- A card with a drop shadow, fading in and out as a group.
    win:pushOpacity(0.6 + 0.4 * math.sin(t * 2))
    win:fillRect(300, 60, 280, 120, "#ffffff", {
        radius = 14,
        shadow = { blur = 24, offsetY = 10, color = "#00000066" },
    })
    win:text(320, 80, "Group opacity", { size = 20, color = "#202030" })
    win:fillPath(star, "#ff7a59", { gradient = { kind = "radial", from = "#ffd166", to = "#ff7a59" } })
    win:popOpacity()

    win:drawImage(badge, 300, 220)
    win:present()
end)

badge:close()