VerseIsland
Feed Learn Leaderboard Guides Reference Explore Search Docs Verse Library
Sign in
Feed Learn 📖 Codex Leaderboard Guides Reference Explore Search Docs Verse Library
Verse Library › Creator Economy
Browse Verse Library

Library

Devices 634
  • Devices171
  • Triggers & Logic118
  • UI & HUD40
  • Audio39
  • Items & Inventory29
  • Events27
  • Scoring & Objectives25
  • Spawning19
  • Classes & Interfaces18
  • Game Modes17
  • Props & Meshes14
  • Variables & Mutability12
  • Player Management11
  • Modules & Structure10
  • Round Flow8
  • Animation6
  • Concurrency6
  • Functions6
  • Getting Started6
  • Teams & Classes6
  • NPCs & AI5
  • Tutorials5
  • VFX & Particles5
  • Arrays & Maps4
  • Cameras4
  • Debugging4
  • Control Flow3
  • Cinematics2
  • Other2
  • Persistence2
  • Scene Graph2
  • Structs & Enums2
  • Building1
  • Physics1
  • Publishing & Islands1
  • Syntax & Types1
  • Vehicles1
  • Weapons1
Verse Language 257
  • Control Flow35
  • Functions26
  • Arrays & Maps25
  • Classes & Interfaces22
  • Variables & Mutability22
  • Concurrency21
  • Syntax & Types18
  • Modules & Structure12
  • Debugging8
  • Devices8
  • Events7
  • Player Management6
  • Structs & Enums6
  • Triggers & Logic6
  • Game Modes5
  • Failure & Options4
  • Scene Graph4
  • UI & HUD4
  • Getting Started3
  • Round Flow3
  • Spawning3
  • VFX & Particles3
  • Reference2
  • Animation1
  • Best Practices1
  • Other1
  • Props & Meshes1
Materials/VFX 154
  • Triggers & Logic27
  • UI & HUD17
  • Devices16
  • VFX & Particles14
  • Props & Meshes11
  • Scoring & Objectives9
  • Game Modes7
  • Items & Inventory7
  • Functions6
  • Arrays & Maps5
  • Animation3
  • Cinematics3
  • Classes & Interfaces3
  • Control Flow3
  • Events3
  • Modules & Structure3
  • Round Flow3
  • Spawning3
  • Getting Started2
  • Scene Graph2
  • Variables & Mutability2
  • Concurrency1
  • Persistence1
  • Player Management1
  • Structs & Enums1
  • Syntax & Types1
General 153
  • Devices22
  • Events20
  • Triggers & Logic20
  • Classes & Interfaces10
  • Variables & Mutability8
  • Round Flow6
  • Scoring & Objectives6
  • UI & HUD6
  • Functions5
  • Player Management5
  • Game Modes4
  • Getting Started4
  • Props & Meshes4
  • Control Flow3
  • Syntax & Types3
  • VFX & Particles3
  • Arrays & Maps2
  • Best Practices2
  • NPCs & AI2
  • Other2
  • Physics2
  • Scene Graph2
  • Spawning2
  • Structs & Enums2
  • Tutorials2
  • Building1
  • Cameras1
  • Cinematics1
  • Failure & Options1
  • Items & Inventory1
  • Teams & Classes1
Player 133
  • Player Management22
  • Teams & Classes19
  • Classes & Interfaces12
  • Devices11
  • Events9
  • Persistence7
  • Triggers & Logic7
  • Arrays & Maps6
  • Functions4
  • Game Modes4
  • Items & Inventory4
  • Round Flow4
  • Debugging3
  • Getting Started3
  • Modules & Structure3
  • Concurrency2
  • Control Flow2
  • Scoring & Objectives2
  • Spawning2
  • Structs & Enums2
  • Physics1
  • Props & Meshes1
  • UI & HUD1
  • Variables & Mutability1
  • Weapons1
Building & Props 131
  • Variables & Mutability15
  • Props & Meshes14
  • Triggers & Logic12
  • Classes & Interfaces10
  • Devices10
  • UI & HUD10
  • Events7
  • Teams & Classes7
  • Animation5
  • Building5
  • Functions5
  • VFX & Particles5
  • Structs & Enums4
  • Control Flow3
  • Game Modes3
  • Items & Inventory3
  • Round Flow3
  • Scene Graph3
  • Arrays & Maps2
  • Concurrency2
  • Reference2
  • Modules & Structure1
NPCs & AI 76
  • NPCs & AI35
  • Spawning7
  • Animation5
  • Variables & Mutability5
  • Classes & Interfaces3
  • Debugging3
  • UI & HUD3
  • Audio2
  • Concurrency2
  • Game Modes2
  • Props & Meshes2
  • Triggers & Logic2
  • Devices1
  • Functions1
  • Getting Started1
  • Reference1
  • VFX & Particles1
Spawning 73
  • Spawning31
  • Events7
  • Concurrency6
  • Player Management6
  • Vehicles5
  • Props & Meshes4
  • Devices3
  • Scene Graph3
  • Items & Inventory2
  • Teams & Classes2
  • Control Flow1
  • Publishing & Islands1
  • Reference1
  • Scoring & Objectives1
Cinematics 71
  • Cameras19
  • Cinematics15
  • Devices11
  • Audio5
  • Animation4
  • Triggers & Logic4
  • Functions2
  • Game Modes2
  • UI & HUD2
  • Classes & Interfaces1
  • Concurrency1
  • Control Flow1
  • Items & Inventory1
  • Modules & Structure1
  • Scene Graph1
  • Templates1
UI 57
  • UI & HUD35
  • Devices5
  • Scoring & Objectives4
  • Classes & Interfaces3
  • Round Flow2
  • Scene Graph2
  • Arrays & Maps1
  • Props & Meshes1
  • Structs & Enums1
  • Templates1
  • Triggers & Logic1
  • Variables & Mutability1
Scene Graph 40
  • Scene Graph9
  • Items & Inventory8
  • Classes & Interfaces3
  • Events3
  • Props & Meshes3
  • Functions2
  • Arrays & Maps1
  • Building1
  • Control Flow1
  • Debugging1
  • Modules & Structure1
  • Player Management1
  • Reference1
  • Structs & Enums1
  • Syntax & Types1
  • Triggers & Logic1
  • UI & HUD1
  • VFX & Particles1
Vehicles 38
  • Spawning11
  • Devices7
  • Vehicles7
  • Props & Meshes4
  • Functions2
  • Game Modes2
  • Failure & Options1
  • Items & Inventory1
  • Reference1
  • Teams & Classes1
  • Tutorials1
