-
-
Notifications
You must be signed in to change notification settings - Fork 1
Custom Plugins
Bobby Comet edited this page Aug 2, 2026
·
3 revisions
This page is the authoring companion to Plugins. A plugin is never executable Python: it is a manifest entry (metadata + Lua template strings) that Conky Studio registers into the node registry and code generator.
plugins.json → loader.validate + register → NodeSpec in palette
↘
lua_gen: logic_expr OR draw_node_* body
↘
Conky runs the generated render.lua
-
logic → substituted
lua_exprbecomes the value assigned toSRC['node_id']in dependency order. -
visual → substituted
lua_draw_bodyis the body oflocal function draw_node_<id>(cr, W, H). - Optional lua_helpers → emitted once per plugin type the first time that type is drawn in a build.
Substitution is plain string replace of {property_key}; not str.format(), not Python eval.
Top level:
{
"api_version": "1.1",
"updated_at": "2026-08-02",
"plugins": [ /* PluginNode objects */ ]
}
{
"id": "logic.example_clamp",
"category": "logic",
"label": "Example Clamp",
"author": "you",
"version": "1.0.0",
"description": "Clamp a number into [lo, hi].",
"color": "#5f8fd6",
"subcategory": "Plugins",
"output_kind": "number",
"tags": ["math", "clamp"],
"simple_mode": true,
"homepage": "",
"license": "",
"properties": [
{
"key": "value",
"label": "Value",
"kind": "float",
"default": 50,
"minimum": -1e9,
"maximum": 1e9,
"bindable": true,
"accepts": ["number", "percent", "celsius"],
"group": "Input",
"help": "Input to clamp"
},
{
"key": "lo",
"label": "Min",
"kind": "float",
"default": 0,
"group": "Range"
},
{
"key": "hi",
"label": "Max",
"kind": "float",
"default": 100,
"group": "Range"
}
],
"lua_expr": "math.min({hi}, math.max({lo}, {value}))"
}
Visual sketch:
{
"id": "visual.plugin.example_box",
"category": "visual",
"label": "Example Box",
"author": "you",
"version": "1.0.0",
"description": "Filled rectangle.",
"color": "#8a5fd6",
"subcategory": "Plugins",
"simple_mode": true,
"tags": ["shape"],
"properties": [
{ "key": "x", "label": "X", "kind": "float", "default": 20, "group": "Position" },
{ "key": "y", "label": "Y", "kind": "float", "default": 20, "group": "Position" },
{ "key": "width", "label": "Width", "kind": "float", "default": 80, "group": "Shape" },
{ "key": "height", "label": "Height", "kind": "float", "default": 40, "group": "Shape" },
{ "key": "color", "label": "Colour", "kind": "color", "default": "#4fd1c5", "group": "Style" },
{ "key": "opacity", "label": "Opacity", "kind": "float", "default": 1, "minimum": 0, "maximum": 1, "step": 0.05, "group": "Style" }
],
"lua_draw_body": "local r, g, b = {color}\ncairo_set_source_rgba(cr, r, g, b, {opacity})\ncairo_rectangle(cr, {x}, {y}, {width}, {height})\ncairo_fill(cr)"
}
| Rule | Detail |
|---|---|
| id | Must match ^(logic|visual)(\.[a-z][a-z0-9_]*)+$ — e.g. logic.clamp, visual.plugin.ring
|
| category | Only logic or visual
|
| Placeholders | Only {property_key}. Every {name} in lua_expr / lua_draw_body / lua_helpers must be a declared property key (hard error otherwise) |
| cr, W, H | Bare names in draw bodies; not {cr}, {W}, {H}
|
| color kind | Substituted as r, g, b float literals for Cairo (e.g. 0.31, 0.82, 0.77), not hex |
| bool | Substituted as Lua true / false via the resolved expression path (bindable uses SRC[...]) |
| output_kind (logic) |
percent · celsius · number · text · category · boolean
|
| Property kinds |
float · int · bool · color · string · enum · font · path · code
|
| enum | Requires non-empty choices (optional choice_labels) |
| Property key |
^[a-z][a-z0-9_]*$, unique within the plugin |
| Collision | Cannot register an id that already belongs to a built-in (or non-plugin) type. Re-install of a previously loaded plugin id is allowed |
| Field | Meaning |
|---|---|
key |
Placeholder name and storage key |
label |
Property panel label |
kind |
Editor widget + substitution style |
default |
Used when unbound |
minimum / maximum / step
|
Numeric editors |
choices / choice_labels
|
Enum values/display labels |
bindable |
May accept a wire |
accepts |
Allowed source/logic KIND_* values for wires |
help |
Tooltip |
group |
Section heading in the property panel |
- Must evaluate to a single expression (or an IIFE
(function() ... end)()if you need locals). - Use
{key}for every input; the loader replaces with a Lua expression (literal orSRC['...']). - Prefer defensive
tonumber(...) or 0when accepting mixed kinds. - For persistent state across frames, use a slot property + a table in
lua_helpers(see officiallogic.smooth), not globals that collide between instances.
Example pattern (helpers once):
"lua_helpers": "local _cs_plugin_smooth = _cs_plugin_smooth or {}\n",
"lua_expr": "(function()\n local k = {slot}\n local v, a = {value}, {alpha}\n ...\nend)()"
- Statements only (no wrapping
function); the generator addslocal function draw_node_...(cr, W, H). -
cris the Cairo context;W/Hare window size. - Framework helpers from the runtime are available:
wall_clock,clamp,lerp,rounded_rect,safe_number,studio_draw_text,studio_heat_rgb, etc. - Create patterns carefully; destroy gradient patterns if you create them.
- Prefer
tonumber({value}) or 0for bindable numbers.
- One plugin per concern — don’t ship a mega-node with twenty unrelated modes unless the UI stays clear.
-
Group properties —
Position,Shape,Data,Style,Animation,Drive. -
Id namespace —
visual.plugin.*for third-party visuals avoids clashing with future built-ins. - Indent Lua with spaces inside the JSON string; keep lines readable (multi-line strings are fine).
-
Tags — short tokens for search (
gauge,animation,network). - simple_mode: true only if the node is useful with defaults and few knobs.
- Version semver; bump when property keys or behaviour change incompatibly.
from conkystudio.plugins.loader import load_manifest_file, validate_only
m = load_manifest_file("my-pack.json")
errors = validate_only(m)
print(errors) # [] = OK
Or install into a test session via Tools → Plugins and check the palette + Build.
- Write
my-pack.jsonwithapi_version1.1and apluginsarray. - Run
validate_only(or open in the dialog and read errors). - Copy to
~/.config/conky-studio/plugins/or Install from the dialog (persists toinstalled-plugins.json). - Create a tiny project: one source → your logic (if any) → your visual → Live Preview.
- Document required ids when sharing the
.jsonproject.
- Does not
evalorexecPython from the pack. - Does not auto-install the entire remote catalogue on startup.
- Does not support
source.*orcanvas.*plugins. - Does not sandbox Conky’s Lua privileges.