# API

> Everything importable from `vela-rbxts`, the published packages, and the versions it is tested against.

Source: https://docs.astra-void.xyz/vela-rbxts/reference/api/

Vela's import surface is small. One package has a public entry point, that entry point exports three
values and four types, and a second subpath exports the transformer you wire into `tsconfig.json`.

```bash
pnpm add vela-rbxts
```

## From `vela-rbxts`

```ts
import {
  defaultConfig,
  defineConfig,
  definePreset,
  plugin,
  createTransformer,
  type TailwindConfig,
  type TailwindConfigInput,
  type VelaPreset,
  type ThemeScreens,
  type VariantDefinition,
  type ClassValue,
  type StylableProps,
} from "vela-rbxts";
```

The plugin and variant types are re-exports of `@vela-rbxts/config`, so nothing needs to be
installed to reach them.

### defineConfig

```ts
function defineConfig(input?: TailwindConfigInput): TailwindConfig;
```

Takes an input-shaped theme object and resolves it against the built-in defaults. The argument is
optional, and `defineConfig()` returns a fresh object deep-equal to `defaultConfig`. It is injected
into `vela.config.ts`'s scope automatically, which is why stripping the import still works.

### defaultConfig

```ts
const defaultConfig: TailwindConfig;
```

The resolved built-in theme: 28 colour families, ten named radius keys plus a `DEFAULT`, and a
single spacing key. This is what Vela uses when no `vela.config.ts` is found.

### createTransformer

```ts
function createTransformer(
  options?: RbxtscTransformerBridgeOptions,
): RbxtscTransformerBridge;

// the returned bridge:
// { name, getFileEligibility, shouldTransformFile, transformSource, transformFile }
```

The rbxtsc host bridge, returning an object whose `name` is `"@vela-rbxts/rbxtsc-host"` plus the
eligibility predicates and the transform entry point. `transformSource` and `transformFile` are the
same function under two names.

You do not need this to use Vela — it exists for tooling that drives the transform itself.

> **Two different createTransformer functions**
>
> `createTransformer` imported from `vela-rbxts` is the **rbxtsc host bridge** described above.
>
> `createTransformer` on `vela-rbxts/transformer` is the **TypeScript program transformer factory**.
> It is a completely different function with a different signature and a different job.
>
> The one that goes in `tsconfig.json` is `vela-rbxts/transformer`. Pass the root package's `createTransformer` to roblox-ts and nothing is transformed, with no error explaining why.

### Types

| Prop | Type | Description |
| --- | --- | --- |
| `TailwindConfig` | `{ theme: { colors: ThemeColors; radius: ThemeScale; spacing: ThemeScale } }` | A fully resolved config — every scale present. What defineConfig returns and what the compiler consumes. |
| `TailwindConfigInput` | `{ theme?: { colors?; radius?; spacing?; extend?: { colors?; radius?; spacing? } } }` | The authoring shape — everything optional, with the extend branch. What you pass to defineConfig. |
| `VelaPreset` | `TailwindConfigInput` | A shareable slice of configuration. Same shape as what you pass to defineConfig; definePreset() types one without resolving it, so it still merges as an input rather than as a finished config. Added in 0.13.0. |
| `ClassValue` | `string \| number \| boolean \| null \| undefined \| Record<string, boolean \| null \| undefined> \| ClassValue[]` | The accepted type of the className prop. Covers conditional dictionary and nested array forms, not just strings. |
| `StylableProps` | `StylableProps<P = unknown>` | Intersects your own props P with { className?: ClassValue }. Use it when a component of yours should forward className. |

### The global augmentation

Importing `vela-rbxts` has a side effect: it declares

```ts
declare global {
  namespace React {
    interface Attributes {
      className?: ClassValue;
    }
  }
}
```

That augmentation is what makes `className` type-check on the host elements. It applies only once
the module is imported somewhere your program includes, typically a one-line `.d.ts`:

```ts title="src/vela-env.d.ts"
import "vela-rbxts";
```

Several helpers exist in `@vela-rbxts/config` but are **not** re-exported from the root. The
functions are `SHADES`, `PALETTE_DEFAULT_KEY`, `resolveThemeColors`, `mergeColorRegistry`,
`normalizeColorRegistry` and `normalizeColorScale`. The types are `Shade`, `PaletteKey`,
`PaletteDefaultKey`, `ThemeScale`, `ColorPalette`, `ColorValue`, `ColorScaleInput`, `ThemeColors`,
`ColorInputMap`, `ThemeConfig` and `ThemeConfigInput`. Reach into `@vela-rbxts/config` directly, and
expect them to be less stable.

## From `vela-rbxts/transformer`

A CommonJS module whose export is a callable program-transformer factory. It also carries
`.createTransformer`, `.createRbxtsTailwindProgramTransformer` and `.default`, all pointing at
itself, so every resolution style lands on the same function.

This is the value that goes in `tsconfig.json`:

```json title="tsconfig.json"
{
  "compilerOptions": {
    "plugins": [{ "transform": "vela-rbxts/transformer" }]
  }
}
```

