← Recipe: package an image and compose visuals

3. Replace src/main.luau

luastra/assets · UI.Image · UI.Shape · about 15 minutes
typed asset → URI → image · shapes stay code-native

The bitmap supplies detailed artwork, while Shape supplies resolution-independent geometry without another packaged file.

When to use it

Replace the complete entry module. Keep the typed reference at module scope and convert it to a URI only at the consuming SDK boundary.

Focused example

--!strict

local Assets = require("luastra/assets")
local UI = require("luastra/ui")

local mark = Assets.image("image/luastra-mark")
local markSource = Assets.uri(mark)
local cover = false
local App = require("luastra/app")
local Root = {}

function Root.render(): UI.Node
    return UI.Screen {
        id = "visuals",
        width = "content",
        padding = "responsive",
        UI.Card {
            id = "visuals/card",
            gap = "lg",
            padding = "lg",
            surface = "elevated",
            UI.Text { id = "visuals/title", text = "Packaged visuals", variant = "title" },
            UI.Image {
                id = "visuals/mark",
                source = markSource,
                label = "Luastra orbit mark",
                width = 280,
                height = 180,
                fit = cover and "cover" or "contain",
                cornerRadius = 24,
            },
            UI.Text {
                id = "visuals/fit-status",
                text = cover and "Fit: cover" or "Fit: contain",
                role = "status",
            },
            UI.Button {
                id = "visuals/toggle-fit",
                text = cover and "Show complete image" or "Fill the frame",
                onTap = "visuals.toggle-fit",
            },
            UI.Row {
                id = "visuals/shapes",
                gap = "lg",
                responsive = true,
                UI.Shape {
                    id = "visuals/decoration",
                    shape = "circle",
                    width = 72,
                    height = 72,
                    fill = "accent",
                    label = "",
                },
                UI.Shape {
                    id = "visuals/featured",
                    shape = "star",
                    width = 88,
                    height = 88,
                    fill = "warning",
                    stroke = "text",
                    strokeWidth = 2,
                    label = "Featured visual",
                },
            },
        },
    }
end

function Root.handle(action: string, target: string, _value: string)
    if action == "visuals.toggle-fit" and target == "visuals/toggle-fit" then
        cover = not cover
    end
end

function Root.snapshot()
    return { source = markSource, cover = cover }
end

return App.compose {
    render = function(_outputs) return Root.render() end,
    handle = Root.handle,
    snapshot = Root.snapshot,
}

Complete inventory

View all pages in Recipe: package an image and compose visuals
← Previous: 2. Replace luastra.jsonNext: 4. Replace tests/smoke.luau →