Skip to main content

Dex

WARNING

Dex is still a work in progress and does not currently have a full release! Please avoiding Dex in production-bound projects, as the library is not fully tested, and the API may be subject to change

The Dex library contains a collection of objects for creating reactive UI components

For more information, see the Usage Guide

Properties

Clock

Dex.Clock: Observable<number>

Observable number that derives its value from the current time in seconds in UTC (i.e. the value returned by os.time())

While subscribed, Dex.Clock automatically updates its value whenever the value of os.time() changes.

Nil

Dex.Nil: Symbol<"Nil">

Symbol that represents a "Nil" value. Because "nil" values can't be represented as values of a Luau table, Dex.Nil can be used in its place. Example usage:

return Dex.Premade("BillboardGui", {
    -- Sets the Adornee property of the premade UI to "Nil" on mount
    Adornee = Dex.Nil,
})

Functions

IsVirtualInstance

Dex.IsVirtualInstance(passedInunknown) → boolean

This function checks if the passed in value is a Dex VirtualInstance

IsState

Dex.IsState(passedInunknown) → boolean

This function checks if the passed in value is a State observable object

GetVirtualInstanceType

Dex.GetVirtualInstanceType(passedInVirtualInstance) → "New" | "Clone" | "Premade"

This function returns the constructor type for VirtualInstance ("New", "Clone", or "Premade"). Errors if the passed in value is not a VirtualInstance.

IsObservable

Dex.IsObservable(passedInunknown) → boolean

This function checks if the passed in value is an Observable.

IsStateRecord

Dex.IsStateRecord(passedInunknown) → boolean

This function checks if the passed in value is a [StateRecord] observable object

Root

Dex.Root(hostInstanceInstance) → Root

Creates a new Root instance. The Root is a reference to a real Roblox Instance and is used to reconcile Virtual Instances.

FlattenObservable

Dex.FlattenObservable(observableObservable<any>) → Observable<any>

If an Observable's current value can be another Observable object, flattens the final resolved value of the last returned Observable in the chain, and automatically subscribes to any observables returned in the chain.

Example:

local coins = Dex.State(Dex.State(3))
local coinsFlattened = Dex.FlattenObservable(coins)
print(coinsFlattened:Current()) -- 3

coins:Set(Dex.State(5))
print(coinsFlattened:Current()) -- 5

coins:Current():Set(7)
print(coinsFlattened:Current()) -- 7

Map

Dex.Map(...Observable<...T>) → ((map...T) → ReturnType) → Observable<ReturnType>

Returns a curryable mapping function, which in turn returns a derived observable from the dependent observables passed in.

Example:

local x = Dex.State(2)
local y = Dex.State(3)

local sum = Dex.Map(x, y)(function(currentX, currentY)
    return currentX + currentY
end)

print(sum:Current()) -- 5

For Observables where the values are a vector or scalar type, math operations can be used as an alias for Dex.Map!

Example:

local x = Dex.State(2)
local y = Dex.State(3)
local sum = x + y

print(sum:Current()) -- 5

CoerceAsObservable

Dex.CoerceAsObservable(valueCanBeObservable<T>) → Observable<T>

This function coerces the passed in value to an Observable. Useful for unwrapped the CanBeObservable type in a component's props.

Spring

Dex.Spring(
targetObservable<T>,
angularFrequencynumber?
) → Spring<T>

Creates an easing observable that simulates the behavior of a critically damped spring. The spring simulates in realtime until the target value is reached.

CAUTION

Spring must have at least one Subscriber (or be mounted on at least one VirtualInstance) to simulate in realtime!

Tween

Dex.Tween(initialValueT | Observable<TweenParams<T>>) → Tween<T>

Creates a new Tween Observable object with the given initial value.

Dict

Dex.Dict(initialValue:{[K]V}) → Dict<K,V>

Creates a new Dict state observable with the given initial value.

Stopwatch

Dex.Stopwatch(propsStopwatchProps?) → Stopwatch

Creates a new Stopwatch Observable, which simulates in realtime while subscribed.

Props:

duration is an optional prop that specifies the end time of the stopwatch. Defaults to math.huge.

isPlaying specifies that stopwatch should play and stop depending on an observable boolean value. If set to true, the stopwatch will immediately start playing.

playOnChange specifies that the stopwatch should restart whenever an input observable changes.

