Fusion Documentation

repository·main·Indexed 20 days ago

https://github.com/dphfox/fusion

A portable Luau companion library designed to make code more descriptive, predictable, and easy to debug across various Luau environments, including Roblox. Fusion provides tools for state management, physics-based animations via Fusion.Spring, and interpolation via Fusion.Tween, along with a comprehensive error ID system for troubleshooting.

Tokens
48.2K
Snippets
162
Records
215
Agent score
74%

What's inside Fusion

  1. Overview of Fusion

    main

    Fusion is a portable Luau companion library designed to enable simpler, more descriptive, and predictable code. It allows developers to assemble straightforward logic chains that are easy to debug and make strong guarantees about code behavior.

    Key features include:

    • Portability: Works with any Luau environment.
    • Roblox Support: Provides batteries-included configuration specifically for Roblox.
    • Extensibility: Designed for deep integration and custom API building in any Luau-based universe.
  2. Fusion API Reference Overview

    main

    The Fusion API Reference provides technical documentation for the library's core modules. The API is organized into several functional areas:

    • General: Error handling and contextual/safe execution patterns.
    • Memory: Management of Scope, innerScope, doCleanup, and scoped operations.
    • Graph: Reactive graph management, specifically the Observer.
    • State: Reactive state primitives including UsedAs, Computed, peek, and Value.
    • Animation: Motion primitives like Spring and Tween.
    • Roblox: Integration utilities for Roblox-specific objects, such as Child, Children, Hydrate, and New.

    For beginners, it is recommended to start with the tutorials before diving into the technical API reference.

  3. What is a StateObject and when to use it

    main

    A StateObject<T> is a reactive graph object that stores a value of type T which can change over time. It inherits from GraphObject, meaning it can broadcast updates to the reactive graph whenever its value changes.

    Important Note for End-Users: This type is primarily an internal implementation detail of Fusion. You should not use StateObject directly in your application logic. Instead, you should use the UsedAs<T> type for your own code to interact with reactive values.

    export type StateObject<T> = GraphObject & {
    	type: "State",
    	kind: string,
    	_EXTREMELY_DANGEROUS_usedAsValue: T
    }
  4. What is the Animatable type in Fusion?

    main

    The Animatable type defines a set of data types that Fusion can decompose into a tuple of parameters for smooth interpolation during animations. If you use a type not included in this list with Tween or Spring objects, the value will not animate; instead, it will immediately snap to its goal value.

    -- Supported Animatable types:
    export type Animatable =
    	number |
    	CFrame |
    	Color3 |
    	ColorSequenceKeypoint |
    	DateTime |
    	NumberRange |
    	NumberSequenceKeypoint |
    	PhysicalProperties |
    	Ray |
    	Rect |
    	Region3 |
    	Region3int16 |
    	UDim |
    	UDim2 |
    	Vector2 |
    	Vector2int16 |
    	Vector3 |
    	Vector3int16
  5. What is hydration in Fusion?

    main
    Hydration is the process of connecting your scripts to a pre-made UI template. It allows logic in your scripts to translate into UI effects, such as setting text in a TextLabel, moving menus, or toggling the visibility of buttons. In Fusion, this is achieved by using the Hydrate function to apply a table of properties to an existing instance.
  6. Share values using Globals

    main

    You can share values across your codebase by placing them in modules that can be required anywhere. These are known as globals. This is useful for sharing static data (like theme colors) or shared state objects that every part of the codebase can interact with.

    Best Practices for Globals:

    • Treat them as read-only: Avoid writing to globals from deep within your codebase to prevent hard-to-locate writes. Changes should ideally come from a single, well-signposted location.
    • Manage from the top-down: Globals should be managed from high up in your program hierarchy. Use callbacks to pass control up the chain rather than managing globals directly from low-level code.
    • Handle memory with init(): To ensure globals are cleaned up correctly, use an init(scope: Fusion.Scope) method to register global state objects into a main scope. This ensures they are destroyed last during the doCleanup() process.
    -- Theme.luau
    local Theme = {}
    Theme.colours = { background = Color3.fromHex("FFFFFF") }
    return Theme
    
    -- Somewhere else
    local Theme = require("path/to/Theme.luau")
    print(Theme.colours.background)
  7. Create reusable components using functions

    main

    In Fusion, components are implemented as standard Luau functions. To create a component, define a function that accepts a scope as its first parameter and a props table as its second. The function should return Fusion content (like an instance created via scope:New).

    By placing scope first, you enable users to use the scoped() syntax, allowing them to call your component as a method of the scope (e.g., scope:ComponentName).

    local function Button(
    	scope: Fusion.Scope,
    	props: {
    		ButtonText: UsedAs<string>
    	}
    ) 
        return scope:New "TextButton" {
            Text = props.ButtonText
        }
    end
    
    -- Usage via bare function call:
    local btn = Button(scope, { ButtonText = "Hello" })
    
    -- Usage via scoped() syntax:
    local scope = scoped(Fusion, { Button = Button })
    local btn = scope:Button { ButtonText = "Hello" }
  8. Create and manage state with Value objects

    main

    A Value is Fusion's simplest state object. It stores a single piece of data that can be updated and read.

    • Creation: Use scope:Value(initialValue) to create a new value object within a scope.
    • Reading: Use the global peek(valueObject) function to retrieve the current value stored in the object.
    • Updating: Use the valueObject:set(newValue) method to update the stored value. Note that :set() returns the value passed to it, allowing it to be used within expressions.
    local Fusion = require(ReplicatedStorage.Fusion)
    local peek = Fusion.peek
    local scope = Fusion.scoped(Fusion)
    
    -- Create a value
    local health = scope:Value(100)
    
    -- Read the value
    print(peek(health)) --> 100
    
    -- Update the value
    health:set(25)
    print(peek(health)) --> 25
  9. Reactive updates with ForValues and state objects

    main

    If the input to ForValues is a state object, the output will automatically update whenever the input table changes. Additionally, you can use use() within the processor function to depend on other state objects; if those dependencies change, the ForValues output will also update.

    local numbers = scope:Value({1, 2, 3, 4, 5})
    local factor = scope:Value(2)
    
    local multiplied = scope:ForValues(numbers, function(use, scope, num)
    	return num * use(factor)
    end)
    
    print(peek(multiplied)) --> {2, 4, 6, 8, 10}
    
    -- Updating the input table triggers an update
    numbers:set({5, 15, 25})
    print(peek(multiplied)) --> {10, 30, 50}
    
    -- Updating a dependency via use() also triggers an update
    factor:set(10)
    print(peek(multiplied)) --> {50, 150, 250}
  10. Reference UI elements using Value Objects

    main

    When you need to maintain code structure, handle complex dependencies, or create cyclic references, use Value Objects (created via scope:Value(defaultValue)).

    Because the :set() method returns the value passed into it, you can define a placeholder value object and then initialize it later in the UI tree. This allows you to reference an element before it is actually constructed.

    Key Behaviors:

    • Delayed Initialization: The value object will hold its initial defaultValue (e.g., nil) until :set() is called. Any code observing the value during this window will see the default.
    • Cyclic References: Value objects allow two elements to refer to each other by providing a placeholder that is filled in once both elements are defined.
    • Structural Integrity: Unlike constants, using value objects allows you to keep the UI tree definition in a single, cohesive block.
    -- 1. Create a placeholder value object
    local selectionTarget: Fusion.Value<Part?> = scope:Value(nil)
    
    local ui = scope:New "Folder" {
    	[Children] = {
    		scope:New "SelectionBox" {
    			Adornee = selectionTarget
    		},
    		-- 2. Initialize the value object later in the tree
    		selectionTarget:set(
    			scope:New "Part" {
    				Name = "Selection Target",
    			}
    		)
    	}
    }
  11. Representing change with State Objects

    main

    Fusion uses 'state objects' to represent dynamic or changeable values. These objects allow you to write reactive code that is easy to read and debug. You can inspect the current value of a state object at any time using the peek() function.

    There are two primary types of state objects:

    1. Value: A state object that you can manually update using the :set() method.
    2. Computed: A state object that automatically determines its own value based on a calculation involving other state objects. You use the use() function within the calculation to track dependencies.

    To manage the lifecycle of these objects and prevent memory leaks, use a scope. Calling scope:doCleanup() will discard all objects created within that scope.

    -- Start tracking some new objects.
    local scope = Fusion:scoped()
    
    -- This creates a state object that you can set manually.
    local myName = scope:Value("Daniel")
    
    -- This creates a state object from a calculation.
    local myGreeting = scope:Computed(function(use)
    	return "Hello! My name is " .. use(myName)
    end)
    
    -- Discard all the objects.
    scope:doCleanup()