# Button Component

This example is a relatively complete button component implemented using Fusion's Roblox API. It handles many common interactions such as hovering and clicking.

This should be a generally useful template for assembling components of your own. For further ideas and best practices for building components, see [the Components tutorial](https://elttob.uk/Fusion/0.3/tutorials/components/components).

## Overview¶

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114

    local Fusion = -- initialise Fusion here however you please!
    local scoped = Fusion.scoped
    local Children, OnEvent = Fusion.Children, Fusion.OnEvent
    type UsedAs<T> = Fusion.UsedAs<T>

    local COLOUR_BLACK = Color3.new(0, 0, 0)
    local COLOUR_WHITE = Color3.new(1, 1, 1)

    local COLOUR_TEXT = COLOUR_WHITE
    local COLOUR_BG_REST = Color3.fromHex("0085FF")
    local COLOUR_BG_HOVER = COLOUR_BG_REST:Lerp(COLOUR_WHITE, 0.25)
    local COLOUR_BG_HELD = COLOUR_BG_REST:Lerp(COLOUR_BLACK, 0.25)
    local COLOUR_BG_DISABLED = Color3.fromHex("CCCCCC")

    local BG_FADE_SPEED = 20 -- spring speed units

    local ROUNDED_CORNERS = UDim.new(0, 4)
    local PADDING = UDim2.fromOffset(6, 4)

    local function Button(
        scope: Fusion.Scope,
        props: {
            Name: UsedAs<string>?,
            Layout: {
                LayoutOrder: UsedAs<number>?,
                Position: UsedAs<UDim2>?,
                AnchorPoint: UsedAs<Vector2>?,
                ZIndex: UsedAs<number>?,
                Size: UsedAs<UDim2>?,
                AutomaticSize: UsedAs<Enum.AutomaticSize>?
            },
            Text: UsedAs<string>?,
            Disabled: UsedAs<boolean>?,
            OnClick: (() -> ())?
    ): Fusion.Child
        local isHovering = scope:Value(false)
        local isHeldDown = scope:Value(false)

        return scope:New "TextButton" {
            Name = props.Name,

            LayoutOrder = props.Layout.LayoutOrder,
            Position = props.Layout.Position,
            AnchorPoint = props.Layout.AnchorPoint,
            ZIndex = props.Layout.ZIndex,
            Size = props.Layout.Size,
            AutomaticSize = props.Layout.AutomaticSize,

            Text = props.Text,
            TextColor3 = COLOUR_TEXT,

            BackgroundColor3 = scope:Spring(
                scope:Computed(function(use)
                    -- The order of conditions matter here; it defines which states
                    -- visually override other states, with earlier states being
                    -- more important.
                    return
                        if use(props.Disabled) then COLOUR_BG_DISABLED
                        elseif use(isHeldDown) then COLOUR_BG_HELD
                        elseif use(isHovering) then COLOUR_BG_HOVER
                        else return COLOUR_BG_REST
                    end
                end),
                BG_FADE_SPEED
            ),

            [OnEvent "Activated"] = function()
                if props.OnClick ~= nil and not peek(props.Disabled) then
                    -- Explicitly called with no arguments to match the typedef.
                    -- If passed straight to `OnEvent`, the function might receive
                    -- arguments from the event. If the function secretly *does*
                    -- take arguments (despite the type) this would cause problems.
                    props.OnClick()
                end
            end,

            [OnEvent "MouseButton1Down"] = function()
                isHeldDown:set(true)
            end,
            [OnEvent "MouseButton1Up"] = function()
                isHeldDown:set(false)
            end,

            [OnEvent "MouseEnter"] = function()
                -- Roblox calls this event even if the button is being covered by
                -- other UI. For simplicity, this does not account for that.
                isHovering:set(true)
            end,
            [OnEvent "MouseLeave"] = function()
                -- If the button is being held down, but the cursor moves off the
                -- button, then we won't receive the mouse up event. To make sure
                -- the button doesn't get stuck held down, we'll release it if the
                -- cursor leaves the button.
                isHeldDown:set(false)
                isHovering:set(false)
            end,

            [Children] = {
                New "UICorner" {
                    CornerRadius = ROUNDED_CORNERS
                },

                New "UIPadding" {
                    PaddingTop = PADDING.Y,
                    PaddingBottom = PADDING.Y,
                    PaddingLeft = PADDING.X,
                    PaddingRight = PADDING.X
    end

    return Button

## Explanation¶

The main part of note is the function signature. It's highly recommended that you statically type the function signature for components, because it not only improves autocomplete and error checking, but also acts as up-to-date, machine readable documentation.

    local function Button(
        scope: Fusion.Scope,
        props: {
            Name: UsedAs<string>?,
            Layout: {
                LayoutOrder: UsedAs<number>?,
                Position: UsedAs<UDim2>?,
                AnchorPoint: UsedAs<Vector2>?,
                ZIndex: UsedAs<number>?,
                Size: UsedAs<UDim2>?,
                AutomaticSize: UsedAs<Enum.AutomaticSize>?
            },
            Text: UsedAs<string>?,
            Disabled: UsedAs<boolean>?,
            OnClick: (() -> ())?
    ): Fusion.Child

The `scope` parameter specifies that the component depends on Fusion's methods. If you're not sure how to write type definitions for scopes, [the 'Scopes' section of the Components tutorial](https://elttob.uk/Fusion/0.3/tutorials/components/components/#scopes) goes into further detail.

The property table is laid out with each property on a new line, so it's easy to scan the list and see what properties are available. Most are typed with [`UsedAs`](https://elttob.uk/Fusion/0.3/api-reference/state/types/usedas), which allows the user to use state objects if they desire. They're also `?` (optional), which can reduce boilerplate when using the component. Not all properties have to be that way, but usually it's better to have the flexibility.

Property grouping

You can group properties together in nested tables, like the `Layout` table above, to avoid long mixed lists of properties. In addition to being more readable, this can sometimes help with passing around lots of properties at once, because you can pass the whole nested table as one value if you'd like to.

The return type of the function is `Fusion.Child`, which tells the user that the component is compatible with Fusion's `[Children]` API, without exposing what children it's returning specifically. This helps ensure the user doesn't accidentally depend on the internal structure of the component.

Back to top


#  Computed ¶

    export type Computed<T> = StateObject<T> & {
        kind: "Computed",
        timeliness: "lazy"

A specialised [state object](https://elttob.uk/Fusion/0.3/api-reference/state/types/stateobject) for tracking single values computed from a user-defined computation.

This type isn't generally useful outside of Fusion itself.

## Members¶

### kind  : "Computed"  ¶

A more specific type string which can be used for runtime type checking. This can be used to tell types of state object apart.

## Learn More¶

  * [Computeds tutorial](https://elttob.uk/Fusion/0.3/tutorials/fundamentals/computeds)

Back to top


# API Reference¶

Welcome to the API Reference! This is where you can find more technical documentation about what the Fusion library provides.

For a beginner-friendly experience, [try the tutorials.](https://elttob.uk/Fusion/0.3/tutorials/)

## Most Popular¶

### General¶

[ Errors ](https://elttob.uk/Fusion/0.3/api-reference/general/errors) [ Contextual ](https://elttob.uk/Fusion/0.3/api-reference/general/members/contextual) [ Safe ](https://elttob.uk/Fusion/0.3/api-reference/general/members/safe)

### Memory¶

[ Scope ](https://elttob.uk/Fusion/0.3/api-reference/memory/types/scope) [ innerScope ](https://elttob.uk/Fusion/0.3/api-reference/memory/members/innerscope) [ doCleanup ](https://elttob.uk/Fusion/0.3/api-reference/memory/members/docleanup) [ scoped ](https://elttob.uk/Fusion/0.3/api-reference/memory/members/scoped)

### Graph¶

[ Observer ](https://elttob.uk/Fusion/0.3/api-reference/graph/members/observer)

### State¶

[ UsedAs ](https://elttob.uk/Fusion/0.3/api-reference/state/types/usedas) [ Computed ](https://elttob.uk/Fusion/0.3/api-reference/state/members/computed) [ peek ](https://elttob.uk/Fusion/0.3/api-reference/state/members/peek) [ Value ](https://elttob.uk/Fusion/0.3/api-reference/state/members/value)

### Animation¶

[ Spring ](https://elttob.uk/Fusion/0.3/api-reference/animation/members/spring) [ Tween ](https://elttob.uk/Fusion/0.3/api-reference/animation/members/tween)

### Roblox¶

[ Child ](https://elttob.uk/Fusion/0.3/api-reference/roblox/types/child) [ Children ](https://elttob.uk/Fusion/0.3/api-reference/roblox/members/children) [ Hydrate ](https://elttob.uk/Fusion/0.3/api-reference/roblox/members/hydrate) [ New ](https://elttob.uk/Fusion/0.3/api-reference/roblox/members/new)

Back to top


# ForKeys

`ForKeys` is a state object that processes keys from another table.

It supports both constants and state objects.

    local data = {Red = "foo", Blue = "bar"}
    local prefix = scope:Value("Key_")

    local renamed = scope:ForKeys(data, function(use, scope, key)
        return use(prefix) .. key
    end)

    print(peek(renamed)) --> {Key_Red = "foo", Key_Blue = "bar"}

    prefix:set("colour")
    print(peek(renamed)) --> {colourRed = "foo", colourBlue = "bar"}

## Usage¶

To create a new `ForKeys` object, call the constructor with an input table and a processor function. The first two arguments are `use` and `scope`, just like [computed objects](https://elttob.uk/Fusion/0.3/tutorials/fundamentals/computeds). The third argument is one of the keys read from the input table.

    local data = {red = "foo", blue = "bar"}
    local renamed = scope:ForKeys(data, function(use, scope, key)
        return string.upper(key)
    end)

You can read the table of processed keys using `peek()`:

    local data = {red = "foo", blue = "bar"}
    local renamed = scope:ForKeys(data, function(use, scope, key)
        return string.upper(key)
    end)

    print(peek(renamed)) --> {RED = "foo", BLUE = "bar"}

The input table can be a state object. When the input table changes, the output will update.

    local foodSet = scope:Value({})

    local prefixes = { pie = "tasty", chocolate = "yummy", broccoli = "gross" }
    local renamedFoodSet = scope:ForKeys(foodSet, function(use, scope, food)
        return prefixes[food] .. food
    end)

    foodSet:set({ pie = true })
    print(peek(renamedFoodSet)) --> { tasty_pie = true }

    foodSet:set({ broccoli = true, chocolate = true })
    print(peek(renamedFoodSet)) --> { gross_broccoli = true, yummy_chocolate = true }

You can also `use()` state objects in your calculations, just like a computed.

    local foodSet = scope:Value({ broccoli = true, chocolate = true })

    local prefixes = { chocolate = "yummy", broccoli = scope:Value("gross") }
    local renamedFoodSet = scope:ForKeys(foodSet, function(use, scope, food)
        return use(prefixes[food]) .. food
    end)

    print(peek(renamedFoodSet)) --> { gross_broccoli = true, yummy_chocolate = true }

    prefixes.broccoli:set("scrumptious")
    print(peek(renamedFoodSet)) --> { scrumptious_broccoli = true, yummy_chocolate = true }

Anything added to the `scope` is cleaned up for you when the processed key is removed.

    local foodSet = scope:Value({ broccoli = true, chocolate = true })

    local shoutingFoodSet = scope:ForKeys(names, function(use, scope, food)
        table.insert(scope, function()
            print("I ate the " .. food .. "!")
        end)
        return string.upper(food)
    end)

    names:set({ chocolate = true }) --> I ate the broccoli!

How ForKeys optimises your code

Rather than creating a new output table from scratch every time the input table is changed, `ForKeys` will try and reuse as much as possible to improve performance.

Say you're converting an array to a dictionary:

    local array = scope:Value({"Fusion", "Knit", "Matter"})
    local dict = scope:ForKeys(array, function(use, scope, index)
        return "Value" .. index
    end)

    print(peek(dict)) --> {Value1 = "Fusion", Value2 = "Knit", Value3 = "Matter"}

Because `ForKeys` only operates on the keys, changing the values in the array doesn't affect the keys. Keys are only added or removed as needed:

    local array = scope:Value({"Fusion", "Knit", "Matter"})
    local dict = scope:ForKeys(array, function(use, scope, index)
        return "Value" .. index
    end)

    print(peek(dict)) --> {Value1 = "Fusion", Value2 = "Knit", Value3 = "Matter"}

    array:set({"Roact", "Rodux", "Promise"})
    print(peek(dict)) --> {Value1 = "Roact", Value2 = "Rodux", Value3 = "Promise"}

`ForKeys` takes advantage of this - when a value changes, it's copied into the output table without recalculating the key. Keys are only calculated when a value is assigned to a new key.

Back to top


![image](https://github.com/user-attachments/assets/d88e0da7-0f48-46d0-86c2-5e721fa350c9)

A **runtime** developer tool for the **Roblox Game Engine** to monitor and

intercept incoming and outgoing network traffic with beautiful opinionated UI.

```lua
-- https://discord.gg/FJcJMuze7S
loadstring(game:HttpGet("https://github.com/notpoiu/cobalt/releases/latest/download/Cobalt.luau"))()

## Features

- Beautiful opinionated ui
- Incoming & Outgoing Event **monitoring**
  - Actors support\*
  - \_\_index hooking
  - UnreliableRemoteEvent Support
- Incoming & Outgoing Event **interception**
  - Block events
  - Replay events
- Pagination Implementation (prevents lag)
- Copy Calling and Intercept code
- File Logs
- Plugin System (https://docs.mspaint.cc/cobalt/plugins/overview)

> \*Actors are supported even on executors that lack the `run_on_actor` function. As long as the `setfflag` and `getfflag` functions are available in the executor's environement

## Video Demo

[![Cobalt Remote Spy Demo](http://img.youtube.com/vi/Ellj_P6-yVI/0.jpg)](http://www.youtube.com/watch?v=Ellj_P6-yVI)

# Development

For development instructions, please refer to [our documentation](https://docs.mspaint.cc/cobalt/development).


**Matter** is a modern ECS library for _[Roblox]_.

[roblox]: https://www.roblox.com/

## Installation

Matter can be installed with [Wally] by including it as a dependency in your
`wally.toml` file.

```toml
Matter = "matter-ecs/matter@0.8.4"

## Migration

If you're currently using the scope `evaera/matter`, prior versions are the same
package. You can migrate by changing your `wally.toml` file to use the scope
`matter-ecs/matter`.

## Building

Before building, you'll need to install all dependencies using [Wally].

You can then sync or build the project with [Rojo]. Matter contains several
project files with different builds of the project. The `default.project.json`
is the package build. The `example.project.json` is the example game build.

[rojo]: https://rojo.space/
[wally]: https://wally.run/

## Contributing

Contributions are welcome, please make a pull request! Check out our
[contribution] guide for further information.

Please read our [code of conduct] when getting involved.

[contribution]: CONTRIBUTING.md
[code of conduct]: CODE_OF_CONDUCT.md

## Project Legacy

Matter was originally pioneered by [@evaera](https://www.github.com/evaera). She
laid the robust foundation for the work we continue today.

## License

Matter is free software available under the MIT license. See the [license] for
details.

[license]: LICENSE.md


Matter is an Entity-Component-System library that empowers developers to build games that are extensible, performant, and easy to debug.

### Data-Driven Architecture

With ECS, your data and your code are separate. Data exists as Components, any number of which can be present on an Entity. Systems contain your game code and run in a fixed order, every frame. Systems query for Entities that have specific Components, and declare what the state of the world should be.

The separation of state and behavior enables quality of life features like Hot Reloading, allowing you to see the changes you've made to your code in real time - as soon as you save the file. No need to stop and start the game.

### Debug View and Editor

Matter comes with a world-class debug view and editor. In addition to viewing all your game state in one place, the debugger integrates with an immediate-mode widget system to make creating debug conditions dead simple. Performance information, queries, logs, and recent errors are displayed for each system, enabling deep insight into what your code is really doing.

All systems run in a fixed order, every frame

#### RenderStepped

moveCutSceneCameraanimateModelscamera3dEffects

#### Heartbeat

spawnEnemiespoisonEnemiesenemiesMovefireWeaponsdoors

### Robust and Durable

Event-driven code can be sensitive to ordering issues and new behaviors can be created accidentally. With ECS, your code runs contiguously in a fixed order every frame, which makes it much more predictable and resilient to new behaviors caused by refactors.

All systems have access to all the data in the game, which means adding a new feature is as simple as creating a new system that simply declares something about the world.


#  Flipbook

Flipbook is a storybook plugin that previews UI components in a sandboxed environment. With it you can isolate distinct parts of your game's UI to hammer out edge cases and complex states without having to run through the whole UI.

With native support for popular UI libraries like [Roact](https://github.com/roblox/roact), [Fusion](https://github.com/Elttob/Fusion), and [Roact 17](https://github.com/grilme99/CorePackages#roact17), no matter how you create UI you can write a story for it in Flipbook

![Screenshot of Flipbook showing off the ButtonWithControls story](docs/static/img/main-screenshot.png)

## Installation

You can install Flipbook from the [Roblox marketplace](https://www.roblox.com/library/8517129161) or from the [GitHub releases](https://github.com/flipbook-labs/flipbook/releases) page.

## Documentation

Learn how to use Flipbook on the [official documentation site](https://flipbook-labs.github.io/flipbook/).

## Contributing

Before opening a pull request, check out our [contributing guide](https://flipbook-labs.github.io/flipbook/docs/contributing/onboarding) to learn how we develop the plugin.

## License

Flipbook is licensed under [MIT License](LICENSE).


### Isolate your UI

With Flipbook you can isolate distinct parts of your game's UI to hammer out edge cases and complex states without having to run through the whole UI

### Controls

Set custom controls that your stories can respond to while iterating to quickly toggle states and provide custom input without changing the story

### Support for Hoarcekat

Bring your existing stories from Hoarcekat over to Flipbook by adding a Storybook to set them up.


Flipbook is a storybook plugin that previews UI components in a sandboxed environment. With it you can isolate distinct parts of your game's UI to hammer out edge cases and complex states without having to run through the whole UI.

By default, Flipbook uses a function-based renderer with support for Roblox Instances to get you up and running, and offers native support for UI libraries like [React](https://flipbook-labs.github.io/flipbook/docs/frameworks/react) and [Fusion](https://flipbook-labs.github.io/flipbook/docs/frameworks/fusion). No matter how you create UI you can write a story for it in Flipbook.


We'll have examples here later. For now, check out [Storyteller](https://github.com/flipbook-labs/storyteller) which includes Story and Storybook types so you can typecheck your modules.


[## 📄 Writing StoriesBefore Flipbook can discover your Stories, you need a Storybook. A Storybook is any ModuleScript with a .storybook extension. It acts as the topmost configuration for each collection of Stories in your project.](https://flipbook-labs.github.io/flipbook/docs/creating-stories/writing-stories)[## 📄 ControlsStories can define controls that make it possible to quickly test out the behavior and variants of the UI you're working on.](https://flipbook-labs.github.io/flipbook/docs/creating-stories/controls)[## 📄 TypecheckingWe'll have examples here later. For now, check out Storyteller which includes Story and Storybook types so you can typecheck your modules.](https://flipbook-labs.github.io/flipbook/docs/creating-stories/typechecking)[## 📄 Story FormatStorybook](https://flipbook-labs.github.io/flipbook/docs/creating-stories/story-format)


Stories can define controls that make it possible to quickly test out the behavior and variants of the UI you're working on.

Here's an example React component that we will build a Story around. The props it takes in will be configurable by the Story's controls.

ReactButtonControls.luau

    local React = require("@pkg/React")

    local function ReactButton(props: {
        text: string,
        isDisabled: boolean,
        onActivated: () -> (),
    })
        return React.createElement("TextButton", {
            Text = props.text,
            TextSize = 16,
            Font = Enum.Font.BuilderSansExtraBold,
            TextColor3 = Color3.fromRGB(50, 50, 50),
            BackgroundColor3 = Color3.fromRGB(255, 255, 255),
            AutoButtonColor = if props.isDisabled then false else true,
            BorderSizePixel = 0,
            Size = UDim2.fromOffset(200, 40),
            [React.Event.Activated] = if props.isDisabled then nil else props.onActivated,
        }, {
            Overlay = if props.isDisabled
                then React.createElement("Frame", {
                    Size = UDim2.fromScale(1, 1),
                    BackgroundColor3 = Color3.fromRGB(0, 0, 0),
                    BackgroundTransparency = 0.6,
                })
                else nil,
        })
    end

    return ReactButton

The Story creates the element and passes in controls through the `props` argument.

ReactButtonControls.story.luau

    local React = require("@pkg/React")

    local ReactButtonControls = require("./ReactButtonControls")

    local controls = {
        text = "Click Me",
        isDisabled = false,

    type Props = {
        controls: typeof(controls),

    return {
        controls = controls,
        story = function(props: Props)
            return React.createElement(ReactButtonControls, {
                text = props.controls.text,
                isDisabled = props.controls.isDisabled,
                onActivated = function()
                    print("click")
                end,
            })
        end,

Opening the `ReactButtonControls` Story in Flipbook will include an accompanying panel for configuring the controls.

As controls are modified the Story will live-reload with the new props.


[## 📄 FusionFusion is a reactive UI library created and maintained by Daniel P H Fox. Flipbook supports Fusion via the packages object. Pass in your installation of Fusion to your Storybook and all stories will be rendered with it.](https://flipbook-labs.github.io/flipbook/docs/frameworks/fusion)[## 📄 ReactFlipbook supports Roblox's transpilation of React 17 through the use of jsdotlua's React fork. Pass in your installation of React and ReactRoblox to your Storybook and all stories will be rendered with it.](https://flipbook-labs.github.io/flipbook/docs/frameworks/react)[## 📄 RoactFlipbook supports Roblox's legacy Roact library. Pass in your installation of Roact to your Storybook and all stories will be rendered with it.](https://flipbook-labs.github.io/flipbook/docs/frameworks/roact)


[## 📄 OnboardingThank you for your interest in contributing to Flipbook! This guide will help you get your environment setup so you can have the best possible development experience.](https://flipbook-labs.github.io/flipbook/docs/contributing/onboarding)[## 📄 Creating ReleasesOnce ready to cut a new release, bump the version in our manifest files and create a PR for it.](https://flipbook-labs.github.io/flipbook/docs/contributing/creating-releases)


# StudioComponents

## [Read the documentation here!](https://sircfenner.github.io/StudioComponents/)

A collection of React implementations of Roblox Studio components such as Checkboxes, Buttons, and Dropdowns. This is intended for building plugins for Roblox Studio.

An example Dropdown

This project is built for [react-lua](https://github.com/jsdotlua/react-lua), Roblox's translation
of upstream ReactJS 17.x into Luau.

## Installation

### Wally

Add `studiocomponents` to your `wally.toml`:

```toml
studiocomponents = "sircfenner/studiocomponents@1.0.0"

### NPM & yarn

Add `studiocomponents` to your dependencies:

```bash
npm install @sircfenner/studiocomponents

```bash
yarn add @sircfenner/studiocomponents

Run `npmluau`.

## License

This project is available under the MIT license. See [LICENSE](LICENSE) for details.


# Nexus-VR-Character-Model
Nexus VR Character Model replaces the default
controls and camera of R15 Roblox characters
and maps the character to the player's headset
and hand controllers.

## Menu
To access the menu, the left controller must be
rotated counter-clockwise and the right controller
must be rotated clockwise so that they are facing
each other or upwards while facing roughly forward.
This gesture is used to be out of the way of most
games.

## Limitations
* Optimizations for specific headsets and controllers
  can't be made because the hardware is not communicated
  to the developer. Some headsets, like the HP Reverb G2,
  may perform poorly.
* R6 characters are not supported. R15 is recommended
  for new projects since R15 gets better support and
  has more functionality.
* The foot-planting code is old and could use a rewrite.
* The menu gesture is not obvious. Most players may
  not know about it.
* `VRService.AvatarGestures` support is incomplete.
  * `ThirdPersonTrack` camera does not work and the camera
    setting is restricted.
  * [Crouching is not supported.](https://devforum.roblox.com/t/vrserviceavatargestures-to-allow-for-vr-crouching/3266565)
  * [Teleporting players is broken with no workaround.](https://devforum.roblox.com/t/animating-your-avatar-in-vr/2954399/9)
  * Rolling the camera with a seat (ex: rollercoaster,
    plane) is not supported.
  * Setting the eye level is unsupported  outside of
    recentering, and the internal recenter APIs don't
    work.
  * The hands might not reach the controller's hands
    due to not being able to disconnect the arms.

## Setup
The repository can be synced into Roblox using
[Rojo](https://github.com/rojo-rbx/rojo), which
will include the [loader](NexusVRCharacterModelLoader.server.lua)
with the `MainModule`. If the loader contains
`MainModule`, it will load the `MainModule`.
Otherwise, the asset id `10728814921` will be
fetched. The behavior allows for automatic
updates while still allowing an easy way to use
static versions. The loader uploaded to the
website does not include the `MainModule`, so
it will default to fetching the latest version.

## [Nexus-VR-Core](https://github.com/thenexusAvenger/nexus-vr-core)
Nexus VR Core is used for user interfaces
in Nexus VR Character Model. When Nexus VR
Character Model is loaded, a module named
`NexusVRCore` will be loaded in `ReplicatedStorage`.
See Nexus VR Core's docs on how to use it
to make user interfaces that can be interacted
with by VR users.

## API
See [included-apis.md](docs/included-apis.md) for the APIs
that can be referenced.

## Contributing
Both issues and pull requests are accepted for this project.

## License
Nexus VR Character Model is available under the terms of the MIT
License. See [LICENSE](LICENSE) for details.


# Lapis
A Roblox DataStore abstraction that offers:
- **Session Locking** - Documents can only be accessed from one server at a time. This prevents some bugs and duping methods.
- **Validation** - Ensure your data is correct before saving it.
- **Migrations** - Update the structure of your data over time.
- **Retries** - Failed DataStore requests will be retried.
- **Throttling** - DataStore requests will never exceed their budget and throw an error.
- **Promise-based API** - Promises are used instead of yielding.
- **Immutability** - By default, documents are deep frozen must be updated immutably. This can be disabled.
- **Save Batching** - Pending `Document:save()` and `Document:close()` calls are combined into one DataStore request when possible.
- **Auto Save** - Documents are automatically saved every 5 minutes.
- **BindToClose** - All documents are automatically closed when the game shuts down.

This library was inspired by [Quicksave](https://github.com/evaera/Quicksave).

## Warning
Lapis has not been battle-tested in a large production game yet. It may contain obscure bugs so use at your own risk.


# Crunchyroll

https://github.com/user-attachments/assets/51bbde10-b439-431e-9e85-a808a9303f0f

no Animator!

Crunchyroll is a dedicated library for calculating coordinates frames of a rig from an array of animation tracks. You can define a rig by calling `crunchyroll.create_rig`, which is a representation of Roblox Motor6Ds. You can then pass this rig into `crunchyroll.solve_animation`, which also takes animation tracks. These are tables which are similar to Roblox's `AnimationTrack`s. Similar to AnimationTracks, you need an animation "asset". You can load a Roblox animation by calling `crunchyroll.load_keyframe_sequence`. Crunchyroll will then give you the coordinate frames of the "limbs" (think Torso, Head, "Left Leg", UpperTorso etc.), and that's it!

# Why use this?

If you don't intend on using Crunchyroll to write your own animation player:

- No instances! You can calculate how an animation looks at any given time without affecting your game in any way. This means you could implement things like proper ping compensation and secure hit detection (secure headshot detection!)
- Allows for extremely convenient still shots of characters
- Great for characters in viewport frames! Animations

If you do write your own animation player:

- Numerical priorities! No more Action1, Action2, Action3.
- No more :LoadAnimation() or any asset ID management.
- Immediate stops! No more forced 0.05s fade time.
- Very fast and performant :3
- potential for things like easy animation skipping!
- remove the physics from animations, makes it significantly easier to write your own animation replication!

# Future support

Eventually, I may consider making a custom animation format which supports things like sinusoidal easing, additive blending, and other features. I do not know how popular this would be though so I am not sure I will implement these right now.

# Example

```luau
local rig = require(...) -- Path to a Crunchyroll R6 rig
local crunchyroll = require(...) -- Path to Crunchyroll

local crunchyroll_animation = crunchyroll.load_keyframe_sequence(ReplicatedStorage.assets.TestAnimation)

crunchyroll_animation.solve_animation(rig, {
    [crunchyroll_animation] = {
        stop_fade_time = 0.25, -- 0.25 seconds
        start_fade_time = 0.25,

        weight = 1, -- Supports blending!
        priority = 1, -- Supports numerical priorities!

        alpha = 0.5 -- Halfway through the animation
})

-- placed into a result table for optimal performance
local left_arm_cframe = rig.result_coordinate_frames["Left Arm"]


Crunchyroll is a dedicated library for calculating coordinates frames of a rig from an array of animation tracks. You can define a rig by calling `crunchyroll.create_rig`, which is a representation of Roblox Motor6Ds. You can then pass this rig into `crunchyroll.solve_animation`, which also takes animation tracks. These are tables which are similar to Roblox's `AnimationTrack`s. Similar to AnimationTracks, you need an animation "asset". You can load a Roblox animation by calling `crunchyroll.load_keyframe_sequence`. Crunchyroll will then give you the coordinate frames of the "limbs" (think Torso, Head, "Left Leg", UpperTorso etc.), and that's it!

# Why use this?

If you don't intend on using Crunchyroll to write your own animation player:

  * No instances! You can calculate how an animation looks at any given time without affecting your game in any way. This means you could implement things like proper ping compensation and secure hit detection (secure headshot detection!)
  * Allows for extremely convenient still shots of characters
  * Great for characters in viewport frames! Animations

If you do write your own animation player:

  * Numerical priorities! No more Action1, Action2, Action3.
  * No more :LoadAnimation() or any asset ID management.
  * Immediate stops! No more forced 0.05s fade time.
  * Very fast and performant :3
  * potential for things like easy animation skipping!
  * remove the physics from animations, makes it significantly easier to write your own animation replication!

# Future support

Eventually, I may consider making a custom animation format which supports things like sinusoidal easing, additive blending, and other features. I do not know how popular this would be though so I am not sure I will implement these right now.

# Example

    local rig = require(...) -- Path to a Crunchyroll R6 rig
    local crunchyroll = require(...) -- Path to Crunchyroll

    local crunchyroll_animation = crunchyroll.load_keyframe_sequence(ReplicatedStorage.assets.TestAnimation)

    crunchyroll_animation.solve_animation(rig, {
        [crunchyroll_animation] = {
            stop_fade_time = 0.25, -- 0.25 seconds
            start_fade_time = 0.25,

            weight = 1, -- Supports blending!
            priority = 1, -- Supports numerical priorities!

            alpha = 0.5 -- Halfway through the animation
    })

    -- placed into a result table for optimal performance
    local left_arm_cframe = rig.result_coordinate_frames["Left Arm"]


You can get Crunchyroll on Wally, or you can get Crunchyroll via rbxm on the [latest GitHub release](https://github.com/ffrostfall/crunchyroll/releases).

    [dependencies]
    crunchyroll = "ffrostfall/crunchyroll@latest"


Animation assets in Crunchyroll are the equivalent of `Animation` instances in Roblox. They are not involved when it comes to _playing_ an animation, they are involved in loading the asset & storing data.

It is important to note, however, that you need `KeyframeSequence`s, not `Animation`s. This is because Crunchyroll parses keyframe sequences. There may be additional support for processing animation instances too, but that is not the case right now.

You can load a keyframe sequence into a Crunchyroll animation like so:

    local crunchyroll = require(path.to.crunchyroll)

    local keyframe_sequence = ReplicatedStorage.assets.walking_keyframe_sequence

    crunchyroll.load_keyframe_sequence(keyframe_sequence)


# A-Chassis 🚗
Welcome to the official GitHub page for A-Chassis. Here, you will find the beta updates and links to the latest versions.

[![Roblox Stable Car](https://badgen.net/badge/Roblox%20Stable%20(Car)/1.7.2/purple?icon=https://upload.wikimedia.org/wikipedia/commons/6/6c/Roblox_Logo.svg)](https://create.roblox.com/store/asset/13999609938)
[![Roblox Stable Bike](https://badgen.net/badge/Roblox%20Stable%20(Bike)/1.7.2M/purple?icon=https://upload.wikimedia.org/wikipedia/commons/6/6c/Roblox_Logo.svg)](https://create.roblox.com/store/asset/113746229283884)
[![GitHub Stable](https://badgen.net/badge/GitHub%20Stable%20(Both)/1.7.2(M)/purple?icon=github)](https://github.com/lisphm/A-Chassis/releases/tag/v1.7.2-stable)

A-Chassis is a free, open-source chassis kit on Roblox. It is set to provide a beginner-friendly, yet scalable starting point for those who want to experiment with automobiles.

- 🔌Easy-to-use plugin system
- 💪Extensive user support
- 🌍Used by hundreds of experiences

If you would like to contribute to the chassis, or if you need help with the chassis, you can check out [our Discord server](https://discord.gg/P2WXGe3U7E).

# Installation 📦
Installing A-Chassis from this page is a simple process.
1. Download the `.rbxm` file from the [Releases](https://github.com/lisphm/A-Chassis/releases) page. You can find previous versions here as well
2. Copy the `.rbxm` file into a place in Roblox Studio

You can also install it with the Roblox model.
1. Go to the [Roblox version](https://create.roblox.com/store/asset/13999609938) and click `Get Model`
2. In a Roblox Studio place, open the
Toolbox
3. Go into the Inventory tab
4. Find and click the A-Chassis model to insert it into the place

# Known Issues 🪧
*Solved issues will be marked with **SOLVED** for one update cycle*
1. Entire car shifts when steering on "New" steering type
2. Bike animation breaks layered clothing


# I strongly recommend you use ByteNet over BridgeNet2: https://github.com/ffrostflame/ByteNet

# BridgeNet2 v1.0.0

## Blazing fast & opinionated networking library designed to reduce bandwidth.

BridgeNet2 is a networking library for Roblox with a focus on performance. It cuts out header data from RemoteEvent calls by 7 bytes, which is beneficial because it cuts down on the total number of packets per player. This in turn decreases server bandwidth used, so you can send more data. Games using BridgeNet2 will never hit the RemoteEvent throttle limit. BridgeNet2 also decreases the amount of time to process packets on the client by approximately 75-80%.

BridgeNet2 has a simplistic API that mirrors RemoteEvents. It does this by using `Bridge:Fire()` instead of `RemoteEvent:FireClient()`, and `Bridge:Connect()` instead of `RemoteEvent.OnServerEvent:Connect()`. BridgeNet2 wraps remoteevents, making the developers job easier, by encapsulating a complex optimization process.

Developers cannot fire a bridge with multiple parameters. This means you have to pass a table into `Bridge:Fire()`, instead of separate arguments. This design choice was chosen because it removes a layer of complexity. This choice is better for performance, stability, and typechecking. Also, doing this means BridgeNet2 never needs to touch the data that's pushed, it can just directly push that data through the RemoteEvent. As a side effect, BridgeNet2 allows developers to group data into an array or dictionary, as found in other Roblox projects.

This library favors performance, and therefore we made choices that resulted in an opinionated library. BridgeNet2 never manipulates your data under the hood, but it does encourage developing in favor of performance.

[Further Documentation](https://ffrostflame.github.io/BridgeNet2/)


# Voxels Engine
A highly extensible voxel engine written in Luau for Roblox.

[Inspired by Minecraft and Terraria]

## Features

* Rendering
    * Render a chunk of terrain procedurally using EditableMeshes and EditableImages
    * Cull hidden faces
* Generation
    * Terrain shape using fractal noise and spline maps
    * Multithreading by giving chunks generation stages
    * Storing data into u8 buffers

## Getting Started

1. Download the latest .rbxl file from [releases](https://github.com/mustafakhafaji/Mineblox/releases).
2. Import file into a new place in Roblox Studio.

## Planned Features

* Biomes
    * Desert
    * Forest
    * Jungle
    * Tundra
* Caves
    * Spaghetti caves
    * Cheese caves

## Contributing

Check out the [contribution guide](CONTRIBUTING.md) for instructions.


# Intro
This is my personal documentation on Roblox thread identities and security tags, which are now called security capabilities. This can also contain other information regarding how code under a specific identity is loaded by the engine, among some other little things.

> [!WARNING]
> This does not cover any of the [Script Capabilities](https://create.roblox.com/docs/scripting/capabilities) that can be sandboxed, as they have their own official documentation page! I will only add the sandboxable capabilities here if the official documentation isn't good enough or it becomes outdated. Currently, [`CapabilityControl`](Capabilities/UndocumentedSandboxable/35%20-%20CapabilityControl.md) and [`Players`](Capabilities/UndocumentedSandboxable/34%20-%20Players.md) are undocumented.

If you want to test anything in this repository, you can see the script's identity by calling `printidentity()` in the script. If you want to see the capabilities, you can refer to this repository or you can run the [Luau script provided](CheckCapabilities.luau).
Of course, depending on how old the client is, identities and their capabilities can be extremely different from other versions of Roblox. So if there comes to be an issue where I made a typo or some information is not correct, please use the most modern version of the client available.

# Explanation of Identities and Capabilities
If you don't exactly know what Identities and Capabilities are, then an explaination is provided here. Every thread on Roblox is assigned an ID, which dictates what the thread is able to access. This system exists to prevent certain scripts from accessing things that can be considered sensitive or only available under specific contexts.
Properties have a Read and Write security (which most of the time, both will be the exact same), while Functions, Events, and Callbacks only have the one security.

A few examples I can provide of Engine APIs being locked down for good reasons with this system:

* `CoreGui.TakeScreenshot` is a very obvious example of a function you don't want everyone to have access to, as it will forcefully take a screenshot. Because of this, Roblox gave this function the [`RobloxScript`](Capabilities/03%20-%20RobloxScript.md) tag, which locks it from anything that cannot access [`RobloxScript`](Capabilities/03%20-%20RobloxScript.md) but allows things like `CoreScript`s to access it.

* [`HttpService.HttpEnabled`](https://create.roblox.com/docs/reference/engine/classes/HttpService#HttpEnabled) is another kind of sensitive property. Imagine a GameScript/Plugin you inserted into your game happened to be backdoor that serialized all of your game's Instances the second it started and sent it off to a remote server. However, it would be a pain if it was given [`RobloxScript`](Capabilities/03%20-%20RobloxScript.md) because that would lock it away from the command bar. This is most likely why Roblox gave this property [`LocalUser`](Capabilities/01%20-%20LocalUser.md) instead since [`GameScript`](Identities/2%20-%20GameScript.md)s and [`StudioPlugin`](Identities/5%20-%20StudioPlugin.md)s cannot use it, but the [`CommandBar`](Identities/4%20-%20CommandBar.md) can.


![Metain](https://metain.dev/og-image.png)

# Metain Connect

The official Roblox Studio plugin for [Metain](https://metain.dev) which builds Roblox games with AI, powered by [Claude](https://anthropic.com).

> [!IMPORTANT]
> Only install this plugin from the [official Creator Store page](https://create.roblox.com/store/asset/77655523450717) or from this repository. Verify the asset ID matches `77655523450717`. Unofficial or copycat plugins could access your Studio session or inject malicious scripts into your game.

## Quick Setup

1. Download [Roblox Studio](https://www.roblox.com/create) if you don't have it
2. Get the plugin either from the [Creator Store](https://create.roblox.com/store/asset/77655523450717) or clone this repo and save it as a [local plugin](https://create.roblox.com/docs/studio/plugins#saving-a-local-plugin) in Studio
3. Open Studio, click **Metain Connect** in the Plugins tab
4. Go to [metain.dev/chat](https://metain.dev/chat), click **Get Connection Code** and enter it in the plugin
5. Start typing what you want to build

For a detailed walkthrough, visit the [Setup Guide](https://metain.dev/setup).

## How It Works

The plugin connects Roblox Studio to Metain's AI through a WebSocket connection. When you send a prompt on [metain.dev/chat](https://metain.dev/chat), the AI generates Luau code and sends commands directly to the plugin, which executes them in your Studio session in real-time.

All changes are recorded in Studio's undo history. You can revert any AI action without affecting your manual work.

## Plugin Capabilities

| Category | Commands |
|----------|----------|
| **Scripts** | Read, create, update and edit Luau scripts |
| **Instances** | Create, rename, move, delete and clone instances |
| **UI** | Create full UI hierarchies from specs |
| **Properties** | Set properties, tags and attributes on any instance |
| **Exploration** | Run Luau code to explore game hierarchy, properties and any service |
| **Undo** | Revert Metain actions without affecting manual changes |

## Security

The plugin only connects when you provide a connection code and can only modify things inside your Studio session. The connection is authenticated and uses a reconnect token for stability.

## Links

- [Website](https://metain.dev)
- [Setup Guide](https://metain.dev/setup)
- [Get Plugin](https://create.roblox.com/store/asset/77655523450717)
- [Discord](https://discord.gg/npVzt2ZZ6S) - join us to shape the future of Metain
- [X (Twitter)](https://x.com/metaindev)


# Get Started with Metain

Set up in under 2 minutes. No keys, no config - just connect and build.

1

### Download Roblox Studio

Roblox Studio is the free game engine where your creations come to life. Download it from the official Roblox site.

[Download Roblox Studio](https://www.roblox.com/create)

Already have Studio? Skip to step 2.

2

### Grab the Metain Plugin

Get our free plugin from the Roblox Creator Store. Click "Get Plugin" - it installs automatically into Studio.

[Get the Plugin](https://create.roblox.com/store/asset/77655523450717)

3

### Connect & Start Building

Open Studio and click Metain Connect in the Plugins tab. On metain.dev, click "Get Connection Code" and enter the code in the plugin. Start typing prompts - the AI builds directly in your game.

[Open Metain Chat](https://metain.dev/chat)

Complete Guide

## Step-by-step walkthrough

New to Roblox? Never installed a plugin before? This guide covers everything.

### What is Roblox Studio?

Roblox Studio is the free tool used to build games on Roblox. If you've ever played a Roblox game, it was made in Studio. You don't need any coding experience to get started with Metain - that's the whole point.

Studio runs on Windows and Mac. It's completely free to download and use.

### Installing Roblox Studio

  1. 1Go to [roblox.com/create](https://www.roblox.com/create) and click **"Start Creating"**. If you don't have a Roblox account yet, you'll need to create one first - it's free.
  2. 2The installer will download automatically. Open it and follow the prompts. On Mac, drag it to your Applications folder.
  3. 3Once installed, open Studio and sign in with your Roblox account. You'll see a screen with templates - you can pick any one or start with a blank Baseplate.

### Getting the Metain Plugin

Plugins are add-ons that extend what Studio can do. The Metain plugin is what connects your Studio session to our AI.

  1. 1Open the [Metain plugin page](https://create.roblox.com/store/asset/77655523450717) on the Roblox Creator Store.
  2. 2Click **"Get Plugin"**. It installs automatically - no files to move, no folders to find.
  3. 3Restart Studio if it was already open. You'll see **"Metain Connect"** in the Plugins tab.

### Stay safe - only use the official plugin

Only install the Metain plugin from our [official Creator Store page](https://create.roblox.com/store/asset/77655523450717). If you find a Metain plugin elsewhere, verify the asset ID matches 77655523450717. Unofficial or copycat plugins could access your Studio session, inject malicious scripts into your game or steal your connection credentials. We will never distribute the plugin outside of the Roblox Creator Store.

### Connecting to Metain

This is where everything comes together. You'll link your Studio session to the Metain chat so the AI can build directly in your game.

  1. 1In Studio, click the **Metain Connect** in the Plugins tab. A small panel will open.
  2. 2Go to [metain.dev/chat](https://metain.dev/chat) in your browser and sign in with your Roblox account.
  3. 3Click **"Get Connection Code"**. You'll get a 6-character code. Enter it in the Studio plugin panel and click Connect.
  4. 4That's it. Start typing what you want to build in the chat - the AI writes the code and places it in your game in real-time.

When you first connect, Roblox Studio will show a permission prompts like this:

You **must press Allow** to let the plugin communicate with our web interface. If you press Deny, the plugin won't be able to sync with your chat session and actions may still consume credits without reaching Studio.

### How it actually works

Metain is an AI that understands Roblox. When you type a prompt like "make a coin collection system" or "add a health bar UI", the AI generates real Luau code and sends it straight to Studio through the plugin. No copy-pasting, no switching tabs.

You don't need to download any extra software, provide API keys or mess with configuration files. Everything runs in your browser - just the Studio plugin and our web chat. The free tier gives you access to the AI with restricted actions per message. If you need more power, you can upgrade anytime from the [pricing page](https://metain.dev/#pricing).

Under the hood, the plugin connects to Metain's servers through a WebSocket and executes AI-generated commands directly in Studio. Powered by [Anthropic's Claude API](https://docs.anthropic.com) with tooling we've built specifically for Roblox development. As the model gets smarter, Metain gets better automatically. The plugin is [open source](https://github.com/metaindev/connect-plugin).

The plugin only connects when you give it a connection code. It can only modify things inside your Studio session - nothing else. You stay in full control.

### Tips for best results

  * -**Be specific.** "Make a red button that gives 10 coins when clicked" works better than "make a button".
  * -**Build step by step.** Start with one thing, test it, then ask for the next. The AI remembers your conversation.
  * -**Use undo.**If the AI does something you don't like, hit the undo button. It only reverts Metain's changes - your manual work stays safe.
  * -**Connection codes expire.** If yours stops working, just generate a new one. The plugin also reconnects automatically if the connection drops.
  * -**Let longer tasks finish.** Complex builds can take a moment. Let them finish rather than cancelling for the best results.
  * -**Select your experience during sign-in.** When you sign in with Roblox, you'll see a screen asking which experiences to grant access to. Make sure to select the game you want Metain to create developer products, game passes or badges for. To change your selection later, sign out of Metain and sign back in - the experience picker will appear again.

### Troubleshooting

  * -**Can't find the Metain button after installing?** Go to the **Plugins** tab in Studio and open **Plugin Management** to make sure the Metain plugin is enabled. You may need to restart Studio after installing.
  * -**Plugin not showing in Plugin Management?** Try reinstalling it from the [Creator Store](https://create.roblox.com/store/asset/77655523450717) and restarting Studio.
  * -For more help with Roblox Studio plugins, see the [official Roblox documentation](https://create.roblox.com/docs/studio/plugins).

[Start Building](https://metain.dev/auth)

Ready in minutes. No setup hassle.


# Build your Roblox game with Metain

Create games by simply typing prompts

Attach

"Metain helps developers build Roblox games faster than ever"

— The Metain Team

AI-Powered

Code generation

Real-time

Studio sync

Luau

Native support

Our Mission

## Ship games faster with AI

Metain transforms how you create Roblox experiences. From UI design to complex scripting our AI handles the heavy lifting

### AI Code Generation

Describe what you want in plain English. Metain generates production-ready Luau scripts instantly.

### UI Builder

Create game UIs by prompting. See results instantly in Studio.

### Live Studio Sync

Changes sync to Roblox Studio in real-time via WebSocket. See your updates instantly.

Pricing

## Simple, transparent pricing

Upgrade to get the capacity that matches your needs

Monthly plansCredit packs

MonthlyAnnual

Without a subscription you are limited to 10 AI actions per message

### Metain+

$4.99/month

12credits/month

Get Metain+

  * 2x more AI power per message
  * Handles scripts and game features
  * +10% bonus on credit packs

### Metain Pro

$9.99/month

28credits/month

Get Pro

Everything in Metain+, plus:

  * More AI actions per message
  * Builds full game systems in one go
  * +15% bonus on credit packs
  * Priority queue

### Metain Ultra

$19.99/month

60credits/month

Get Ultra

Everything in Pro, plus:

  * Tackles complex multi-part builds
  * +20% bonus on credit packs
  * Early access to new features

### Enterprise

Custom

For teams at scale

[Contact Sales](mailto:sales@metain.dev)

Everything in Ultra, plus:

  * Custom solutions
  * Team create
  * No queue
  * Dedicated support
  * SLA guarantee

Limited time/purchase withusing crypto

Cancel anytime—Purchased credits never expire—No surprise charges


# We know you can't wait

to start building your next game...

Metain is temporarily down for maintenance. Leave your email to get notified when we're live again.

Notify Me

Stay connected

[](https://discord.gg/npVzt2ZZ6S)[](https://x.com/metaindev)


# Get Started

Sign in with your Roblox account to get started

Continue with Roblox

By signing in, you agree to our [Terms of Service](https://metain.dev/terms) and [Privacy Policy](https://metain.dev/privacy). You must be 13+ to use this service.

[Follow us on](https://x.com/metaindev)

FAQ

### How do I connect Metain to my game?

You need the free [Metain plugin](https://create.roblox.com/store/asset/77655523450717) in Roblox Studio. Open Studio, click Metain Connect in the Plugins tab, then enter the connection code from [metain.dev/chat](https://metain.dev/chat). See the full [setup guide](https://metain.dev/setup) for step-by-step instructions.

### What is Metain Creations?

[Metain Creations](https://creations.metain.dev) is where you can list your game for visibility from the Metain community and search engines. It also has community-curated assets you can submit or use. To use an asset with Metain, add it to your Roblox inventory first so Metain can reference it. Animations have a separate editor where you can load, customize and export any animation freely.

### Why can't I create gamepasses, dev products or badges?

When you sign in with Roblox, there's a screen where you pick which game to give Metain access to. If you skipped it or picked the wrong one, sign out of Metain and sign back in. The game picker will appear again.

### Why can't I export animations?

On the Roblox sign-in screen, you need to select which account or group to export to. If you didn't, sign out and sign back in to pick one. You can also save animations as .rbxmx files and import them into Studio yourself, but Metain won't have context about animations exported manually.


# Privacy Policy

Last updated: March 2026

## 1. Introduction

Metain ("we", "us", "our") operates the Metain platform at metain.dev. This Privacy Policy explains how we collect, use and protect your information when you use our Service.

## 2. Information We Collect

### From Roblox OAuth

When you sign in with Roblox, we receive:

  * Roblox User ID
  * Username
  * Display Name

We do not receive your Roblox password, email, friends list or payment information from Roblox.

### From Your Use of Metain

  * Prompts you submit to generate code
  * Code and UI generated for you
  * Projects you save
  * Credit usage and transaction history

### Automatically Collected

  * IP address
  * Browser type and version
  * Device information
  * Pages visited and features used
  * Date and time of access

## 3. How We Use Your Information

  * **Provide the Service:** Generate code, save projects, manage credits
  * **Improve the Service:** Analyze usage patterns, fix bugs, enhance features
  * **Security:** Detect fraud, prevent abuse, protect users
  * **Communication:** Send account alerts, respond to support requests
  * **Legal compliance:** Meet regulatory and legal obligations

We process your information on the following legal bases: to perform our contract with you (providing the Service), for our legitimate interests (improving security, preventing abuse, analyzing usage patterns) and to comply with legal obligations.

## 4. What We Do NOT Do

In compliance with Roblox's Creator Third Party App Policy:

  * **We do not sell your personal data.**
  * **We do not use your prompts or code to train AI models.**
  * We do not share your data with advertisers.
  * We do not use third-party profiling services.

## 5. Third-Party Services

We use the following third-party services to operate Metain:

#### Roblox (Authentication)

Provides OAuth login. Subject to [Roblox Privacy Policy](https://en.help.roblox.com/hc/en-us/articles/115004647846-Roblox-Terms-of-Use)

#### Stripe (Payments)

Processes payments. We do not store your credit card information. Stripe may collect device data and browsing behavior on checkout pages. Subject to [Stripe Privacy Policy](https://stripe.com/privacy)

#### Anthropic (AI Processing)

Processes prompts to generate code. Prompts are sent to Anthropic's API but are not used to train their models (per our API agreement). Subject to [Anthropic Privacy Policy](https://www.anthropic.com/legal/privacy)

#### Cryptomus (Crypto Payments)

Processes cryptocurrency payments. We do not store your wallet addresses or crypto transaction details. Subject to [Cryptomus Privacy Policy](https://cryptomus.com/privacy)

## 6. Cookies

We use essential cookies to keep you logged in and remember your preferences. Stripe may also set cookies on checkout pages for fraud prevention. We do not use advertising or tracking cookies.

## 7. Data Retention

  * Account data is retained while your account is active.
  * After account deletion, your data is removed within 90 days.
  * We may retain anonymized, aggregated data for analytics.
  * Some data may be retained longer if required by law.

## 8. Your Rights

You have the right to:

  * **Access:** Request a copy of your data
  * **Delete:** Request deletion of your account and data
  * **Export:** Download your projects and generated code
  * **Correct:** Update inaccurate information
  * **Object:** Object to processing based on our legitimate interests
  * **Complain:** Lodge a complaint with your local data protection authority

To exercise these rights, contact us at [privacy@metain.dev](mailto:privacy@metain.dev)

## 9. Age Requirement

Metain is only available to users aged 13 and older, as required by Roblox OAuth. We do not knowingly collect data from children under 13. If we discover we have collected data from a child under 13, we will delete it promptly.

## 10. Data Security

We implement reasonable security measures to protect your data, including encryption in transit (HTTPS) and secure storage. However, no method of transmission or storage is 100% secure.

## 11. International Users

Metain is operated from the United States. If you access the Service from outside the US, your data will be transferred to and processed in the US. We apply the protections described in this policy to your data regardless of where it is processed.

## 12. Changes to This Policy

We may update this Privacy Policy from time to time. We will notify you of material changes by updating the "Last updated" date. Continued use of the Service after changes constitutes acceptance of the updated policy.

## 13. Contact Us

For questions about this Privacy Policy or your data, contact us at: [privacy@metain.dev](mailto:privacy@metain.dev)


# Terms of Service

Last updated: March 2026

## 1. Agreement to Terms

By accessing or using Metain ("Service"), you agree to be bound by these Terms of Service ("Terms"). If you do not agree to these Terms, do not use the Service. Metain ("we", "us", "our") operates the Service at metain.dev.

## 2. Roblox Disclaimer

By using Metain, you acknowledge and agree that:

  * These Terms are between you and Metain only and not with Roblox Corporation.
  * **Metain is not affiliated with, endorsed by or sponsored by Roblox Corporation.**
  * Roblox Corporation is not responsible or liable for your use of Metain.
  * Roblox Corporation has no obligation to provide any maintenance or support for Metain.
  * You waive and release any and all claims, liabilities, damages, losses and expenses against Roblox Corporation arising from or related to your use of Metain.

"Roblox" and related trademarks are property of Roblox Corporation. Use of Metain is also subject to the [Roblox Terms of Use](https://en.help.roblox.com/hc/en-us/articles/115004647846-Roblox-Terms-of-Use).

## 3. Eligibility

You must be at least 13 years old to use Metain. This requirement is enforced through Roblox OAuth authentication. By using the Service, you represent that you meet this age requirement.

## 4. Account & Authentication

Metain uses Roblox OAuth for authentication. We receive your Roblox user ID, username and display name. You are responsible for maintaining the security of your Roblox account. We are not responsible for any unauthorized access resulting from your failure to protect your account.

## 5. License to Use

We grant you a limited, personal, non-exclusive, non-transferable, revocable license to use Metain for personal or internal business purposes, subject to these Terms.

## 6. AI-Generated Content

Metain uses artificial intelligence to generate Luau code and UI components. You acknowledge that:

  * AI-generated outputs may contain errors, bugs or inaccuracies.
  * You are solely responsible for reviewing, testing and validating all generated code before use.
  * We do not guarantee that generated code will be secure, functional or fit for any particular purpose.
  * You assume all risk associated with using AI-generated content in your Roblox games.

## 7. Ownership

**Your Content:** You retain ownership of all prompts you submit and all code generated for you through the Service. You may use your generated code for any lawful purpose, including commercial Roblox games.

**Our Service:** We retain all rights to the Metain platform, including our software, branding and underlying technology. Nothing in these Terms transfers any intellectual property rights in the Service to you.

## 8. Data Usage

In compliance with Roblox's Creator Third Party App Policy:

  * **We do not sell your data.**
  * **We do not use your prompts or generated code to train AI models.**
  * Your data is only used to provide and improve the Service.

## 9. Credits & Billing

Metain operates on a credit-based system:

  * Free accounts can use the Service with restricted AI actions per message.
  * Paid subscriptions (Metain+, Pro, Ultra) provide monthly credit allocations that reset each billing cycle.
  * Subscription credits are non-refundable and do not roll over between billing periods.
  * One-time credit packs can be purchased separately and never expire.
  * Subscribers receive bonus credits on credit pack purchases (10-20% depending on tier).
  * Subscriptions can be cancelled anytime. You retain access until the end of your current billing period.
  * We reserve the right to change pricing with 30 days notice.
  * All fees are non-refundable except where required by law.

Payments are processed by Stripe. By purchasing a subscription or credit pack, you agree to Stripe's terms of service. We do not store your payment details.

Cryptocurrency payments may be made via Cryptomus. Crypto transactions are final and non-reversible. No refunds will be issued for crypto purchases.

## 10. Prohibited Uses

You may not use Metain to:

  * Generate malicious code, exploits or scripts intended to harm Roblox users or games.
  * Violate Roblox's Terms of Use or Community Standards.
  * Engage in any illegal activity.
  * Attempt to reverse engineer, copy or resell the Service.
  * Use automated tools to abuse the Service.

## 11. Disclaimer of Warranties

THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. WE DO NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE OR SECURE.

## 12. Limitation of Liability

TO THE MAXIMUM EXTENT PERMITTED BY LAW, METAIN SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL OR PUNITIVE DAMAGES ARISING FROM YOUR USE OF THE SERVICE. OUR TOTAL LIABILITY SHALL NOT EXCEED THE AMOUNTS YOU PAID TO US IN THE TWELVE (12) MONTHS PRECEDING THE CLAIM.

## 13. Termination

You may stop using Metain at any time. We may suspend or terminate your access if you violate these Terms or for any other reason at our discretion. Upon termination, your right to use the Service ends and any remaining credits in your account are forfeited. Provisions that by their nature should survive (such as ownership, disclaimers and limitations of liability) will remain in effect.

## 14. Changes to Terms

We may update these Terms from time to time. We will notify you of material changes by updating the "Last updated" date. Continued use of the Service after changes constitutes acceptance of the new Terms.

## 15. Governing Law

These Terms are governed by the laws of the State of Delaware, United States, without regard to conflict of law principles. Any disputes shall be resolved in the courts of Delaware.

## 16. Contact

For questions about these Terms, contact us at [legal@metain.dev](mailto:legal@metain.dev)


# LuauCeption
Running Luau inside Luau. Inspired by [@Rerumu's LuauInLuau](https://gist.github.com/Rerumu/ecaf1de2f2b31d0fa91b9bac8e1e15d8).

## Notes
- There's existing work on getting analysis to work (at the ``analysis`` branch), however it doesn't work (code aborts)

## Testing
LuauCeption uses [lune](https://github.com/lune-org/lune) (runtime) and [frktest](https://github.com/itsfrank/frktest) (library). See ``src/tests`` to view the tests stuff.

To run tests, ensure you've initialized submodules (as the frktest library is imported using submodules) and simply run the ``run.luau`` script with lune.

The old testing script (``Test.luau``) at ``utils/_helpers`` is still available, however it won't be used or updated for newer work.

# Development Setup
* Make sure to install [Rokit](https://github.com/rojo-rbx/rokit) and [emscripten](https://emscripten.org) >5.0.2
* Also install [Wasynth](https://github.com/Rerumu/Wasynth) from compiled releases and put in `./utils` directory

## Special thanks
- [@Rerumu](https://github.com/Rerumu) - a LOT of troubleshooting
- Tryptamine (@Lemonchat) - C exception handling
- gamerer123 (@Lemonchat) - pointing out a oversight in the V3 implementation (that broke number precision)


### ⚠ This library is in early stages of development with breaking changes being made often.

ECR is a Luau ECS library.

- A library and not a framework
- Uses typechecking.
- Sparse-set based storage that can support perfect SoA.
- Carefully optimized memory usage and performance.
- Signals for detecting changes to components.

## Getting started

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

## Code sample

```lua
local ecr = require(ecr)

-- define components
local Position = ecr.component() :: Vector3
local Velocity = ecr.component() :: Vector3

-- define a system
local function update_physics(world: ecr.Registry, dt: number)
    for id, pos, vel in world:view(Position, Velocity) do
        world:set(id, Position, pos + vel*dt)
    end
end

-- instantiate the world
local world = ecr.registry()

-- create entities and assign components
for i = 1, 10 do
    local id = world:create()
    world:set(id, Position, Vector3.new(i, 1, 1))
    world:set(id, Velocity, Vector3.new(10, 0, 0))
end

-- run system
update_physics(world, 1/60)


# Crash Course

ECR is a sparse-set based ECS library heavily inspired by [EnTT](https://github.com/skypjack/entt).

This is a brief introduction on how to use the library and some of the concepts involved with it.

## Registry

The registry, or often called a _world_ , is a container for entities and their components.

lua

    local registry = ecr.registry()

## Entities

An entity represents an object in the world is referenced using a unique id.

lua

    local id: ecr.entity = registry:create()
    registry:contains(id) -- true

    registry:destroy(id)
    registry:contains(id) -- false

Entities can be freely created and destroyed.

## Components

A component is data that can be added to entities.

There is the _component type_ , which represents a type of data, and there is the _component value_ , which is a value for a type added to an entity.

Component types are created by `ecr.component()`, which returns an id representing that type. This can be typecasted to the type of value it represents.

lua

    local Name = ecr.component() :: string
    local Health = ecr.component() :: number

Entities can have any amount of components added to or removed from them, whenever. They behave like tables, where they can have any amount of key-value pairs, where the component type is the key, and the component value is the value. Entities initially have no components when created, and will have all its components removed when destroyed.

lua

    registry:set(id, Health, 100) -- adds a new component with a value of 100
    registry:get(id, Health) -- 100

    registry:remove(id, Health) -- removes the component
    registry:has(id, Health) -- false

Component values cannot be `nil`, components should be removed instead.

## Views

A view allows you to look into the registry and get all entities that have the specified component types.

lua

    registry:view(Health)

    registry:view(Position, Velocity)

To get all entities in a view you iterate over it.

lua

    for id, position, velocity in registry:view(Position, Velocity) do
        print(id, position, velocity)
    end

You can add or remove components and create or destroy entities during iteration.

Components added or entities created during iteration will not be returned during that iteration.

You can also exclude component types from views. Any entities that have an excluded type will not be included in the view.

lua

    local view = registry:view(A, B):exclude(C)

Views are cheap to create and do not store their own state, so they do not need to be stored aside, and can be created on the fly as needed.

## Signals

The registry contains three different signals for when a component type is added, changed or removed for any entity.

lua

    registry:on_add(type):connect(listener)
    registry:on_change(type):connect(listener)
    registry:on_remove(type):connect(listener)

All three listeners are called with:

  1. The entity whose component is being changed.
  2. The new component value (always `nil` in the case of `on_remove`).

`on_add` is fired _after_ the component is added.

`on_change` and `on_remove` is fired _before_ the component is changed or removed, so you can still retrieve the old value if needed.

You cannot modify the registry within a listener, they should only be used to help track entities or clean up values.

## Observers

An observer is similar to a view, except it only returns entities whose components have been added or changed and still have those components at the time of iteration.

An observer can be created using `Registry:track()`.

lua

    local observer = registry:track(Position, Model)

    return function()
        for entity, position, model in observer do
            print("changed: ", position, model)
        end
    end

After iterating, the observer automatically clears so that only fresh changes are iterated.

Observers provide a concise way to track and act on only specific entities that have changed since the last time a system ran.

Unlike a view, observers do store their own state, and must be stored aside to keep track over time.

## Example Usage

All component types are defined in a single file to keep things organised. All component types must also be defined before the registry using them is created.

cts.luau

lua

    local ecr = require(ecr)

    return ecr.name {
        Health = ecr.component() :: number,
        Poisoned = ecr.component() :: number

`ecr.name` can be used to associate names with components, for clearer error messages when debugging.

The library doesn't have any bult-in support for systems, the user is free to do this however they please.

Examples using plain functions:

deal_poison_damage.luaureduce_poison_timer.luaudestroy_dead.luau

lua

    local cts = require(cts)

    return function(world: ecr.Registry, dt: number)
        for id, health in world:view(cts.Health, cts.Poisoned) do
            world:set(id, health, health - 10 * dt)
        end
    end

lua

    local cts = require(cts)

    return function(world: ecr.Registry, dt: number)
        for id, time in world:view(cts.Poisoned) do
            local new_time = time - dt

            if new_time <= 0 then
                world:remove(id, cts.Poisoned)
            else
                world:set(id, cts.Poisoned, new_time)
            end
        end
    end

lua

    local cts = require(cts)

    return function(world: ecr.Registry)
        for id, health in world:view(cts.Health) do
            if health <= 0 then
                world:destroy(id)
            end
        end
    end

main.luau

lua

    local ecr = require(ecr)
    local cts = require(cts)

    local function loop(systems: {(ecr.Registry, number) -> ()}, world: ecr.Registry, dt: number)
        for _, system in systems do
            system(world, dt)
        end
    end

    local systems = {
        require(deal_poison_damage),
        require(reduce_poison_timer),
        require(destroy_dead)

    local world = ecr.registry()

    for i = 1, 10 do
        local id = world:create()
        world:set(id, cts.Health, 100)
        world:set(id, cts.Poisoned, math.random(3, 5)) -- poison randomly for 3-5 seconds
    end

    while true do
        loop(systems, world, 1/60)
    end

## End

At this point, the main concepts and features of ECR have been covered. You can read other guides on more advanced usage or view the API for more details.


# ECR

## Functions

### registry()

Creates a new registry.

  * **Type**

lua

        function ecr.registry(): Registry

### component()

Creates a new component type.

  * **Type**

lua

        function ecr.component(): unknown
        function ecr.component<T>(constructor: () -> T): T

  * **Details**

Returns a unique id representing a new component type.

Can be given a constructor which can be invoked when [`registry:add()`](https://centau.github.io/ecr/api/Registry.html#add.md) or [`registry:patch()`](https://centau.github.io/ecr/api/Registry.html#patch.md) is used.

  * **Example**

No constructor.

lua

        local Position = ecr.component() :: Vector3
        local Health = ecr.component() :: number

With constructor.

lua

        local Position = ecr.component(Vector3.new)

        local Health = ecr.component(function()
            return {
                Current = 100,
                Max = 100
        end)

### tag()

Creates a new tag component type.

  * **Type**

lua

        function ecr.tag(): nil

  * **Details**

Returns a unique id representing a new component type.

Tag components are a special type of component that have no value.

### is_tag()

Checks if a component type is a tag.

  * **Type**

lua

        function ecr.is_tag<T>(ctype: T): boolean

### queue()

Creates a new queue.

  * **Type**

lua

        function ecr.queue(): Queue<...unknown>
        function ecr.queue<T...>(signal: ISignal<T...>) -> Queue<T...>

        type ISignal<T...> =
            { connect: (ISignal, (T...) -> ()) -> () } |
            { Connect: (ISignal, (T...) -> ()) -> () }

  * **Details**

Can accept any signal object that matches the interface to automatically connect a callback where any arguments it is called with are added to the queue.

### name()

Associates names with components for debugging.

  * **Type**

lua

        function ecr.name<T>(names: T & Map<string, unknown>) -> T

  * **Details**

Allows for errors raised to display the component name instead of its argument position.

### buffer_to_array()

Converts a buffer of entities into an array of entities.

  * **Type**

lua

        function ecr.buffer_to_array(buf: buffer, size: number, arr: Array<entity>?) -> Array<entity>

  * **Details**

Copies the first `size` ids from the buffer to a target array.

If no target array is given, one will be created.

### array_to_buffer()

Converts an array of entities into a buffer of entities.

  * **Type**

lua

        function ecr.buffer_to_array(arr: Array<entity>, size: number, buf: buffer?) -> buffer

  * **Details**

Copies the first `size` ids from an array to a target buffer.

If no target buffer is given, one will be created.

## Constants

### entity

Special component type that represents entities in a registry.

  * **Type**

lua

        ecr.entity: entity

### context

The context entity id.

  * **Type**

lua

        ecr.context: entity

### null

The null entity id.

  * **Type**

lua

        ecr.null: entity

  * **Details**

Attempting to use this entity with a registry will error.

The following expression will always return `false`:

lua

        registry:contains(ecr.null)

### id_size

The size of the entity id in bytes.

  * **Type**

lua

        ecr.id_size: number


# Entity Type

Entities are represented by a special component type, `ecr.entity`.

This can be used in the same way as custom components types, except instead of representing components, represents entities themselves.

This type cannot be used to modify the registry, methods like `add()`, `set()`, `remove()` do not work with this type.

## Get all entities

You can get all entities that currently exist in the registry with:

lua

    for id in registry:view(ecr.entity) do
        print(id)
    end

    -- or

    local entities = registry:storage(ecr.entity).entities

## Exclude-only views

You can get all entities without certain components with:

lua

    for entity in registry:view(ecr.entity):exclude(...) do end

## Listeners

You can listen to when an entity is created with:

lua

    registry:on_add(ecr.entity):connect(function)

And when an entity is destroyed with:

lua

    registry:on_remove(ecr.entity):connect(function)


# Context

All registries have a special entity, that uses a reserved id `ecr.context`, called the _context entity_.

Often you will need to store data about the world that isn't specific to an entity, data such as a round counter, in-game timer, etc.

The context entity can be used to store data like this; the world's context.

This entity does not exist by default, it is automatically created the first time [`Registry:context()`](https://centau.github.io/ecr/api/Registry.html#context) is called, subsequent calls return the same entity.

lua

    local Round = ecr.component() :: number

    registry:context():set(Round, 1)

    -- or, if you prefer

    registry:set(ecr.context, Round, 1)

This entity can still be destroyed (and later recreated), and is affected by [`Registry:clear()`](https://centau.github.io/ecr/api/Registry.html#clear).


# Groups

Groups are a technique used to optimize iteration over a set of component types. Groups achieve perfect [SoA](https://en.wikipedia.org/wiki/AoS_and_SoA) for the best iteration performance at the cost of more expensive addition and removal of group-owned components.

## Creation

Groups can be created as followed:

lua

    registry:group(A, B, C)

This creates a new group with components `A`, `B` and `C`. These 3 components are now said to be _owned_ by the group.

Each component type can only be owned by a single group. The following code would result in an error:

lua

    registry:group(A, B)
    registry:group(B, D)

This errors because 2 different groups cannot claim ownership of `B`.

Groups do not have to be stored aside when they are created, the first time a group is created it is stored permanently inside the registry, future `registry:group()` calls will just return the same group for the same set of components.

Once a group is created, it will ensure that its owned components are aligned with each other in memory whenever a component is added or removed from an entity.

## Usage

A group is iterated in the same way as a view.

lua

    for id, position, velocity in registry:group(Position, Velocity) do
        registry:set(id, Position, position + velocity*dt)
    end

Components can be added, changed and removed during iteration.

The exact size of a group can also be read:

lua

    local size = #registry:group(A, B)

## Limitations

  * As mentioned before, each component type can only be owned by one group, groups cannot share components so you need to profile to determine where the most benefit is gained.

  * In a rare case, causing an entity to join a group during iteration of a view with a group-owned component, will invalidate the view iterator.

This is due to how groups organise their components in memory. This can be avoided if you:

    1. queue the entities to add components later, instead of during iteration.
    2. know that adding those group-owned components will not cause the entity to enter the group.

Views can detect and will error if the above rules are broken so you do not need to worry about it until it happens.

## When to group

While views are fast, in certain situations like where a view contains many components, iteration of a view may be the bottleneck of a system. In such cases, by grouping components together, iteration becomes as fast as possible, removing the bottleneck.

You should only use grouping when you have profiled and identified that the iteration of a view is a system bottleneck.


# Storage

Each component type in the registry has its own [pool](https://centau.github.io/ecr/api/Pool.html). A pool stores every entity that has that component type, and their corresponding value for that component type. Pools are the underlying containers the registry directly modifies.

ECR was designed with transparent access to data in mind, and so, you can access these pools directly if needed.

lua

    type Pool<T> = {
        -- amount of entities in the pool (so amount that have the component type)
        size: number,

        -- buffer (used as an array) of all entities in the pool
        entities: buffer,

        -- array of all component values (value for entities[i] is values[i])
        values: Array<T>

A pool for a type is retrieved like so:

lua

    local pool = registry:storage(ctype)

You can read from pools, but you cannot write to pools, with the exception of writing to values of `Pool.values`. The registry maintains the size and values of `Pool.entities`, so those should not be changed.

Buffers aren't nice to work with, so you can use [`ecr.buffer_to_array()`](https://centau.github.io/ecr/api/ecr.html#buffer_to_array) to access entities easier.

lua

    local entities = ecr.buffer_to_array(pool.entities, pool.size)

This can be useful for e.g:

  * Getting all entities and components to replicate a registry from server to client for the first time they join.

  * Modifying values directly for performance in systems acting on many entities.

lua

        local Position = ecr.component(Vector3.new)
        local Velocity = ecr.component(Vector3.new)

        local function update_positions(dt: number)
            -- groups sort their pools so that all entities in all of the group's
            -- pools are sorted in the same order from 1 up to the group's size
            -- this makes positions[i] correspond to velocities[i] (perfect SoA)
            local n = #registry:group(Position, Velocity)
            local positions = registry:storage(Position).values
            local velocities = registry:storage(Velocity).values

            for i = 1, n do
                positions[i] += velocities[i] * dt
            end

If needed you can also get all pools inside the registry via an iterator.

lua

    for ctype, pool in registry:storage() do


# Tags

Tags are special component types that store no value.

A tag can be created with:

lua

    local Tag = ecr.tag()

Tags types are used in the same way as any other component type. They are useful for marking entities in some state, and are more efficient than something like `ecr.component() :: true`.

Example usage:

lua

    local Selected = ecr.tag()

    registry:add(id, Selected)
    registry:has(id, Selected) -- true

    registry:remove(id, Selected)
    registry:has(id, Selected) -- false

lua

    local TargetPosition = ecr.component() :: Vector3

    local function move_selected(position: Vector3)
        for id in world:view(Selected) do
            world:set(id, TargetPosition, position)
        end
    end

To check if an entity has a tag, favor `Registry:has()` over `Registry:get()`, since tags have no value and will return `nil`.

You can check if a component type is a tag type or not with `ecr.is_tag(ctype)`.


# Registry

Container for entities and components.

lua

    type ecr.Registry

## Methods

WARNING

There are certain [restrictions](https://centau.github.io/ecr/api/restrictions.html) with what you can do with the registry that you should be aware of.

### create()

Creates a new entity and returns the entity id.

  * **Type**

lua

        function Registry:create(): entity
        function Registry:create(id: entity): entity

        type entity = ecr.entity

  * **Details**

An entity can be created using a specific id that was created by another registry or previously by the same registry.

A previously used but now unused id may be reused every `32,000` creations.

WARNING

Be wary of storing ids of destroyed entities for long periods of time or they may eventually refer to a newly created entity.

WARNING

The total amount of entities in a registry at any given time _cannot_ exceed `65,535`. Attempting to exceed this limit will throw an error.

### destroy()

Removes the entity from the registry and removes all of its components.

  * **Type**

lua

        function Registry:destroy(id: entity)

### contains()

Checks if the given entity exists in the registry.

  * **Type**

lua

        function Registry:contains(id: entity): boolean

### add()

Adds all given components to an entity.

  * **Type**

lua

        function Registry:add<T...>(id: entity, components: T...)

  * **Details**

Adds the given components to the entity by using each component constructor or no value at all if the component is a tag type.

Adding a component to an entity that already has the component will do nothing.

### set()

Adds or changes an entity's component.

  * **Type**

lua

        function Registry:set<T>(id: entity, component: T, value: T)

  * **Details**

Adds the component to the entity with the given value if the entity does not already have the component.

Changes the component value for the given entity if the entity already has the component.

### patch()

Updates an entity's component.

  * **Type**

lua

        function Registry:patch<T>(id: entity, component: T, patcher: (T) -> T)

  * **Details**

Takes a callback which is given the current component value as the only argument. The value returned by the callback is then set as the new value.

If there is a constructor defined for the given component and the entity does not have the component, the constructor will be called and the returned value passed into the callback.

  * **Example**

lua

        registry:patch(entity, Health, function(health)
            return health - 10
        end)

### has()

Checks if an entity has all of the given components.

  * **Type**

lua

        function Registry:has<T...>(id: entity, components: T...): boolean

  * **Details**

Will return `true` only if the entity has _every_ component given.

### get()

Gets an entity's component values.

  * **Type**

lua

        function Registry:get<T...>(id: entity, components: T...): T...

  * **Details**

Will error if the entity does not have a component.

### try_get()

Gets an entity's component value.

  * **Type**

lua

        function Registry:try_get<T>(id: entity, components: T): T?

  * **Details**

Will return `nil` if the entity does not have a component.

### remove()

Removes the given components from an entity.

  * **Type**

lua

        function Registry:remove<T...>(id: entity, components: T...)

  * **Details**

Will do nothing if the entity does not have a component.

### clear()

Removes all entities and components from the registry.

  * **Type**

lua

        function Registry:clear<T...>(components: T...)

  * **Details**

If components are given, removes all given components from all entities without destroying the entities.

If no components are given, then all entities in the registry will be destroyed.

### view()

Creates a [`view`](https://centau.github.io/ecr/api/View.html) with the given component types.

  * **Type**

lua

        function Registry:view<T...>(components: T...): View<T...>

### track()

Creates an [`observer`](https://centau.github.io/ecr/api/Observer.html) with the given component types.

  * **Type**

lua

        function Registry:track<T...>(...: T...): Observer<T...>

### group()

Creates a [`group`](https://centau.github.io/ecr/api/Group.html) with the given component types.

  * **Type**

lua

        function Registry:group<T...>(...: T...): Group<T...>

  * **Details**

Rearranges the internal storage of components for better iteration performance when iterated together.

Groups must be mutually exclusive, i.e. each component type can only belong to a single group.

WARNING

This method introduces [restrictions](https://centau.github.io/ecr/tuts/groups.html#limitations) on adding components during views.

### on_add()

Returns a [signal](https://centau.github.io/ecr/api/Signal.html) which is fired whenever the given component type is added to an entity.

  * **Type**

lua

        function Registry:on_add<T>(component: T): Signal<entity, T>

The signal is fired _after_ the component is changed.

The listener is called with the entity and new component value.

WARNING

The registry cannot be modified within a listener.

### on_change()

Returns a [signal](https://centau.github.io/ecr/api/Signal.html) which is fired whenever the given component type is changed for an entity.

  * **Type**

lua

        function Registry:on_change<T>(component: T): Signal<entity, T>

The signal is fired _before_ the component is changed.

The listener is called with the entity and new component value.

WARNING

The registry cannot be modified within a listener.

### on_remove()

Returns a [signal](https://centau.github.io/ecr/api/Signal.html) which is fired whenever the given component is removed from an entity.

  * **Type**

lua

        function Registry:on_remove<T>(component: T): Signal<entity, nil>

  * **Details**

The signal is fired _before_ the component is removed.

The listener is called with the entity.

WARNING

The registry cannot be modified within a listener.

### handle()

Returns a [handle](https://centau.github.io/ecr/api/Handle.html) to an entity.

  * **Type**

lua

        function Registry:handle(id: entity?): Handle

  * **Details**

If no entity is given then a new one is created.

Handles are cached so that `registry:handle(id) == registry:handle(id)` is always true.

### context()

Returns a [handle](https://centau.github.io/ecr/api/Handle.html) to the context entity.

  * **Type**

lua

        function Registry:context(): Handle

  * **Details**

Will automatically create the context entity if it does not already exist.

### storage()

Returns the [pool](https://centau.github.io/ecr/api/Pool.html) for a given component type.

  * **Type**

lua

        function Registry:storage<T>(component: T): Pool<T>
        function Registry:storage(): () -> (unknown, Pool<unknown>)

  * **Details**

If called with no arguments, returns an iterator to get all component types and their corresponding pool in the registry.

### has_none()

Checks if the given entity has no components.

  * **Type**

lua

        function Registry:has_none(id: entity): boolean

### release()

Removes the entity from the registry.

  * **Type**

lua

        function Registry:release(id: entity)

  * **Details**

DANGER

This method does not remove any of the entity's components. Using this method on an entity that still has components is _undefined behavior_.


# Handle

Thin wrapper around an entity and its registry.

lua

    type ecr.Handle

## Properties

### registry

The registry the entity belongs to.

  * **Type**

lua

        Handle.registry: Registry

### entity

The entity the handle refers to.

  * **Type**

lua

        Handle.entity: entity

## Methods

The `Handle` class wraps the following registry methods:

  * destroy()
  * has_none()
  * add()
  * set()
  * patch()
  * has()
  * get()
  * try_get()
  * remove()

The `set()` method will also return the handle it is called on.

  * **Example**

lua

        local e = registry:handle()

        e:set(A, 1)
         :set(B, 2)

        print(e:get(A, B)) --> 1, 2


# Queue

Queues values to be processed later.

lua

    type ecr.Queue<T...>

## Methods

### add()

Adds a set of values to a queue.

  * **Type**

lua

        function Queue:add<T...>(...: T...)

  * **Details**

Each time this method is called, the size of the queue increases by one.

All arguments given are later returned together in the same iteration.

Queues are FIFO.

WARNING

The first value in the argument list cannot be `nil` since that will cause iteration to stop early.

### clear()

Clears the queue.

  * **Type**

lua

        function Queue:clear<T...>()

## Iteration

Iterates all values added to the queue.

  * **Type**

lua

        for ...: T... in Queue<T...> do

  * **Details**

The queue returns in sets of values passed to `Queue:add()` in the same order it was called in.

The queue automatically clears itself after iteration.

WARNING

Adding values during iteration will cause them to be cleared when iteration completes and they will never be iterated.


# Restrictions

The API omits sanity checks in areas that would be costly to do so, allowing you to run into problems like iterator invalidation and undefined behavior. This means that there are certain restrictions on what you can do. All restrictions are documented here and at the relevant API references.

## Signals

  * Listeners cannot disconnect other listeners. Listeners can disconnect themselves.

  * The registry cannot be modified within a listener, you cannot add or remove components, and create or destroy entities.

## Modifying During Iteration

This applies to the iteration of views, observers and groups.

  * During iteration, adding or removing components from entities not currently being iterated can _invalidate the iterator_.

## Pools

[`storage()`](https://centau.github.io/ecr/api/Registry.html#storage.md) returns the underlying storages used by the registry to store entities and components. You can use these for more direct access than views and also modify the values of `Pool.values` directly.

  * Changing `Pool.entities` or `Pool.size` is _undefined behavior_.

## Releasing Ids

  * Destroying an entity that still has components with [`release()`](https://centau.github.io/ecr/api/Registry.html#release.md) is _undefined behavior_.

## Multithreading

  * Components can be added or removed during iteration as long as it is the only thread doing so for that set of components.

This does not apply if a component in that set belongs to a group that has other group components being used in another thread, e.g One thread can add/remove component `X` and another thread can add/remove `Y` and `Z` as long as `X` is not grouped with `Y` or `Z`.

  * The same set of components can be iterated by multiple threads at the same time if they are reading only.


# Signal

Manage listeners to an event.

lua

    type ecr.Signal<T...>

## Methods

### connect()

Connects a given function to the signal to be called whenever the signal is fired.

  * **Type**

lua

        function Signal:connect<T...>((T...) -> ()): Connection

  * **Details**

New connections made within a listener will not be ran until the next time the signal is fired.

## Connection

lua

    type ecr.Connection<T...>

### disconnect()

Disconnects a listener from a signal.

  * **Type**

lua

        function Connection:disconnect()

  * **Details**

WARNING

Disconnecting other listeners from within a listener is not allowed. Disconnecting a listenener from within itself is allowed.

### Reconnect()

Reconnects a listener to a signal.

  * **Type**

lua

        function Connection:reconnect()


# Pool

The container used by the registry internally to store entities and component values for each component type.

## Properties

### size

The amount of entities contained in the pool.

  * **Type**

lua

        Pool.size: number

### entities

A buffer of all entities with the given component type.

  * **Type**

lua

        Pool.entities: buffer

  * **Details**

0-indexed.

Sorted in the same order as [`Pool.values`](https://centau.github.io/ecr/api/Pool.html#values).

    * i.e. `entities[n]`'s component value is located at `values[n + 1]`.

### values

An array of all values for the given component type.

  * **Type**

lua

        Pool.values: Array<T>

  * **Details**

1-indexed.

Sorted in the same order as [`Pool.entities`](https://centau.github.io/ecr/api/Pool.html#entities.md).