Skip to content

Scripting api

There is a console command (called xs) in voxedit and a command line parameter in voxconvert to execute lua scripts for generating voxels. This command expects the lua script filename (.lua can be omitted) and the additional arguments for the main() method.


If you are new to lua you can read more about it on lua-users.


voxedit

Calling xs <script> help (in the script console) will print the supported arguments for the given script file in voxedit.


voxconvert

./vengi-voxconvert --script "<script> help" --scriptcolor 1 --input in.qb --output out.qb

--scriptcolor defines the color palette index that is given to the script as parameter.


By default the script files will be searched in a scripts folder next to where the binary is located and in the usual search paths (see configuration for more details). You can also give the full path to the script file.

There are two or three functions in each script: arguments, description and main. arguments returns a list of parameters for the main function. The default parameters for main are node, region and color. color is the palette index starting from 0 (the selected color in the palette panel in voxedit or the specified color index in voxconvert as given by --scriptcolor). description returns a brief description of what the script is doing.

So the first few parameters are the same for each script call. And the script defines any additional parameter for the main function by returing values in the arguments function.

Examples

Without parameters

function main(node, region, color)
    local volume = node:volume()
    local mins = region:mins()
    local maxs = region:maxs()
    for x = mins.x, maxs.x do
        for y = mins.y, maxs.y do
            for z = mins.z, maxs.z do
                volume:setVoxel(x, y, z, color)
            end
        end
    end
end

Execute this via console xs scriptfile

With one parameter

function arguments()
    return {
        { name = 'n', desc = 'height level delta', type = 'int', default = '2' }
    }
end

function description()
    return 'Example'
end

function main(node, region, color, n)
    [...]
end

Execute this via console xs scriptfile 1 where 1 will be the value of n. Omitting the 1 will add the default value from the argument list.

Download a file and import it

local function basename(str)
    local name = string.gsub(str, "(.*/)(.*)", "%2")
    return name
end

function main(_, _, _)
    local url = "https://github.com/vengi-voxel/vengi/raw/9c101f32b84f949ed82f7545883e80a318760580/data/voxel/guybrush.vox"
    local filename = basename(url)
    local stream = g_http.get(url)
    g_import.scene(filename, stream)
end

Find the best palette match

function main(node, region, color)
    -- find match (palette index) for red in the current palette (RGB value)
    -- this value can be used in e.g. volume:setVoxel(x, y, z, match)
    local match = node:palette():match(255, 0, 0)
    [...]
end

This will find the best match in the currently used palette and return the index.

Arguments