Tutorials 37
  • Game Modes6
  • Triggers & Logic5
  • Classes & Interfaces4
  • Events4
  • Props & Meshes3
  • Building2
  • Devices2
  • Items & Inventory2
  • Scoring & Objectives2
  • Animation1
  • Arrays & Maps1
  • Cameras1
  • Concurrency1
  • Physics1
  • Player Management1
  • Structs & Enums1
Weapons 30
  • Game Modes6
  • Weapons6
  • Devices5
  • Items & Inventory3
  • Scoring & Objectives3
  • Spawning2
  • Teams & Classes2
  • Best Practices1
  • Functions1
  • Triggers & Logic1
Items 28
  • Items & Inventory23
  • Devices2
  • Triggers & Logic2
  • Spawning1
Assets 20
  • Modules & Structure6
  • Arrays & Maps3
  • Functions3
  • Scene Graph2
  • Best Practices1
  • Devices1
  • Events1
  • Failure & Options1
  • Physics1
  • Variables & Mutability1
Animation 19
  • Animation10
  • Variables & Mutability4
  • Devices1
  • Player Management1
  • Props & Meshes1
  • Scene Graph1
  • Syntax & Types1
Release Notes 17
  • Classes & Interfaces5
  • Modules & Structure3
  • Concurrency2
  • Control Flow2
  • Variables & Mutability2
  • Debugging1
  • Devices1
  • Items & Inventory1
Input & Controls 16
  • Functions4
  • UI & HUD3
  • Control Flow2
  • Animation1
  • Arrays & Maps1
  • Cinematics1
  • Debugging1
  • Devices1
  • Events1
  • Items & Inventory1
Publishing 8
  • Control Flow5
  • Arrays & Maps1
  • Devices1
  • Syntax & Types1
Audio 7
  • Audio5
  • UI & HUD2
Landscape 7
  • Other4
  • VFX & Particles2
  • Scene Graph1
Persistence 6
  • Structs & Enums2
  • Items & Inventory1
  • Persistence1
  • Publishing & Islands1
  • Variables & Mutability1
Physics 5
  • Functions2
  • Classes & Interfaces1
  • Devices1
  • Syntax & Types1
Creator Economy 3
  • Publishing & Islands2
  • Modules & Structure1
Discovery 3
  • Devices1
  • NPCs & AI1
  • Structs & Enums1
Editor & Project 3
  • Other1
  • Props & Meshes1
  • Tutorials1

Data Science and Analytics for Verse

