# Scope and status

> What Vela covers at 0.13.0, which Tailwind families are permanently out, and where enforcement has gaps.

Source: https://docs.astra-void.xyz/vela-rbxts/getting-started/scope-and-status/

Vela borrows Tailwind's syntax, not its scope. What it ships is a Roblox-oriented mapping. Utilities
that correspond to real Roblox properties and helper instances, plus a few structural emulations
where the correspondence can be built honestly. Margins become a wrapper frame, and `divide-*`
becomes separator frames. Everything that cannot be expressed is rejected loudly. This page maps
where those edges are at **0.13.0**.

## What is in scope

Utilities apply to exactly eight host elements:

`frame`, `scrollingframe`, `canvasgroup`, `textlabel`, `textbutton`, `textbox`, `imagelabel`, `imagebutton`

They also apply to **components** — any tag starting with an uppercase letter, or any member
expression such as `<Switch.Root />`. A `className` there lowers into props and helper children on
the component itself, which reaches the screen only if the component forwards what it does not
consume. See [How it works](https://docs.astra-void.xyz/vela-rbxts/getting-started/how-it-works.md#classname-on-components).

Anything that is neither is skipped, keeps its `className` verbatim, and reports
`classname-on-unsupported-host`. That covers lowercase intrinsics Vela does not implement, such as
`screengui`, and namespaced tags such as `<svg:rect />`, which never count as components.

Within those eight the covered ground is wide. Paint: colours (arbitrary hex and `/N` opacity
modifiers included), gradients, borders, rings and outlines, per-corner radius, shadows and opacity.
Space. Padding, margins, gap and `space-*`, `divide-*` separators, sizing with min and max
constraints, position on all four edges, anchor point, translation, rotation, scale, aspect ratio,
z-index and layout order. Layout: flex layout and flex items, grid with real cell sizing,
visibility, overflow and the ScrollingFrame families. Then typography, image scaling, interactivity
and overscroll, and arbitrary length values across most of it. Finally a `TweenService`-backed
motion layer with the runtime variants — `hover:`, `active:`, `focus:`, `dark:`, the breakpoints and
their `max-` complements, and the attribute-backed states you define yourself. `opacity-*` is the
one utility that reaches past the element it is written on
([how far, and where it stops](https://docs.astra-void.xyz/vela-rbxts/reference/utilities.md#effects)). A config can add
utilities through [plugins](https://docs.astra-void.xyz/vela-rbxts/reference/config.md#plugins), and the
[utilities reference](https://docs.astra-void.xyz/vela-rbxts/reference/utilities.md) enumerates all of it.

Two things cut across all of it. Every pixel offset a utility lowers is a
[rem unit](https://docs.astra-void.xyz/vela-rbxts/guides/theming.md#rem) following the viewport. And the whole set emits for
[Vide](https://docs.astra-void.xyz/vela-rbxts/guides/vide.md) as well as React, with the same utilities, the same diagnostics,
and a byte-identical static emit.

## What is permanently out

Vela distinguishes a class it has never heard of, reported as `unsupported-utility-family`, from a
real Tailwind family Roblox UI cannot express, reported as `no-roblox-equivalent`. The second list
is a design decision, not a roadmap. Letter spacing, per-element filters, 3D transforms, the CSS
positioning model, grid spans, cursors, text indentation, and the rest of the
[not-implemented table](https://docs.astra-void.xyz/vela-rbxts/reference/utilities.md#not-implemented). Each entry names what
Roblox is missing.

## The gaps that do not announce themselves

Most of Vela's edges produce a diagnostic. The ones below do not, and they are worth reading twice.

> **Four silent gaps**
>
> **Host-element restrictions are editor-only on the static path.** Vela knows which utilities make sense on which tag. That table drives completions, hover and the `unsupported-host-utility` diagnostic in the language server. **The static transform never consults it**, so `<frame className="text-red-500" />` compiles clean and emits `TextColor3` on a Frame. Install the [editor tooling](https://docs.astra-void.xyz/vela-rbxts/guides/editor-setup.md) to catch it. The runtime path *does* apply the rule, but by dropping the utility without saying so.
>
> **Components that drop what they are handed.** If the component does not forward its unrecognized
> props to a host element and render `children`, all of it vanishes. There is no warning in the editor
> or the build.
>
> **A class value the compiler cannot read is unchecked.** Where the final string is only known in
> game, nothing warns about anything in it. `bg-blu-600` is a diagnostic in a literal, and total
> silence in `` `flex
> ${tone}` ``. Coverage is not the problem. The in-game resolver handles every family the static path does, and branches whose tokens are written out resolve at compile time with their diagnostics intact. What is left is genuinely opaque text. The theme is re-parsed from serialized text there too, so a value not shaped like `Color3.fromRGB(r,
> g, b)` or `new UDim(a, b)` degrades silently.
> [Dynamic class names](https://docs.astra-void.xyz/vela-rbxts/guides/dynamic-class-names.md) covers the divergence.
>
> **Gradient stops set to `transparent`.** They produce no diagnostic — the stop is dropped, and a two-stop gradient renders as a flat fill. Every other family without a transparency channel does warn.

## One behavior worth knowing before you write anything

> **Preflight neutralizes the Roblox host defaults**
>
> Roblox paints every `GuiObject` as an opaque grey box with a 1px border, and a framework that only *adds* properties can never take that back. So a supported host element **carrying a `className`** starts from `BackgroundTransparency = 1` and `BorderSizePixel = 0` instead.
>
> Anything that paints opts back out: a `bg-*`, `opacity-*`, a gradient stop, or a `BackgroundColor3`
> / `BackgroundTransparency` prop of your own. A background painted by a variant reopens it at
> runtime, so `hover:bg-sky-500` still works on an otherwise transparent element. An element with no
> `className` is untouched, and so is a **component**.
>
> Anywhere the grey default was load-bearing, the element renders invisible. [`preflight: false`](https://docs.astra-void.xyz/vela-rbxts/reference/config.md#preflight) restores the old behaviour wholesale.

## Sharp edges still open

`gap-*` on a `grid` element emits a conflicting `UIListLayout` alongside the `UIGridLayout` it feeds
([utilities reference](https://docs.astra-void.xyz/vela-rbxts/reference/utilities.md#grid)). And `divide-*` separators remain
sensitive to explicit `LayoutOrder` and still double-count the parent's `gap-*`, a consequence of
separators being list items ([utilities reference](https://docs.astra-void.xyz/vela-rbxts/reference/utilities.md#divide)).

Three newer edges sit beside them. The static path emits `<uishadow>` in lowercase, which
`Instance.new` rejects. A plugin utility that reaches back into itself expands to nothing, without a
diagnostic. And an `opacity-*` arriving from an ancestor component composes over a
`BackgroundTransparency` you set as a prop. All five are tracked in the
[release notes](https://docs.astra-void.xyz/vela-rbxts/reference/release-notes.md#still-open).

## Release state

Every package in the repo is at **0.13.0**, versioned in lockstep: `vela-rbxts` itself, the
`@vela-rbxts/*` scope, the three `@rbxts/vela-runtime*` packages, and the `vela-rbxts-lsp` VS Code
extension. A fix anywhere moves everything.

`@rbxts/vela-runtime-core` holds the target-neutral half: the resolution engine, theme
normalization, rem maths, rich text, and margin and divide computation. `@rbxts/vela-runtime` and
`@rbxts/vela-runtime-vide` are the React and Vide hosts over it. Rojo maps the whole
`node_modules/@rbxts` directory into a place, so keeping the hosts apart is what stops a Vide game
from shipping React.

Almost nothing is enforced at install time. The only `peerDependencies` are each host's own UI
library, declared **optional**, and the only `engines` field is the VS Code extension's
`vscode: ^1.91.0`. A mismatched roblox-ts or TypeScript fails at build rather than at install.
Prebuilt native binaries also miss two platforms: Windows on ARM and linux arm64 musl.

## A performance note

Config discovery runs for **every eligible source file** — the walk up the tree, and a read of
whatever config it lands on. That is what lets two directories carry different configs.

The expensive part is not per file: the loaded config is keyed on the file's own text and resolved
once per directory per build.

Keep `vela.config.ts` to a plain `defineConfig` call with literal values — no imports beyond
`vela-rbxts`, no computed theme generation, no side effects. It is executed as real code, and any
edit invalidates the cache. A JSON config skips the transpile step and is cached the same way.

## See also

- [How it works](https://docs.astra-void.xyz/vela-rbxts/getting-started/how-it-works.md) for the pipeline, the two lowering paths, and the rules that keep you on the good one.
- [Release notes](https://docs.astra-void.xyz/vela-rbxts/reference/release-notes.md) for what changed in each version.
- [Diagnostics](https://docs.astra-void.xyz/vela-rbxts/reference/diagnostics.md) for every warning code and what triggers it.
- [Troubleshooting](https://docs.astra-void.xyz/vela-rbxts/guides/troubleshooting.md) for the symptom-first version of this page.
- [Editor setup](https://docs.astra-void.xyz/vela-rbxts/guides/editor-setup.md) for the checks the compiler does not run.
