-- A bouncing ball that follows clicks. Escape or the close button ends it.
local ui = require("@neyuki/ui")
local math = require("@neyuki/math")
local win = ui.open({ title = "Neyuki UI", width = 640, height = 400 })
local ball = { x = 320, y = 200, vx = 180, vy = 120, r = 24 }
local clicks = 0
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 == "mousedown" and event.button == "left") then
ball.x, ball.y = event.x, event.y
clicks += 1
end
end
local w, h = win:size()
ball.x += ball.vx * dt
ball.y += ball.vy * dt
if (ball.x < ball.r or ball.x > w - ball.r) then ball.vx = -ball.vx end
if (ball.y < ball.r or ball.y > h - ball.r) then ball.vy = -ball.vy end
ball.x = math.clamp(ball.x, ball.r, w - ball.r)
ball.y = math.clamp(ball.y, ball.r, h - ball.r)
win:clear("#1e1e2e")
win:line(0, h / 2, w, h / 2, "#313244", { width = 2 })
win:circle(ball.x, ball.y, ball.r + 6, "#89b4fa55")
win:circle(ball.x, ball.y, ball.r, "#89b4fa")
win:fillRect(12, 12, 200, 44, "#313244", { radius = 8 })
win:text(24, 22, "clicks: " .. tostring(clicks), { size = 18, color = "#cdd6f4" })
win:text(12, h - 28, "click to move the ball, escape to quit", { size = 14, color = "#a6adc8" })
win:present()
end)