Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/armory3d/armorpaint/llms.txt

Use this file to discover all available pages before exploring further.

Plugins are MiniC scripts that integrate deeply with ArmorPaint at startup, adding new importers, UI panels, and node categories. They live in the plugins/ data folder and are toggled in Preferences → Plugins. When a plugin is enabled, ArmorPaint reads its name from config.plugins, loads the corresponding .c file, and evaluates it through the built-in MiniC interpreter. A plugin can register callbacks for the render loop, the sidebar UI, and its own teardown — allowing it to behave exactly like a built-in feature.
Plugins are executed by the MiniC interpreter — a C-like language subset embedded in ArmorPaint. Not every feature of standard C is available; in particular, the preprocessor, standard library headers, and direct system calls are absent. All APIs you call must be registered builtins exposed through minic_api.c.

Plugin Lifecycle

1

Plugin discovery

On startup, ArmorPaint reads config.plugins — a string_array_t listing enabled plugin filenames (e.g. "io_gltf.c"). Each name corresponds to a file under the plugins/ data directory.
2

plugin_start(plugin_name)

plugin_start reads the plugin file with data_get_blob, sets the internal _plugin_name context variable, then calls minic_eval_named to parse and execute the script. The resulting minic_ctx_t * is stored on the plugin_t so all registered callbacks can reference it later.
void plugin_start(char *plugin);
3

Plugin self-registration

The top-level code of the plugin script calls plugin_create() to allocate a plugin_t and registers its callbacks with plugin_notify_on_ui, plugin_notify_on_update, and plugin_notify_on_delete.
4

Runtime callbacks

Each frame the Plugins tab iterates over g_plugins and calls on_ui for every plugin that registered one. The update callback on_update is driven by the engine’s frame loop. Both run inside the plugin’s own minic_ctx_t.
5

plugin_stop(plugin_name)

When a plugin is disabled, plugin_stop looks up the plugin_t, calls on_delete (if registered), then frees the MiniC context and removes the entry from the global plugin map.
void plugin_stop(char *plugin);

Callbacks

CallbackWhen it fires
on_uiOnce per frame while the Plugins tab is open
on_updateEvery engine frame
on_deleteOnce, when the plugin is stopped or disabled

Core Plugin API Reference

Plugin Registration

Call these at the top level of your plugin script to create a plugin instance and bind callbacks.
// Allocate and register a new plugin_t; returns a pointer to it
void *plugin_create();

// Bind an on_ui callback — called every frame in the Plugins tab
void plugin_notify_on_ui(void *plugin, void *fn);

// Bind an on_update callback — called every engine frame
void plugin_notify_on_update(void *plugin, void *fn);

// Bind an on_delete callback — called when the plugin is stopped
void plugin_notify_on_delete(void *plugin, void *fn);

Custom Texture Importers

Register a handler for a file extension. ArmorPaint will call your function with the file path when a texture of that type is imported, and expect a gpu_texture_t * in return.
// Register a texture importer for the given file extension (e.g. "exr")
void plugin_register_texture(char *format, void *fn);

// Remove a previously registered texture importer
void plugin_unregister_texture(char *format);

Custom Mesh Importers

Register a handler for a mesh file extension. The function receives the file path and must return a raw_mesh_t * built with plugin_make_raw_mesh.
// Register a mesh importer for the given file extension (e.g. "obj")
void plugin_register_mesh(char *format, void *fn);

// Remove a previously registered mesh importer
void plugin_unregister_mesh(char *format);

Mesh Construction

plugin_make_raw_mesh allocates and initialises a raw_mesh_t from packed vertex data arrays. Positions and normals are stored as quantised 16-bit integers; indices are 32-bit unsigned integers. scale_pos is the world-space scale factor that maps the quantised values back to floating-point coordinates.
raw_mesh_t *plugin_make_raw_mesh(
    char        *name,
    i16_array_t *posa,      // position array  (4 × i16 per vertex: x, y, z, w)
    i16_array_t *nora,      // normal array    (2 × i16 per vertex)
    u32_array_t *inda,      // index array
    float        scale_pos  // world-space position scale
);

Node Categories

Plugins can inject new groups into the material or brush node search list. Pass a category name and an any_array_t * containing the node type strings to expose.
// Add a category to the material node editor
void plugin_material_category_add(char *category_name, any_array_t *node_list);

