# Lua

Run Lua games in the browser with wasmoon — no build step, just an HTML shell.

Source: https://docs.wavedash.com/engines/lua

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-lua" />
<PlaytestLink href="https://wavedash.com/playtest/lua-example/b1ba96d9-43a4-4218-8a96-2cda3ef33e43" />

You can ship a Lua game to Wavedash by running Lua 5.4 in the browser with [wasmoon](https://github.com/ceifa/wasmoon). No build step — wasmoon loads from a CDN at runtime, and you bind whatever JS objects your Lua code needs (`window`, `document`, `Wavedash`) as Lua globals.

<Note>
For the Love2D engine specifically, see the dedicated [Love2D guide](/engines/love2d). This page covers plain Lua runtimes.
</Note>

## Setup

Create a `web/` folder with an `index.html` that bootstraps wasmoon and a `main.lua` with your game.

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>My Lua Game</title>
    <style>
      html, body { margin: 0; height: 100%; background: #111; }
      #gameCanvas { width: 100%; height: 100%; display: block; }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas"></canvas>
    <script type="module">
      import { LuaFactory } from "https://cdn.jsdelivr.net/npm/wasmoon@1.16.0/+esm";

      const factory = new LuaFactory();
      const lua = await factory.createEngine();

      const Wavedash = window.Wavedash;

      lua.global.set("window", window);
      lua.global.set("document", document);
      lua.global.set("Math", Math);
      lua.global.set("Wavedash", Wavedash);

      const main = await fetch("./main.lua").then((r) => r.text());
      await lua.doString(main);
    </script>
  </body>
</html>
```

## SDK integration

With `Wavedash` bound as a global, Lua calls it using method-call syntax (`:`) so the SDK receives `this`:

```lua
-- window, document, Math, and Wavedash are bound as globals by index.html
-- (the wasmoon engine was created and main.lua fetched before this code runs)

-- wasmoon runtime is loaded and this script has been fetched.
Wavedash:updateLoadProgressZeroToOne(0.5)

local canvas = document:getElementById("gameCanvas")
local ctx = canvas:getContext("2d")

local function loop(now)
  -- update + draw
  window:requestAnimationFrame(loop)
end

-- ...install input handlers, kick off the loop...

-- Game state initialized and loop is ready to start.
Wavedash:updateLoadProgressZeroToOne(1.0)
Wavedash:init({ debug = true })
```

Any SDK method works: `Wavedash:setAchievement("first_win", true)`, `Wavedash:requestStats()`, etc. See [SDK setup](/sdk/setup) and [Functions reference](/sdk/functions) for the full list.

## wavedash.toml

```toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./web"
entrypoint = "index.html"
```