The factory throws if roblox-ts does not hand it a TypeScript instance. Plugin options are in
[Configuration](https://docs.astra-void.xyz/vela-rbxts/reference/config.md#tsconfig-plugin-options).

## Published packages

| Package | What it is | Install directly? |
|---|---|---|
| `vela-rbxts` | The entry point: config helpers, types, the global augmentation, the transformer subpath, and — since 0.11.0 — the `vela` CLI | **Yes** — this is the only one an app installs |
| `@vela-rbxts/compiler` | The Rust compiler behind an N-API binding: transform, completions, hover, diagnostics, document colors | No, pulled in transitively |
| `@vela-rbxts/compiler-wasm` | The same compiler built to WebAssembly, for hosts that cannot load the native addon — a browser, most usefully | Only if you are lowering classes outside Node |
| `@vela-rbxts/config` | The theme schema, `defineConfig`, `defaultConfig`, and the color merge helpers | Only to reach a helper the root package does not re-export |
| `@vela-rbxts/core` | Shared constants, including the supported host element tags | No — and nothing depends on it, so it never arrives transitively either |
| `@vela-rbxts/ir` | The intermediate style representation shared between the compiler and its consumers | No |
| `@vela-rbxts/types` | Shared TypeScript types | No |
| `@vela-rbxts/rbxtsc-host` | The roblox-ts adapter: file eligibility, config discovery, diagnostic mapping | No |
| `@rbxts/vela-runtime-core` | The target-neutral half of the runtime: resolution engine, theme normalization, rem math, rich text, margin and divide computation | No, pulled in by whichever host you emit for |
| `@rbxts/vela-runtime` | The React runtime host every transformed module imports, as one ModuleScript the place shares | No — it ships with `vela-rbxts` |
| `@rbxts/vela-runtime-vide` | The same host for Vide, imported instead when the project sets `framework: "vide"` | No — it ships with `vela-rbxts` |
| `@vela-rbxts/lsp` | The language server binary and its platform packages | Only if you wire up a non-VS Code editor yourself |
| `vela-rbxts-lsp` | The VS Code extension, published as a VSIX rather than to npm | Install from the marketplace as `astra-void.vela-rbxts-lsp` |

For almost every project: install `vela-rbxts`, add the transformer to `tsconfig.json`, install the
VS Code extension. Everything else arrives as a dependency.

The three `@rbxts/vela-runtime*` packages are the exception to "nothing of Vela's reaches your
place". They sit under the `@rbxts` scope because roblox-ts only resolves a package whose scope
directory is one of the project's `typeRoots`. That is the one every roblox-ts project lists and
every Rojo template maps. So they need no tsconfig or Rojo change. But pnpm needs
`nodeLinker: hoisted` for the directory to be real,
[covered in installation](https://docs.astra-void.xyz/vela-rbxts/getting-started/installation.md#install-the-packages).

Each host declares its own UI library as an **optional** peer, which keeps a Vide project from
installing React. The host you do not emit for is inert.

The root package also declares two `bin` entries, `vela` and `vela-rbxts`, pointing at the same CLI.
It lowers a source tree ahead of `rbxtsc` for projects that cannot register the transformer — see
[the CLI reference](https://docs.astra-void.xyz/vela-rbxts/reference/cli.md).

All packages are versioned in lockstep at **0.13.0**, the VS Code extension included. Never mix
versions across the `@vela-rbxts/*` scope. What changed in each release is in the
[release notes](https://docs.astra-void.xyz/vela-rbxts/reference/release-notes.md).

Three subpaths beyond the roots are public. `@vela-rbxts/rbxtsc-host/project-config` exposes config
discovery and loading, which the VS Code extension uses to evaluate the config files it watches.
`@vela-rbxts/compiler/native` exposes the raw N-API binding. Both roots also declare
`"./package.json"` in their exports maps. The root package ships a `schema.json` describing the
config input shape — point a `vela.config.json`'s `$schema` at it.

## Version requirements

**No package declares an `engines` field** except the VS Code extension, which requires VS Code
`^1.90.0`. **No package declares any `peerDependencies`** either. roblox-ts, TypeScript and React
are ordinary dependencies throughout, so nothing is checked at install time. You find out from a
build failure, and in the TypeScript case below, from one that does not mention versions.

What the project is developed and tested against:

| Tool | Version |
|---|---|
| Node | 24 (what CI runs) |
| TypeScript | 5.9.3, pinned exactly — see below |
| roblox-ts | `^3.0.0` |
| `@rbxts/react` | `^17.3.7-ts.1` |
| `@rbxts/services` | `^1.6.0` |

> **TypeScript is an upper bound, not just a floor**
>
> `@vela-rbxts/rbxtsc-host` resolves `typescript` from **your** project and calls into its API directly. TypeScript 7 moved enough of that API to break the call. A project on the current TypeScript fails on its first file with `compiler-invocation-failed: Cannot read properties of undefined (reading 'Latest')`.
>
> `5.9.3` is the tested pin and `6.x` also builds. roblox-ts's own `typescript` does not save you — it pins `=5.5.3` for itself, while Vela reads the one in your project.

`@rbxts/services` is a genuine runtime dependency: the runtime helper imports `UserInputService` and
`Workspace` from it to evaluate variants.

### Prebuilt compiler binaries

The compiler ships N-API binaries for these targets:

- `x86_64-unknown-linux-gnu`
- `x86_64-unknown-linux-musl`
- `aarch64-unknown-linux-gnu`
- `aarch64-apple-darwin`
- `x86_64-apple-darwin`
- `x86_64-pc-windows-msvc`

There is **no `aarch64-pc-windows-msvc` build** and no linux arm64 musl build, so those two targets
need the compiler crate built from source.

Two things look like escape hatches and are not. The napi-rs loader ends with a WASI fallback
reaching for `@vela-rbxts/compiler-wasm32-wasi`, which is not published. It always falls through to
`Cannot find native binding.`, whose advice to reinstall without a lockfile is misleading on a
platform that has no binary. And `@vela-rbxts/compiler-wasm` is a separate package with its own API,
not a drop-in fallback.

## See also

- [Configuration](https://docs.astra-void.xyz/vela-rbxts/reference/config.md) for the schema `defineConfig` accepts.
- [Diagnostics](https://docs.astra-void.xyz/vela-rbxts/reference/diagnostics.md) for what the transformer reports.
