# Build an Ember applet

An Ember applet is a small web app that runs inside Ember. You write HTML, CSS, and JavaScript, describe the app in `applet.json`, then sign and package it as a `.ember-applet` file.

You need Node.js 22 or newer and a local checkout of the Ember repository. The complete author kit lives in `docs/applets`. Read the [applet specification](/docs/applets/APPLET_SPEC.md) before building. It is the source of truth for manifests, package limits, security rules, and every `window.ember` API. The folder also includes v1 and v2 JSON schemas, TypeScript types, a key tool, a package tool, and a WASI backend template.

## Make the applet

Create a folder with these files:

```text
my-applet/
  applet.json
  index.html
  app.js
  styles.css
```

Put this in `applet.json`:

```json
{
  "manifestVersion": 1,
  "id": "com.example.hello",
  "name": "Hello Ember",
  "description": "My first Ember applet.",
  "version": "1.0.0",
  "entry": "index.html",
  "icon": "applet"
}
```

The ID must use reverse-domain form, such as `com.example.hello`. Keep it stable once people install your applet. Ember uses it to identify updates and to separate each applet's data.

Add a page in `index.html`. Load Ember's SDK before your application script. The SDK supplies `window.ember`; remote and inline scripts are blocked.

```html
<!doctype html>
<html lang="en">
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Hello Ember</title>
  <body>
    <h1>Hello from my applet</h1>
    <script src="/_ember/sdk.js"></script>
    <script src="app.js"></script>
  </body>
</html>
```

Then add any browser-side behavior in `app.js`. Bundle every script, stylesheet, font, and image with your applet. Ember does not allow inline or remote scripts.

## Use Ember APIs

Applets cannot call Tauri or native system APIs. Ember adds a small `window.ember` API when an applet declares a supported permission or capability.

For example, add `storage` to the manifest:

```json
"permissions": ["storage"]
```

Then use it from `app.js`:

```js
await window.ember.storage.set("greeting", "Hello Ember");
const greeting = await window.ember.storage.get("greeting");
console.log(greeting);
```

Each applet has its own 5 MB JSON store. Declare only what the applet needs. Version 2 manifests add native HTTP, browser networking, credentials, OAuth, external links, fullscreen, workers, a guest terminal, trusted extension calls, and optional WASI backends. Use manifest version 2 when you need any of those features. It requires a `capabilities` object and does not use version 1's `permissions` array.

Copy `docs/applets/ember.d.ts` into a TypeScript project for SDK types. The [applet specification](/docs/applets/APPLET_SPEC.md) gives an example and limits for every capability, including network origins, request headers, credential placement, and backend execution.

## Sign and package it

Keep your private key outside the applet folder. From the Ember repository root, create a development key once:

```sh
npm run applet:key -- ../ember-dev-key.pem
```

Package the applet:

```sh
npm run applet:pack -- path/to/my-applet ../ember-dev-key.pem
```

This writes `com.example.hello-1.0.0.ember-applet`. The packager hashes the applet's files and signs those hashes. Do not edit the package after it is created.

## Test it in Ember

Open Ember, choose Library, and select the `.ember-applet` file. Ember verifies its contents and signature, then shows its identity and requested capabilities before installing it. Launch it from the Library.

For a fuller working example, inspect `applets/notes` in the Ember repository. It includes a manifest, local UI files, storage, and applet settings. If you use an AI coding agent, give it the whole `docs/applets` directory and the instructions in the AI agent guide.
