> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overlayed.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Your First App

> Get a brand new Overlayed app up and running.

This guide takes you from an empty folder to a running Overlayed app with a window on screen. Along the way it explains
what each piece is for - the two config files, the CLI, the `.overlayed` directory - and gives you a checkpoint at each
step so you know it worked before moving on.

<Info>
  Already comfortable with Electron and just want the commands? The [Quickstart](/quick-start) is the condensed version
  of this flow. For the architecture behind it, see [App Structure](/essentials/app-structure).
</Info>

## What an Overlayed App Is

Four facts frame everything below:

1. **It's your Electron app with Overlayed inside.** There is no scaffolding command and no framework to adopt - you
   start from a plain Electron project, install `@overlayed/app`, and call `overlayed()` once at startup. That call
   returns the `overlay` object the rest of your code uses.
2. **Your UI is a website, not local files.** The Electron side creates windows and loads your frontend from a URL - a
   local dev server while developing, `https://your-site.overlayedapps.com` in production. Never `file://`.
3. **It runs on a custom Electron build.** `@overlayed/electron` provides the `ogg-electron` command - use it anywhere
   you would normally run `electron`. Your imports (`app`, `BrowserWindow`, etc.) still come from `electron` as usual.
4. **Local development is tied to a registered application.** `overlayed()` requires an `applicationId` from the
   [Overlayed Dashboard](https://overlay.dev/settings/applications), and the CLI caches your app's metadata locally in a
   `.overlayed` directory before the app can start.

<Info>
  If you'd rather follow along from working code, the [example apps repo](https://github.com/overlayed-gg/examples) is
  a good starting place for this guide.
</Info>

## From Empty Folder to Overlay Window

<Steps>
  <Step title="Create a bare Electron project">
    Start with a minimal TypeScript Electron project. Two files matter: a `package.json` that runs the app through
    `ogg-electron`, and a `tsconfig.json` that compiles `src/` to `dist/`.

    <CodeGroup>
      ```json package.json theme={null}
      {
      	"name": "my-overlay",
      	"version": "0.0.1",
      	"type": "module",
      	"main": "dist/main.js",
      	"scripts": {
      		"start": "tsc && ogg-electron ."
      	}
      }
      ```

      ```json tsconfig.json theme={null}
      {
      	"compilerOptions": {
      		"module": "NodeNext",
      		"moduleResolution": "NodeNext",
      		"strict": true,
      		"skipLibCheck": true,
      		"outDir": "dist"
      	},
      	"include": ["src"]
      }
      ```
    </CodeGroup>

    <Warning>
      Keep `"type": "module"`. `@overlayed/app` is ESM-only and cannot be loaded as CommonJS - a CJS build fails
      with `Cannot use import statement outside a module`. See
      [Understanding Bundles](/deployment/introduction) for the build-format rules.
    </Warning>

    <Info>
      Prefer to start from something working? Clone one of the completed
      [example apps](https://github.com/overlayed-gg/examples) instead and follow along from step 3.
    </Info>
  </Step>

  <Step title="Install the Overlayed packages">
    Install the two runtime packages into your project, pinned to exact versions, and the CLI globally:

    <CodeGroup>
      ```bash pnpm theme={null}
      pnpm i @overlayed/app @overlayed/electron --save-exact
      pnpm i -g @overlayed/cli
      ```

      ```bash npm theme={null}
      npm i @overlayed/app @overlayed/electron --save-exact
      npm i -g @overlayed/cli
      ```
    </CodeGroup>

    * `@overlayed/app` - the runtime: the `overlayed()` function and everything on the `overlay` object.
    * `@overlayed/electron` - the custom Electron build and the `ogg-electron` command your `start` script uses.
    * `@overlayed/cli` - the `overlayed` command used for authentication, initialization, and later
      [bundling](/deployment/introduction).
  </Step>

  <Step title="Authenticate with the platform">
    The CLI (and your app, in development) talk to the Overlayed API, so authenticate once per machine:

    ```bash theme={null}
    overlayed login
    ```

    This opens the dashboard page for creating an API key in your browser; paste the key back into the prompt, and
    it's stored locally. **Checkpoint:** `overlayed whoami` prints the email you're logged in as.

    <Info>
      You'll need access to the Overlayed Dashboard to create an API key and an application. You can apply for
      access [here](https://overlayed.gg/contact).
    </Info>
  </Step>

  <Step title="Add the two config files">
    An Overlayed project has two configuration touchpoints. `src/overlayed.ts` is your app's *runtime* setup - it
    calls `overlayed()` and exports the `overlay` object everything else imports. `overlayed.config.ts` at the
    project root is read by the *CLI* for `overlayed init` and, later, bundling.

    <CodeGroup>
      ```typescript src/overlayed.ts theme={null}
      import { overlayed } from "@overlayed/app";
      import * as Siege from "@overlayed/app/siege";
      import electron from "electron";

      export const overlay = overlayed({
      	electron,
      	applicationId: "YOUR_APPLICATION_ID", // From the Overlayed Dashboard
      	modules: [Siege.module()],
      	keybinds: {
      		toggleMainWindow: {
      			keys: ["AltLeft", "KeyX"],
      			mode: "toggle",
      		},
      	},
      });
      ```

      ```typescript overlayed.config.ts theme={null}
      import { defineConfig } from "@overlayed/app";

      export default defineConfig({
      	applicationId: "YOUR_APPLICATION_ID", // Must match src/overlayed.ts
      	app: {
      		include: [], // Only needed for bundling - configure later
      	},
      	site: {
      		include: [],
      	},
      });
      ```
    </CodeGroup>

    * `applicationId` comes from the [Overlayed Dashboard](https://overlay.dev/settings/applications) and must be
      the same in both files.
    * `modules` subscribes you to specific game events (in this example, Rainbow Six Siege). Alternatively pass
      `universal: true` to react to every supported game. See [OverlayedOptions](/packages/overlayed-options) for
      every option.
    * `keybinds` is required; this one is a placeholder you can wire to a window later - see
      [Show/Hide Window Keybinds](/guides/keybinds-show-hide-windows).
  </Step>

  <Step title="Initialize the dev environment">
    ```bash theme={null}
    overlayed init
    ```

    This reads the `applicationId` from `overlayed.config.ts`, fetches your application's metadata from the API, and
    caches it in `.overlayed/meta.json`. Your app reads that cache at startup during development.

    Add `.overlayed` to your `.gitignore` - it's fetched data, not source. Details in
    [Local Development](/essentials/local-development).
  </Step>

  <Step title="Create the entry point and a window">
    All electron windows must be created through `overlay.windows`, but they return the `BrowserWindow` that you're
    used to.

    <Tabs>
      <Tab title="Desktop window (no game needed)">
        The fastest way to see something on screen. `createWindow` returns a regular Electron `BrowserWindow`,
        so it appears on your desktop immediately - no game required.

        ```typescript src/main.ts theme={null}
        import { app } from "electron";
        import { overlay } from "./overlayed";

        app.on("ready", () => {
        	const window = overlay.windows.createWindow({
        		width: 800,
        		height: 600,
        	});

        	// Any URL works for a first smoke test - remember to
        	// point this at your frontend dev server later.
        	window.loadURL("https://google.com");
        });
        ```
      </Tab>

      <Tab title="In-game window (game required)">
        To render inside the game, wait for the `gameReady` event - it fires once Overlayed has prepared a game
        you subscribed to via `modules` - then use `createInGameWindow`.

        ```typescript src/main.ts theme={null}
        import { app } from "electron";
        import { overlay } from "./overlayed";

        overlay.on("gameReady", ({ game, inGameRenderingSupported }) => {
        	if (!inGameRenderingSupported) {
        		return; // Fall back to a desktop window here
        	}

        	const window = overlay.windows.createInGameWindow({
        		width: 400,
        		height: 300,
        	});

        	// Remember to point this at your frontend dev server later.
        	window.loadURL("https://google.com");
        });
        ```

        The full lifecycle (`gameLaunch`, `gameReady`, `gameClose`) is covered in
        [Game Launch & Close Events](/guides/game-launch-close-events).
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run it">
    <CodeGroup>
      ```bash pnpm theme={null}
      pnpm start
      ```

      ```bash npm theme={null}
      npm start
      ```
    </CodeGroup>

    If you skipped `overlayed init`, the very first run behaves differently: Overlayed detects the missing
    `.overlayed` cache, fetches and caches the metadata itself, then **exits on purpose** with a message explaining
    why. Just run the start script again - this only ever happens once, and never in a packaged app.

    **Checkpoint:** the app stays running and your window appears (on the desktop, or in-game once your subscribed
    game is ready). That's your first Overlayed app.
  </Step>
</Steps>

## Loading Your UI the Right Way

The URL you pass to `loadURL` should differ between development and production. In development, load your local
frontend dev server; in production, load the site URL Overlayed deployed for you:

```typescript theme={null}
const siteUrl = import.meta.env.DEV
	? new URL("http://localhost:5173") // Your frontend dev server
	: overlay.windows.getProductionSiteUrl();

window.loadURL(siteUrl.toString());
```

<Warning>
  Avoid loading the production URL (`https://your-site.overlayedapps.com`) during local development - it requires release
  headers that only exist in deployed builds, and you'll get a "Configuration Required" page instead of your UI. See
  [Local Development](/essentials/local-development).
</Warning>

This split is what makes the [website-based architecture](/essentials/app-structure) pay off: once deployed, you can
ship UI fixes without your users reinstalling anything.

## FAQ

<AccordionGroup>
  <Accordion title="Is there a command that scaffolds a project for me?">
    No. The CLI's commands are `login`, `logout`, `whoami`, `init`, and `bundle` - none generate a project. Start
    from any Electron project (the [Electron quick start](https://www.electronjs.org/docs/latest/tutorial/quick-start)
    works) or clone a completed [example app](https://github.com/overlayed-gg/examples).
  </Accordion>

  <Accordion title="Do I need a game installed to develop?">
    Not for most work. Out-of-game windows (`createWindow`), keybind config, logging, and your frontend all work
    without a game. You need a subscribed, running game only for the in-game pieces: `gameReady`,
    `createInGameWindow`, and [game events](/essentials/game-events). See the
    [supported games](/games/introduction) list.
  </Accordion>

  <Accordion title="Why did my app exit immediately the first time I ran it?">
    That's the automatic first-run initialization. Without `.overlayed/meta.json`, the app fetches your application
    metadata, caches it, and exits so the next run can load the cache - run it again and it starts normally. If it
    exits with "Failed to fetch application metadata" instead, run `overlayed login` first, then `overlayed init`.
  </Accordion>

  <Accordion title="Why do I need both overlayed.ts and overlayed.config.ts?">
    They serve different consumers. `overlayed()` in `src/overlayed.ts` configures your app at runtime (modules,
    keybinds, flags). `overlayed.config.ts` is read by the CLI - `overlayed init` takes the `applicationId` from it,
    and `overlayed bundle` uses its `include` globs when you [deploy](/deployment/introduction). Keep the
    `applicationId` identical in both.
  </Accordion>

  <Accordion title="Can I call overlayed() in more than one file?">
    Overlayed initializes once - after the first call, subsequent calls return the same instance. The convention is
    a dedicated `src/overlayed.ts` that exports `overlay`, and every other file imports from there.
  </Accordion>

  <Accordion title="Can I use JavaScript instead of TypeScript?">
    Yes, with no extra changes - though Overlayed is built [TypeScript-first](/typescript), and typed access to
    options, events, and keybind names is a big part of the experience.
  </Accordion>

  <Accordion title="My window doesn't show up in-game - what do I check?">
    In order:

    1. **Subscription**: `gameReady` only fires for games passed via `modules` (or with `universal: true`).
    2. **Timing**: for freshly launched games there's a deliberate delay before injection - `gameReady` does not
       fire the instant the game starts.
    3. **`inGameRenderingSupported`**: when it's `false` for the session, in-game rendering isn't available and you
       should fall back to a desktop window.

    [Game Launch & Close Events](/guides/game-launch-close-events) walks through all three.
  </Accordion>

  <Accordion title="I get 'Could not find overlayed instance' in the renderer">
    The preload script didn't expose the Overlayed globals to your frontend. Make sure your window's preload script
    imports `@overlayed/app/preload`. See the troubleshooting section in
    [Local Development](/essentials/local-development).
  </Accordion>

  <Accordion title="What's left before other people can use my app?">
    Fill in the `include` globs in `overlayed.config.ts`, run `overlayed bundle` to upload an app bundle and a site
    bundle, and create a release for each in the dashboard. [Understanding Bundles](/deployment/introduction)
    covers the whole pipeline.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Show/Hide Window Keybinds" icon="keyboard" href="/guides/keybinds-show-hide-windows">
    Wire the keybind you declared to your window's visibility.
  </Card>

  <Card title="Game Launch & Close Events" icon="play" href="/guides/game-launch-close-events">
    Create and tear down windows around the game's lifecycle.
  </Card>

  <Card title="Creating Windows" icon="window" href="/windows/introduction">
    In-game vs. out-of-game windows and the windows API.
  </Card>

  <Card title="Understanding Bundles" icon="box" href="/deployment/introduction">
    Bundle and release your app when it's ready to ship.
  </Card>
</CardGroup>
