# JavaScript

Bundle a JavaScript game with esbuild and ship it to Wavedash.

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

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-js" />
<PlaytestLink href="https://wavedash.com/playtest/javascript-example/ffaf73a7-6052-4654-b460-2110819f6928" />

The recommended setup is a small bundler (`esbuild`) plus the `@wvdsh/sdk-js` package — that gives you a real `import Wavedash from "@wvdsh/sdk-js"` and full editor autocomplete on every method, event, and payload. If you want to skip the build step entirely, see the [vanilla JS path](#vanilla-js-no-build-step) at the bottom of the page.

## Install dependencies

```bash
npm install @wvdsh/sdk-js
```

The default export is the live, fully-typed Wavedash SDK singleton.

## Setup

```
my-game/
├── wavedash.toml
├── package.json
├── src/main.js       # source
└── web/
    ├── index.html    # loads ./main.bundle.js
    └── main.bundle.js  # esbuild output (gitignored)
```

### `package.json`

```json
{
  "name": "my-game",
  "private": true,
  "scripts": {
    "build": "esbuild src/main.js --bundle --format=esm --target=es2022 --outfile=web/main.bundle.js"
  },
  "dependencies": {
    "@wvdsh/sdk-js": "^1.3.0"
  },
  "devDependencies": {
    "esbuild": "^0.24.0"
  }
}
```

### `web/index.html`

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>My Game</title>
    <style>
      html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #111; }
      #gameCanvas { width: 100%; height: 100%; display: block; }
    </style>
  </head>
  <body>
    <canvas id="gameCanvas"></canvas>
    <script type="module" src="./main.bundle.js"></script>
  </body>
</html>
```

### `src/main.js`

<Urgent>
**Calling `Wavedash.init()` is required.** Your game stays hidden behind the Wavedash loading screen until you do. Call it once your game is ready to play.
</Urgent>

```javascript
import Wavedash from "@wvdsh/sdk-js";

const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");

// Load assets in stages and report progress as you go.
Wavedash.updateLoadProgressZeroToOne(0);
await loadImages();                          // e.g. fetch sprite sheets
Wavedash.updateLoadProgressZeroToOne(0.5);
await loadAudio();                           // e.g. decode sound effects
Wavedash.updateLoadProgressZeroToOne(1);
Wavedash.init({ debug: true });

let last = performance.now();
(function loop(now) {
  const dt = Math.min(0.05, (now - last) / 1000);
  last = now;
  update(dt);
  draw();
  requestAnimationFrame(loop);
})(last);
```

Call `updateLoadProgressZeroToOne(...)` with intermediate values during async asset loading. `init()` automatically signals load completion, so call it last.

### Build and run

```bash
npm install
npm run build
wavedash dev
```

## wavedash.toml

```toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./web"
```

## Vanilla JS, no build step

If your game is plain JavaScript and you'd rather skip the bundler, just use `window.Wavedash` directly — the host injects it before your code runs. Drop the `<script type="module" src="./main.bundle.js">` for a plain `<script src="./main.js">`, and write `main.js` against the global:

```javascript
/// <reference types="@wvdsh/sdk-js" />

const Wavedash = window.Wavedash;
Wavedash.updateLoadProgressZeroToOne(0);
await loadImages();
Wavedash.updateLoadProgressZeroToOne(0.5);
await loadAudio();
Wavedash.updateLoadProgressZeroToOne(1);
Wavedash.init({ debug: true });
```

The triple-slash reference is optional — when `@wvdsh/sdk-js` is installed, it tells VS Code (and other LSP-aware editors) to load the SDK's types so `window.Wavedash` becomes fully typed in the rest of the file. The line is a comment, so nothing executes and you still have zero build step. Without the reference (or without the package installed) the SDK still works — you just lose autocomplete.

## SDK features

Once initialized, `Wavedash` exposes leaderboards, achievements, stats, and user data:

```javascript
const user = Wavedash.getUser();

const lb = await Wavedash.getLeaderboard("high-scores");
await Wavedash.uploadLeaderboardScore(lb.data.id, score, true);

Wavedash.setAchievement("first_clear", true);
```
