This document describes scripting behavior implemented today.
Scripts are packaged under:
scripts/<script_id>.lua
<script_id>can be either a layer id from PSLlayers begin ... endor a frame id from PSLframes begin ... end.- Missing script for a layer/frame is valid (no-op).
- Unknown script file (no matching layer/frame id) fails context build.
- Non-
.luafiles inscripts/fail context build.
Render flow (scripting parts):
- Build layer runtime state (
visible=true) for all layers. - Build frame runtime state (
visible=true,value_override=nil) for all frames. - For each planned scripted layer, execute Lua script with globals
dataandlayer. - For each planned scripted frame, execute Lua script with globals
dataandframe. - Apply final layer/frame runtime state to draw pass.
Scripts run in an isolated Lua environment with a restricted global base.
The runtime exposes helper functions directly in script scope.
Formatting and math helpers:
percent(part, total) -> string- Computes
(part / total) * 100and appends%. - Example:
percent(5.0, 10.0)->"50%". totalmust not be0.
- Computes
currency(amount) -> string- Formats dollars with 2 decimals.
- Example:
currency(12.5)->"$12.50".
round(value, places) -> number- Rounds to decimal places.
- Example:
round(12.345, 2)->12.35.
save_amount(regular, sale) -> number- Returns
regular - sale, rounded to 2 decimals. - Example:
save_amount(9.99, 7.49)->2.5.
- Returns
unit_price(total, qty, unit) -> string- Example:
unit_price(5.99, 16, "oz")->"$0.37/oz". qtymust be greater than0.
- Example:
unit_price_each(total, count) -> string- Example:
unit_price_each(10.00, 4)->"$2.50 ea". countmust be greater than0.
- Example:
Value and string helpers:
default(value, fallback) -> any- Returns
fallbackonly whenvalueisnil. - Example:
default(nil, "N/A")->"N/A".
- Returns
concat(...) -> string- Concatenates arguments after string conversion.
- Example:
concat("BUY ", 1, " GET ", 1)->"BUY 1 GET 1".
pad_left(value, width, pad) -> string- Example:
pad_left(42, 5, "0")->"00042". padmust not be empty.
- Example:
pad_right(value, width, pad) -> string- Example:
pad_right(42, 5, "0")->"42000". padmust not be empty.
- Example:
truncate(value, max_len) -> string- Truncates to
max_lencharacters and appends…when needed. - Example:
truncate("Organic Honeycrisp Apples", 12)->"Organic Hon…".
- Truncates to
trim(value) -> string- Trims both sides.
trim_left(value) -> string- Trims leading whitespace.
trim_right(value) -> string- Trims trailing whitespace.
Structured/date helpers:
price_parts(amount) -> table- Returns
{ dollars = string, cents = string }. - Example:
price_parts(12.99)->{ dollars = "12", cents = "99" }.
- Returns
date_format(input, pattern) -> string- Input must be
YYYY-MM-DD. - Supports token replacement for
YYYY,MM, andDD. - Example:
date_format("2026-05-15", "MM/DD/YYYY")->"05/15/2026".
- Input must be
Color helpers:
parse_rgb(input) -> table- Parses space-separated RGB components into
{ r, g, b }. - Example:
parse_rgb("0.25 0.25 0.25")->{ r = 0.25, g = 0.25, b = 0.25 }.
- Parses space-separated RGB components into
parse_cmyk(input) -> table- Parses space-separated CMYK components into
{ c, m, y, k }. - Example:
parse_cmyk("0.25 0.25 0.25 0.25")->{ c = 0.25, m = 0.25, y = 0.25, k = 0.25 }.
- Parses space-separated CMYK components into
cmyk_to_rgb(c, m, y, k) -> table- Converts CMYK to RGB and returns
{ r, g, b }. - RGB outputs are clamped to
[0, 1].
- Converts CMYK to RGB and returns
local v = data.getSlot("slot_name")data.getSlot behavior:
- Reads top-level value from JSON object.
- Returns Lua
string,number,boolean, ornil. - Missing key returns
nil. - JSON arrays/objects fail hard with runtime error.
layer is a strict userdata with mutable fields:
layer.visible: boolean
Rules:
- Invalid
layer.visibleassignment fails render hard.
frame is a strict userdata with mutable fields:
frame.visible: booleanframe.value: string | nilframe.fill_color: { r: number, g: number, b: number } | nilframe.stroke_color: { r: number, g: number, b: number } | nilframe.stroke_width: number | nil(must be positive when set)frame.text_color: { r: number, g: number, b: number } | nil
Rules:
- Invalid
frame.visibleassignment fails render hard. - Invalid
frame.valueassignment fails render hard. frame.fill_color,frame.stroke_color, andframe.text_coloraccept RGB tables only (CMYK tables are rejected).- Invalid
frame.stroke_widthassignment fails render hard. frame.value = nilclears override.
When frame.value is non-empty string:
textboxuses script override text.imageuses script override as asset alias (package alias or alias created byloadimage).barcodeuses script override as barcode payload.
When frame.value is nil or empty string, renderer falls back to normal PSL evaluation.
When style overrides are set:
frame.fill_coloroverrides color used byfillon rect paths.frame.stroke_colorandframe.stroke_widthoverride color/width used bystrokeon line/rect paths.frame.text_coloroverrides text color fortextboxops.- Unused style overrides emit non-fatal render warnings.
- Script compile/runtime/type errors fail render immediately.
- Errors include frame id and frame index context.