Native Apple UI, live in Lua

Make the idea
the app.

Build polished macOS and iOS interfaces with declarative Lua, real AppKit/UIKit controls, and no compile cycle between edits.

⌘ Edit. Run. See it immediately.

World Weather↻
London, England

Light rain

24°
HUMIDITY68%
WIND23 km/h W
VISIBILITY10 km
7-DAY FORECAST
FRI ☂24°SAT ☀20°SUN ☁22°MON ☂20°TUE ☀21°

A real native window, rendered from Lua

The lua-objc film

Build. Run.
Keep moving.

A short film about building native Apple apps in Lua, from the first edit to a running interface.

Lua Studio for iPad

From a prompt
to a running app.

Describe the iPhone app you want. Lua Studio turns the idea into an editable project, shows the changed files, and runs it in a native iPhone preview right on your iPad.

Build on iPad today iPhone app coming soon

Original Lua Studio iPad screenshot inside a flat device frame, alongside an iPhone Assistant concept labeled Coming soon. The iPad workspace and its phone preview retain their original proportions.
The live iPad workspace. Studio for iPhone is coming soon. View full size
01

Describe

Start with your app idea in the AI assistant.

02

Shape the code

Review and edit the project files as they are created.

03

Run on iPad

See your iPhone app in a live native preview.

The short version

Less waiting.
More making.

SwiftUI is elegant. The compile-and-preview loop around it can be anything but. lua-objc keeps the expressive part and removes the ceremony between an edit and the thing you are building.

01

Native by default

AppKit and UIKit controls do the real work: selection, keyboard behavior, accessibility, focus, and platform metrics.

02

Fast to change

Edit a Lua controller or etlua view, run it directly, and get a fresh native window without an Xcode build step.

03

Easy to verify

Headless tests, screenshots, and native layout dumps make behavior and geometry inspectable by people and agents.

A small proof

Weather, without
the weather report.

One app. A real network request, native loading state, a location sidebar, and a seven-day forecast that scrolls when it needs to.

lua-objc Weather app showing a location sidebar and detailed seven-day forecast
EXAMPLE / WEATHER APPKIT

Stable structure belongs in etlua. State, network boundaries, and actions stay in Lua. The result is simple to read, simple to test, and still feels at home on the platform.

Read the weather walkthrough

Start with a folder

Your next screen
is a Lua file.

Keep the shape familiar: a model for data, a controller for actions, and views for declarative structure. The framework instantiates the controller returned by init.lua and calls its createWindow() method. Reusable view components return view trees.

Coming from PHP? Think Laravel with Blade.

The workflow is familiar: a controller prepares model data and passes it to a template. Here, Controller.lua renders views/*.etlua into real AppKit/UIKit controls. Partials, layouts, and reusable Lua view components keep presentation organized.

The key difference is lifetime. Controllers and native widgets stay alive across clicks, typing, and asynchronous results. Native callbacks invoke actions, and controllers explicitly update the views. Model changes do not yet trigger automatic reconciliation.

Use Laravel as a guide for separating responsibilities: models own queries and mutations, controllers coordinate actions, and views own presentation. This is an architectural comparison; the models are ordinary Lua code, with no Eloquent-style ORM implied.

Read the Laravel comparison
apps/weather/views/CityDetail.etluaVIEW
<% if #city.forecast > 0 then -%>
      <Divider />
      <Label text="7-day forecast" size="14" weight="semibold" />
      <ScrollView contentWidth="772" contentHeight="188" fixedHeight="200" fillWidth="true" horizontal="true">
        <HStack spacing="12" alignment="top" fixedWidth="772">
          <% for _, day in ipairs(city.forecast) do -%>
          <VStack spacing="4" alignment="center" fixedWidth="100">
            <Label text="<%= day.date %>" size="11" color="secondary" />
            <Image src="<%= day.icon %>" fixedWidth="28" fixedHeight="28" label="<%= day.desc %>" />
            <Label text="<%= day.tempMax or "--" %>°" size="16" weight="medium" />
            <Label text="<%= day.precipProbability or "--" %>% rain" size="10" color="secondary" />
          </VStack>
          <% end -%>
        </HStack>
      </ScrollView>
    <% end -%>
demo/hello/views/Window.etluaVIEW
<VStack flexGrow="1" padding="24" spacing="12" alignment="leading">
      <Label text="Hello from Lua" size="24" weight="bold" />
      <Label text="A SwiftUI-like API backed by native AppKit controls." size="14" />
      <SystemImage name="swift" size="64" label="Swift" />
</VStack>
demo/hello/Controller.luaLIVE
local ns  = require("AppKit")
local xml = require("ui.xml")

function Controller:createWindow()
  local cfg = xml.renderFile(VIEWS .. "Window.etlua")
  return ns.Window(cfg)
end
$ ./lua-objc demo/hello ●

Built with lua-objc

Meet Diskmap.

A native Mac app that turns storage into a visual map, with the context to review cleanup before anything moves.

Explore Diskmap
An isolated Diskmap storage map and category rows in a promotional composition.

Open source, Apple-shaped

A faster path from
thought to interface.

Contributors are very welcome. Bring a widget, an example, a test, a design idea, or simply a sharp question.