Skip to content

Syntax

expOrbit is a very simple mathamatical programming language built specifically for Galaxy. Its entire purpose is to make building orbits from parametric equations simple. expOrbit files are meant to be short, they compile once and are used in the orbit calculations for rendering and generation. Currently expOrbit only supports star orbit editing.

Mandatory Fields

All expOrbit files must have x and z declared as variables.

x = math.cos(3 * t)
--[[ This file will error and not compile! ]]
1
2
3
x = math.cos(3 * t)
z = math.sin(2 * t)
--[[ This file will compile! ]]

Examples

x = math.cos(3 * t)
z = math.sin(2 * t)
1
2
3
4
5
6
7
8
9
--[[ Using orbitScale will ensure the orbit complies ]]
--[[ with the generator's requested scale ]]

x = orbitScale * (0.34 * (
    math.sin(t) + 2 * math.sin(t * 2)
))
z = orbitScale * (0.34 * (
    math.cos(t) - 2 * math.cos(t * 2)
))

More Complex Examples

These examples combine features from the rest of the expOrbit docs, including functions, conditionals, globals, and the math library.

This uses helper functions, math.lerp(), and math.clamp() to create a flower-like orbit that slowly expands and contracts.

def normalizedSin(angle) {
    return 0.5 + 0.5 * math.sin(angle)
}

def flowerRadius(angle) {
    petals = 0.58 + 0.18 * math.sin(6 * angle)
    pulse = math.lerp(0.82, 1.18, normalizedSin(angle / 3))

    return orbitScale * math.clamp(petals * pulse, 0.2, 1)
}

radius = flowerRadius(t)

x = radius * math.cos(t)
z = radius * math.sin(t)

math.noise() adds smooth variation to the radius so the orbit feels organic instead of perfectly circular.

def ringNoise(angle) {
    return math.noise(
        math.cos(angle) * 1.7,
        math.sin(angle) * 1.7,
        angle * 0.2
    )
}

angle = t
radius = orbitScale * (0.74 + 0.16 * ringNoise(angle))

x = radius * math.cos(angle)
z = radius * math.sin(angle)

This uses if, else if, and math.fmod() to swap between three different radius profiles over one rotation.

def segmentRadius(angle) {
    phase = math.fmod(angle, math.tau)

    if (phase < math.tau / 3) {
        return 0.5 + 0.18 * math.sin(3 * angle)
    } else if (phase < (2 * math.tau) / 3) {
        return 0.72 + 0.1 * math.cos(5 * angle)
    }

    return 0.42 + 0.24 * math.sin(2 * angle)
}

radius = orbitScale * segmentRadius(t)

x = radius * math.cos(t)
z = radius * math.sin(t)

The character global can be used as a phase offset so the same script produces a different orbit per orbit character.

offset = character * (math.pi / 8)
angle = t + offset

radius = orbitScale * (
    0.62
    + 0.12 * math.sin(4 * angle)
    + 0.08 * math.cos(2 * t)
)

x = radius * math.cos(angle + 0.35 * math.sin(t / 2))
z = radius * math.sin(angle - 0.35 * math.cos(t / 2))