Luar

An In-Process Framework-Aware Language Service for Roblox Studio.

🚩 The Framework Problem

When you build games using dynamic architectures (like the Mince Game Framework), standard static type checkers break down. You completely lose autocomplete on your codebase.

Without autocomplete, you lose context. You are forced to memorize your entire API, making writing documentation and collaborating with others on a codebase significantly more difficult.

Enter Luar

Luar is an in-process language service that deeply understands the Mince framework. It runs natively inside Roblox Studio to restore perfect, context-aware autocomplete to your entire codebase instantly.

12
local CombatController = Mince:Get("
CombatController
DataService
Matchmaking
Client Module Controllers.CombatController
🌍

A Perfect Game Model

Luar goes beyond reading individual scripts; it builds a holistic model of your entire game. It automatically detects where the Mince framework is bootstrapped and meticulously maps out your project's architectural tree.

Because it possesses this global context, Luar perfectly understands execution boundaries. It knows exactly which controllers are restricted to the Client and which services are securely isolated on the Server.

Smart Linting & Filtering

This total game awareness powers Environment-Appropriate Autocomplete (e.g., hiding Server dependencies from Client-side suggestions) and provides framework-specific linting to catch architectural violations before you even hit Play.

24
local Fetch = Mince:GetEvent("FetchData")
⚠️
MINCE_EVENT_SERVER_MISSING
Event "FetchData" has no corresponding get on the server. It may throw an error.

An Unorthodox Philosophy: Lazy vs. Eager

Traditional solvers (like TypeScript) eagerly build a massive Abstract Syntax Tree (AST) to validate the whole project upfront. But inside Roblox Studio, strict memory caps mean a global solver would quickly freeze the engine.

To overcome this, Luar is built as a completely open-source, lazy analyzer (inspired by rust-analyzer and Roslyn):

  • Zero AST: On keystroke, it skips the AST and builds a lightning-fast Concrete Syntax Tree (CST) instead.
  • Pending Proxies: Symbols are instantly hydrated with lightweight promise proxies.
  • Demand-Driven: It performs zero type-solving logic until the exact millisecond the UI asks for it.
Powered by open-source tooling: The CST generation is made possible by luaup, a lossless Luau parser.
~0.4ms
CST Gen & Hydration
0ms
Solving Overhead

🧩 The Logical Resolution Chain

Watch how the solver decomposes an expression. The code below shows a typical nested function call. Click the steps on the right to trace how the pre-hydrated promise proxy resolves the type on demand.
local MyTable = {}
MyTable.MyFunction = function()
return {
thread = coroutine.running()
}
end
local MyValue = MyTable.MyFunction().thread

⚙️ Ingesting the Ecosystem

Luar constructs a mathematical model of your entire workspace. The ultimate goal is to provide seamless, intelligent autocompletion for the Mince Game Framework, combining base Lua rules, Roblox API definitions, and custom framework logic.

Standard Luau
Roblox API Dump
Mince Framework
⚙️

ApiRegistry & Intrinsics

Synthesizes static documentation and Mince component logic into queryable structures.

Type Environment

The unified source of truth ready for UI autocomplete queries.

🪄

Magic Handlers

Standard static types are often too rigid. For instance, knowing Instance:GetChildren() returns an array isn't enough, you need to know what children exist. Magic Handlers are custom Lua functions that bypass static rules to execute bespoke resolution logic for complex methods.

🔥

The Just-In-Time Type Transformer

Executing Complex Type Functions On The Fly

How does a Luau-native engine support dynamic Type Functions? It builds them as it needs them. Luar features a blazing-fast JIT Transformer that physically executes type manipulations during resolution. Consider this custom type function:

type function simple_keyof(ty: type)
if not ty:is("table") then
error("Can only call keyof on tables.")
end
local union = nil
for property in ty:properties() do
union = if union then types.unionof(union, property) else property
end
return if union then union else types.singleton(nil)
end
1. Emulation

When a Type Function is encountered, Luar uses its own version of the type checker runtime to emulate the exact behavior locally.

2. Transformation

The syntax is dynamically transformed into an executable closure, turning Luau into different Luau, that runs inside a strictly controlled sandbox.

3. Execution (~0.18ms)

The sandbox executes the logic. Because it is native Luau running inside Luau, the overhead is virtually zero. The example type function above runs and transforms the type in ~0.18 milliseconds.

📝

Moonwave Support

Luar builds a seamless layer on top of the default roblox autocomplete. It steps in exactly where Roblox falls short, resolving Mince-specific types without conflicting with default suggestions. Because it handles these custom injections, it natively parses Moonwave, the standard documentation generator for Luau.

Write rich documentation directly above your functions and classes. Luar instantly reads specified tags like @param, @return, and @deprecated, injecting that rich context straight into your hover panels and autocomplete suggestions.

--[=[
Destroys the galaxy.
@deprecated v2.0.0 -- Use `save_galaxy` instead.
@param Target The galaxy to destroy.
]=]
local function DestroyGalaxy(Target: Galaxy)
-- ...
end