Module — 2 files
These files compile together (same module folder).
file_1.verse
# DSAV (Data Science & Analytics for Verse) module
DSAV<public> := module:

    # NOTE: Project DSAV uses the Matrices module made by @topo-ology. This required module can be found here: 
    # https://dev.epicgames.com/community/snippets/bO9r/fortnite-matrices
    using { Matrices }
    using { /UnrealEngine.com/Temporary/SpatialMath }
    using { /Verse.org/Random }

    <# DATA CLEANING #>

    # Returns true if the given array contains a missing value, meaning either NaN or unset optional entries.
    (Column:[]?float).HasNA<public>()<transacts>:logic=
        var Result : logic = false
        for (Index := 0..Column.Length - 1):
            if (FilledEntry := Column[Index]?):
                if (FilledEntry = NaN):
                    set Result = true
            else:
                set Result = true
        Result

    # Returns true if the given matrix contains a NaN entry.
    (InMatrix:Matrix).HasNA<public>()<transacts>:logic=
        var Result : logic = false
        for (Row := 0..InMatrix.Rows - 1):
            for (Col := 0..InMatrix.Cols - 1):
                if (Entry := InMatrix.Rep[Row][Col], Entry = NaN):
                    set Result = true
        Result

    # Returns the input matrix without duplicated rows (if any), maintaining the first row of any duplicates.
    (InMatrix:Matrix).DropDuplicates<public>()<transacts>:Matrix =
        var UniqueRows : [][]float = array{}

        for (RowIndex := 0..InMatrix.Rows - 1):
            if (CurrentRow := InMatrix.Rep[RowIndex]):
                var Duplicate : logic = false
                for (UniqueRow : UniqueRows):
                    if (CurrentRow = UniqueRow):
                        set Duplicate = true
                if (Duplicate = false):
                    set UniqueRows = UniqueRows + array{CurrentRow}
        if (UniqueRows.Length > 0):
            if (Result := ConstructMatrix[UniqueRows]):
                Result
            else:
                InMatrix
        else:
            InMatrix

    

    <# DESCRIPTIVE STATISTICS; UNIVARIATE MOMENTS #>

    # Calculates the average value of an array of floats.
    (Column:[]float).Mean<public>()<decides><transacts>:float=
        var Sum : float = 0.0
        for (Index := 0..Column.Length - 1):
            if (Entry := Column[Index]):
                set Sum += Entry
        (1.0*Sum)/(1.0*Column.Length)

    # Calculates the average value of a column in a matrix.
    (InMatrix:Matrix).Mean<public>(Column:int)<decides><transacts>:float=
        InRows : int = InMatrix.Rows
        var Sum : float = 0.0
        for (Index := 0..InRows - 1):
            if (Entry := InMatrix.Rep[Index][Column]):
                set Sum += Entry
        (1.0*Sum)/(1.0*InRows)

    # Calculates the population variance of an array of floats.
    (Column:[]float).Var<public>()<decides><transacts>:float=
        Mean : float = Column.Mean[]
        SquaredTerms : []float = for (Index := 0..Column.Length - 1):
            Pow(Column[Index] - Mean,2.0)
        var Sum : float = 0.0
        for (Index := 0..SquaredTerms.Length - 1):
            set Sum += SquaredTerms[Index]
        (1.0*Sum)/(1.0*Column.Length)

    # Calculates the population variance of a column in a matrix.
    (InMatrix:Matrix).Var<public>(Column:int)<decides><transacts>:float=
        InRows : int = InMatrix.Rows
        Mean : float = InMatrix.Mean[Column]
        SquaredTerms : []float = for (Index := 0..InRows - 1):
            Pow(InMatrix.Rep[Index][Column] - Mean,2.0)
        var Sum : float = 0.0
        for (Index := 0..InRows - 1):
            set Sum += SquaredTerms[Index]
        (1.0*Sum)/(1.0*InRows)

    # Calculates the sample variance of an array of floats.
    (Column:[]float).SVar<public>()<decides><transacts>:float=
        Variance : float = Column.Var[]
        Variance*((1.0*Column.Length)/(1.0*Column.Length-1.0))

    # Calculates the sample variance of a column in a matrix.
    (InMatrix:Matrix).SVar<public>(Column:int)<decides><transacts>:float=
        InRows : int = InMatrix.Rows
        Variance : float = InMatrix.Var[Column]
        Variance*((1.0*InRows)/(1.0*InRows-1.0))

    # Calculates the population standard deviation of an array of floats.
    (Column:[]float).StdDev<public>()<decides><transacts>:float=
        Variance : float = Column.Var[]
        Sqrt(Variance)

    # Calculates the population standard deviation of a column in a matrix.
    (InMatrix:Matrix).StdDev<public>(Column:int)<decides><transacts>:float=
        Variance : float = InMatrix.Var[Column]
        Sqrt(Variance)

    # Calculates the sample standard deviation of an array of floats.
    (Column:[]float).SStdDev<public>()<decides><transacts>:float=
        SampleVariance : float = Column.SVar[]
        Sqrt(SampleVariance)

    # Calculates the sample standard deviation of a column in a matrix.
    (InMatrix:Matrix).SStdDev<public>(Column:int)<decides><transacts>:float=
        SampleVariance : float = InMatrix.SVar[Column]
        Sqrt(SampleVariance)



    <# DESCRIPTIVE STATISTICS; UNIVARIATE QUANTILES #>

    # Calculates the largest possible difference of floats within an array.
    (Column:[]float).Range<public>()<decides><transacts>:float=
        var MaxValue : float = 0.0
        var MinValue : float = 0.0
        for (Index := 0..Column.Length - 1):
            if (Entry := Column[Index]):
                if (Index = 0 or Entry > MaxValue):
                    set MaxValue = Entry
                if (Index = 0 or Entry < MinValue):
                    set MinValue = Entry

        MaxValue - MinValue

    # Calculates the largest possible difference of floats within a column in a matrix.
    (InMatrix:Matrix).Range<public>(Column:int)<decides><transacts>:float=
        InRows : int = InMatrix.Rows
        var MaxValue : float = 0.0
        var MinValue : float = 0.0
        for (Index := 0..InRows - 1):
            if (Entry := InMatrix.Rep[Index][Column]):
                if (Index = 0 or Entry > MaxValue):
                    set MaxValue = Entry
                if (Index = 0 or Entry < MinValue):
                    set MinValue = Entry

        MaxValue - MinValue

    # The following code is a sorting algorithm developed by Epic Games staff member Sarah Rust (@summergrrrl), taken from her module SortingAlgorithms.
    # These serve as helper functions to find quartiles of an array. 
    # Source: https://dev.epicgames.com/community/snippets/LNY1/fortnite-merge-sort

    ###

    # A divide-and-conquer sorting algorithm that divides an array into two, sorts each divided array, and then merges the arrays together.
    # This is a recursive implementation, where the function calls itself to merge sort the divided arrays.
    # The base case (the condition to stop the recursion) is the array has only one element.
    # This is a generic implementation using parametric types, so you can provide your own type and your own comparison function as arguments.
    MergeSort<public>(Array:[]t, Compare(L:t, R:t)<decides><transacts>:t where t:type)<transacts>:[]t=
        Length:int = Array.Length
        if:
            Length > 1 # Verify there is more than one element in the array, otherwise we've reached the base case.
            Mid:int = Floor(Length / 2) # Get the middle index of the array.
            Left:[]t = Array.Slice[0, Mid] # Split the array in half. This keeps elements from the beginning to Mid - 1 index.
            Right:[]t = Array.Slice[Mid] # Split the array in half. This keeps elements from Mid index to the end of the array.
        then:
            # Call MergeSort on the left half of the array.
            LeftSorted:[]t = MergeSort(Left, Compare)
 
            # Call MergeSort on the right half of the array.
            RightSorted:[]t = MergeSort(Right, Compare)
 
            # Combine the two arrays and return the result.
            Merge(LeftSorted, RightSorted, Compare)
        else:
 
            # Return the array passed in because we've reached the base case.
            Array
 
    # A helper function for MergeSort that combines the divided arrays in an order based on the Compare function.
    Merge(Left:[]t, Right:[]t, Compare(L:t, R:t)<decides><transacts>:t where t:type)<transacts>:[]t=
        var LeftIndex:int = 0
        var RightIndex:int = 0
        var MergedArray:[]t = array{}
 
        # Loop through all the elements in the arrays to add them to the MergedArray variable.
        loop:
            if (LeftElement := Left[LeftIndex], RightElement := Right[RightIndex]):
                # Check the element in the left half array with the element in the right half array.
                # Uses the Compare function passed in as an argument
                if (Compare[LeftElement, RightElement]):
                    set MergedArray += array{LeftElement}
                    set LeftIndex += 1
                else:
                    set MergedArray += array{RightElement}
                    set RightIndex += 1
            else:
                # We've added all of the elements from one of the arrays at this point.
                # Now check which array still has elements to merge in and add all remaining elements.
                if (LeftIndex >= Left.Length):
                    option{set MergedArray += Right.Slice[RightIndex]}
                else:
                    option{set MergedArray += Left.Slice[LeftIndex]}
                # Exit out of the loop because we've finished adding all elements.
                break
 
        # Return the merged array.
        MergedArray

    ###

    # Additional helper function to sort in ascending order:
    Ascending(L:float, R:float)<decides><transacts>:float =
        R > L

    # Finds the middle-positioned float in a sorted array of floats.
    (Column:[]float).Median<public>()<decides><transacts>:float=
        SortedColumn : []float = MergeSort(Column, Ascending)
        N : int = SortedColumn.Length
        if (Mod[N, 2] = 0):
            if (LeftMiddleEntry := SortedColumn[Floor[1.0*N / 2.0]], RightMiddleEntry := SortedColumn[Ceil[1.0*N / 2.0]]):
                1.0*(LeftMiddleEntry + RightMiddleEntry)/2.0
            else:
                0.0
        else if (MiddleEntry1 := SortedColumn[Ceil[(1.0*N + 1.0) / 2.0]], MiddleEntry2 := SortedColumn[Floor[1.0*N / 2.0]]):
            (MiddleEntry1 + MiddleEntry2)/2.0
        else:
            0.0

    # Finds the first quartile in a sorted array of floats.
    (Column:[]float).Q1<public>()<decides><transacts>:float=
        Column.Percentile[25.0]

    # Finds the third quartile in a sorted array of floats.
    (Column:[]float).Q3<public>()<decides><transacts>:float=
        Column.Percentile[75.0]

    # Calculates the Xth percentile of an array of floats, using the nearest-rank method.
    (Column:[]float).Percentile<public>(X:float)<decides><transacts>:float=
        SortedColumn : []float = MergeSort(Column, Ascending)
        Fraction : float = 1.0*X / 100.0
        ExactPosition : float = Fraction * (1.0*SortedColumn.Length - 1.0)
        FloorIdx : int = Floor[ExactPosition]
        CeilIdx : int = Ceil[ExactPosition]
        FloorPos : float = SortedColumn[FloorIdx]
        CeilPos : float = SortedColumn[CeilIdx]
        (FloorPos + CeilPos) / 2.0

    # Calculates the interquartile range of an array of floats.
    (Column:[]float).IQR<public>()<decides><transacts>:float=
        Column.Q3[] - Column.Q1[]

    # Counts the number of outliers in an array of floats, defined as entries outside 1.5*IQR from Q1 and Q3.
    (Column:[]float).CountOutliers<public>()<decides><transacts>:int=
        var Count : int = 0
        for (Index := 0..Column.Length - 1):
            if (Entry := Column[Index]):
                if (Entry > Column.Q3[] + 1.5*Column.IQR[] or Entry < Column.Q1[] - 1.5*Column.IQR[]):
                    set Count += 1
        Count



    <# DESCRIPTIVE STATISTICS; MULTIIVARIATE MOMENTS #>

    # Calculates the sample covariance of 'x' and 'y', being arrays of floats. Fails if their number of entries are different.
    Cov<public>(x:[]float, y:[]float)<decides><transacts>:?float =
        block:
            var Sum : float = 0.0
            if (x.Length <> y.Length):
                false
            else:
                for (Entry := 0..x.Length-1):
                    Term : float = (x[Entry] - x.Mean[]) * (y[Entry] - y.Mean[])
                    set Sum += Term
            option{(1.0*Sum) / (1.0*x.Length - 1.0)}

    # Calculates the sample covariance of column 'XCol' of matrix 'X' and column 'YCol' of matrix 'Y'. Fails if their number of entries are different.
    Cov<public>(X:Matrix, Y:Matrix, XCol : int, YCol : int)<decides><transacts>:?float =
        block:
            var Sum : float = 0.0
            if (X.Rows <> Y.Rows):
                false
            else:
                for (Entry := 0..X.Rows-1):
                    Term : float = (X.Rep[Entry][XCol] - X.Mean[XCol]) * (Y.Rep[Entry][YCol] - Y.Mean[YCol])
                    set Sum += Term
            option{(1.0*Sum) / (1.0*X.Rows - 1.0)}
            
    # Calculates the covariance matrix of columns in 'X'.
    Cov<public>(X:Matrix)<decides><transacts>:Matrix =
        block:
            Result : [][]float = for (Row :=0..X.Cols- 1):
                for (Col :=0..X.Cols- 1):
                    Cov[X, X, Row, Col]?
            ConstructMatrix[Result]

    # Calculates the Pearson correlation coefficient of 'x' and 'y', being arrays of floats. Fails if their number of entries are different.
    Corr<public>(x:[]float, y:[]float)<decides><transacts>:?float =
        block:
            var Result : float = 0.0
            if (x.Length <> y.Length):
                false
            else:
                if (UnfailedCov := Cov[x,y]?):
                    set Result = UnfailedCov
            Denominator : float = x.SStdDev[] * y.SStdDev[]
            set Result /= Denominator
            option{Result}

    # Calculates the Pearson correlation coefficient of 'x' and 'y', being columns in a matrix. Fails if their number of entries are different.
    Corr<public>(X:Matrix, Y:Matrix, XCol : int, YCol : int)<decides><transacts>:?float =
        block:
            var Result : float = 0.0
            if (X.Rows <> Y.Rows):
                false
            else:
                if (UnfailedCov := Cov[X, Y, XCol, YCol]?):
                    set Result = UnfailedCov
            Denominator : float = X.SStdDev[XCol] * Y.SStdDev[YCol]
            set Result /= Denominator
            option{Result}

    # Calculates the coefficient of determination of 'x' and 'y', being arrays of floats. Fails if their number of entries are different.
    R2<public>(x:[]float, y:[]float)<decides><transacts>:?float =
        block:
            if (x.Length <> y.Length):
                false
            else:
                var Result : float = Corr[x, y]?
                set Result = Pow(Result, 2.0)
                option{Result}

    # Calculates the coefficient of determination of 'x' and 'y', being columns in a matrix. Fails if their number of entries are different.
    R2<public>(X:Matrix, Y:Matrix, XCol : int, YCol : int)<decides><transacts>:?float =
        block:
            if (X.Rows <> Y.Rows):
                false
            else:
                var Result : float = Corr[X, Y, XCol, YCol]?
                set Result = Pow(Result, 2.0)
                option{Result}

    <# REGRESSION #>

    # Performs Ordinary Least Squares to derive coefficient estimates for 'X', with option to add the intercept term, such that 'y' is linearly explained by 'X'. Fails if either:
    #  * X and y have an unequal number of rows
    #  * XtX is not invertible
    OLSEstimates<public>(X:Matrix, y:[]float, ?Intercept : logic = false)<decides><transacts>:[]float =
        block:
            var XResult : Matrix = Matrix{}
            if (Intercept = true):
                XWithOnesRep : [][]float = for (Row := 0..X.Rows - 1):
                    for (Col := 0..X.Cols):
                        if (Col = 0):
                            1.0
                        else:
                            X.Rep[Row][Col-1]
                XWithOnes : Matrix = ConstructMatrix[XWithOnesRep]
                set XResult = XWithOnes
            else:
                set XResult = X
            Xt :Matrix = XResult.Transpose[]
            XtX :Matrix = Xt*XResult
            XtXinv : Matrix = XtX.Inverse[]
            yMatrixForm : Matrix = VectorAsMatrix[y]
            Xty : Matrix = Xt * yMatrixForm
            BetaHat : Matrix = XtXinv * Xty
            MaybeTheResult : ?[]float = OneDMatrixAsVector[BetaHat]
            Result : []float = MaybeTheResult?
            Result

    # Performs OLSEstimates and additionally provides corresponding standard errors for 'X', with option to add the intercept term. Fails if either:
    #  * X and y have an unequal number of rows
    #  * XtX is not invertible
    OLSEstimates2<public>(X:Matrix, y:[]float, ?Intercept : logic = false)<decides><transacts>:[]tuple(float, float) =
        var XResult : Matrix = Matrix{}
        if (Intercept = true):
            XWithOnesRep : [][]float = for (Row := 0..X.Rows - 1):
                for (Col := 0..X.Cols):
                    if (Col = 0):
                        1.0
                    else:
                        X.Rep[Row][Col-1]
            XWithOnes : Matrix = ConstructMatrix[XWithOnesRep]
            set XResult = XWithOnes
        else:
            set XResult = X
        Xt :Matrix = XResult.Transpose[]
        XtX :Matrix = Xt*XResult
        XtXinv : Matrix = XtX.Inverse[]

        Betas : []float = OLSEstimates[X, y, ?Intercept := Intercept]
        MSE : float = MeanSquaredError[XResult, y, Betas]
        
        var Result : []tuple(float, float) = for (BetaPos := 0..Betas.Length - 1):
            SE : float = Sqrt(MSE * XtXinv.Rep[BetaPos][BetaPos])
            (Betas[BetaPos], SE)

        Result

    # Calculates the t-statistic for the (coefficient, standard error)-tuple in 'CSE'.
    (CSE:tuple(float, float)).Tstat<public>()<decides><transacts>:float=
        CSE(0) / CSE(1)

    # Calculates the t-statistics for multiple (coefficient, standard error)-tuples in 'CSE'.
    (CSE:[]tuple(float, float)).Tstat<public>()<decides><transacts>:[]float=
        Result : []float = for (Index := 0..CSE.Length - 1):
            Beta : float = CSE[Index](0)
            SE : float = CSE[Index](1)
            Tstat : float = Beta / SE
            Tstat
        Result

    # Calculates whether the coefficient in 'CSE' is significantly different from 0, at a 5% significance level.
    (CSE:tuple(float, float)).IsSignif<public>()<decides><transacts>:logic=
        if (CSE.Tstat[] > 1.96 or CSE.Tstat[] < -1.96):
            true
        else:
            false

    # Calculates whether the coefficients in 'CSE' are significantly different from 0, at a 5% significance level.
    (CSE:[]tuple(float, float)).IsSignif<public>()<decides><transacts>:logic=
        var Result : logic = true
        for (Index := 0..CSE.Length - 1):
            if (CSE[Index].IsSignif[] = false):
                set Result = false
        Result

    # Performs a Logistic Regression using gradient descent to derive coefficient estimates for 'X', with option to add the intercept term, such that the log-odds of 'y' being 1 
    # is linearly explained by 'X'. Fails if:
    #  * X and y have an unequal number of rows
    #  * y contains values other than 0.0 or 1.0
    LogRegEstimates<public>(X:Matrix, y:[]float, ?Intercept : logic = false)<decides><transacts>:[]float =
        block:
            var XResult : Matrix = Matrix{}
            if (Intercept = true):
                XWithOnesRep : [][]float = for (Row := 0..X.Rows - 1):
                    for (Col := 0..X.Cols):
                        if (Col = 0):
                            1.0
                        else:
                            X.Rep[Row][Col-1]
                XWithOnes : Matrix = ConstructMatrix[XWithOnesRep]
                set XResult = XWithOnes
            else:
                set XResult = X

            var Beta : []float = for (Index := 0..XResult.Cols - 1):
                0.0

            var NonBinary : logic = false
            for (Outcome := 0..y.Length - 1):
                if (y[Outcome] <> 0.0 and y[Outcome] <> 1.0):
                    set NonBinary = true

            if (NonBinary = true):
                Print("Error: y contains values other than 0.0 or 1.0.")
            else:
                LearningRate : float = 0.01
                MaxIterations : int = 1000

                for (Iteration := 0..MaxIterations - 1):
                    Predictions : []float = for (Row := 0..XResult.Rows - 1):
                        var LinearCombination : float = 0.0
                        for (Col := 0..XResult.Cols - 1):
                            set LinearCombination += XResult.Rep[Row][Col] * Beta[Col]
                        1.0 / (1.0 + Exp(-LinearCombination))

                    Errors : []float = for (Index := 0..y.Length - 1):
                        Predictions[Index] - y[Index]

                    for (Col := 0..XResult.Cols - 1):
                        var Gradient : float = 0.0
                        for (Row := 0..XResult.Rows - 1):
                            set Gradient += Errors[Row] * XResult.Rep[Row][Col]
                        set Gradient /= 1.0*XResult.Rows
                        set Beta[Col] -= LearningRate * Gradient

            Beta

    # Prints an ASCII scatter plot graph in the output log, given data points (x[i], y[i]) and optional titles. Provides the option to return the line equation of best fit.
    ScatterPlot<public>(x:[]float, y:[]float, ?XAxisLabel : string = "", ?YAxisLabel : string = "", ?Title : string = "", ?Fit : logic = false)<decides><transacts>:void =
        if (x.Length <> y.Length):
            Print("Error: Arrays x and y have unequal length.")
        else if (x.Length = 0 or y.Length = 0):
            Print("Error: One of the input arrays have length 0.")
        else if (x.Length = 1 or y.Length = 1):
            Print("Error: At least 2 data points are needed to plot the graph.")
        else block:
            var MinX : float = 0.0
            var MaxX : float = 0.0
            var MinY : float = 0.0
            var MaxY : float = 0.0
            if (FirstEntry := x[0]):
                set MinX = FirstEntry
                set MaxX = FirstEntry
                for (Index := 1..x.Length-1):
                    if (EntryX := x[Index], EntryY := y[Index]):
                        if (EntryX < MinX):
                            set MinX = EntryX
                        else if (EntryX > MaxX):
                            set MaxX = EntryX
                        if (EntryY < MinY):
                            set MinY = EntryY
                        else if (EntryY > MaxY):
                            set MaxY = EntryY

            RangeX : float = MaxX - MinX
            RangeY : float = MaxY - MinY
            SignificantFiguresX : float = if (RangeX > 0.0, LogResult := Log(10.0, RangeX)):
                1.0*Ceil[LogResult]
            else:
                1.0
            SignificantFiguresY : float = if (RangeY > 0.0, LogResult := Log(10.0, RangeY)):
                1.0*Ceil[LogResult]
            else:
                1.0

            var StepX : float = 0.0
            if (RangeX <= 2.0 * Pow(10.0, SignificantFiguresX - 1.0)):
                set StepX = 0.5 * Pow(10.0, SignificantFiguresX - 1.0)
            else if (RangeX <= 4.0 * Pow(10.0, SignificantFiguresX - 1.0)):
                set StepX = Pow(10.0, SignificantFiguresX - 1.0)
            else if (RangeX <= 8.0 * Pow(10.0, SignificantFiguresX - 1.0)):
                set StepX = 2.0 * Pow(10.0, SignificantFiguresX - 1.0)
            else:
                set StepX = 5.0 * Pow(10.0, SignificantFiguresX - 1.0)

            var StepY : float = 0.0
            if (RangeY <= 2.0 * Pow(10.0, SignificantFiguresY - 1.0)):
                set StepY = 0.5 * Pow(10.0, SignificantFiguresY - 1.0)
            else if (RangeY <= 4.0 * Pow(10.0, SignificantFiguresY - 1.0)):
                set StepY = Pow(10.0, SignificantFiguresY - 1.0)
            else if (RangeY <= 8.0 * Pow(10.0, SignificantFiguresY - 1.0)):
                set StepY = 2.0 * Pow(10.0, SignificantFiguresY - 1.0)
            else:
                set StepY = 5.0 * Pow(10.0, SignificantFiguresY - 1.0)

            NumberlineX : []float = for (Index := 0..23 - 1):
                NearestMultiple[MinX, StepX] + 0.2*(Index - 1)*StepX
            NumberlineY : []float = for (Index := 0..19 - 1):
                NearestMultiple[MinY, StepY] + 0.25*(Index - 1)*StepY

            RoundedPositionX : []float = for (Index := 0..x.Length-1):
                ( NearestMultiple[x[Index], 0.2*StepX] - NumberlineX[0])/(0.2*StepX)
            RoundedPositionY : []float = for (Index := 0..y.Length-1):
                (NearestMultiple[y[Index], 0.25*StepY] - NumberlineY[0])/(0.25*StepY)

            var ResultRep : [][]float = for (Row := 0..19-1):
                for (Col := 0..23-1):
                    0.0
            for (Index := 0..RoundedPositionX.Length-1):
                if (IndexX := Int[RoundedPositionX[Index]], IndexY := Int[RoundedPositionY[Index]]):
                    set ResultRep[19 - 1 - IndexY][IndexX] = 250.0
            RawPlot : Matrix = ConstructMatrix[ResultRep]

            FrameRep : [][]float = for (Row := 0..22-1):
                for (Col := 0..27-1):
                    if (Col = 0):
                        if (Row = 2 or Row = 6 or Row = 10 or Row = 14 or Row = 18):
                            45.0
                        else:
                            0.0
                    else if (Col = 1):
                        if (Row = 0):
                            94.0
                        else if (Row = 21):
                            0.0
                        else:
                            124.0
                    else if (Row = 20):
                        if (Col = 26):
                            62.0
                        else:
                            95.0
                    else if (Row = 21):
                        if (Col = 4 or Col = 9 or Col = 14 or Col = 19 or Col = 24):
                            39.0
                        else:
                            0.0
                    else:
                        if (Entry := RawPlot.Rep[Row-1][Col-3]):
                            Entry
                        else:
                            0.0
            
            Graph : Matrix = ConstructMatrix[FrameRep]

            NumberlineXFirst : float = NumberlineX[1]
            NumberlineXLast : float = NumberlineX[NumberlineX.Length - 2]
            DistanceBetweenNumberlineXValues : int = 40 - FloatToTrimmedString[NumberlineXFirst].Length
            var SpaceBetweenNumberlineXValues : string = "" 
            for (Index := 0..DistanceBetweenNumberlineXValues - 1):
                set SpaceBetweenNumberlineXValues += " "

            NumberlineYFirst : float = NumberlineY[NumberlineY.Length - 2]
            NumberlineYLast : float = NumberlineY[1]
            
            DistanceForNumberlineYValues : int = Max(FloatToTrimmedString[NumberlineYFirst].Length, FloatToTrimmedString[NumberlineYLast].Length)
            var SpaceOfDistanceOfNumberlineYValues : string = ""
            for (Index := 0..DistanceForNumberlineYValues - 1):
                set SpaceOfDistanceOfNumberlineYValues += " "
            DifferenceInDistanceOfNumberlineYValues : int = Abs(FloatToTrimmedString[NumberlineYFirst].Length - FloatToTrimmedString[NumberlineYLast].Length)
            var SpaceDifferenceOfDistanceOfNumberlineYValues : string = ""
            for (Index := 0..DifferenceInDistanceOfNumberlineYValues - 1):
                set SpaceDifferenceOfDistanceOfNumberlineYValues += " "

            DisplayedNumberlineYFirst : string = 
                if (FloatToTrimmedString[NumberlineYFirst].Length > FloatToTrimmedString[NumberlineYLast].Length):
                    FloatToTrimmedString[NumberlineYFirst]
                else:
                    SpaceDifferenceOfDistanceOfNumberlineYValues + FloatToTrimmedString[NumberlineYFirst]
            DisplayedNumberlineYLast : string = 
                if (FloatToTrimmedString[NumberlineYFirst].Length > FloatToTrimmedString[NumberlineYLast].Length):
                    SpaceDifferenceOfDistanceOfNumberlineYValues + FloatToTrimmedString[NumberlineYLast]
                else:
                    FloatToTrimmedString[NumberlineYLast]
            
            var ReturnString:[]char = "\n"
            for (Row:=0..Graph.Rows-1):
                if (Row = 2):
                    set ReturnString += "\t{DisplayedNumberlineYFirst}"
                else if (Row = 18):
                    set ReturnString += "\t{DisplayedNumberlineYLast}"
                else:
                        set ReturnString += "\t{SpaceOfDistanceOfNumberlineYValues}"
                for (Col:=0..Graph.Cols-1, Entry:=Graph.Rep[Row][Col]):
                    if (StringValue := ASCIIMap[Int[Entry]]):
                        set ReturnString += StringValue
                        if (Row = 0 and Col = 2 and YAxisLabel.Length > 0):
                            set ReturnString += "-{YAxisLabel}-"
                    else:
                        set ReturnString += "? "
                set ReturnString += "\n"
            set ReturnString += 
                "\t        {SpaceOfDistanceOfNumberlineYValues}{FloatToTrimmedString[NumberlineXFirst]}{SpaceBetweenNumberlineXValues}{FloatToTrimmedString[NumberlineXLast]}"
            if (Title.Length > 0):
                Print("***** {Title} *****")
            Print("{ReturnString}")
            if (XAxisLabel.Length > 0):
                Print("     -{XAxisLabel}-")
            if (Fit = true, xMat := VectorAsMatrix[x], Betas := OLSEstimates[xMat, y, ?Intercept := true], Intercept := Betas[0], Gradient := Betas[1]):
                Print("Line of best fit: y = {Gradient}x + {Intercept}")
            Print("See Output Log window for an accurate representation\n")

    # Calculates the mean of the absolute error terms of the model defined by 'BetaHat', such that 'y' is explained by 'X'.
    MeanSquaredError<public>(X:Matrix, y:[]float, BetaHat:[]float)<decides><transacts>:float =
        block:
            InRows : int = X.Rows
            InCols : int = X.Cols
            SquaredErrors : []float = for(Row:=0..InRows-1):
                var yHat : float = 0.0
                for(Col:=0..InCols-1):
                    XjBj : float = X.Rep[Row][Col] * BetaHat[Col]
                    set yHat += XjBj
                Error : float = y[Row] - yHat
                Element : float = Pow(Error, 2.0)
                Element
            var Sum : float = 0.0
            for(Row:=0..InRows-1):
                if (Element := SquaredErrors[Row]):
                    set Sum += Element
            (1.0*Sum)/(1.0*InRows)

    # Calculates the root of the Mean Squared Error.
    RootMeanSquaredError<public>(X:Matrix, y:[]float, BetaHat:[]float)<decides><transacts>:float =
        block:
            MSE : float = MeanSquaredError[X, y, BetaHat]
            RMSE : float = Sqrt(MSE)
            RMSE

    # Calculates the mean of the absolute error terms of the model defined by 'BetaHat', such that 'y' is explained by 'X'.
    MeanAbsoluteError<public>(X:Matrix, y:[]float, BetaHat:[]float)<decides><transacts>:float =
        block:
            InRows : int = X.Rows
            InCols : int = X.Cols
            AbsoluteErrors : []float = for(Row:=0..InRows-1):
                var yHat : float = 0.0
                for(Col:=0..InCols-1):
                    XjBj : float = X.Rep[Row][Col] * BetaHat[Col]
                    set yHat += XjBj
                var Error : float = y[Row] - yHat
                if (Error < 0.0):
                    set Error *= -1.0
                Error
            var Sum : float = 0.0
            for(Row:=0..InRows-1):
                if (Element := AbsoluteErrors[Row]):
                    set Sum += Element
            (1.0*Sum)/(1.0*InRows)

    # Divides the Mean Squared Error by the population variance of 'y'.
    NormalizedMeanSquaredError<public>(X:Matrix, y:[]float, BetaHat:[]float)<decides><transacts>:float =
        block:
            MSE : float = MeanSquaredError[X, y, BetaHat]
            NMSE : float = MSE / y.Var[]
            NMSE


    <# DISTRIBUTIONS #>

    # Draws from an approximated normal distribution with mean 'Mu' and standard deviation 'Sigma'
    RandNormPDF<public>(Mu:float, Sigma:float)<transacts>:float =
        block:
            RandU1:float = GetRandomFloat(0.0, 1.0)
            RandU2:float = GetRandomFloat(0.0, 1.0)
            Z:float = Sqrt(-2.0*Ln(RandU1)) * Cos(2.0*PiFloat*RandU2) # Box-Muller algorithm
            Result:float = Sigma * Z + Mu
            Result

    # Draws from an approximated lognormal distribution with mean 'Mu' and standard deviation 'Sigma' of the normal.
    RandLogNormPDF<public>(Mu:float, Sigma:float)<transacts>:float =
        block:
            Y :float = RandNormPDF(Mu, Sigma)
            Exp(Y)

    <# DATA EXPORT #>

    # Converts the input matrix into CSV text format, retrievable from the output log.
    PrintCSV<public>(X:Matrix)<transacts>:void=
        var ReturnString : string = "\n"
        for (Row := 0..X.Rows - 1):
            for (Col := 0..X.Cols - 1):
                if (set ReturnString += "{X.Rep[Row][Col]}") {}
                if (Col < X.Cols - 1):
                    set ReturnString += ","
            set ReturnString += "\n"
        Print(ReturnString)

    <# HELPER FUNCTIONS #>

    # Converts an array of floats 'Input' to a 1-dimensional matrix
    VectorAsMatrix<public>(Input : []float)<decides><transacts>: Matrix =
        block:
            Result : [][]float = for (Element : Input):
                array{Element}
            ConstructMatrix[Result]

    # Converts a 1-dimensional matrix 'Input' to an array of floats. Fails if the matrix has more than one column.
    OneDMatrixAsVector<public>(Input : Matrix)<decides><transacts>: ?[]float =
        block:
            InRows : int = Input.Rows
            InCols : int = Input.Cols
            if (InCols <> 1):
                false
            Result : []float = for(Row:=0..InRows-1):
                if (Element := Input.Rep[Row][0]):
                    Element
                else:
                    0.0
            option{Result}

    # Converts an array with optional floats to an array with floats.
    OptionalArrayToArray<public>(OptArray : []?float)<transacts>: []float =
        for (MaybeAFloat : OptArray, Value := MaybeAFloat?):
            Value

    # Returns a submatrix with reduced rows ('Dimension' = 0) or reduced columns ('Dimension' = 1), selecting the indices of rows/columns specified in 'Scope'.
    (InMatrix:Matrix).Submatrix<public>(Dimension: int, Scope:[]int)<decides><transacts>:Matrix=
        block:
            var NRows : int = 0
            var NCols : int = 0
            if (Dimension = 0):
                set NRows = Scope.Length
                set NCols = InMatrix.Cols
                Result : [][]float = for (Index : Scope):
                    InMatrix.Rep[Index]
                ConstructMatrix[Result]
            else:
                set NRows = InMatrix.Rows
                set NCols = Scope.Length
                Result : [][]float = for (Row := 0..NRows- 1):
                    for (Index := 0..NCols- 1):
                        InMatrix.Rep[Row][Index]
                ConstructMatrix[Result]

    # Helper function for ScatterPlot(). Returns 'Number' rounded to the nearest 'X'.
    NearestMultiple<public>(Number: float, X: float)<decides><transacts>: float =
        var Result : float = 0.0
        DivisionResult := Number / X
        if (RoundedResult := Round[DivisionResult]):
            set Result = RoundedResult * X
        Result

    # Helper function for ScatterPlot(). Returns 'Number' in string format without unnecessary decimal places.
    FloatToTrimmedString<public>(Number: float)<decides><transacts>: string =
        StringForm : string = ToString(Number)
        var TrimmedString : string = ""
        if (Number - 1.0*Round[Number] = 0.0):
            var DecimalIndex : int = 99
            for (Index := 0..StringForm.Length - 1):
                if (Digit := StringForm[Index]):
                    if (Digit = '.'):
                        set DecimalIndex = Index
                    else if (Index < DecimalIndex):
                        set TrimmedString += "{Digit}"
            TrimmedString
        else:
            var DecimalPlacesToCut : int = 0
            var NonZeroFound : logic = false
            for (Index := 0..6-1):
                if (NonZeroFound = false, DecimalDigit := StringForm[StringForm.Length - 1 - Index]):
                    if (DecimalDigit <> '0'):
                        set NonZeroFound = true
                    else:
                        set DecimalPlacesToCut += 1
            set TrimmedString = StringForm
            TrimmedString.Slice[0, StringForm.Length - DecimalPlacesToCut]
        

    # Limited ASCII Map of digits to symbols. For simplicity, 'space' is mapped to 0. 
    # Reference: https://theasciicode.com.ar/ascii-printable-characters/single-quote-apostrophe-ascii-code-39.html
    ASCIIMap<public>: [int]string = map{
        250 => "· ",
        124 => "| ",
        95  => "_ ",
        94  => "^ ",
        62  => "> ",
        45  => "- ",
        39  => "' ",
        0   => "  "
    }
