# Forge

A window manager for [Vide](https://github.com/centau/vide) — rules for what may be open, when. Forge owns no rendering, no popups, no notifications. It just decides whether a window is allowed to open, and gives you a reactive `Vide.Source<boolean>` per window to bind however you like.

> ## ⚠️ Upgrading from Forge < 0.5.0?
>
> Forge 0.5.0 is a complete rewrite with a different API and no code shared with the old "app manager" version (decorators, `@App`, `@ChildApp`, context providers, etc. are all gone).
>
> If you're using an older Forge and aren't ready to migrate, pin the old version:
> - **npm:** [`@rbxts/forge@0.4.8`](https://www.npmjs.com/package/@rbxts/forge/v/0.4.8) (last pre-rewrite release)
> - **Repo:** [`Loner1536/Forge` at tag `v0.4.6`](https://github.com/Loner1536/Forge/tree/v0.4.6) (last pre-rewrite commit in this git history — 0.4.7/0.4.8 were published without a matching commit)
>
> There is no automated migration path — the new API is small enough to rewrite by hand once you read below.

## Install

```sh
npm install @rbxts/forge
```

## Usage

```ts
import Forge from "@rbxts/forge";

const forge = new Forge({
	windows: {
		hud: { defaults: { open: true }, persistent: true },
		shop: { hotkey: Enum.KeyCode.B },
		buyPrompt: { parent: "shop" },
	},
	exclusive: {
		main: ["shop", "inventory"],
	},
});

forge.shop.open();
forge.shop.toggle();
Visible={forge.shop.state}
```

Window names, and every `parent`/`closes`/`blockedBy`/lane reference to another window, are typed against the config itself — typos are compile errors and everything autocompletes.

## Rules per window

- `parent` — closing (or displacing) the parent closes this window too, recursively.
- `closes` — opening this window force-closes these, regardless of exclusivity.
- `blockedBy` — this window refuses to open while any of these are open.
- `defaults.open` — starting state override (e.g. a HUD that starts open).
- `persistent` — survives `closeAll()`.
- `hotkey` — one bind or several: a `Enum.KeyCode`, or `{ hold, press }` for hold-combos (e.g. controller shoulder + face button). Built on Roblox's Input Action System.
- `onOpen` / `onClose` — side-effect callbacks.

## Exclusivity lanes

```ts
exclusive: {
	main: ["shop", "inventory"],               // shorthand, mode defaults to "displace"
	modal: { mode: "block", members: ["shop", "settings"] },
}
```

- `"displace"` (default) — opening a lane member closes whichever other member is open.
- `"queue"` — opening a lane member while another is open queues it; it opens automatically once the lane frees up.
- `"block"` — opening a lane member while another is open fails (`open()` returns `false`).

## Handle API

Every registered window gets:

```ts
forge.<name>.open(force?)  // returns false if blocked/queued (unless force)
forge.<name>.close()
forge.<name>.toggle()
forge.<name>.state         // Vide.Source<boolean> — pass, don't call, to stay reactive
```

Plus manager-level methods:

```ts
forge.closeAll()               // closes everything except persistent windows
forge.reset()                  // restores every window to its defaults
forge.attachHotkeys(parent)    // binds all `hotkey`s under an Instance, returns a cleanup fn
```

## License

MIT
