Config forms
The pre-run form a script declares: number, text, checkbox, select, color, brush and palette fields.
A script can declare a small form that's shown before it runs. What the user fills in arrives as the app.config table, keyed by each field's id. Fields are plain data — a script never describes UI — and the editor renders and validates them. Colors, brushes and palettes are how a script asks for something from the user's own stuff: the engine never reads their libraries, so a script gets exactly what they pick.
number— A number input. In Lua: number. Options:default(The starting value.);min(The smallest allowed value.);max(The largest allowed value.);optional(Allow it to be left empty.);randomMin / randomMax(The range Randomize picks from, inside min..max (default min..max; without both bounds Randomize leaves it alone). Whole numbers when the bounds and default are.);randomize(false keeps the value when the user randomizes the form.).text— A line of text. In Lua: string. Options:default(The starting text.);optional(Allow it to be left empty.).checkbox— An on/off switch. In Lua: boolean. Options:default(Whether it starts checked.);randomize(false keeps the value when the user randomizes the form.).select— A choice from a fixed list. In Lua: string (the chosen option's value). Options:options(The choices, each { value, label }.);default(The value selected at the start.);randomize(false keeps the choice when the user randomizes the form.).color— A color, picked with the editor's color picker — with the sprite's palette and the recent colors one click away. Give each role its own field (leaf light, leaf dark, bark…) and the user chooses them all. In Lua: string, "#rrggbb" (or "#rrggbbaa" with alpha) — accepted directly wherever a color goes. Options:default(The starting color, "#rrggbb" or "#rrggbbaa" (black if omitted).);randomize(true lets Randomize pick a color too (it keeps the alpha). Off by default: most scripts' colors are tuned.).brush— One of the user's saved brushes, chosen from their brush library. In Lua: table { name, width, height, mask } — pass it to app.defineBrush; absent when optional and left empty. Options:optional(Allow it to be left empty (then app.config.<id> is nil).).palette— One of the user's saved palettes, chosen from their palette library. In Lua: list of "#rrggbb" (or "#rrggbbaa") strings — pass it to app.setPalette, or pick from it with color math; absent when optional and left empty. Options:optional(Allow it to be left empty (then app.config.<id> is nil).).
Example form (JSON) and the script that uses it:
{
"fields": [
{
"id": "leafLight",
"type": "color",
"label": "Leaf (light)",
"default": "#6cc24a"
},
{
"id": "leafMid",
"type": "color",
"label": "Leaf (mid)",
"default": "#3a8f4a"
},
{
"id": "leafDark",
"type": "color",
"label": "Leaf (dark)",
"default": "#23603a"
},
{
"id": "barkLight",
"type": "color",
"label": "Bark (light)",
"default": "#8a5a35"
},
{
"id": "barkDark",
"type": "color",
"label": "Bark (dark)",
"default": "#5a3a22"
},
{
"id": "stamp",
"type": "brush",
"label": "Leaf brush",
"optional": true
}
]
}local layer, frame = app.getActiveLayerId(), app.getActiveFrameId()
local c = app.config
-- trunk: two bark colors the user chose
app.drawRectangle(layer, frame, 14, 20, 17, 31, { color = c.barkDark, fill = "filled" })
app.drawRectangle(layer, frame, 14, 20, 15, 31, { color = c.barkLight, fill = "filled" })
-- canopy: three leaf colors, with the user's own brush if they picked one
if c.stamp then app.defineBrush("leaf", c.stamp) end
for i, color in ipairs({ c.leafDark, c.leafMid, c.leafLight }) do
app.drawStroke(layer, frame, { { 8, 18 - i * 4 }, { 24, 18 - i * 4 } },
{ color = color, brush = c.stamp and "leaf" or nil, brushSize = 4 })
endBranching
Any field can carry a when — { "<earlier field id>": [values] } — and then shows only while each named select holds one of those option values (or checkbox is true/false) and is itself shown. Conditions only look back at earlier selects and checkboxes, so they chain to any depth: switch the root and its whole branch hides. A hidden field is left out of app.config, so the script falls back to its own default — read every field as optional.
{
"fields": [
{
"id": "kind",
"type": "select",
"label": "Kind",
"options": [
{
"value": "broadleaf",
"label": "Broadleaf"
},
{
"value": "conifer",
"label": "Conifer"
}
],
"default": "broadleaf"
},
{
"id": "crown",
"type": "select",
"label": "Crown",
"options": [
{
"value": "round",
"label": "Round"
},
{
"value": "weeping",
"label": "Weeping"
}
],
"when": {
"kind": [
"broadleaf"
]
}
},
{
"id": "droop",
"type": "number",
"label": "Droop",
"min": 0,
"max": 100,
"randomMin": 20,
"randomMax": 80,
"when": {
"crown": [
"weeping"
]
}
},
{
"id": "tiers",
"type": "number",
"label": "Tiers",
"min": 2,
"max": 12,
"when": {
"kind": [
"conifer"
]
}
},
{
"id": "newLayer",
"type": "checkbox",
"label": "Draw on a new layer",
"randomize": false
}
]
}Randomize
Every form gets a Randomize button. It rolls each number within randomMin..randomMax (default min..max; a number without both bounds is kept), picks any select option and flips checkboxes; colors only roll with randomize: true, and text, brushes and palettes are never touched. Set randomMin/randomMax to the range that still looks good, and randomize: false on settings that aren't about the art (new layer, respect selection...).
As Markdown: config-forms.md.