example_scatter_plot.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Random }
using { Matrices }
using { DSAV }


example_scatter_plot := class(creative_device):

    @editable AimTrainingButton : button_device = button_device{}
    @editable AimTrainingProp : creative_prop = creative_prop{}
    @editable AimTrainingZone : prop_manipulator_device = prop_manipulator_device{}
    @editable Beta1SignDiffFromZero : analytics_device = analytics_device{}
    @editable Beta1NotSignDiffFromZero : analytics_device = analytics_device{}

    var Trial : int = 0
    var GameTime : float = 0.0
    var PropCoords : vector3 = vector3{X:=0.0,Y:=0.0,Z:=0.0}

    # Defining samples:
    @editable var x_array : []?float = for (Index := 0..50-1): # Set n = 50
        false
    @editable var y_array : []?float = for (Index := 0..50-1): # Set n = 50
        false
    
    OnBegin<override>()<suspends>:void= 
        AimTrainingButton.InteractedWithEvent.Subscribe(SpawnAimTrainingProp)
        AimTrainingZone.DamagedEvent.Subscribe(SpawnAimTrainingProp)

    SpawnAimTrainingProp(Agent:agent):void=  # Set up a recursive function to relocate the target, until all entries in the defined arrays are filled
        if (Trial > 0):
            if (set y_array[Trial-1] = option{GetSimulationElapsedTime() - GameTime}) {}  # Set each y-entry as the time taken to hit a target
        set GameTime = GetSimulationElapsedTime()

        PropRotation := AimTrainingProp.GetTransform().Rotation
        if (Trial <= x_array.Length):
            RandomX := GetRandomFloat(-400.0,400.0)  # Define a new random position for the target
            RandomY := GetRandomFloat(0.0,2000.0)
            RandomZ := GetRandomFloat(100.0,300.0)
            if (AimTrainingProp.TeleportTo[transform{Translation := vector3{X:=RandomX,Y:=RandomY,Z:=RandomZ},Rotation := PropRotation}]) {}  # Teleport the prop to that position
            
            if (Trial > 0):
                if (Trial = 1):
                    if (set x_array[0] = option{0.0}) {}
                else:
                    if (set x_array[Trial-1] = option{Distance(vector3{X:=RandomX,Y:=RandomY,Z:=RandomZ}, PropCoords)}) {}  # Set each x-entry as the distance between consecutive targets
            set PropCoords = vector3{X:=RandomX,Y:=RandomY,Z:=RandomZ}

            set Trial += 1
        else:  # Finishing condition
            if (AimTrainingProp.TeleportTo[transform{Translation := vector3{X:=0.0,Y:=0.0,Z:=-200.0},Rotation := PropRotation}]) {}  # Hide the target
            Print("Aim training finished")
            
            if (Plot := ScatterPlot[OptionalArrayToArray(x_array), OptionalArrayToArray(y_array),
             ?XAxisLabel:= "Distance between consecutive targets", ?YAxisLabel:= "Time taken (s) per target",
             ?Title:= "Scatter plot of hit times and distances between consecutive targets", ?Fit := true]):
                Plot  # Make the scatter plot

                if (xMat := VectorAsMatrix[OptionalArrayToArray(x_array)], Estimates := OLSEstimates2[xMat, OptionalArrayToArray(y_array), ?Intercept := true]):
                    if (Estimates[1].IsSignif[]):  
                        Beta1SignDiffFromZero.Submit(Agent)  # Store the number of cases where the gradient is statistically significant in the Creator Portal for further analysis
                    else:
                        Beta1NotSignDiffFromZero.Submit(Agent)

            else:
                Print("Error: Invalid plot")
Sign in to download module

Copy-paste each file above is always free.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in
    📄
    Source
    @Matrix
    Epic Games Community
    @Matrix

    Created by a member of the Epic Games community. Rights remain with the original author, under Epic's community content terms. Terms ↗

    View original Sources & licensing
    Request removal
    Last updated Jun 23, 2026
    Verse module (2 files)
    Build failed · 66 errors

    Download the full module (zip) from the code panel above.

    Keep exploring
    Related topics
    • vector2 Verse Language
    • vector2 Verse Language
    • vector3 Verse Language
    • Dotproduct 2 Verse Language
    • dotproduct Verse Language

    Related

    Open in graph →

    Related topics

    • vector2
    • vector2
    • vector3
    • Dotproduct 2
    • dotproduct
    VerseIsland · an archipelago of Verse & UEFN knowledge
    🗺️ Island atlas Learn Guides History About & Press Sources & Licensing Status

    Not affiliated with Epic Games. Fortnite, UEFN, Unreal Engine, and Verse are trademarks of Epic Games, Inc. Content is attributed to its source — see Sources & Licensing.

    🦜

    Scout · your island guide

    The Isle of Verse