Eased

Dex.Eased(
targetObservable<T>,
infoTweenInfo
) → Eased<T>

Creates an eased Observable that tweens its value in realtime every time the input Observable changes its value, based on the TweenInfo provided.

CAUTION

Eased must have at least one Subscriber (or be mounted on at least one VirtualInstance) to simulate in realtime!

State

Dex.State(initialValueT) → State<T>

Creates a new State Observable object with the given initial value.

IntSpring

Dex.IntSpring(
targetObservable<T>,
angularFrequencynumber
) → IntSpring<T>

Creates an easing observable that simulates the behavior of a critically damped spring, constrained to the Integer range. Rounds the current position towards the target value, which is useful for UI components like currency or ammo counters.

CAUTION

Springs must have at least one Subscriber (or be mounted on at least one VirtualInstance) to simulate in realtime!

CustomObservable

Dex.CustomObservable(
getCurrent() → T,
createUpdateStream(notifyChange() → ()) → (() → ())
) → Observable<T>
WARNING

Consider opting for other Dex constructs (like State) over custom observables.

When writing custom Dex observables, Make sure to implement the getCurrent and createUpdateStream parameters correctly, as failing to do so may cause memory leaks or unresponsive UI.

Creates a new Dex Observable object. Observables are used to hold, derive, or map state within a Dex application.

The first parameter should be a function that always returns the current state of the observable whenever called.

For example, to observe the value of workspace.CurrentCamera.ViewportSize:

local function getCurrent()
    return workspace.CurrentCamera.ViewportSize
end

The second parameter is a callback which sets up any event handling required to notify whenever the current state changes, and returns a "cleanup" function to close the event handling.

For example, to observe the value of workspace.CurrentCamera.ViewportSize:

local function createUpdateStream(notifyChange: () -> ())
    -- Start tracking changes to ViewportSize, and
    -- forward these to the `notifyChange` callback
    local connection = workspace.CurrentCamera
        :GetPropertyChangedSignal("ViewportSize")
        :Connect(notifyChange)

    -- Return a function which closes the update stream,
    -- cleaning up our connection.
    return function()
        connection:Disconnect()
    end
end

createUpdateStream is automatically called by Dex the first time an observable is subscribed (or used by a mounted VirtualInstance), and its return function to close the update stream is automatically called when the Observable's last subscriber is unsubscribed and/or the last VirtualInstance utilizing it is unmounted.

Putting it all together, we can create a custom observable which tracks the ViewportSize of the player's camera:

local function getCurrent()
    return workspace.CurrentCamera.ViewportSize
end
local function createUpdateStream(notifyChange: () -> ())
    local connection = workspace.CurrentCamera
        :GetPropertyChangedSignal("ViewportSize")
        :Connect(notifyChange)
    
    -- closeUpdateStream:
    return function()
        connection:Disconnect()
    end
end
local playerViewportSize = Dex.CustomObservable(
    getCurrent,
    createUpdateStream
)
print(playerViewportSize:Current()) -- Output: 1920, 1080

Custom observables may be useful for connecting third party libraries or other systems in your game's codebase to a Dex UI application.

Timer

Dex.Timer(propsTimerProps) → Timer

Creates a new Timer Observable, which simulates in realtime while subscribed.

Props:

duration is a required prop that specifies the initial time of the timer.

isPlaying specifies that timer should play and stop depending on an observable boolean value. If set to true, the timer will immediately start playing.

playOnChange specifies that the timer should restart whenever an input observable changes.

AngleSpring

Dex.AngleSpring(
targetObservable<T>,
angularFrequencynumber?
) → AngleSpring<T>

Creates an easing observable that simulates the behavior of a critically damped spring, wrapped around the range [-pi, pi]. The spring simulates in realtime until the target value is reached.

CAUTION

AngleSpring must have at least one Subscriber (or be mounted on at least one VirtualInstance) to simulate in realtime!

New

Dex.New(
classNamestring,
props{[string]any}?,
children{[any]CanBeObservable<VirtualInstance?>}
) → VirtualInstance

Creates a new VirtualInstance that represents a newly-created Roblox Instance (via Instance.new(className)).

Clone

Dex.Clone(
templateInstance | VirtualInstance,
props{[string]any}?,
children{[any]CanBeObservable<VirtualInstance?>}
) → VirtualInstance

