# Packages

> The @loom-dev scope — what each package owns, which ones you install, and the boundaries between them.

Source: https://docs.astra-void.xyz/loom/reference/packages/

Loom is a pnpm workspace with a Rust half and a TypeScript half. Only two packages are things you
install directly; the rest are internal boundaries that happen to be published so the dependency
graph resolves.

## What you install

| Package | Role |
| --- | --- |
| `@loom-dev/preview` | The Vite plugin — including the generated page, entry detection, gallery discovery and the gallery shell — plus the browser stand-ins for `@rbxts/react-roblox` and `@rbxts/services`, and the globals installer. |
| `loom-dev` | The `loom` CLI: `preview` and `build`, flag/`loom.config.ts` handling, and the `loom-dev/embed` and `loom-dev/next` APIs. A wrapper over the plugin. |

## The rest of the scope

| Package | Owns |
| --- | --- |
| `@loom-dev/scene` | The Scene IR types — the contract every other package is written against. Mirrors the `loom-scene` Rust crate. |
| `@loom-dev/layout` | A typed async wrapper over the WASM layout engine: `initLayout()`, `computeLayout(scene, viewport)`. |
| `@loom-dev/runtime` | Roblox datatypes, the `Instance` model, signals, services, the scheduler, and the [Luau standard library](https://docs.astra-void.xyz/loom/reference/luau-globals.md). |
| `@loom-dev/renderer` | Scene IR → DOM, plus the incremental patching session with pointer and keyboard input delegation, and the font registry (`registerFont`, `onFontsChanged`, `clearRegisteredFonts`, and `familyIsAvailable` since `0.9.6`). |
| `@loom-dev/react` | The `@rbxts/react` adapter — a custom `react-reconciler` host config driving live loom instances. |
| `@loom-dev/vide` | The `vide` signals adapter, on the same Scene IR. |

## Secondary entry points

| Specifier | What it is |
| --- | --- |
| `@loom-dev/preview/vite` | The Vite plugin. Always import it by this bare specifier — a file path moves the anchor it resolves its aliases from. |
| `@loom-dev/preview/globals` | The Roblox datatype globals, as a side effect. Only needed on a hand-rolled build the plugin cannot see. |
| `@loom-dev/renderer/fonts` | The openly licensed Roblox typefaces, registered on import. **The preview imports it for you** as of `0.9.0` — it is a separate entry so a project embedding the adapters directly can choose, since the font packages sit behind it. See [Fonts and text metrics](https://docs.astra-void.xyz/loom/guides/fonts.md). |
| `loom-dev/embed` | `createGalleryServer()`, `buildGallery()`, `findGalleryTargets()` — the CLI's two pipelines as functions. |
| `loom-dev/next` | The Next.js config wrapper around the same two pipelines. |

## The Rust half

| Crate | Owns |
| --- | --- |
| `loom-scene` | Scene IR types and schema — the single source of truth `@loom-dev/scene` mirrors. |
| `loom-layout` | The layout engine. |
| `loom-layout-wasm` | A `wasm-bindgen` wrapper around `loom-layout`, built with `wasm-pack --target web`. |

The build emits into `packages/layout/pkg/`, which `@loom-dev/layout` imports directly. Consumers
receive that binary prebuilt and never need a Rust toolchain.

## Dependency direction

```text
loom-dev ──► @loom-dev/preview ──► @loom-dev/react ──► @loom-dev/renderer ──► @loom-dev/scene
                                          │                    │
                                          └──► @loom-dev/runtime└──► @loom-dev/layout ──► pkg/*.wasm
```

Nothing below `@loom-dev/react` knows a frontend framework exists. That is what let the `vide`
adapter drop in beside the React one without changes to the layout engine or the renderer, and it is
the intended extension point for a future Luau frontend.

The gallery shell lives in `@loom-dev/preview`, not the CLI: gallery mode is a plugin option
(`loomPreview({ targets })`), and the CLI is one of its callers rather than its owner. `loom-dev`
keeps only what is genuinely command-shaped — argument parsing, `loom.config.ts`, and the embed API.

## Versioning

All published `@loom-dev/*` packages move together — changesets marks them `fixed`, so a bump to one
bumps them all. The workspace is a single coherent runtime, and mismatched versions across the scope
are never a supported combination.

## Example apps in the repo

Useful as copy-paste references when integrating:

| App | Shows |
| --- | --- |
| `apps/example` | The minimal roblox-ts client entry the CLI auto-detects — no config of any kind. |
| `apps/interactive` | A `vite.config.ts` holding nothing but `loomPreview()`, and no `index.html`: the plugin-only path, plus input and signal wiring. |
| `apps/gallery-demo` | `loomPreview({ targets })` over `*.loom.tsx` scenes, including one that throws on purpose to exercise error containment. |
| `apps/playground` | The same plugin with a hand-written `index.html` of its own. |
| `apps/vide-example` | The same pipeline driven by `vide` instead of React. |
