Automate ArmorPaint workflows using MiniC scripts. Access the application context, config, project state, and UI from scripts running in the built-in script editor.
Use this file to discover all available pages before exploring further.
ArmorPaint includes a built-in script editor powered by the MiniC interpreter, letting you automate tasks, inspect application state, and prototype new behaviours without recompiling the application. Unlike plugins — which are loaded at startup and run continuously — scripts are evaluated on demand by pressing Run in the Scripts tab. A script can, however, register persistent update callbacks so it continues to run across frames after execution. Both scripts and plugins share the same MiniC API surface, making it straightforward to promote a finished script into a proper plugin.
MiniC is a C-language subset. Standard library headers (#include <stdio.h> and similar), the C preprocessor, pointer arithmetic on arbitrary types, and other advanced C features are not available. Use only the registered builtins exposed through minic_api.c.
MiniC is a lightweight interpreter embedded directly in ArmorPaint. It understands a large subset of C syntax — structs, pointers, typed arrays, control flow, and function definitions — but it executes scripts through an interpreter rather than compiling them to native code. This makes it suitable for live automation and rapid prototyping directly inside the application.Key characteristics:
C-like syntax: functions, structs, if/else, for/while, return, and basic pointer operations work as expected.
Registered builtins: all ArmorPaint, engine, math, UI, file, and array APIs are pre-registered as native functions — no #include is required.
Garbage-collected heap: memory is managed by ArmorPaint’s GC; use gc_alloc / gc_free for manual control when needed.
printf support: the built-in printf formats a string and writes to the Console via console_log.
The Script editor is accessible as Workspace 3 (WORKSPACE_SCRIPT = 3 in enums.h) or by opening the Scripts tab in the right sidebar. The editor features:
Syntax highlighting loaded from text_coloring.json.
Line numbers and scroll-past-end mode.
Minimap — a scaled overview of the full script rendered as a tiny raster, visible when the panel is wider than 800 scaled pixels.
Autocomplete (Ctrl+Space) — lists registered builtin names that match the identifier prefix at the cursor.
Toggle comment (Ctrl+/) — adds or removes // on the current line.
Multiple script files — managed via a combo box; scripts are saved inside the project file as project.script_datas.
To run a script, click the Run button. ArmorPaint calls minic_eval on the current script text, which executes the top-level statements (typically your main() function call).
Use console_log, console_info, and console_error to print diagnostic output while developing scripts. Messages appear in the Console tab at the bottom of the UI.
These functions return live pointers to ArmorPaint’s global state structures. Fields are defined in types.h and exposed to MiniC as registered structs.
// Returns the full application context (tool, brush settings, viewport mode, etc.)context_t *script_get_context();// Returns user preferences (window size, plugin list, keymap, theme, etc.)config_t *script_get_config();// Returns the current project (assets, layers, materials, camera, scripts, etc.)project_t *script_get_project();
context_t fields (commonly used)
typedef struct context { mesh_object_t paint_object; // The active paint mesh object int ddirty; // Draw dirty flag — set to 2 to force a viewport redraw int pdirty; // Paint dirty int rdirty; // Render dirty void *material; // Active material slot void *layer; // Active layer slot void *brush; // Active brush slot int tool; // Active tool (tool_type_t) float brush_radius; float brush_opacity; float brush_hardness; float brush_scale; float brush_angle; int brush_blending; int viewport_mode; // viewport_mode_t int xray; bool capturing_screenshot;} context_t;
Scripts can persist across frames by registering callback functions with the engine.
// Register a function to be called every engine framevoid script_notify_on_update(void *fn);// Register a function to be called exactly once on the next framevoid script_notify_on_next_frame(void *fn);// Call fn once after delay seconds have elapsedvoid script_timer(float delay, void *fn);
ArmorPaint supports named stages (scenes). Scripts can switch stages directly or with a fade transition.
// Immediately switch to the named stagevoid script_set_stage(char *name);// Fade to black, switch to stage, then fade back invoid script_fade_to_stage(char *name);// Return the name of the currently active stage (or NULL)char *script_get_stage();
// Find a paint object in g_project by nameobject_t *script_get_object(char *name);// Tween an object's position toward `to` at the given speedvoid script_tween_to(object_t *obj, vec4_t to, float speed);// Switch the active tilesheet animation on the material of the given objectvoid script_set_tilesheet_anim(object_t *obj, char *anim);
// Set the viewport display mode (viewport_mode_t enum)void context_set_viewport_mode(int mode);// Set camera control style: 0 = Orbit, 1 = Rotate, 2 = Flyvoid context_set_camera_controls(int i);// Activate a tool by tool_type_t indexvoid context_select_tool(int i);// Returns the currently active paint mesh objectmesh_object_t *context_main_object();
// Save the current project; pass true to quit after savingvoid project_save(bool save_and_quit);// Get the current project file pathchar *project_filepath_get();// Override the current project file pathvoid project_filepath_set(char *s);
// Export textures to disk at the given path// Set bake_material to true to bake fill layers before exportingvoid export_texture_run(char *path, bool bake_material);
// Create an off-screen render target (gpu_texture_format_t for format)gpu_texture_t *gpu_create_render_target(int width, int height, int format);// Capture the viewport into target; x/y/w/h are normalised 0–1 UV coordinatesvoid viewport_capture_screenshot_to(gpu_texture_t *target, float x, float y, float w, float h);// Save the captured texture to disk (opens the file-save dialog)void viewport_save_texture(gpu_texture_t *screenshot);
Run it from the Scripts tab by clicking Run. Combine it with script_timer or script_notify_on_update if you need to trigger the export after a delay or condition.
The built-in rotate.c template from the Scripts menu shows how to use script_notify_on_update to run code every frame:
void on_update() { mesh_object_t *o = context_main_object(); transform_rotate(o->base->transform, vec4_z_axis(), 0.005); context_t *c = script_get_context(); c->ddirty = 2; // Force a viewport redraw each frame}void main() { script_notify_on_update(on_update);}
Setting context.ddirty = 2 after modifying a transform tells the renderer that the scene has changed and a new frame should be drawn. Without it, the viewport may not update.