# Luau Type Checking Beta

January 16, 2020

Hello!

We’ve been quietly working on building a type checker for Lua for quite some time now. It is now far enough along that we’d really like to hear what you think about it.

I am very happy to offer a beta test into the second half of the Luau effort.

## Beta Test

First, a word of caution: In this test, we are changing the syntax of Lua. We are pretty sure that we’ve mostly gotten things right, but part of the reason we’re calling this a beta is that, if we learn that we’ve made a mistake, we’re going to go back and fix it even if it breaks compatibility.

Please try it out and tell us what you think, but be aware that this is not necessarily our final form. 🙂

Beta testers can try it out by enabling the “Enable New Lua Script Analysis” beta feature in Roblox Studio.

## Overview

Luau is an ahead-of-time typechecking system that sits atop ordinary Lua code. It does not (yet) feed into the runtime system; it behaves like a super powerful lint tool to help you find bugs in your code quickly.

It is also what we call a gradual type system. This means that you can choose to add type annotations in some parts of your code but not others.

## Two Modes

Luau runs in one of two modes: strict, and nonstrict.

### Nonstrict Mode

Nonstrict mode is intended to be as helpful as possible for programs that are written without type annotations. We want to report whatever we can without reporting an error in reasonable Lua code.

  * If a local variable does not have a type annotation and it is not initially assigned a table, its type is any
  * Unannotated function parameters have type any
  * We do not check the number of values returned by a function
  * Passing too few or too many arguments to a function is ok

### Strict Mode

Strict mode is expected to be more useful for more complex programs, but as a side effect, programs may need a bit of adjustment to pass without any errors.

  * The types of local variables, function parameters, and return types are deduced from how they are used
  * Errors are produced if a function returns an inconsistent number of parameters, or if it is passed the wrong number of arguments

Strict mode is not enabled by default. To turn it on, you need to add a special comment to the top of your source file.

## New syntax

You can write type annotations in 5 places:

  * After a local variable
  * After a function parameter
  * After a function declaration (to declare the function’s return type)
  * In a type alias, and
  * After an expression using the new as keyword.

## Type syntax

### Primitive types

`nil`, `number`, `string`, and `boolean`

### any

The special type any signifies that Luau shouldn’t try to track the type at all. You can do anything with an any.

### Tables

Table types are surrounded by curly braces. Within the braces, you write a list of name: type pairs:

Table types can also have indexers. This is how you describe a table that is used like a hash table or an array.

### Functions

Function types use a `=>` to separate the argument types from the return types.

If a function returns more than one value, put parens around them all.

### Unions

You can use a `|` symbol to indicate an “or” combination between two types. Use this when a value can have different types as the program runs.

### Options

It’s pretty commonplace to have optional data, so there is extra syntax for describing a union between a type and `nil`. Just put a `?` on the end. Function arguments that can be `nil` are understood to be optional.

### Type Inference

If you don’t write a type annotation, Luau will try to figure out what it is.

## Future Plans

This is just the first step!

We’re excited about a whole bunch of stuff:

  * Nonstrict mode is way more permissive than we’d like
  * Generics!
  * Editor integration


# Recap: September & October 2022

November 1, 2022

## Semantic subtyping

One of the most important goals for Luau is to avoid _false positives_ , that is cases where Script Analysis reports a type error, but in fact the code is correct. This is very frustrating, especially for beginners. Spending time chasing down a gnarly type error only to discover that it was the type system that’s wrong is nobody’s idea of fun!

We are pleased to announce that a major component of minimizing false positives has landed, _semantic subtyping_ , which removes a class of false positives caused by failures of subtyping. For example, in the program

an error is reported, even though there is no problem at runtime. This is because `CFrame`’s multiplication has two overloads:

The current syntax-driven algorithm for subtyping is not sophisticated enough to realize that this is a subtype of the desired type:

Our new algorithm is driven by the semantics of subtyping, not the syntax of types, and eliminates this class of false positives.