Creates a new VirtualInstance that represents a cloned Roblox Instance from a given template instance (via template:Clone()).

Premade

Dex.Premade(
classNamestring,
props{[string]any}?,
children{[any]CanBeObservable<VirtualInstance?>}
) → VirtualInstance

Creates a new VirtualInstance that represents a pre-existing Roblox Instance to be modified by Dex.

If passed into the the Render function for a Dex.Root component, the root instance will be used used.

ObserveFusionState

Dex.ObserveFusionState(
Fusionany,
fusionStateObjectFusion.StateObject<T>
) → Observable<T>

Interoperability function that maps a Fusion StateObject to a Dex Observable object. The returned observable is garbage collected once dereferenced and unsubscribed/unmounted.

The Fusion library must be provided, as Fusion StateObjects only work when embedded in a Fusion runtime.

Show raw api
{
    "functions": [
        {
            "name": "IsVirtualInstance",
            "desc": "This function checks if the passed in value is a Dex VirtualInstance",
            "params": [
                {
                    "name": "passedIn",
                    "desc": "",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 11,
                "path": "src/Reflection/IsVirtualInstance.luau"
            }
        },
        {
            "name": "IsState",
            "desc": "This function checks if the passed in value is a [State] observable object",
            "params": [
                {
                    "name": "passedIn",
                    "desc": "",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 11,
                "path": "src/Reflection/IsState.luau"
            }
        },
        {
            "name": "GetVirtualInstanceType",
            "desc": "This function returns the constructor type for VirtualInstance (\"New\",\n\"Clone\", or \"Premade\"). Errors if the passed in value is not a\nVirtualInstance.",
            "params": [
                {
                    "name": "passedIn",
                    "desc": "",
                    "lua_type": "VirtualInstance"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "\"New\" | \"Clone\" | \"Premade\""
                }
            ],
            "function_type": "static",
            "source": {
                "line": 16,
                "path": "src/Reflection/GetVirtualInstanceType.luau"
            }
        },
        {
            "name": "IsObservable",
            "desc": "This function checks if the passed in value is an Observable.",
            "params": [
                {
                    "name": "passedIn",
                    "desc": "",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 11,
                "path": "src/Reflection/IsObservable.luau"
            }
        },
        {
            "name": "IsStateRecord",
            "desc": "This function checks if the passed in value is a [StateRecord] observable\nobject",
            "params": [
                {
                    "name": "passedIn",
                    "desc": "",
                    "lua_type": "unknown"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "boolean"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 12,
                "path": "src/Reflection/IsStateRecord.luau"
            }
        },
        {
            "name": "Root",
            "desc": "Creates a new Root instance. The Root is a reference to a real Roblox\nInstance and is used to reconcile Virtual Instances.",
            "params": [
                {
                    "name": "hostInstance",
                    "desc": "",
                    "lua_type": "Instance"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Root"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 110,
                "path": "src/Reconciler/Root.luau"
            }
        },
        {
            "name": "FlattenObservable",
            "desc": "If an Observable's current value can be another Observable object, flattens\nthe final resolved value of the last returned Observable in the chain,\nand automatically subscribes to any observables returned in the chain.\n\nExample:\n```lua\nlocal coins = Dex.State(Dex.State(3))\nlocal coinsFlattened = Dex.FlattenObservable(coins)\nprint(coinsFlattened:Current()) -- 3\n\ncoins:Set(Dex.State(5))\nprint(coinsFlattened:Current()) -- 5\n\ncoins:Current():Set(7)\nprint(coinsFlattened:Current()) -- 7\n```",
            "params": [
                {
                    "name": "observable",
                    "desc": "",
                    "lua_type": "Observable<any>"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<any>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 30,
                "path": "src/Util/FlattenObservable.luau"
            }
        },
        {
            "name": "Map",
            "desc": "Returns a curryable mapping function, which in turn returns a derived\nobservable from the dependent observables passed in.\n\nExample:\n```lua\nlocal x = Dex.State(2)\nlocal y = Dex.State(3)\n\nlocal sum = Dex.Map(x, y)(function(currentX, currentY)\n    return currentX + currentY\nend)\n\nprint(sum:Current()) -- 5\n```\n\nFor Observables where the values are a vector or scalar type, math\noperations can be used as an alias for `Dex.Map`!\n\nExample:\n```lua\nlocal x = Dex.State(2)\nlocal y = Dex.State(3)\nlocal sum = x + y\n\nprint(sum:Current()) -- 5\n```",
            "params": [
                {
                    "name": "...",
                    "desc": "",
                    "lua_type": "Observable<...T>"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "((map: ...T) -> ReturnType) -> Observable<ReturnType>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 68,
                "path": "src/Util/MapObservable.luau"
            }
        },
        {
            "name": "CoerceAsObservable",
            "desc": "This function coerces the passed in value to an Observable. Useful for\nunwrapped the CanBeObservable<T> type in a component's props.",
            "params": [
                {
                    "name": "value",
                    "desc": "",
                    "lua_type": "CanBeObservable<T>"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 23,
                "path": "src/Util/CoerceAsObservable.luau"
            }
        },
        {
            "name": "Spring",
            "desc": "Creates an easing observable that simulates the behavior of a critically\ndamped spring. The spring simulates in realtime until the target value is\nreached.\n\n:::caution\nSpring must have at least one Subscriber (or be mounted on at least one\nVirtualInstance) to simulate in realtime!\n:::",
            "params": [
                {
                    "name": "target",
                    "desc": "",
                    "lua_type": "Observable<T>"
                },
                {
                    "name": "angularFrequency",
                    "desc": "",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Spring<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 188,
                "path": "src/Observables/Spring.luau"
            }
        },
        {
            "name": "Tween",
            "desc": "Creates a new [Tween] Observable object with the given initial value.",
            "params": [
                {
                    "name": "initialValue",
                    "desc": "",
                    "lua_type": "T | Observable<TweenParams<T>>"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Tween<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 196,
                "path": "src/Observables/Tween.luau"
            }
        },
        {
            "name": "Dict",
            "desc": "Creates a new Dict state observable with the given initial value.",
            "params": [
                {
                    "name": "initialValue:",
                    "desc": "",
                    "lua_type": "{[K]: V}"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Dict<K, V>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 350,
                "path": "src/Observables/StateRecord.luau"
            }
        },
        {
            "name": "Stopwatch",
            "desc": "Creates a new [Stopwatch] Observable, which simulates in realtime while\nsubscribed.\n\n#### Props:\n\n`duration` is an optional prop that specifies the end time of the stopwatch.\nDefaults to `math.huge`.\n\n`isPlaying` specifies that stopwatch should play and stop depending on an\nobservable boolean value. If set to `true`, the stopwatch will immediately\nstart playing.\n\n`playOnChange` specifies that the stopwatch should restart whenever an input\nobservable changes.",
            "params": [
                {
                    "name": "props",
                    "desc": "",
                    "lua_type": "StopwatchProps?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Stopwatch"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 192,
                "path": "src/Observables/Stopwatch.luau"
            }
        },
        {
            "name": "Eased",
            "desc": "Creates an eased Observable that tweens its value in realtime every time\nthe input Observable changes its value, based on the TweenInfo provided.\n\n:::caution\nEased must have at least one Subscriber (or be mounted on at least one\nVirtualInstance) to simulate in realtime!\n:::",
            "params": [
                {
                    "name": "target",
                    "desc": "",
                    "lua_type": "Observable<T>"
                },
                {
                    "name": "info",
                    "desc": "",
                    "lua_type": "TweenInfo"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Eased<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 90,
                "path": "src/Observables/Eased.luau"
            }
        },
        {
            "name": "State",
            "desc": "Creates a new [State] Observable object with the given initial value.",
            "params": [
                {
                    "name": "initialValue",
                    "desc": "",
                    "lua_type": "T"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "State<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 88,
                "path": "src/Observables/State.luau"
            }
        },
        {
            "name": "IntSpring",
            "desc": "Creates an easing observable that simulates the behavior of a critically\ndamped spring, constrained to the Integer range. Rounds the current position\ntowards the target value, which is useful for UI components like currency or\nammo counters. \n\n:::caution\nSprings must have at least one Subscriber (or be mounted on at least one\nVirtualInstance) to simulate in realtime!\n:::",
            "params": [
                {
                    "name": "target",
                    "desc": "",
                    "lua_type": "Observable<T>"
                },
                {
                    "name": "angularFrequency",
                    "desc": "",
                    "lua_type": "number"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "IntSpring<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 117,
                "path": "src/Observables/IntSpring.luau"
            }
        },
        {
            "name": "CustomObservable",
            "desc": ":::warning\nConsider opting for other Dex constructs (like State) over custom\nobservables.\n\nWhen writing custom Dex observables, Make sure to implement the `getCurrent`\nand `createUpdateStream` parameters correctly, as failing to do so may\ncause memory leaks or unresponsive UI.\n:::\n\nCreates a new Dex Observable object. Observables are used to hold, derive,\nor map state within a Dex application.\n\nThe first parameter should be a function that always returns the current\nstate of the observable whenever called.\n\nFor example, to observe the value of `workspace.CurrentCamera.ViewportSize`:\n```lua\nlocal function getCurrent()\n    return workspace.CurrentCamera.ViewportSize\nend\n```\n\nThe second parameter is a callback which sets up any event handling required\nto notify whenever the current state changes, and returns a \"cleanup\"\nfunction to close the event handling.\n\nFor example, to observe the value of `workspace.CurrentCamera.ViewportSize`:\n```lua\nlocal function createUpdateStream(notifyChange: () -> ())\n    -- Start tracking changes to ViewportSize, and\n    -- forward these to the `notifyChange` callback\n    local connection = workspace.CurrentCamera\n        :GetPropertyChangedSignal(\"ViewportSize\")\n        :Connect(notifyChange)\n\n    -- Return a function which closes the update stream,\n    -- cleaning up our connection.\n    return function()\n        connection:Disconnect()\n    end\nend\n```\n\n`createUpdateStream` is automatically called by Dex the first time an\nobservable is subscribed (or used by a mounted VirtualInstance), and its\nreturn function to close the update stream is automatically called when the\nObservable's last subscriber is unsubscribed and/or the last VirtualInstance\nutilizing it is unmounted.\n\nPutting it all together, we can create a custom observable which tracks the\nViewportSize of the player's camera:\n```lua\nlocal function getCurrent()\n    return workspace.CurrentCamera.ViewportSize\nend\nlocal function createUpdateStream(notifyChange: () -> ())\n    local connection = workspace.CurrentCamera\n        :GetPropertyChangedSignal(\"ViewportSize\")\n        :Connect(notifyChange)\n    \n    -- closeUpdateStream:\n    return function()\n        connection:Disconnect()\n    end\nend\nlocal playerViewportSize = Dex.CustomObservable(\n    getCurrent,\n    createUpdateStream\n)\nprint(playerViewportSize:Current()) -- Output: 1920, 1080\n```\n\nCustom observables may be useful for connecting third party libraries or\nother systems in your game's codebase to a Dex UI application.",
            "params": [
                {
                    "name": "getCurrent",
                    "desc": "",
                    "lua_type": "() -> T"
                },
                {
                    "name": "createUpdateStream",
                    "desc": "",
                    "lua_type": "(notifyChange: () -> ()) -> (() -> ())"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 310,
                "path": "src/Observables/Observable.luau"
            }
        },
        {
            "name": "Timer",
            "desc": "Creates a new [Timer] Observable, which simulates in realtime while\nsubscribed.\n\n#### Props:\n\n`duration` is a required prop that specifies the initial time of the timer.\n\n`isPlaying` specifies that timer should play and stop depending on an\nobservable boolean value. If set to `true`, the timer will immediately start\nplaying.\n\n`playOnChange` specifies that the timer should restart whenever an input\nobservable changes.",
            "params": [
                {
                    "name": "props",
                    "desc": "",
                    "lua_type": "TimerProps"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Timer"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 202,
                "path": "src/Observables/Timer.luau"
            }
        },
        {
            "name": "AngleSpring",
            "desc": "Creates an easing observable that simulates the behavior of a critically\ndamped spring, wrapped around the range [-pi, pi]. The spring simulates in\nrealtime until the target value is reached.\n\n:::caution\nAngleSpring must have at least one Subscriber (or be mounted on at least one\nVirtualInstance) to simulate in realtime!\n:::",
            "params": [
                {
                    "name": "target",
                    "desc": "",
                    "lua_type": "Observable<T>"
                },
                {
                    "name": "angularFrequency",
                    "desc": "",
                    "lua_type": "number?"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "AngleSpring<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 132,
                "path": "src/Observables/AngleSpring.luau"
            }
        },
        {
            "name": "New",
            "desc": "Creates a new [VirtualInstance] that represents a newly-created Roblox\nInstance (via `Instance.new(className)`).",
            "params": [
                {
                    "name": "className",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "props",
                    "desc": "",
                    "lua_type": "{[string]: any}?"
                },
                {
                    "name": "children",
                    "desc": "",
                    "lua_type": "{[any]: CanBeObservable<VirtualInstance?>}"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "VirtualInstance"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 22,
                "path": "src/VirtualInstanceCreators.luau"
            }
        },
        {
            "name": "Clone",
            "desc": "Creates a new [VirtualInstance] that represents a cloned Roblox Instance\nfrom a given template instance (via `template:Clone()`).",
            "params": [
                {
                    "name": "template",
                    "desc": "",
                    "lua_type": "Instance | VirtualInstance"
                },
                {
                    "name": "props",
                    "desc": "",
                    "lua_type": "{[string]: any}?"
                },
                {
                    "name": "children",
                    "desc": "",
                    "lua_type": "{[any]: CanBeObservable<VirtualInstance?>}"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "VirtualInstance"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 47,
                "path": "src/VirtualInstanceCreators.luau"
            }
        },
        {
            "name": "Premade",
            "desc": "Creates a new VirtualInstance that represents a pre-existing Roblox Instance\nto be modified by Dex.\n\nIf passed into the the Render function for a [Dex.Root] component, the root\ninstance will be used used.",
            "params": [
                {
                    "name": "className",
                    "desc": "",
                    "lua_type": "string"
                },
                {
                    "name": "props",
                    "desc": "",
                    "lua_type": "{[string]: any}?"
                },
                {
                    "name": "children",
                    "desc": "",
                    "lua_type": "{[any]: CanBeObservable<VirtualInstance?>}"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "VirtualInstance"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 75,
                "path": "src/VirtualInstanceCreators.luau"
            }
        },
        {
            "name": "ObserveFusionState",
            "desc": "Interoperability function that maps a Fusion StateObject to a Dex\nObservable object. The returned observable is garbage collected once\ndereferenced and unsubscribed/unmounted.\n\nThe Fusion library must be provided, as Fusion StateObjects only work when\nembedded in a Fusion runtime.",
            "params": [
                {
                    "name": "Fusion",
                    "desc": "",
                    "lua_type": "any"
                },
                {
                    "name": "fusionStateObject",
                    "desc": "",
                    "lua_type": "Fusion.StateObject<T>"
                }
            ],
            "returns": [
                {
                    "desc": "",
                    "lua_type": "Observable<T>"
                }
            ],
            "function_type": "static",
            "source": {
                "line": 22,
                "path": "src/Interop/ObserveFusionState.luau"
            }
        }
    ],
    "properties": [
        {
            "name": "Clock",
            "desc": "Observable number that derives its value from the current time in seconds\nin UTC (i.e. the value returned by `os.time()`)\n\nWhile subscribed, `Dex.Clock` automatically updates its value whenever the\nvalue of `os.time()` changes.",
            "lua_type": "Observable<number>",
            "source": {
                "line": 15,
                "path": "src/Observables/Clock.luau"
            }
        },
        {
            "name": "Nil",
            "desc": "Symbol that represents a \"Nil\" value. Because \"nil\" values can't be\nrepresented as values of a Luau table, `Dex.Nil` can be used in its place.\nExample usage:\n```lua\nreturn Dex.Premade(\"BillboardGui\", {\n    -- Sets the Adornee property of the premade UI to \"Nil\" on mount\n    Adornee = Dex.Nil,\n})\n```",
            "lua_type": "Symbol<\"Nil\">",
            "source": {
                "line": 19,
                "path": "src/Symbols/init.luau"
            }
        }
    ],
    "types": [],
    "name": "Dex",
    "desc": ":::warning\nDex is still a work in progress and does not currently have a full release!\nPlease avoiding Dex in production-bound projects, as the library is not fully\ntested, and the API may be subject to change\n:::\n\nThe Dex library contains a collection of objects for creating reactive UI\ncomponents\n\nFor more information, see the [Usage Guide](../docs/intro)",
    "source": {
        "line": 55,
        "path": "src/init.luau"
    }
}