Custom Operators
🔧 Creating a Custom Operator
Section titled “🔧 Creating a Custom Operator”You can register your own operator at runtime from Lua by providing a callback that mutates fields in the context. Custom operators work alongside built-in ones and participate in the scheduler plan. The binding does not infer write masks; keep callbacks lightweight and explicit about which fields they touch.
🛠️ Workflow
Section titled “🛠️ Workflow”- Register —
sim.sim_add_operator(ctx, name, fn[, dependencies])installs your callback. - Expose params (optional) —
sim.sim_operator_set_params(ctx, op, params)publishes typed params for UI/introspection. - Tweak params — adjust at runtime with
sim.sim_operator_param_set/enum_set/field_set.
Registration API
Section titled “Registration API”local op = sim.sim_add_operator(ctx, "bias", function(c) -- do work; return true/false or a SimResult codeend)
-- the newest operator index is sim_operator_count(ctx) - 1local op_index = sim.sim_operator_count(ctx) - 1dependencies(optional 4th arg) is an array of operator handles this operator depends on.- The callback receives the context only; read params via
sim_operator_param*using the operator index you captured.
📚 Parameter Schema (optional)
Section titled “📚 Parameter Schema (optional)”Expose typed parameters for UIs and introspection with sim_operator_set_params:
sim.sim_operator_set_params(ctx, op, { { name = "gain", type = "float", default = 1.0, min = 0.0, max = 10.0 }, { name = "field", type = "field", default = 0 }, { name = "mode", type = "enum", options = {"fast", "accurate"}, default = "fast" },})Supported type values: float, integer, boolean, enum, field. Enums require an options array of strings. Optional keys: default, min, max, required, description.
Update values later with:
sim.sim_operator_param_set(ctx, op_index, "gain", 0.5)sim.sim_operator_param_enum_set(ctx, op_index, "mode", "accurate")sim.sim_operator_param_field_set(ctx, op_index, "field", field_handle)💡 Example Patterns
Section titled “💡 Example Patterns”Constant Addition (with params)
Section titled “Constant Addition (with params)”local field = sim.sim_add_field(ctx, {256}, { fill = 0.0 })local bias_idxlocal bias_op = sim.sim_add_operator(ctx, "bias", function(c) local gain = sim.sim_operator_param(c, bias_idx or 0, "gain") or 0.0 local f = sim.sim_get_field(c, field) local v = f:values() for i = 1, #v do v[i] = v[i] + gain endend)
bias_idx = sim.sim_operator_count(ctx) - 1sim.sim_operator_set_params(ctx, bias_op, { { name = "gain", type = "float", default = 0.1, min = -10.0, max = 10.0 },})Clamp Values
Section titled “Clamp Values”local clamp_idxlocal clamp_op = sim.sim_add_operator(ctx, "clamp", function(c) local lo = sim.sim_operator_param(c, clamp_idx or 0, "lo") or -1.0 local hi = sim.sim_operator_param(c, clamp_idx or 0, "hi") or 1.0 local f = sim.sim_get_field(c, 0) local v = f:values() for i = 1, #v do if v[i] < lo then v[i] = lo end if v[i] > hi then v[i] = hi end endend)
clamp_idx = sim.sim_operator_count(ctx) - 1sim.sim_operator_set_params(ctx, clamp_op, { { name = "lo", type = "float", default = -1.0 }, { name = "hi", type = "float", default = 1.0 },})Sine Drive (self-contained state)
Section titled “Sine Drive (self-contained state)”local phase = 0.0local sine_idxlocal sine_op = sim.sim_add_operator(ctx, "sine_drive", function(c) local f = sim.sim_get_field(c, 0) local v = f:values() phase = phase + sim.sim_get_timestep(c) * 1.0 local s = math.sin(phase) for i = 1, #v do v[i] = v[i] + s endend)
sine_idx = sim.sim_operator_count(ctx) - 1sim.sim_operator_set_params(ctx, sine_op, { { name = "freq", type = "float", default = 1.0 },})💡 Notes & Tips
Section titled “💡 Notes & Tips”- Keep Lua operators lightweight; heavy per-element loops can bottleneck CPU execution. Use native operators when performance matters.
- The scheduler does not infer write masks for Lua operators; avoid side effects outside the fields you explicitly manage.
- Pair schemas with
sim_operator_param_*helpers to make callbacks configurable from UI or scripts. - If you need GPU or backend-specific kernels, implement a native operator instead of Lua callbacks.