Supported types are:

  • int: min, max values are supported, too

  • float: min, max values are supported, too

  • enum: enum as a property specifies a list of string separated by ,

  • str: string input

  • colorindex: a color index from current palette (clamped)

  • hexcolor: a hex RGBA color string (e.g. #8B4513 or #8B4513FF) that is automatically matched to the closest color in the node's palette

  • bool:

The description field is just for the user interface of the script parameter list.

A default value can get set, too.

The order in the arguments table defines the order in which the arguments are passed over to the script.

API Reference

The scripting API provides several global objects and types for working with voxel data. The detailed documentation for each API is auto-generated and can be found in the linked pages below.

Global Objects

Global Description
g_algorithm General purpose algorithms
g_cmd Command execution
g_font Voxel font binding
g_http HTTP request functions
g_import Import images, palettes, and scenes
g_io File I/O operations
g_log Logging functions
g_lsystem Logging functions
g_noise Noise generation functions
g_normalpalette Create and manipulate palettes
g_palette Create and manipulate palettes
g_quat Quaternion creation
g_region Create and work with regions
g_scenegraph Access to scene graph for creating and managing nodes
g_sculpt Sculpting functions
g_shape Shape generation functions
g_sparsevolume Sparse volume functions
g_sys System utilities
g_var Console variable access
g_vec2, g_vec3, g_vec4, g_ivec2, g_ivec3, g_ivec4 Vector creation

Types

Type Description
Keyframe Animation keyframe data
Image Image data
Normal Palette Normal palette
Palette Color palette
Region Bounding region for volumes
SceneGraphNode A node in the scene graph (model, group, camera, etc.)
Stream Data stream for reading/writing
Volume Voxel volume data

Quick Access Examples

-- Access the scene graph
local node = g_scenegraph.get()

-- Create a new region
local myregion = g_region.new(0, 0, 0, 10, 10, 10)

-- Create a new palette
local pal = g_palette.new()
pal:load("built-in:minecraft")

-- Generate noise
local value = g_noise.noise3(g_vec3.new(x, y, z))

-- Create shapes
g_shape.cube(pos, width, height, depth, color)

-- HTTP requests
local stream = g_http.get("https://example.com/file.vox")
g_import.scene("model.vox", stream)

Other useful information

  • y going upwards - see basics for further details.

Brush scripts

VoxEdit supports Lua-based brush scripts that let you create custom interactive brushes. Unlike generator scripts (which use main() and are executed once via the xs command), brush scripts define a generate() function that is called each time the brush is applied. They also provide an interactive preview in the viewport.

Brush scripts are placed in the brushes/ directory and are automatically discovered when VoxEdit starts. Each script appears as its own selectable entry in the brush toolbar with a script-defined icon. Use the Rescan button in the brush panel to reload scripts after adding or modifying them.

Brush script structure

A brush script can define the following functions:

  • generate(node, region, color, ...) (required) - Called when the brush is applied. Same API as generator scripts but uses generate instead of main.
  • arguments() - Returns parameter definitions (same format as generator scripts).
  • description() - Returns a brief description string.
  • calcregion(cx, cy, cz, ...) - Returns 6 integers (minX, minY, minZ, maxX, maxY, maxZ) defining the brush region for preview. If not defined, a single voxel at the cursor is used.
  • settings() - Returns a table with script settings. Currently supports { preview = "simple" } to use outline-only preview instead of full voxel preview (useful for expensive scripts).
  • icon() - Returns an icon name string for the brush toolbar button (e.g. "circle", "star", "wand"). If not defined, a default icon is used. Available icon names include: blend, box, boxes, brush, circle, cloud, diamond, eraser, expand, flame, footprints, grid2x2, grid3x3, group, hammer, hexagon, image, layers, mountain, move, paintbrush, palette, penline, pencil, pipette, ruler, scan, scroll, snowflake, sparkles, spray, square, stamp, star, sun, swords, target, trees, triangle, wand, waves, zap.
  • gizmo() - Returns a table describing a 3D gizmo to display in the viewport, or nil for no gizmo.
  • applygizmo(translation, rotation, scale, operation) - Called when the user interacts with the gizmo. Returns true if the brush state was changed by the gizmo.

The generate() function receives the same global objects as generator scripts (g_noise, g_shape, g_palette, etc.). Additionally, brush scripts have access to g_brushcontext which. For further details see g_brushcontext

Brush script examples

Sphere brush

local brush = require "brushes.modules.brush"

function arguments()
    return {
        { name = 'radius', desc = 'Radius of the sphere in voxels', type = 'int', default = '3', min = '1', max = '15' }
    }
end

function description()
    return "Places a sphere of voxels at the cursor position"
end

function icon()
    return "circle"
end

function calcregion(cx, cy, cz, radius)
    return brush.sphereRegion(cx, cy, cz, radius)
end

function generate(node, region, color, radius)
    local volume = node:volume()
    local center = region:center()
    brush.fillSphere(volume, center.x, center.y, center.z, radius, color)
end

Gizmo support

Brush scripts can display interactive 3D gizmos in the viewport for advanced manipulation. Define gizmo() and applygizmo() functions:

local offset = { x = 0, y = 0, z = 0 }

function gizmo()
    return {
        position = { offset.x, offset.y, offset.z },
        operations = { "translate" },  -- "translate", "rotate", "scale",
                                       -- "translatex", "translatey", "translatez",
                                       -- "bounds", "line"
        snap = 1.0,
        localMode = false
    }
end

function applygizmo(translation, rotation, scale, operation)
    offset.x = offset.x + translation.x
    offset.y = offset.y + translation.y
    offset.z = offset.z + translation.z
    return false -- return true if the gizmo operation requires a preview volume regeneration
end

Brush utilities module

A shared Lua module brushes/modules/brush.lua provides common helper functions:

local brush = require "brushes.modules.brush"

function generate(node, region, color)
    local volume = node:volume()
    local center = region:center()
    brush.fillSphere(volume, center.x, center.y, center.z, 3, color)
end

Available functions: - brush.sphereRegion(cx, cy, cz, radius) - returns 6 values for sphere bounds - brush.fillSphere(volume, cx, cy, cz, radius, color) - fills a sphere - brush.fillSphericalShell(volume, cx, cy, cz, outerRadius, innerRadius, color) - fills a hollow sphere - brush.fillBox(volume, region, color) - fills a box region - brush.fillCylinder(volume, cx, cy, cz, radius, height, axis, color) - fills a cylinder (axis: "x", "y", "z") - brush.distanceSquared(x1, y1, z1, x2, y2, z2) - squared distance between two points

Differences from generator scripts

Generator Scripts Brush Scripts
Entry function main(node, region, color, ...) generate(node, region, color, ...)
Location scripts/ directory brushes/ directory
Invocation xs command or --script Selected as a brush in the toolbar
Preview None Live preview at cursor position
Region Selected model region Defined by calcregion() or cursor
Preview region N/A Optional calcregion() callback

Available scripts

animate.lua

Add animations to an existing model if you name the nodes properly.

xs animate.lua

cover.lua

Generates a new voxel on top of others with the current selected color and the specified height.

cover

xs cover.lua 1

grass.lua

Generate grass on top of voxels.

grass

xs grass.lua

grid.lua

Generates a grid with given color, thickness and size.

grid

xs grid.lua 1 1 5 5 5

noise.lua

Generates perlin noise with the frequency and amplitude as parameters with the current selected color.

noise

xs noise.lua 0.3 1.0

pyramid.lua

Generates a pyramid with the current selected color and with each level being 3 voxels high.

pyramid

xs pyramid.lua 3

thicken.lua

Thickens the voxel - take 1 voxel and convert to 8 voxels (creates a new node for the result).

thickenbefore thickenafter

xs thicken.lua 1

others

There are other scripts available in the repository.

Available modules

volume.lua

This module is here to ease the process of visiting all the voxels in a volume

Keep in mind the -1 is an empty voxel

local vol = require "modules.volume"

function main(node, region, color, emptycnt, octaves, lacunarity, gain, threshold)
    local visitor = function (volume, x, y, z)
        local color = volume:voxel(x, y, z)
        if color == -1 then
            -- empty voxel
        else
            -- solid voxel
        end
    end

    local condition = function (volume, x, y, z)
        -- add your checks here
        return true
    end
    vol.conditionYXZ(node:volume(), region, visitor, condition)
end