If you want to know more about semantic subtyping in Luau, check out our [technical blog post](https://luau-lang.org/2022/10/31/luau-semantic-subtyping.html) on the subject.

## Other analysis improvements

  * Improve stringification of function types.
  * Improve parse error warnings in the case of missing tokens after a comma.
  * Improve typechecking of expressions involving variadics such as `{ ... }`.
  * Make sure modules don’t return unbound generic types.
  * Improve cycle detection in stringifying types.
  * Improve type inference of combinations of intersections and generic functions.
  * Improve typechecking when calling a function which returns a variadic e.g. `() -> (number...)`.
  * Improve typechecking when passing a function expression as a parameter to a function.
  * Improve error reporting locations.
  * Remove some sources of memory corruption and crashes.

## Other runtime and debugger improvements

  * Improve performance of accessing debug info.
  * Improve performance of `getmetatable` and `setmetatable`.
  * Remove a source of freezes in the debugger.
  * Improve GC accuracy and performance.

## Thanks

Thanks for all the contributions!

  * [AllanJeremy](https://github.com/AllanJeremy)
  * [JohnnyMorganz](https://github.com/JohnnyMorganz)
  * [jujhar16](https://github.com/jujhar16)
  * [petrihakkinen](https://github.com/petrihakkinen)


# Luau Recap for 2025: Runtime

December 19, 2025

Hello everyone!

It has been a while since the last recap and we wanted to go over changes we have made in Luau since the last update.

Because of the amount of time that passed, in this part of the recap, we are going to focus on the runtime changes: new library functions, compiler changes, native code generation changes and Luau C API updates!

## New libraries and functions

We have added the [vector library](https://rfcs.luau.org/vector-library.html) to construct and work without native `vector` type.

Before this, the type was available, but the embedder had to provide construction and methods to work with it. It also meant that it lacked built-in call optimizations for common methods.

With the built-in library, we get fast-call optimization, support for vector constants and constant-folding in the compiler and native code generation comes out of the box!

In the `math` library, we have added [`math.map`](https://rfcs.luau.org/function-math-map.html), [`math.lerp`](https://rfcs.luau.org/function-math-lerp.html) and [`math.isnan`/`math.isinf`/`math.isfinite`](https://rfcs.luau.org/math-isnan-isfinite-isinf.html) functions.

Finally, for the `buffer` library, [`buffer.readbits`/`buffer.writebits`](https://rfcs.luau.org/function-buffer-bits.html) API was added.

## Require by string

After the earlier approval of the require-by-string RFC, we have built a separate Luau.Require library that any project can include.

It will bring the common semantics of the string require while supporting the full set of features such as alias and configuration resolution while remaining customizable in different environments with both real and virtual file systems representing the Luau file hierarchy.

## Runtime changes and improvements

A new `lua_newuserdatataggedwithmetatable` API lets you create tagged userdata objects with an associated shared metatable (using `lua_setuserdatametatable`) in a single call. In our applications, we have measured a 3x speedup of creating new userdata objects, which is especially important when they represent small and frequently allocated structures like colors or matrices.

And speaking of userdata, Luau now guarantees that it will be suitable for objects that require 16 byte alignment. As long as you provide Luau with a global allocator which also respects that.

For lightuserdata, new `lua_rawgetp`/`lua_rawsetp`/`lua_rawgetptagged`/`lua_rawsetptagged` have been added to match Lua 5.2+ and allow you to index tables with lightuserdata keys directly and more performantly.

Yieldable C functions can now call other yieldable functions using the `luaL_callyieldable` method. Previously, C functions could yield only once and couldn’t yield from nested calls, but now that is possible.

One limitation we still have is making nested yieldable protected calls. We will be looking into supporting that in the future.

Protected calls using `pcall` or `xpcall` are now stackless when performed in a yieldable context. This means that calling those functions will not apply the C call depth limit to your Luau code.

We will be looking into making those stackless even in non-yieldable contexts as well as improving overall performance of `pcall`/`xpcall` next year.

Our runtime is now more robust against out-of-memory errors and is easier to work with in low memory conditions:

  * `luaL_where` and `luaL_error` can be called without `lua_checkstack`
  * `luau_load` will no longer throw an error on out-of-memory
  * `lua_checkstack` will report a failure on out-of-memory instead of throwing an error
  * `lua_cpcall` function has returned and allows you to enter a protected environment to execute your target C function

There were also some small bug fixes:

  * Using ‘%c’ with a 0 value in `string.format` appends a ‘\0’ instead of doing nothing
  * `xpcall` is consistent before and after target function yields

Finally, a few new C API functions that weren’t mentioned:

  * `lua_clonetable` lets you clone a table
  * `lua_tolstringatom` is an alternative to `lua_tostringatom` but also provides you with the length of the string
  * `lua_unref` no longer accepts references that are not in the table

## Changes in the compiler

On the compiler side, we have made improvements to constant propagation, inlining and a few other things.

With the introduction of the `vector` library mentioned earlier, we have provided constant propagation and type inference for vector library globals. Vector arithmetic and library functions are also constant-folded when possible and vector constants are embedded into the bytecode.

Constant-folding has also been added to `string.char` and `string.sub` methods. String concatenation and string interpolation will also be constant-folded for constant strings or even when only some of the strings in the expression are constant.

Inlining has received multiple improvements.

The inlining cost model is now aware of the work constant-folding has done and will not consider constant expressions to have a cost of evaluation.

This means that functions computing a constant based on other global constants is a very likely inlining candidate:

Further improvements made it so that code which can be considered dead based on the state of global constant locals does not increase the cost:

Inlining can now propagate constant variables that are not representable as literal values. For example, passing a function into a function as an argument can cause the argument function to be inlined!

And the biggest change is that the inlining cost model is now updated per call to take constant arguments into account. This means that a large function can sometimes collapse into a small one, which is much more suitable for inlining:

Some smaller features are rewriting `const * var` and `const + var` operations into `var * const` and `var + const` when `var` is known to be a number from type annotations. This allows the expression to use one bytecode instruction instead of two for a small performance improvement.

Finally, with all these optimizations, we have added a way for the embedder to disable them for a specific built-in function call in case it has a different overwritten meaning.

## Changes in Native Code Generation

A lot of work is still going into our native code generation module, which has gained support for working on Android and has been tested in production.

Once again, `vector` library introduction required us to provide native lowering of all those functions for best performance. It is now possible to remove a lot of code in case you had those native IR hook functions for vectors.

In particular, for `vector.dot` we are lowering it to a CPU dot product instruction when possible. `vector.lerp` and `math.lerp` enjoy a new `MULADD_NUM` instruction that lowers to CPU fused-multiply-add when that is available.

Load-store propagation pass has been added to detect duplicate loads of vector components as well as allowing loads from previous stores to re-use the existing register value or extract a single component from it using a new `EXTRACT_VEC` instruction.

Unused stores of vectors into VM registers can also now be removed.

Multiple optimizations have been done to ensure our basic blocks are as long as possible without being broken up by control flow. The longer the basic block, the easier it is to optimize and reuse values.

We have updated the lowering of `bit32.btest` to use a new `CMP_INT` instruction which no longer causes that call to generate a branch.

Equality comparisons `==`/`~=` are also performed without branching now. With some extra handling, checks like `type(x) == "number"` of `typeof(x) == "string"` are now transformed into a tag check or a direct string pointer comparison, all without introducing branches.

Operators `and`/`or` for a simple value will use the new `SELECT_IF_TRUTHY` instruction which will also keep the basic block linear.

An additional optimization to keep blocks linear is a specialized instruction `GET_CACHED_IMPORT` for resolving imports. Multiple calls to global functions can be in a block without creating unnecessary diamond shapes in the control-flow graph.

Finally, we are now lifting the checks for safe execution environment to the start of the block and also skipping tag checks on type-annotated function arguments that are not being modified inside the function.

Load-store propagation was very effective for vectors so we extended it to upvalues, buffers and userdata.

Multiple upvalue lookups to the same slot can now be reused without reloading the memory. We keep all the stores for now until we get new dead store optimizations, but we can still skip reloading the values that have just been stored outside.

To support this for buffer data, we had to introduce new instructions for properly truncating data. For example, if you write `0xabcd` with `buffer.writei8`, you cannot just re-use the same value for a future read at that location, but need to truncate it to `0xcd`. And of course that might not be a constant value you can constant-fold.

Userdata is actually very similar to buffers, using the same IR instructions for access. But with load-store propagation, we are able to remove temporary userdata allocation. Custom userdata types with proper IR hooks can now generate code that is very efficient without having to be built-in.

In the following example, we are reading a userdata field ‘uv’ from another userdata twice to access its components:

Previously, this would have created the temporary ‘v.uv’ object twice:

      %6 = LOAD_POINTER R0

      CHECK_USERDATA_TAG %6, 13i, exit(0)

      %8 = BUFFER_READF32 %6, 24i, tuserdata

      %9 = BUFFER_READF32 %6, 28i, tuserdata

      CHECK_GC

      %11 = NEW_USERDATA 8i, 12i

      BUFFER_WRITEF32 %11, 0i, %8, tuserdata

      BUFFER_WRITEF32 %11, 4i, %9, tuserdata

      %20 = BUFFER_READF32 %11, 0i, tuserdata

      %21 = FLOAT_TO_NUM %20

      %28 = BUFFER_READF32 %6, 24i, tuserdata

      %29 = BUFFER_READF32 %6, 28i, tuserdata

      %31 = NEW_USERDATA 8i, 12i

      BUFFER_WRITEF32 %31, 0i, %28, tuserdata

      BUFFER_WRITEF32 %31, 4i, %29, tuserdata

      STORE_POINTER R4, %31

      STORE_TAG R4, tuserdata

      %40 = BUFFER_READF32 %31, 4i, tuserdata

      %41 = FLOAT_TO_NUM %40

      %50 = MUL_NUM %21, %41

After new optimizations, we propagate the fields, remove unused temporary allocations and perform the target multiplication:

      %6 = LOAD_POINTER R0

      CHECK_USERDATA_TAG %6, 13i, exit(0)

      %8 = BUFFER_READF32 %6, 24i, tuserdata

      %9 = BUFFER_READF32 %6, 28i, tuserdata

      CHECK_GC

      %21 = FLOAT_TO_NUM %8

      %41 = FLOAT_TO_NUM %9

      %50 = MUL_NUM %21, %41

In the future, we are looking to apply load-store propagation to table accesses as well.

Another area of optimization that we are looking into are optimizations around implicit integer values. Operations like adding or subtracting integer numbers coming from buffers or `bit32` library results can now use integer CPU instructions automatically. Additional optimizations around int/uint/double conversions lets us stay longer with those integer values as long as results perfectly match the ones that double numbers would give.

Other work we have done this year includes:

  * Arithmetic optimization for basic identities like `1 * a => a`, `a * 2 => a + a` and others
  * Optimization data now flows between separate basic blocks as long as they end up glued together in 1:1 relationship
  * Unused GC object stores to VM registers can now be removed as long as no one will observe their death by garbage collection
  * Float load/store has been separated from float/double conversion for better value reuse
  * Constant information can be attached to IR registers instead of VM registers for values without a VM storage location
  * Loop step value extraction optimization has been fixed to work in additional cases
  * Optimization for register spills and handling of code with more live registers than can fit into CPU registers

We have a lot of work planned for improving native code generation next year!

## Community

A big thank you goes to our [open source community](https://github.com/luau-lang/luau) for their contributions over the last year. Some of the improvements that we have mentioned come directly from your PRs or your feedback!


# Recap: February 2021

March 1, 2021

It’s been a busy few months in Luau!

## Infallible parser

Traditional compilers have focused on tasks that can be performed on complete programs, such as type-checking, static analysis and code generation. This is all good, but most programs under development are incomplete! They may have holes, statements that will be filled in later, and lines that are in the middle of being edited. If we’d like to provide support for developers while they are writing code, we need to provide tools for incomplete programs as well as complete ones.

The first step in this is an _infallible_ parser, that always returns an Abstract Syntax Tree, no matter what input it is given. If the program is syntactically incorrect, there will also be some syntax errors, but the parser keeps going and tries to recover from those errors, rather than just giving up.

The Luau parser now recovers from errors, which means, for example, we can give hints about programs in an IDE.

## Type assertions

The Luau type checker can’t know everything about your code, and sometimes it will produce type errors even when you know the code is correct. For example, sometimes the type checker can’t work out the intended types, and gives a message such as “Unknown type used… consider adding a type annotation”.

Previously the only way to add an annotation was to put it on the _declaration_ of the variable, but now you can put it on the _use_ too. A use of variable `x` at type `T` can be written `x :: T`. For example the type `any` can be used almost anywhere, so a common usage of type assertions is to switch off the type system by writing `x :: any`.

## Typechecking improvements

We’ve made various improvements to the Luau typechecker:

  * We allow duplicate function definitions in non-strict mode.
  * Better typechecking of `and`, `(f or g)()`, arrays with properties, and `string:format()`.
  * Improved typechecking of infinite loops.
  * Better error reporting for function type mismatch, type aliases and cyclic types.

## Performance improvements

We are continuing to work on optimizing our VM and libraries to make sure idiomatic code keeps improving in performance. Most of these changes are motivated by our benchmark suite; while some improvements may seem small and insignificant, over time these compound and allow us to reach excellent performance.

  * Table key assignments as well as global assignments have been optimized to play nicer with modern CPUs, yielding ~2% speedup in some benchmarks
  * Luau function calls are now ~3% faster in most cases; we also have more call optimizations coming up next month!
  * Modulo operation (%) is now a bit faster on Windows, resulting in ~2% performance improvement on some benchmarks

## Debugger improvements

Our Luau VM implementation is focused on performance and provides a different API for implementation of debugger tools. But it does have its caveats and one of them was inability to debug coroutines (breakpoints/stepping).

The good news is that we have lifted that limitation and coroutines can now be debugged just like any regular function. This can especially help people who use Promise libraries that rely on coroutines internally.

## Library changes

`table` library now has a new method, `clear`, that removes all keys from the table but keeps the internal table capacity. When working with large arrays, this can be more efficient than assigning a table to `{}` \- the performance gains are similar to that of using `table.create` instead of `{}` _when you expect the number of elements to stay more or less the same_. Note that large empty tables still take memory and are a bit slower for garbage collector to process, so use this with caution.

In addition to that we found a small bug in `string.char` implementation that allowed creating strings from out-of-range character codes (e.g. `string.char(2000)`); the problem has been fixed and these calls now correctly generate an error.

## Coming soon…

  * _Generic function types_ will soon be allowed!

  * _Typed variadics_ will soon allow types to be given to functions with varying numbers of arguments!

And there will be more!


# Recap: June 2021

June 30, 2021

Most of our team was busy working on improving Luau interaction with Roblox Studio for an upcoming feature this month, but we were able to add typechecking and performance improvements as well!

## Constraint Resolver

To improve type inference under conditional expressions and other dynamic type changes (like assignments) we have introduced a new constraint resolver framework into Luau type checker.

This framework allows us to handle more complex expressions that combine `and`/`not` operators and type guards.

Type guards support include expressions like:

  * `if instance:IsA("ClassName") then`
  * `if enum:IsA("EnumName") then`
  * `if type(v) == "string" then`

This framework is extensible and we have plans for future improvements with `a == b`/`a ~= b` equality constraints and handling of table field assignments.

It is now also possible to get better type information inside `else` blocks of an `if` statement.

A few examples to see the constraint resolver in action:

Please note that constraints are currently placed only on local and global variables. One of our goals is to include support for table members in the future.

## Typechecking improvements

We have improved the way we handled module `require` calls. Previously, we had a simple pattern match on the `local m = require(...)` statement, but now we have replaced it with a general handling of the function call in any context.

Handling of union types in equality operators was fixed to remove incorrect error reports.

A new `IsA` method was introduced to EnumItem to check the type of a Roblox Enum. This is intended to replace the `enumItem.EnumType == Enum.NormalId` pattern in the code for a construct that allows our constraint resolver to infer better types.

Additional fixes include:

  * `table.pack` return type was fixed
  * A limit was added for deeply nested code blocks to avoid a crash
  * We have improved the type names that are presented in error messages and Roblox Studio
  * Error recovery was added to field access of a `table?` type. While you add a check for `nil`, typechecking can continue with better type information in other expressions.
  * We handled a few internal compiler errors and rare crashes

## Editor features

If you have Luau-Powered Type Hover beta feature enabled in Roblox Studio, you will see more function argument names inside function type hovers.

## Behavior changes

We no longer allow referencing a function by name inside argument list of that function:

`local function f(a: number, b: typeof(f)) -- 'f' is no longer visible here`

## Performance improvements

As always, we look for ways to improve performance of your scripts:

  * We have fixed memory use of Roblox Actor scripts in Parallel Luau beta feature
  * Performance of table clone through `table.move` has been greatly improved
  * Table length lookup has been optimized, which also brings improvement to table element insertion speed
  * Built-in Vector3 type support that we mentioned in [April](https://devforum.roblox.com/t/native-luau-vector3-beta/) is now enabled for everyone


# Blueprint

    a Roblox Studio plugin designed to replace the default script sources with a dedicated template seamlessly

    Github
    Creator Marketplace
    Devforum

## Installation
### [Creator Marketplace 🖱](https://create.roblox.com/store/asset/16867958047/Blueprint)
_The Creator Marketplace is the easiest way to install Blueprint. You'll get access to automatic updates and be able to use the plugin anywhere you have Roblox Studio installed._

### Manual Installation
1. Download the plugin (.rbxmx) file from [Releases](https://github.com/OssieNomae/Blueprint/releases)
2. Drag and Drop the plugin file into the Roblox Studio "Plugins Folder" _(TopBar -> Plugins -> Plugins Folder)_

## Usage
1. From the Studio TopBar go to "Plugins" -> "Blueprint" Toolbar -> "Open Blueprint" Button -> Select Script Type from the dropdown menu
2. Modify the created blueprint script
3. Close the blueprint script tab to save!

Now, create a new script instance to witness the source get changed!


# Solder

**Solder** is a `.rbxm` / `.rbxmx` bundler written in **Luau** inspired by [wax](https://github.com/latte-soft/wax) for the [Lune](https://lune-org.github.io/docs) runtime.

It packages Roblox model files containing only scripts and folders into a single Luau module, ready to be distributed or embedded. This makes Solder especially useful for security projects that require embedding or distributing Roblox scripts in a controlled and verifiable way.

The bundling process preserves your project's hierarchy, can optionally track original line numbers for better debugging, and supports custom environment naming for error reporting.

## ✨ Features

- **Bundle `.rbxm` / `.rbxmx` files** into a standalone Luau module
- **Customizable environment name** shown in runtime errors
- **Optional line tracking** for accurate error locations
- **Root override** to start bundling from a specific path inside the model
- **Quiet mode** for scripting/automation
- **Validation** to ensure input models contain only supported instance types:
  - `Folder`
  - `Script`
  - `LocalScript`
  - `ModuleScript`

## 💻 Installation

Solder runs on **Lune 0.10.1** and is designed to be installed via **[Pesde](https://pesde.dev/) 0.7.0**:

```sh
pesde install 1suite/solder

Note that the **Solder CLI** is not backwards compatible with older Lune versions, unlike the **Bundler API** which supports Lune versions **0.8.9** through **0.10.1** for projects using older versions of Lune.

## 🚀 Usage

```sh
solder [options]

# Alternatively you can use it outside a pesde project like this:

pesde x 1suite/solder [options]

### Options

| Option                   | Description                                                                        |
| ------------------------ | ---------------------------------------------------------------------------------- |
| `--help`                 | Show help and exit                                                                 |
| `--version`              | Show version information                                                           |
| `--input <file>`         | Path to the `.rbxm` / `.rbxmx` file to bundle                                      |
| `--output <file>`        | Path to write the bundled output                                                   |
| `--quiet`                | Suppress non-essential output                                                      |
| `--track-lines`          | Store original line offsets for better debugging                                   |
| `--override-root ` | Start bundling from a specific model path (e.g. `SomeFolder.MainHandler`)          |
| `--env-name <name>`      | Set the environment name displayed in runtime errors (defaults to `SolderRuntime`) |

## 📄 Examples

### Basic bundling

```sh
solder --input MyModel.rbxm --output BundledModule.luau

### With line tracking and custom environment name

```sh
solder \
  --input MyModel.rbxm \
  --output BundledModule.luau \
  --track-lines \
  --env-name "MyRuntime"

### Bundling from a specific folder inside the model

```sh
solder \
  --input MyModel.rbxm \
  --output BundledModule.luau \
  --override-root "Server.MainHandler"

## 🛠 Using the Runtime SDK

To use the runtime SDK with a syncing tool such as Rojo, simply require the module like this in your Luau code:

```luau
-- replace the @pkg alias with the require alias you use for packages
local solder = require("@pkg/solder").SDK

With this, you gain a virtual `solder` table that can be utilized in unbundled code, whether for testing or other use cases.

At runtime, this `require` call returns a table containing the `SDK` field. This `SDK` field resolves to the main `solder` table, which provides the core API accessible in your code.

Note that require's first argument should match the string pattern `@%w+/solder$`. **If it doesn't, it will lead to undefined behavior when trying to use the SDK.**

### What You Get

The returned `solder` table includes:

* **`require`**: The real underlying `require` function, bypassing the virtualized version.
* **`environmentName`**: A string used as the environment name in unhandled error messages.
* **`script`**: The actual `script` global for the current Luau environment.
* **`lineTrackingEnabled`**: A boolean indicating if line tracking is enabled for this build.
* **`getRealLine(line: number): number`**: A function to convert a bundled file line number to the original source line number.

## 📦 Using the Lune Bundler API

If you append the `.Bundler` suffix to your require path, like this:

```luau
local bundler = require("@pkg/solder").Bundler

you will get access to the **Bundler API**, which provides additional functionality for bundling scripts programmatically and **is only compatible with the Lune runtime. It is not available on bundled models.**

## 📋 Requirements

* **Pesde 0.7.0** or above
* Roblox `.rbxm` or `.rbxmx` model file as input
* Model must only contain:
  * Folders
  * Script / LocalScript / ModuleScript instances

## 📜 License

This project is licensed under the MIT License.
See [LICENSE](LICENSE.txt) for details.


# pesde/argon

v2.0.28 Â· published ...

Argon - Full featured tool for Roblox development

Target

Lune

**Full featured tool for Roblox development**

# Argon

Argon is a powerful CLI that improves Roblox development experience. This is core part of Argon project as this is where all the processing happens. [Argon VS Code](https://github.com/argon-rbx/argon-vscode) extension is user-friendly wrapper of this CLI and [Argon Roblox](https://github.com/argon-rbx/argon-roblox) is a Roblox Studio plugin that is required for live syncing.

Some of the key features of Argon:

  * Two-Way sync of code and other instances with their properties
  * Building projects in Roblox binary or XML format
  * Beginner-friendly and professional at the same time
  * Extremely customizable and fast
  * Lots of useful helper commands
  * Workflow automation (CI/CD)

## Visit [argon.wiki](https://argon.wiki/) to learn more!

Or follow one of these direct links to:

  * [Install](https://argon.wiki/docs/installation) Argon
  * [Get Started](https://argon.wiki/docs/category/getting-started) with Argon
  * Learn about Argon [Commands](https://argon.wiki/docs/category/commands)
  * Explore the Argon [API](https://argon.wiki/api/project)
  * Follow the latest [Changes](https://argon.wiki/changelog/argon)


# ophidiedev/minstance

v0.8.0 Â· published ...

A very fast Instance serializer for Roblox that can serialize 40,000 Instances and compress it into a 100K+ character string in only 0.4s

Target

Roblox

# MInstance

A very fast Instance serializer for Roblox that can serialize 40,000 Instances and compress it into a 100K+ character string in only 0.4s

[](https://www.npmjs.com/package/@rbxts/minstance) [](https://pesde.daimond113.com/packages/ophidiedev/minstance) [](https://wally.run/package/ophidiedev/minstance)

Note

The original source code for the MInstance project can be found [here](https://github.com/kieldbg/MInstance)

## Features

  * Supports majority of Roblox data types and can serialize most properties with no issues.
  * Extremely fast performance!
  * Supports properties with its value being set to reference to another Instance, achieving this without setting UUIDs. This allows properties such as `SelectionBox.Adornee` to perfectly work as long as it is referencing an Instance that is a descendant of the main Instance being deserialized.
  * Supports MeshParts, which some other serializers fail to serialize properly. This is optional and you have to manually enable it in `DeserializationSettings`. (LOADS SLOW due to requiring to fetch the assets from Roblox's APIs)
  * Serializes attributes.
  * Instead of relying on an API dump to get properties like all other serializers do, the module will be updated to use `ReflectionService:GetPropertiesOfClass()` the moment that it is enabled, which is more futureproof than relying on the API dump.
  * You have the option to encode serialized data into Base94, which allows you to store serialized data into `DataStore`.

## Installation

Add to your `wally.toml`:

    minstance = "ophidiedev/[[email protected]](https://pesde.dev/cdn-cgi/l/email-protection)"

Add to your `pesde.toml`:

    minstance = { name = "ophidiedev/minstance", version = "^0.7.0" }

Add to your `package.json`:

    "@rbxts/minstance": "^0.7.0"

## Licenses

  * The original source code for MInstance is MIT Licensed the original source can be found [here](https://github.com/kieldbg/MInstance).


# josephh310/vide_typed

v0.4.4 Â· published ...

Vide with types, fixed for the new luau version

Target

Roblox

Vide is a reactive Luau UI library inspired by [Solid](https://www.solidjs.com/).

  * Fully Luau typecheckable
  * Declarative and concise syntax.
  * Reactively driven.

## Getting started

Read the [crash course](https://centau.github.io/vide/tut/crash-course/1-introduction) for a quick introduction to the library.

## Code sample

    local create = vide.create
    local source = vide.source

    local function Counter()
        local count = source(0)

        return create "TextButton" {
            Text = function()
                return "count: " .. count()
            end,

            Activated = function()
                count(count() + 1)
            end
    end


# bizwiz3/aura

v0.1.2 Â· published ...

The HTTP client for Lune. Aura is a lightweight wrapper around Lune's native net library for handling request. Inspired by Axios, it simplifies data fetching by handling JSON encoding/decoding, URL normalization, and standardized response objects automatically.

Target

Lune

# ð Aura

The HTTP client for Lune. Aura is a lightweight wrapper around Lune's native net library for handling request. Inspired by Axios, it simplifies data fetching by handling JSON encoding/decoding, URL normalization, and standardized response objects automatically.

## â¨ Features

**Auto-JSON:** Automatically encodes request bodies and decodes response bodies.

**Zero-Lag Localhost:** Automatically patches the Windows localhost IPv6 delay (2s â 4ms).

**Safe Decoding:** Uses pcall to ensure malformed JSON doesn't crash your runtime.

**Standardized:** Consistent response objects across all HTTP methods.

## Installation

    pesde add bizwis3/aura
    pesde install

## Quick Start

### Basic GET Request

    local aura = require("path/to/aura")
    local res = aura.get({ url = "https://jsonplaceholder.typicode.com/posts/1" })

    if res.ok then
        print(res.body.title) -- Already decoded into a table!
    end

### Basic POST Request

    local res = aura.post({
        url = "http://localhost:8080/users",
        body = {
            name = "John Doe",
            job = "Lune Developer"
    })

## API Reference

**REQUEST CONFIGURATION (`AuraRequest`)**

Property| Type| Description
---|---|---
**url**| `string`| The target URL.
**method**| `string`| HTTP Method (GET, POST, etc).
**body**| `table` or `string`| Data to be sent. Tables are auto-JSON encoded.
**headers**| `table`| Custom HTTP headers.
**query**| `table`| URL Query parameters.
**options**| `table`| Options

**RESPONSE OBJECT (`AuraResponse`)**

Property| Type| Description
---|---|---
**ok**| `boolean`| `true` if the status code is 200-299.
**status**| `number`| The HTTP status code (e.g., 200, 404).
**statusMessage**| `string`| The status text from the server (e.g., "OK").
**headers**| `table`| A dictionary of response headers.
**body**| `any`| The decoded JSON table or raw response string.

## Example Errors

    Aura Request got an issue:

     Status : 300 (Multiple Choices)
     Method : GET
     URL    : http://localhost:8080/
     Time   : 0.0019 seconds

    Aura Request got an issue:

     Status : 404 (Not Found)
     Method : GET
     URL    : http://localhost:8080/notfound
     Time   : 0.0015 seconds


# pesde/stylua

v2.4.0 Â· published ...

A Lua code formatter

Target

Lune

# StyLua
[](https://crates.io/crates/stylua) [](https://github.com/JohnnyMorganz/StyLua/actions/workflows/ci.yml) [](https://codecov.io/gh/JohnnyMorganz/StyLua)

A deterministic code formatter for Lua 5.1, 5.2, 5.3, 5.4, LuaJIT, [Luau](https://luau.org/) and [CfxLua/FiveM Lua](https://docs.fivem.net/docs/scripting-manual/runtimes/lua/), built using [full-moon](https://github.com/Kampfkarren/full-moon). StyLua is inspired by the likes of [prettier](https://github.com/prettier/prettier), it parses your Lua codebase, and prints it back out from scratch, enforcing a consistent code style.

StyLua mainly follows the [Roblox Lua Style Guide](https://roblox.github.io/lua-style-guide/), with a few deviations.

## Installation

There are multiple ways to install StyLua:

### With Github Releases

Pre-built binaries are available on the [GitHub Releases Page](https://github.com/JohnnyMorganz/StyLua/releases).

By default, these are built with **all syntax variants enabled (Lua 5.2, 5.3, 5.4, LuaJIT and Luau)**, to cover all possible codebases. See configuring runtime syntax selection if you need to select a particular syntax of Lua to format. Alternatively, see installing from crates.io on how to install a particular flavour of StyLua.

### From Crates.io

If you have [Rust](https://www.rust-lang.org/) installed, you can install StyLua using cargo. By default, this builds for just Lua 5.1. You can pass the `--features <flag>` argument to add extra syntax variants:

    cargo install stylua
    cargo install stylua --features lua52
    cargo install stylua --features lua53
    cargo install stylua --features lua54
    cargo install stylua --features luajit
    cargo install stylua --features luau

You can specify multiple features at once, and then use configuration in a `.stylua.toml` file to defer syntax selection to runtime.

### GitHub Actions

The [stylua-action](https://github.com/marketplace/actions/stylua) GitHub Action can install and run StyLua. This action uses the prebuilt GitHub release binaries, instead of running cargo install, for faster CI startup times.

### pre-commit

You can use StyLua with [pre-commit](https://pre-commit.com/). There are 3 possible pre-commit hooks available:

  * `stylua`: installs via cargo - requires the Rust toolchain
  * `stylua-system`: runs a `stylua` binary available on the PATH. The binary must be pre-installed
  * `stylua-github`: automatically installs the relevant prebuilt binary from GitHub Releases

Add the following to your `.pre-commit-config.yaml` file:

    - repo: https://github.com/JohnnyMorganz/StyLua
      rev: v2.4.0
      hooks:
        - id: stylua # or stylua-system / stylua-github

### npm

StyLua is available as a binary [published to npm](https://www.npmjs.com/package/@johnnymorganz/stylua-bin) as `@johnnymorganz/stylua-bin`. This is a thin wrapper that installs the binary and makes it available through npm / npx.

    npx @johnnymorganz/stylua-bin --help

StyLua is also available as a WASM library at [@johnnymorganz/stylua](https://www.npmjs.com/package/@johnnymorganz/stylua). It is usable in Node.js, or in the browser (using a bundler).

### Docker

StyLua is available on the [Docker Hub](https://hub.docker.com/r/johnnymorganz/stylua).

If you are using Docker, the easiest way to install StyLua is:

    COPY --from=JohnnyMorganz/StyLua:2.4.0 /stylua /usr/bin/stylua

### Homebrew

StyLua is available on macOS via the [Homebrew](https://brew.sh) package manager.

    brew install stylua

### pip / uv

You can install StyLua using pip / uv, by passing in the git repository as the archive URL

    pip install git+https://github.com/johnnymorganz/stylua
    uv tool install git+https://github.com/johnnymorganz/stylua

### Other Installation Methods

  * [VSCode Extension](https://marketplace.visualstudio.com/items?itemName=JohnnyMorganz.stylua)
  * [Aftman](https://github.com/LPGhatguy/aftman)

    aftman add johnnymorganz/[[email protected]](https://pesde.dev/cdn-cgi/l/email-protection)

  * A community maintained package repository. Please note, these packages are maintained by third-parties and we do not control their packaging manifests.

[](https://repology.org/project/stylua/versions)

### Other Editor Integrations

Note that these integrations require the StyLua binary to already be installed and available on your system.

  * Sublime: [Sublime Text Package](https://github.com/aerobounce/Sublime-Pretty-Lua)
  * Neovim: [stylua-nvim](https://github.com/ckipp01/stylua-nvim) / [stylua.nvim](https://github.com/wesleimp/stylua.nvim)
  * Zed: [Zed Lua StyLua formatter settings](https://zed.dev/docs/languages/lua#stylua)

## Usage

Once installed, pass the files to format to the CLI:

    stylua src/ foo.lua bar.lua

This command will format the `foo.lua` and `bar.lua` file, and search down the `src` directory to format any files within it. StyLua can also read from stdin, by using `-` as the file name.

### Glob Filtering

By default, when searching through a directory, StyLua looks for all files matching the glob `**/*.lua` (or `**/*.luau` when `luau` is enabled) to format. You can also specify an explicit glob pattern to match against when searching:

    stylua --glob '**/*.luau' -- src # format all files in src matching **/*.luau
    stylua -g '*.lua' -g '!*.spec.lua' -- . # format all Lua files except test files ending with `.spec.lua`

Note that the `-g/--glob` argument can take multiple strings at once, so `--` is required to separate between the glob patterns and the files to format.

By default, glob filtering (and `.styluaignore` files) are only applied during directory traversal and searching. Files passed directly (e.g. `stylua foo.txt`) will override the glob / ignore and always be formatted. To disable this behaviour, pass the `--respect-ignores` flag (`stylua --respect-ignores foo.txt`).

### Filtering using `.styluaignore`

You can create a `.styluaignore` file, with a format similar to `.gitignore`. Any files matching the globs in the ignore file are ignored by StyLua. For example, for a `.styluaignore` file with the following contents:

    vendor/

running `stylua .` will ignore the `vendor/` directory.

### Filtering when using stdin

If you are formatting stdin by specifying `-` as the filename (usually as part of an editor integration) you can optionally provide the filename via `--stdin-filepath`. To respect glob or `.styluaignore` filtering, pass `--respect-ignores`.

    stylua --respect-ignores --stdin-filepath src/foo.lua -

### `--check`: Checking files for formatting

To check whether files require formatting (but not write directly to them), use the `--check` flag. It will take files as input, and output a diff to stdout instead of rewriting the file contents. If there are any files that require formatting, StyLua will exit with status code 1.

There are different styles of output available:

  * `--output-format=standard`: output a custom diff (default)
  * `--output-format=unified`: output a unified diff, consumable by tools like `patch` or `delta`
  * `--output-format=json`: output JSON representing the changes, useful for machine-readable output
  * `--output-format=summary`: output a summary list of file paths that are incorrectly formatted

### `--verify`: Verifying formatting output

As a safety measure, you can use the `--verify` flag to verify the output of all formatting before saving the file.

If enabled, the tool will re-parse the formatted output to verify if the AST is still valid (no syntax errors) and is similar to the input (possible semantic changes).

This is useful when adopting StyLua in a large codebase, where it is difficult to manually check all formatting is correct. Note that this may produce false positives and negatives - we recommend manual verification as well as running tests to confirm.

### Ignoring parts of a file

To skip formatting a particular part of a file, you can add `-- stylua: ignore` before it. This is useful if there is a particular style you want to preseve for readability, e.g.:

    -- stylua: ignore
    local matrix = {
        { 0, 0, 0 },
        { 0, 0, 0 },
        { 0, 0, 0 },

To skip a block of code, use `-- stylua: ignore start` and `-- stylua: ignore end`:

    local foo = true
    -- stylua: ignore start
    local   bar   =   false
    local  baz      = 0
    -- stylua: ignore end
    local foobar = false

Note that ignoring cannot cross scope boundaries - once a block is exited, formatting is re-enabled.

### Formatting Ranges

To format a specific range within a file, use `--range-start <num>` and/or `--range-end <num>`. Both arguments are inclusive and optional - if an argument is not provided, the start/end of the file is used respectively.

Only whole statements lying within the range are formatted. If part of a statement falls outside the range, the statement is ignored.

In editors, `Format Selection` is supported.

### Requires Sorting

StyLua has built-in support for sorting require statements. We group consecutive require statements into a single "block", and then requires are sorted only within that block. Blocks of requires do not move around the file.

StyLua only considers requires of the form `local NAME = require(EXPR)`, and sorts lexicographically based on `NAME`. (StyLua can also sort Roblox services of the form `local NAME = game:GetService(EXPR)`)

Requires sorting is off by default. To enable it, add the following to your `stylua.toml`:

    [sort_requires]
    enabled = true

### Language Server Mode

StyLua can run as a language server, connecting with language clients that follow the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/). It will then respond to `textDocument/formatting` and `textDocument/rangeFormatting` requests. Formatting is only performed on files with a `lua` or `luau` language ID.

If the initialization option `respect_editor_formatting_options` is set to `true`, the formatting handler will override the configurations `indent-width` and `indent-type` with values from [FormattingOptions](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#formattingOptions).

You can start the language server by running:

    stylua --lsp

StyLua will listen to LSP messages on stdin and respond on stdout.

## Configuration

StyLua has opinionated defaults, but also provides a few options that can be set per project.

### Finding the configuration

The CLI looks for a `stylua.toml` or `.stylua.toml` starting from the directory of the file being formatted. It will keep searching upwards until it reaches the current directory where the tool was executed. If not found, we search for an `.editorconfig` file, otherwise fall back to the default configuration. This feature can be disabled using `--no-editorconfig`. See [EditorConfig](https://editorconfig.org/) for more details.

Use `--config-path <path>` to provide a custom path to the configuration. If the file provided is not found/malformed, StyLua will exit with an error.

By default, StyLua does not search further than the current directory. Use `--search-parent-directories` to recursively search parent directories. This will keep searching ancestors and, if not found, will then look in `$XDG_CONFIG_HOME` / `$XDG_CONFIG_HOME/stylua` / `$HOME/.config` and `$HOME/.config/stylua`.

**Note: enabling searching outside of the current directory is NOT recommended due to possibilities of conflicting formatting:**

It is recommended to keep a `.stylua.toml` file in your project root so that other developers can make use of the same configuration.

If a project uses the default configuration of StyLua without a configuration file present, enabling external searching may cause conflicting formatting.

### Configuring Runtime Syntax Selection

By default, StyLua releases comes with all flavours of Lua bundled into one binary, with a union of all syntax styles. We do this to make it easier to get started with StyLua on any codebase or project using Lua.

However, there are times where the union of syntaxes collide, causing issues. For example, Lua 5.2's goto label syntax (`::label::`) conflicts with Luau's type assertion syntax (`x :: number`), and the latter ends up taking priority.

To disambiguate a particular syntax style for your codebase, set `syntax = "Style"` in your `.stylua.toml` file, e.g.:

    syntax = "Lua52"

Alternatively, you can specify it on the command line, with `stylua --syntax lua52 ...`

### Options

StyLua only offers the following options:

Option| Default| Description
---|---|---
`syntax`| `All`| Specify a disambiguation for the style of Lua syntax being formatted. Possible options: `All` (default), `Lua51`, `Lua52`, `Lua53`, `Lua54`, `LuaJIT`, `Luau`, `CfxLua`
`column_width`| `120`| Approximate line length for printing. Used as a guide for line wrapping - this is not a hard requirement: lines may fall under or over the limit.
`line_endings`| `Unix`| Line endings type. Possible options: `Unix` (LF) or `Windows` (CRLF)
`indent_type`| `Tabs`| Indent type. Possible options: `Tabs` or `Spaces`
`indent_width`| `4`| Character size of single indentation. If `indent_type` is set to `Tabs`, this option is used as a heuristic to determine column width only.
`quote_style`| `AutoPreferDouble`| Quote style for string literals. Possible options: `AutoPreferDouble`, `AutoPreferSingle`, `ForceDouble`, `ForceSingle`. `AutoPrefer` styles will prefer the specified quote style, but fall back to the alternative if it has fewer string escapes. `Force` styles always use the specified style regardless of escapes.
`call_parentheses`| `Always`| Whether parentheses should be applied on function calls with a single string/table argument. Possible options: `Always`, `NoSingleString`, `NoSingleTable`, `None`, `Input`. `Always` applies parentheses in all cases. `NoSingleString` omits parentheses on calls with a single string argument. Similarly, `NoSingleTable` omits parentheses on calls with a single table argument. `None` omits parentheses in both cases. Note: parentheses are still kept in situations where removal can lead to obscurity (e.g. `foo "bar".setup -> foo("bar").setup`, since the index is on the call result, not the string). `Input` removes all automation and preserves parentheses only if they were present in input code: consistency is not enforced.
`space_after_function_names`| `Never`| Specify whether to add a space between the function name and parentheses. Possible options: `Never`, `Definitions`, `Calls`, or `Always`
`block_newline_gaps`| `Never`| Specify whether to preserve leading and trailing newline gaps for blocks. Possible options: `Never`, `Preserve`
`collapse_simple_statement`| `Never`| Specify whether to collapse simple statements. Possible options: `Never`, `FunctionOnly`, `ConditionalOnly`, or `Always`

Default `stylua.toml`, note you do not need to explicitly specify each option if you want to use the defaults:

    syntax = "All"
    column_width = 120
    line_endings = "Unix"
    indent_type = "Tabs"
    indent_width = 4
    quote_style = "AutoPreferDouble"
    call_parentheses = "Always"
    collapse_simple_statement = "Never"
    space_after_function_names = "Never"
    block_newline_gaps = "Never"

    [sort_requires]
    enabled = false


# project_roadwork/light_reflector

v1.1.1-beta Â· published ...

A vehicle-based light reflector that reflects decals and basepart reflectors at long distances on a road.

Target

Roblox

# Light Reflector

**Version: 1.1.1-beta**

**A vehicle-based light reflector system that reflects `Decals` and `BasePart` reflectors at long distances on roads.**

[](https://opensource.org/licenses/MPL-2.0) [](https://codeberg.org/project-roadwork/light-reflector.git) [](https://github.com/project-roadwork/light-reflector.git)

Note

 __**Please use the main repository especially with contributions or commits!**_ _Additionally, please **DO NOT** make any changes in the mirrored repository as it cannot be pulled into the main repo.__

**The main repository is in Codeberg; however, I provided a _push_ mirror on GitHub (pulls are not supported). Open an issue in Codeberg if you have concerns with this.**

Warning

**This script is under `alpha` and some functions may not work correctly or be unstable. Additionally, there are no _external_ documentation for this module at the moment.**

### Wally / Pesde Notice

**Older versions in Pesde AND Wally are not accurate! Accurate older releases are in Codeberg (not GitHub).**

**Additionally, the published packages are broken with version mismatching.**

_Additionally, this is my first time using Pesde AND Wally - apologies if something is not formatted correctly._

### Issues

  1. **Broken Wally and Pesde packages, with mismatched versioning**
     * The Pesde package has version issues as well due to my custom pre-release tag `infdev`
  2. **Rojo may not work correctly?**
  3. **Possible BasePart memory leak on games with Instance Streaming**
  4. **Many `:GetAttribute` calls popping up in the Microprofiler**
  5. **No external documentation**
  6. **Some signs and reflectors may not work at all in very rare occasions**

## Global features

  1. Adaptive waiting on performance-critical functions
  2. Distance fall-off
  3. Angle-based brightness
  4. Multi-vehicle support
  5. Non-tweened fading/transitions for gradual brightness
  6. Option to use `Tags` with `CollectionService`

## Sign/Gantry System Features

  1. Utilizes `SurfaceGuis` and `ImageLabel` OR `Decals` by itself for reflectivity
  2. Uses `.ImageTransparency`, `.Brightness`, and `.LightInfluence`
  3. SurfaceGui pooling to increase performance
  4. Automatic sign `:Dot` support
     * This determines if the vehicle is facing the sign or not to determine reflectiveness
  5. Automatic part rotation for `Top` faces
     * Part rotation is needed since the orientation of images in `Decals` and `SurfaceGuis` are NOT the same
     * This may break the visuals of actual non-square parts due to rotations
  6. Best for large reflective highway signs on gantries

## Reflector System Features

  1. Utilizes `BaseParts` for reflectivity
  2. Uses `.Color` and `.Material`
  3. Wedge `:Dot` support, with face (`Enum.NormalId`) selection on non-wedges
     * This determines if the vehicle is facing the part or not to determine reflectiveness
  4. Best for pavement reflectors on the road

### Hybrid System Features

  1. Works alongside the Reflector System with no separate loop needed
  2. Uses `.Color`, `.Material`, AND `.Transparency` with similar equations to the Sign/Gantry System
  3. Face (`Enum.NormalId`) selection
  4. Best for reflective traffic light shields, non-decal signs, etc.

## Essential Public API

  1. `.Start()` \- Starts the module
  2. `.Cleanup()` \- Resets states and cleans up the module
  3. `.Configure({})` \- Parses user configuration before starting (if you cannot do it IN the module first)
  4. `.RegisterVehicle(car: Instance, isHeadlightEnabled: () -> boolean, getIntensity: () -> number)` \- Registers vehicles into the module
  5. `.UnregisterVehicle(car: Instance)` \- Unregisters vehicles from the module

## Example Usage

    local LightReflector = require(path.to.module)

    local function determineIntensity(car)
      local finalIntensity = 1
    -- logic to see if high beams are enabled or not (thus increase the intensity)
      return finalIntensity
    end

    LightReflector.Configure({
      -- make any config changes here
    })

    LightReflector.Start()

    workspace.Cars.ChildAdded:Connect(function(car)
        if car:IsA("Model") and car:FindFirstChildOfClass("VehicleSeat") then
            print("Indexed Vehicle")
            LightReflector.RegisterVehicle(car, true, determineIntensity) -- true is the placeholder of what "enables" the light source like a Headlight boolean value
        end
    end)

    workspace.Cars.ChildRemoved:Connect(function(car)
        if car:IsA("Model") and car:FindFirstChildOfClass("VehicleSeat") then
            LightReflector.UnregisterVehicle(car)
        end
    end)

**Other examples such as server pre-tagging and a vehicle handler are provided in the examples folder.**

## Systems Diagram

## Older YouTube Showcase

_**Not up to date, uses 0.1.x**_ [](https://www.youtube.com/watch?v=YK-_NzeLqjI)

## Contributing

**This section exists due to the file-level copyleft nature of the Mozilla Public License 2.0.**

_By contributing to this project, you agree that your contributions may be redistributed and relicensed by this project under other open-source and/or open-content licenses in the future (such as Apache-2.0)._

**View the reason why this clause exists in [./CONTRIBUTING.md](https://pesde.dev/packages/project_roadwork/light_reflector/1.1.1-beta/CONTRIBUTING.md)**

## License

**License: [Mozilla Public License 2.0](https://mozilla.org/MPL/2.0/) (open source).**

_This may be changed to a more permissive license in the future if most people seem uncomfortable with it._

Note

### Mozilla Public License 2.0 Summary

**Warning: This summary does NOT act as a subsitute for the entire legal text. This is also not legal advice**

  * **The Mozilla Public License 2.0 (MPL-2.0) is a weak copyleft license**

  * **You must make any changes you made to the MPL covered files available under the MPL**

  * _**You can use the code in your games as long as you keep the MPL covered files open sourced under MPL in separate files**_

    * _You do **NOT** have to disclose the source of your entire game unlike the GPL/GNU license, **only the MPL covered files ITSELF**_

### License Comparison (not legal advice)

Feature / License| Expact (aka "MIT")| Apache 2.0| MPL 2.0| GPL / AGPL v3
---|---|---|---|---
**Permissive**| â | â | â¹ï¸ Partial| â
**Patent Clause**| â| â | â | â
**Proprietary Use OK**| â | â | â Â¹| â (Must release whole source)
**Roblox Asset Usage**| â | â | â¹ï¸ Depends; must share any changes| â May violate terms

  * Â¹ Proprietary use in MPL is permitted (allowed) as long as the MPL-covered files remain open souce.


# riptide/core

v0.5.0 Â· published ...

A lightweight and professional framework for Roblox.

Target

Roblox

        ____  _       __  _     __
       / __ \(_)___  / /_(_)___/ /__
      / /_/ / / __ \/ __/ / __  / _ \
     / _, _/ / /_/ / /_/ / /_/ /  __/
    /_/ |_/_/ .___/\__/_/\__,_/\___/

# ð Riptide Framework

Riptide is a lightweight, strictly-typed, and modular Roblox framework. It features phased initialization, safe dependency injection, a robust unified networking layer, and a shared ComponentService for managing tagged instances.

## ð¦ Installation

Warning

`v0.5.0` is the last release with first-class Wally support. Starting from the next major cycle, Pesde is the primary package manager.

### Via Pesde (recommended)

Add Riptide to your `pesde.toml` dependencies:

    [dependencies]
    Riptide = { name = "riptide/core", version = "^0.5.0", target = "roblox" }

Then install dependencies:

    pesde install

### Via Wally

Add Riptide to your `wally.toml`:

    [dependencies]
    Riptide = "thereplicatedfirst/riptide@^0.5.0"

### Manual

Download `Riptide.rbxm` from the [latest release](https://github.com/riptide-project/framework/releases/latest) and insert it into `ReplicatedStorage`.

## ð How to Start

Riptide does not start automatically. You must launch the framework from your own Server and Client entry points.

### Server Initialization (`main.server.lua`)

    local Riptide = require(ReplicatedStorage.Packages.Riptide)
    local MyServerModules = ServerScriptService:WaitForChild("MyServerModules")
    local MySharedModules = ReplicatedStorage:WaitForChild("SharedModules")
    local MyComponents = ReplicatedStorage:WaitForChild("Components") -- optional

    Riptide.Server.Launch({
        ModulesFolder = MyServerModules, -- Folder or { Folder, ... }
        SharedModulesFolder = MySharedModules, -- optional: Folder or { Folder, ... }
        ComponentsFolder = MyComponents, -- optional
    })

### Client Initialization (`main.client.lua`)

    local Riptide = require(ReplicatedStorage.Packages.Riptide)
    local MyClientModules = ReplicatedStorage:WaitForChild("MyClientModules")
    local MySharedModules = ReplicatedStorage:WaitForChild("SharedModules")
    local MyComponents = ReplicatedStorage:WaitForChild("Components") -- optional

    Riptide.Client.Launch({
        ModulesFolder = { MyClientModules }, -- Folder or { Folder, ... }
        SharedModulesFolder = { MySharedModules }, -- optional: Folder or { Folder, ... }
        ComponentsFolder = MyComponents, -- optional
    })

## ð Module Lifecycle & Dependency Injection (DI)

Riptide completely eliminates the need for `require()` circles. Any `ModuleScript` inside your designated `ModulesFolder` will be automatically loaded into the Riptide Registry.

Note

Services and Controllers are registered by canonical module ID (relative path from `ModulesFolder`, e.g. `Economy/PlayerData`). Short names are still supported as aliases when unique.

If two modules share the same short name, Riptide marks that alias as ambiguous and requires full canonical path lookups.

Examples:

  * `Riptide.GetService("Economy/PlayerData")` â always deterministic
  * `Riptide.GetService("PlayerData")` â only if alias is unique
  * `Riptide.GetService("Data")` â ï¸ returns `nil` when alias is ambiguous

Methods are executed in strict phases:

  1. **`Init(Riptide)`**: Called synchronously. Use this to `GetService` or `GetController` and set up your variables.
  2. **`Start(Riptide)`**: Called asynchronously via `task.spawn`. All modules are fully initialized at this point, so it is safe to interact with them and run game logic.

### Example DI Module

    --!strict
    local RiptidePkg = require(ReplicatedStorage.Packages.Riptide)
    type Riptide = RiptidePkg.Riptide

    local PlayerState = {}

    function PlayerState:Init(Riptide: Riptide)
        -- Easily inject other modules
        self.DataService = Riptide.GetService("DataService")

        -- Listen to the unified Network layer
        Riptide.Network.Register("PlayerJumped", function(player, height)
            print(player.Name .. " jumped " .. height .. " studs!")
        end)
    end

    function PlayerState:Start(Riptide: Riptide)
        self.DataService:GiveMoney(100)
    end

    return PlayerState

## ð¡ Networking (`Riptide.Network`)

Riptide automatically creates a single RemoteEvent and RemoteFunction inside its own package under the hood. No `ReplicatedStorage` clutter!

As of `v0.4.0`, network event dispatch uses a reusable trampoline handler in the hot-path to reduce closure allocations during heavy event traffic.

**Client-Side API**

  * `Network.Register(name, callback)`: Listen for server events.
  * `Network.Unregister(name, callback)`: Remove a previously registered handler.
  * `Network.FireServer(name, ...)`: Send event data to the server.
  * `Network.InvokeServer(name, ...)`: Request data from the server.

**Server-Side API**

  * `Network.Register(name, callback)`: Listen for client events. Callback automatically receives `player` as the first argument.
  * `Network.Unregister(name, callback)`: Remove a previously registered handler.
  * `Network.FireClient(player, name, ...)`: Send event data to a specific player.
  * `Network.FireAllClients(name, ...)`: Broadcast event data to everyone.
  * `Network.InvokeClient(player, name, ...)`: Request data from a client.

## ð§© ComponentService (`Riptide.ComponentService`)

A shared (server & client) system for managing component objects linked to tagged Instances via `CollectionService`.

As of `v0.4.0`, ComponentService startup is idempotent: repeated `_start(...)` calls are ignored to prevent duplicated CollectionService listeners.

Each Component is a `ModuleScript` whose name matches the tag. It must expose a `new(instance)` constructor and optionally a `Destroy(self)` cleanup method.

### Example Component (`Lava.lua`)

    local Lava = {}
    Lava.__index = Lava

    function Lava.new(instance: BasePart)
        local self = setmetatable({
            _instance = instance,
            _connection = nil :: RBXScriptConnection?,
        }, Lava)

        self._connection = instance.Touched:Connect(function(hit)
            local humanoid = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
            if humanoid then
                (humanoid :: Humanoid):TakeDamage(10)
            end
        end)

        return self
    end

    function Lava:Destroy()
        if self._connection then
            self._connection:Disconnect()
            self._connection = nil
        end
    end

    return Lava

**API**

  * `ComponentService:Get(instance)`: Get the first component attached to an instance.
  * `ComponentService:Get(instance, tagName)`: Get a specific component by tag name.

## ð License

This project is licensed under the MIT License - see the [LICENSE](https://pesde.dev/packages/riptide/core/0.5.0/LICENSE) file for details.


# bizwiz3/nova

v0.3.4 Â· published ...

A high-performance, filesystem-based web framework built specifically for the Lune runtime.

Target

Lune

[ ](https://pesde.dev/packages/bizwiz3/nova) [ ](https://github.com/BizWiz3/nova/blob/main/README.md) [ ](https://github.com/BizWiz3/nova/actions/workflows/ci.yml)

### A high-performance, filesystem-based web framework built specifically for the [Lune](https://lune-org.github.io/docs/) runtime.

## Table of Contents

  * Table of Contents
  * Installation & Usage
    * Manual Installation
      * Usage
    * Install a boilerplate
  * Core Features
  * Route Definition
  * Routing Conventions
  * Middleware Chaining

## Installation & Usage

### Manual Installation

Manually install Nova via the Pesde package manager:

    pesde add bizwiz3/nova
    pesde install

#### Usage

In your root project or `src/` directory, create your entry file.

_Example:_ `index.luau`

_Paste the code below:_

    local Nova = require("@path/to/nova")

    local app = Nova.new(8080)

    app:listen() -- To run the server

### Install a boilerplate

Installing a boilerplate for much easier setup

    pesde x bizwiz/nova_setup
    pesde install

## Core Features

  * **Filesystem Routing:** Routes are automatically mapped to the directory structure of the `app` folder.
  * **Pattern Matching:** Native support for dynamic segments using `[params]` syntax.
  * **Middleware Pipeline:** Functional middleware chaining for global and route-specific logic.
  * **Unified Response Utility:** Standardized handling for JSON and HTML content types.
  * **Environment Management:** Automatic `.env` loading and process injection.
  * **Integrated Logger:** Colored terminal output for request monitoring and debugging.

## Route Definition

Nova organizes routes by folder. To create a route at `/`, you must create an `app/` directory first in your root project or `src/` directory.

Create a luau file inside the `app/` directory and name it `route.luau`.

_Should look like this:_

    project-dir/
    âââ src/
        âââ app/
        |   âââ route.luau
        âââ index.luau

_Or like this_

    project-dir/
    âââ app/
    |    âââ route.luau
    âââ index.luau

_Paste the code below inside the`route.luau`:_

    local Nova = require("@path/to/nova")

    local App = {}

    function App.Get()
        return Nova.response({ msg = "Hello, Nova" })
    end

    return App

The Module name `App` itself does not matter, but it must have `Get`, `Post`, etc. as its public function.

## Routing Conventions

Nova follows a predictable mapping from the filesystem to the URL path:

Path| Filesystem Map
**/**| `app/route.luau`
**/users**| `app/users/route.luau`
**/posts/**| `app/posts/[id]/route.luau`

## Middleware Chaining

Utilize the `chain` helper to apply logic sequentially before a request reaches the final handler:

    local Nova = require("@path/to/nova")

    local function validate(req, next)
        if not req.headers["x-api-key"] then
            return Nova.response({ error = "Forbidden" }, { status = 403 })
        end
        next()
    end

    Route.Get = Nova.chain({ validate }, function(req)
        return Nova.response({ data = "Authorized access" })
    end)

_More info about middlewares soon._


# pesde/asphalt

v2.0.0-rc.5 Â· published ...

An assets-as-files tool for Roblox

Target

Lune

# Asphalt

Asphalt is a command line tool used to upload assets to Roblox and easily reference them in code. It's a modern alternative to [Tarmac](https://github.com/Roblox/Tarmac).

The documentation below is associated with the current commit on main. To view documentation for a specific release, go to the Tags page and view the README for that tag.

## Features

  * Syncs your images, sounds, videos, animations, and models to Roblox! See the supported asset types
  * Generates Luau or TypeScript code so you can use them in your game
  * Can target Roblox users or groups
  * Processes SVGs into PNGs and alpha bleeds images for crisp edges
  * Allows defining assets you already uploaded

## Installation

### [Mise](https://mise.jdx.dev)

    mise use ubi:jacktabscode/asphalt

### [Cargo](https://crates.io/crates/asphalt) (build from source)

    cargo install asphalt

View other installation options

### [Pesde](https://github.com/pesde-pkg/pesde)

    pesde add --dev pesde/asphalt --target lune

### [Rokit](https://github.com/rojo-rbx/rokit)

    rokit add jacktabscode/asphalt

### [Homebrew](https://brew.sh) (macOS/Linux)

    brew tap jacktabscode/tap
    brew install asphalt

[Asphalt cannot be installed with Foreman.](https://github.com/Roblox/foreman/issues/97)

## Commands

### `asphalt sync`

Syncs all of your assets defined in your inputs.

There are three targets you can use to sync assets:

  * `cloud`: Uploads your assets to Roblox. This will generate a `asphalt.lock.toml` file which you should commit to source control. This is the default target.

  * `studio`: Syncs assets locally to Roblox Studio. This is useful for testing assets in Studio before uploading them to Roblox.

  * `debug`: Syncs assets to an `.asphalt-debug` folder in the current directory. You can use this option see how Asphalt will process your files.

    asphalt sync # Equivalent to --target cloud
    asphalt sync --target studio
    asphalt sync --target debug

You can also perform a dry run to verify which assets will be synced. This exits with a non-zero status code if any asset hashes have changed. You can use this for CI checks to ensure that your assets are up-to-date.

    asphalt sync --dry-run

### `asphalt migrate-lockfile`

Will migrate your lockfile to the newest format, if there is one. See `asphalt migrate-lockfile --help` for more information.

### `asphalt upload`

Uploads a single asset to Roblox. See `asphalt upload --help` for more information.

## Configuration

Asphalt is configured with a project file called `asphalt.toml`. It is required for the program to run.

See an example

    #:schema https://raw.githubusercontent.com/jackTabsCode/asphalt/refs/heads/main/schema.json

    [creator]
    type = "user"
    id = 9670971

    [codegen]
    typescript = true
    style = "flat"

    [inputs.assets]
    path = "assets/**/*"
    output_path = "src/shared"

    [inputs.assets.web]
    "some_sound_on_roblox.ogg" = { id = 123456789 }
    "some_image_on_roblox.png" = { id = 987654321 }

### Format

  * `creator`: Creator
    * The Roblox creator to upload the assets under.
  * `codegen`: Codegen (optional)
    * Code generation options.
  * `inputs`: map<string, Input>
    * A map of input names to input configurations.

#### Creator

  * `type`: "user" or "group"
  * `id`: number

#### Codegen

  * `typescript`: boolean (optional)
    * Generate a TypeScript definition file.
  * `style`: "flat" | "nested" (optional)
    * The code generation style to use. Defaults to `flat`, which lets you index assets as if they were paths. You may consider using `nested` if you are not a TypeScript user as Luau does not support template literal types.
  * `strip_extensions`: boolean (optional)
    * Whether to strip the file extension. Defaults to `false` for the same reason described above.
  * `content`: boolean (optional)
    * Whether to output `Content` instead of `string`s. Defaults to `false`.

#### Input

  * `path`: glob
    * A glob pattern to match files to upload.
  * `output_path`: string
    * The directory path to output the generated code.
  * `web`: map<string, WebAsset>
    * A map of paths relative to the input path to existing assets on Roblox.
  * `bleed`: boolean (optional)
    * Whether to alpha bleed images. Defaults to `true`. Keep in mind that changing this setting won't invalidate your lockfile or reupload your images.

#### WebAsset

  * `id`: number

## Authentication

You can specify your API key this using the `--api-key` argument, or the `ASPHALT_API_KEY` environment variable.

You can get one from the [Creator Dashboard](https://create.roblox.com/dashboard/credentials).

The following permissions are required:

  * `asset:read`
  * `asset:write`

Make sure that you select an appropriate IP and that your API key is under the Creator (user, or group) that you've defined in `asphalt.toml`.

## Supported Asset Types

  * Images (.png, .jpg, .bmp, .tga, .svg)
    * SVGs are supported by Asphalt by converting them to PNGs. If an SVG uses the `currentColor` fill, it will be converted to white so that it can be colored on Roblox.
  * Audio (.mp3, .ogg, .wav, .flac)
  * Videos (.mp4, .mov)
    * When uploading videos, you must provide the `--expected-price` argument, which is the price you expect to be charged for the video. See the [Roblox documentation on Videos](https://create.roblox.com/docs/en-us/ui/video-frames#upload-videos) for more details.
  * Animations (.rbxm, .rbxmx)
    * Asphalt detects animations by looking to see if the saved class is a KeyframeSequence or a CurveAnimation. If it isn't, Asphalt will assume it is a Model.
  * Roblox Models (.rbxm, .rbxmx)
  * 3D Models (.fbx, .gltf, .glb)
    * Roblox does not offer control over the import settings through the web API. As such, this is not a route most should take. You should instead use the [3D Importer](https://create.roblox.com/docs/art/modeling/3d-importer) to upload these assets, then either sync them with Rojo or save them as Roblox model files.

## Code Generation

The formatting of code generation (such as spaces, tabs, width, and semicolons) is not guaranteed by Asphalt and may change between releases without being noted as a breaking change.

Therefore, it is recommended to add Asphalt's generated files to your linter/formatter's "ignore" list. Here are instructions for the most commonly used tools:

  * [Stylua](https://github.com/JohnnyMorganz/StyLua?tab=readme-ov-file#glob-filtering)
  * [Biome](https://biomejs.dev/guides/configure-biome/#ignore-files)
  * [ESLint](https://eslint.org/docs/latest/use/configure/ignore)

## Attributions

Thank you to [Tarmac](https://github.com/Roblox/tarmac) for the alpha bleeding implementation, which was used in this project.


# studio713/fem

v0.2.1 Â· published ...

A framework for plugins

Target

Roblox

# Fem

A framework for building Roblox Studio plugins. Handles the boilerplate so you can focus on what your plugin actually does.

## Installation

Add Fem to your `pesde.toml`:

    [dependencies]
    fem = { name = "studio713/plugin_framework", version = "^0.1.0" }

Then run:

    pesde install

## Quick Start

    local Fem = require(...)

    -- Configure logging
    Fem.Logger.Configure({
        Name = "MyPlugin",
        Level = "Info"
    })

    -- Listen for unload
    Fem.Unloading:Connect(function()
        Fem.Logger.Info("Plugin unloading")
    end)

    -- Create a toolbar with a button
    local toolbar = Fem.Ribbon.NewToolbar("My Plugin")
    local button = toolbar:CreateButton({
        text = "Open Panel",
        tooltip = "Opens the main panel",
        icon = "rbxassetid://0",
    })

    -- Create a dock widget
    local widget = Fem.Widget.NewDockWidget("MyPanel", DockWidgetPluginGuiInfo.new(
        Enum.InitialDockState.Right,
        true, false,
        300, 400,
        200, 100
    ))

    -- Wire up the button to toggle the widget
    button:SetCallback(function()
        widget:Toggle()
    end)

## API

### Logger

Configure logging behaviour for your plugin.

    Fem.Logger.Configure({
        Name = "MyPlugin",   -- prefix shown in all log messages
        Level = "Info",      -- minimum level to show: "Internal" | "Info" | "Warn" | "Error" | "Fatal"
    })

    Fem.Logger.Info("hello")
    Fem.Logger.Warn("something looks off")
    Fem.Logger.Error("something went wrong")
    Fem.Logger.Fatal("unrecoverable error")

### Tracker

Manages cleanup of connections, instances, threads, and custom objects. Useful for making sure everything gets cleaned up when your plugin unloads.

    local tracker = Fem.Tracker.new()

    -- Track a signal connection
    tracker:Track(workspace.ChildAdded:Connect(function() end))

    -- Track an instance
    tracker:Track(someInstance)

    -- Track a thread
    tracker:Track(task.delay(5, function() end))

    -- Track a custom object with a cleanup function
    tracker:TrackCustomObject(myObject, cleanupMethod)

    -- Clean everything up
    tracker:Clean()

### Ribbon

Creates toolbars and buttons in the Studio ribbon.

    local toolbar = Fem.Ribbon.NewToolbar("My Plugin")

    local button = toolbar:CreateButton({
        text    = "Open Panel",
        tooltip = "Opens the main panel",
        icon    = "rbxassetid://0",
    })

    button:SetCallback(function()
        -- handle click
    end)

### Widget

Creates UI containers. Both types share the same interface.

#### DockWidget

A panel docked inside Studio.

    local widget = Fem.Widget.NewDockWidget("MyPanel", DockWidgetPluginGuiInfo.new(
        Enum.InitialDockState.Right,
        true, false,
        300, 400,
        200, 100
    ))

#### Overlay

A `ScreenGui` parented to `CoreGui`, sits on top of the viewport.

    local overlay = Fem.Widget.NewOverlay("MyOverlay")

#### Shared methods

    widget:Show()
    widget:Hide()
    widget:Toggle()
    widget:SetEnabled(true)

### Unloading

A signal fired just before the plugin unloads. Use this to do any final cleanup.

    Fem.Unloading:Connect(function()
        -- cleanup
    end)


# pesde/luau_lsp

v1.63.0 Â· published ...

Language Server Implementation for Luau

Target

Lune

# Luau Language Server

An implementation of a language server for the [Luau](https://github.com/Roblox/luau) programming language.

## Getting Started

Install the extension from the VSCode Marketplace or OpenVSX Registry:

  * VSCode Marketplace: <https://marketplace.visualstudio.com/items?itemName=JohnnyMorganz.luau-lsp>
  * OpenVSX Registry: <https://open-vsx.org/extension/JohnnyMorganz/luau-lsp>

Alternatively, check out [Getting Started for Language Server Clients](https://github.com/JohnnyMorganz/luau-lsp/blob/main/editors/README.md) to setup your own client for a different editor.

A [Nightly Release](https://github.com/JohnnyMorganz/luau-lsp/actions/workflows/nightly.yml) runs every day with the latest changes on main. You can download the relevant release for your platform and manually install the `.vsix`. The nightly release builds with debug symbols and profiling instrumentation for debugging.

### For General Users

The language server will start working immediately for general Luau code. There is built-in support for Luau's generalised [require-by-string semantics](https://rfcs.luau.org/new-require-by-string-semantics.html), using `require("./module")`.

To provide global type definitions for a custom environment, specify `luau-lsp.types.definitionFiles`. Corresponding documentation is configured using `luau-lsp.types.documentationFiles`.

If you use Luau in a different environment and are interested in using the language server, or looking for any specific features, please get in touch!

### For Rojo Users (requires `v7.3.0+`)

By default, the latest Roblox type definitions and documentation are preloaded out of the box. This can be disabled by configuring `luau-lsp.platform.type`.

The language server uses Rojo-style sourcemaps to resolve DataModel instance trees for intellisense. This is done by running `rojo sourcemap --watch default.project.json --output sourcemap.json`. The server listens to changes of a `sourcemap.json` file present at the workspace root. It is recommended to add this file to your `.gitignore`.

The following settings are configurable for sourcemap generation:

  * `luau-lsp.sourcemap.enabled`: Whether sourcemap support is enabled (default: on)
  * `luau-lsp.sourcemap.autogenerate`: Whether sourcemaps are automatically generated by the client. If disabled, the server will listen to manual changes to a `sourcemap.json` file (default: on)
  * `luau-lsp.sourcemap.rojoProjectFile`: What project file to use (default: `default.project.json`)
  * `luau-lsp.sourcemap.includeNonScripts`: Whether to include non script instances in the sourcemap. May be disabled for expensive DataModels (default: on)
  * `luau-lsp.sourcemap.sourcemapFile`: What sourcemap file to use (default: `sourcemap.json`)

If you do not use Rojo, you can still use the Luau Language Server, you just need to manually generate a `sourcemap.json` file for your particular project layout. You can configure `luau-lsp.sourcemap.generatorCommand` to run a custom generator. If your generator does not support file watching, enable `luau-lsp.sourcemap.useVSCodeWatcher`.

> Note: in the diagnostics type checker, the types for DataModel (DM) instances will resolve to `any`. This is a current limitation to reduce false positives. However, autocomplete and hover intellisense will correctly resolve the DM type. To enable this mode for diagnostics, set `luau-lsp.diagnostics.strictDatamodelTypes` (off by default). [Read more](https://github.com/JohnnyMorganz/luau-lsp/issues/83#issuecomment-1192865024).

**A companion Studio plugin is available to provide DataModel information for Instances which are not part of your Rojo build / filetree: [Plugin Marketplace](https://www.roblox.com/library/10913122509/Luau-Language-Server-Companion)**

## Standalone

The tool can run standalone, similar to [`luau-analyze`](https://github.com/JohnnyMorganz/luau-analyze-rojo), to provide type and lint warnings in CI, with full Rojo resolution and API types support. The entry point for the analysis tool is `luau-lsp analyze`.

Install the binary and run `luau-lsp --help` for more information.

## Configuration

There are 2 types of configuration styles for the language server. General configuration is provided by `.luaurc` files, which allow you to configure language strictness, lints, and require aliases. More information is available in Luau's [RFC documentation](https://rfcs.luau.org/config-luaurc.html).

The second configuration style is specific to the language server. See `luau-lsp` in your editor's settings for more details.

## Supported Features

  * Diagnostics (incl. type errors)
  * Autocompletion
  * Hover
  * Signature Help
  * Go To Definition
  * Go To Type Definition
  * Find References
  * Document Link
  * Document Symbol
  * Color Provider
  * Rename
  * Semantic Tokens
  * Inlay Hints
  * Documentation Comments ([Moonwave Style](https://github.com/evaera/moonwave) \- supporting both `--- comment` and `--[=[ comment ]=]`, but must be next to statement)
  * Code Actions
  * Workspace Symbols
  * Folding Range
  * Call Hierarchy

The following are extra features defined in the LSP specification, but most likely do not apply to Luau or are not necessary. They can be investigated at a later time:

  * Go To Declaration (do not apply)
  * Go To Implementation (do not apply)
  * Code Lens (not necessary)
  * Document Highlight (not necessary - editor highlighting is sufficient)
  * Selection Range (not necessary - editor selection is sufficient)
  * Inline Value (applies for debuggers only)
  * Moniker
  * Formatting (see [stylua](https://github.com/JohnnyMorganz/StyLua))
  * Type Hierarchy (Luau currently does not provide any [public] ways to define type hierarchies)

## Crash Reporting

The language server implements opt-in crash reporting, using [Sentry](https://sentry.io/).

On VSCode, this is configured via the setting `luau-lsp.server.crashReporting.enabled`. When a crash is encountered, an out-of-process crash handler will upload the crash details to Sentry via HTTP.

When a crash is reported, the report stores the following information:

  * Crash reason and thread stack trace
  * Device metadata: OS name, version and CPU architecture
  * Dynamic libraries loaded into the process (including filesystem paths)

This information is transferred through a [Minidump](https://docs.sentry.io/platforms/native/guides/minidumps/#what-is-a-minidump) file. This file is not stored after processing. No general usage data is recorded.

Crash Reporting is only available for Windows and macOS, and is not active for Standalone mode (`luau-lsp analyze`)

## Build From Source

Submodules are required to build the project. You should use `--recurse-submodules` when you initally clone the project; e.g.

    git clone https://github.com/JohnnyMorganz/luau-lsp.git --recurse-submodules

To compile the project, execute the following commands in the project root directory.

    git submodule update --init --recursive
    mkdir build && cd build
    cmake .. -DCMAKE_BUILD_TYPE=Release
    cmake --build . --target Luau.LanguageServer.CLI --config Release

You can build `Luau.LanguageServer.Test` for unit tests. Some tests make assumptions about relative file paths. When running tests, ensure that your current working directory is set to the root of the repository.


# josephh310/observers_typed

v1.1.0 Â· published ...

Utility observer functions, with updated types

Target

Roblox

# observers-typed

> Utility observer functions, with updated types â for Roblox.

A strongly-typed collection of observer utility functions for Roblox, based on Sleitnick's observer library.

## Installation

Install via [pesde](https://github.com/daimond113/pesde):

    pesde add josephh310/observers_typed

## Usage

    local Observers = require(path.to.observers_typed)

    Observers.observeTag(...)
    Observers.observeAttribute(...)
    Observers.observeProperty(...)
    Observers.observePlayer(...)
    Observers.observeCharacter(...)
    Observers.observeLocalCharacter(...)

Every observer function returns a **stop function** that, when called, disconnects all internal connections and runs any pending cleanup functions.

## API

### `observeTag`

    observeTag<T>(tag: string, callback: (instance: T) -> (() -> ())?, valid_ancestry: (Instance | { Instance })?): () -> ()

Observes instances tagged with a [CollectionService](https://create.roblox.com/docs/reference/engine/classes/CollectionService) tag. The callback fires for each matching instance and may return a cleanup function that is called when the instance loses the tag, is destroyed, or (if `valid_ancestry` is provided) leaves the allowed ancestor hierarchy.

    local stopObserving = Observers.observeTag("MyTag", function(instance: Instance)
        print("Observing", instance)

        return function()
            print("Stopped observing", instance)
        end
    end)

    -- Stop the observer after 10 seconds:
    task.wait(10)
    stopObserving()

#### Ancestor inclusion list

By default, tagged instances are observed anywhere in the game hierarchy. Pass a `valid_ancestry` argument to restrict observation to instances that are descendants of the given ancestor(s). This can be a single `Instance` or a table of `Instance`s.

    -- Only observe "MyTag" instances that are inside the Workspace:
    Observers.observeTag("MyTag", function(instance: Instance)
        -- ...
    end, workspace)

    -- Or pass multiple ancestors as a table:
    Observers.observeTag("MyTag", function(instance: Instance)
        -- ...
    end, { workspace, game:GetService("ReplicatedStorage") })

### `observeAttribute`

    observeAttribute<T>(instance: Instance, name: string, callback: (value: T) -> (() -> ())?, guard: ((value: T) -> boolean)?): () -> ()

Observes an attribute on an instance. The callback fires whenever the attribute has a non-nil value, and the optional cleanup function is called when the value changes away from the previous one. The generic type `T` allows you to specify the expected attribute type.

    Observers.observeAttribute(workspace.Model, "MyAttribute", function(value)
        print("MyAttribute is now:", value)

        return function()
            print("MyAttribute is no longer:", value)
        end
    end)

An optional `guard` predicate can be provided to narrow which values trigger the callback:

    -- Only fire the callback when the attribute is a string:
    Observers.observeAttribute(
        workspace.Model,
        "MyAttribute",
        function(value)
            print("value is a string:", value)
        end,
        function(value)
            return typeof(value) == "string"
        end
    )

### `observeProperty`

    observeProperty<I, P>(instance: I & Instance, property: P & keyof<I>, callback: (value: index<I, P>) -> (() -> ())?): () -> ()

Observes a property of an instance. The callback fires immediately with the current value and again whenever the property changes. The optional cleanup function is called before each new callback invocation. The generic types `I` and `P` ensure that the property name is valid for the given instance type, and the callback receives the correctly typed value.

    Observers.observeProperty(workspace.Model, "Name", function(newName: string)
        print("New name:", newName)

        return function()
            print("Model's name is no longer:", newName)
        end
    end)

### `observePlayer`

    observePlayer(callback: (player: Player) -> (() -> ())?): () -> ()

Observes all players in the game. The callback fires for every player currently in the game and for each new player that joins. The optional cleanup function is called with the player's `Enum.PlayerExitReason` when they leave.

    Observers.observePlayer(function(player)
        print("Player joined:", player.Name)

        return function(exitReason: Enum.PlayerExitReason)
            print("Player left:", player.Name, "| Reason:", exitReason.Name)
        end
    end)

### `observeCharacter`

    observeCharacter(callback: (player: Player, character: Model) -> (() -> ())?, allowedPlayers: { Player }?): () -> ()

Observes every character in the game. The callback fires whenever any player's character spawns and receives both the `Player` and their `Model`. The optional cleanup function is called when the character is removed.

    Observers.observeCharacter(function(player, character)
        print("Character spawned for", player.Name)

        return function()
            print("Character removed for", player.Name)
        end
    end)

An optional `allowedPlayers` array restricts observation to only the listed players:

    Observers.observeCharacter(function(player, character)
        -- Only fires for somePlayer and anotherPlayer
    end, { somePlayer, anotherPlayer })

### `observeLocalCharacter`

    observeLocalCharacter(callback: (character: Model) -> (() -> ())?): () -> ()

> **Client-only.** Will error if called from the server.

Observes the local player's character. The callback fires when the local character spawns, and the optional cleanup function is called when it is removed.

    -- In a LocalScript or client-context script:
    Observers.observeLocalCharacter(function(character)
        print("Local character spawned")

        return function()
            print("Local character removed")
        end
    end)

## Cleanup Pattern

All observer functions return a stop function. Call it to disconnect the observer and run any active cleanup functions immediately:

    local stop = Observers.observeTag("MyTag", function(instance)
        -- ...
    end)

    -- Later, when the observer is no longer needed:
    stop()

## License

MIT â see [LICENSE.md](https://pesde.dev/packages/josephh310/observers_typed/1.1.0/LICENSE.md) for details.


# Ember
Ember is a powerful and highly optimized 2D particle system for Roblox, built to simulate ParticleEmitter behavior within GUI elements.

# Features
- **Particle Emitter wrapping**: Uses the ParticleEmitter instance as base for the object, meaning you can use it to determine where to emit and change its properties through the instance itself.
- **Flipbook Support**: Allows the usage of flipbook particles, provided the dimensions of the image (accessiable through `Ember.FlipbookDimensions`).
- **Dynamic Emission Controls**:
  - Emit at a fixed position
  - Emit randomly within a GUI parent
- **Replicates Particle Behavior**: Supports all properties that particle emitters have with a few changes due to the translation from 3D to 2D
- **Highly Efficient**: Applies different tricks to cut down the rendering times (mentioned bellow).

## Optimized for Performance
Ember is built with performance in mind:
- Uses a single `ScreenGui` which is constantly being enabled and disabled to batch-render particles without needing to update the GUI descendants.
- Avoids unnecessary instance creation using particle pooling.
- Caches the properties of the ParticleEmitter through tables to speed up indexing
- Automatically adapts particle emission rates depending on the user’s quality settings, making it scalable across all devices—from low-end phones to high-end PCs.

## Usage

```lua
local Ember = require(path.to.Ember)

local uiEmitter = Ember.new(particleEmitter, UDim2.fromScale(0.5, 0.5))

uiEmitter:EmitInParent(15, guiFrame) -- Emit 15 particles randomly inside a Frame
uiEmitter:EmitAtPosition(10, UDim2.fromScale(0.25, 0.75)) -- Emit at a custom position
uiEmitter:Emit(20) -- Emit 20 particles at default position or inside a parent, depending on the parent of the particleEmitter.

uiEmitter:Clear() -- Removes all active particles
uiEmitter:Destroy() -- Clean up the emitter

## Flipbook usage
If you're using flipbook animations, make sure to set the `FlipbookDimensions` (`1024`, `512`, `256`, `128`, `64`, `32`, `16`, `8`) based on your sprite sheet size:

```lua
uiEmitter.FlipbookDimensions = Ember.FlipbookDimensions.By512x512

Default dimensions are 1024x1024, if you forget to set it up ember will automatically notify you that you need to set up the dimensions.

# Installation

1. Drop `Ember.lua` into your project.
2. Require it in your client scripts.
3. Create 2D emitter through the `Ember.new()` function.
4. Either use the provided objects method to emit or use the Enabled property of the ParticleEmitter to emit constantly

## Compatibility

- **Client-side only**
yesterday

Update README.md
- Works with all Roblox-supported platforms: PC, mobile, console and VR
yesterday

Update README.md
- Does not require any third-party libraries

## License

None