// Add a category to the brush node editor
void plugin_brush_category_add(char *category_name, any_array_t *node_list);

// Remove a previously added material category
void plugin_material_category_remove(char *category_name);

// Remove a previously added brush category
void plugin_brush_category_remove(char *category_name);

Custom Node Handlers

Once a category is registered, map each node type string to the function that generates its shader code:
// Set the shader-code-generation callback for a material node type
void plugin_material_custom_nodes_set(char *node_type, void *fn);

// Set the shader-code-generation callback for a brush node type
void plugin_brush_custom_nodes_set(char *node_type, void *fn);

// Remove a material node handler
void plugin_material_custom_nodes_remove(char *node_type);

// Remove a brush node handler
void plugin_brush_custom_nodes_remove(char *node_type);

// Get the active Kong shader context used by parser_material
void *plugin_material_kong_get();

Minimal Plugin Example

1

Create the plugin file

Create my_plugin.c and place it in the plugins/ data folder.
2

Create the plugin and register callbacks

// my_plugin.c  (MiniC)

void on_update() {
    // Runs every engine frame
}

void on_ui() {
    // Draw plugin UI inside the Plugins tab
    ui_text("My Plugin is running", UI_ALIGN_LEFT, 0);
}

void on_delete() {
    // Clean up when the plugin is stopped
    console_log("my_plugin unloaded");
}

void main() {
    void *plugin = plugin_create();
    plugin_notify_on_update(plugin, on_update);
    plugin_notify_on_ui(plugin, on_ui);
    plugin_notify_on_delete(plugin, on_delete);
}
3

Enable in Preferences

Open Preferences → Plugins, locate my_plugin.c in the file list, and enable it. ArmorPaint calls plugin_start("my_plugin.c") and your main() runs immediately.

Custom Mesh Importer Example

The following plugin registers a .msh importer. When a .msh file is imported, ArmorPaint calls import_msh with the file path; the function reads the buffer, assembles position/normal/index arrays, and returns a raw_mesh_t *.
// msh_importer.c  (MiniC)

raw_mesh_t *import_msh(char *path) {
    buffer_t    *buf  = data_get_blob(path);
    // ... parse buf into posa / nora / inda arrays ...
    i16_array_t *posa = i16_array_create(vertex_count * 4);
    i16_array_t *nora = i16_array_create(vertex_count * 2);
    u32_array_t *inda = u32_array_create(index_count);
    // ... fill arrays ...
    return plugin_make_raw_mesh("my_mesh", posa, nora, inda, 1.0);
}

void on_delete() {
    plugin_unregister_mesh("msh");
}

void main() {
    void *plugin = plugin_create();
    plugin_notify_on_delete(plugin, on_delete);
    plugin_register_mesh("msh", import_msh);
    console_info("msh_importer loaded");
}

Installing Plugins

1

Copy the plugin file

Copy your .c plugin file into the ArmorPaint plugins/ data folder. On most platforms this is next to the ArmorPaint executable or under the user data directory.
2

Enable the plugin

Either open Preferences → Plugins and tick the plugin’s checkbox, or drag and drop the .c file into the ArmorPaint window — import_plugin_run will copy it to the plugins/ folder automatically and log a confirmation in the console.
3

Verify

The plugin’s on_ui output will appear in the Plugins sidebar tab. Errors are printed to the Console tab.

Built-in Plugins

ArmorPaint ships with the following plugins compiled in when the WITH_PLUGINS flag is set. They are registered by plugins_init() at startup and serve as reference implementations.

io_gltf

Imports GLB and glTF meshes, including skinned animation frames, via io_gltf_parse and io_gltf_parse_skinned.

io_fbx

Imports FBX meshes and skinned animation frames via io_fbx_parse and io_fbx_parse_skinned.

io_exr

Imports OpenEXR HDR textures via io_exr_parse.

io_psd

Imports Photoshop PSD files with per-layer texture extraction via io_psd_parse.

io_svg

Imports SVG vector graphics as textures via io_svg_parse.

io_tiff

Imports TIFF textures (.tiff and .tif) via io_tiff_parse.

uv_unwrap

Provides automatic UV unwrapping via proc_uv_unwrap, accessible from the UV tab.

Build docs developers (and LLMs) love