Describing user-settable parameters

Various entities in the frontscope system, particularly Sequences and Visualizers, can employ user-settable parameters for which controls will appear in the browser user interface (UI). The value selected for each parameter will be reflected in a property of the object implementing the entity. But many aspects of each parameter (what type of values it can have, how it should appear in the UI, and so on) must be specified in the TypeScript code by an object with a particular structure: an instance of the ParamInterface, documented here. (Then the collection of all of these specification objects for a given Visualizer, for example, is supplied to its implementation as its "parameter description," as detailed in the visualizer building documentation.)

All of the properties that can be specified for a parameter are enumerated on this page. Most of them are data properties, and each of these is listed with its data type. To understand these data types, it is important to know that the ParamInterface is generic, depending on a ParamType from the following table of possibilities. Most importantly, each ParamType is associated with a TypeScript data type, which will be the type of the property in the Sequence or Visualizer associated with the parameter. In the table, the designation "input" in the "Rendering in UI" column means a standard browser text input box.

ParamType Associated TypeScript type Rendering in UI Comments
BOOLEAN boolean checkbox true or false
COLOR string color picker hex color code
COLOR_ARRAY string[] color picker can add/delete color blocks
NUMBER number input arbitrary floating point value
INTEGER number input must be a whole number
BIGINT bigint input must be a whole number
EXTENDED_BIGINT bigint | ±Infinity input
FORMULA MathFormula input mathjs formula expression
ENUM number drop down menu restricted to a list of options
STRING string input arbitrary string value
NUMBER_ARRAY number[] input whitespace- or comma-separated
BIGINT_ARRAY bigint[] input whitespace- or comma-separated
VECTOR p5.Vector input 2 numbers separated by whitespace or ,

In the following descriptions of the ParamInterface properties, the ParamType specified for the instance is abbreviated as PT, and its associated TypeScript type is written as RealizedPropertyType[PT]. Also, a question mark after the property name means that it is optional whether or not to specify that property; all other properties are required.

default: RealizedPropertyType[PT]
Specifies the default value that this parameter will have in the UI when the entity it belongs to is being displayed. If the user does not enter any other value, this default value will show up as the corresponding property of the entity.
type: PT
The ParamType of the parameter, from the above list. Note that if you have imported ParamType into your code, this property must be specified with the ParamType. prefix, for example, as ParamType.NUMBER_ARRAY.
from?: {[key: string]: number | string}
If the type property is ParamType.ENUM, this property should be set to the Enum object from which the parameter value will be selected.
displayName: string | ((dependency: never) => string)
The text label in the UI for the control corresponding to this parameter. It may be specified as one specific string (and usually is), but if the visibleDependency property of the ParamInterface (see below) is set, it can also be specified by a function that takes the value of the visibleDependency parameter and returns a string for the label. That way, the displayed label can depend on the value of another parameter, which is occasionally useful.
required: boolean
Specifies whether the parameter must be set. When this property is true, an empty input in the UI will cause an error, rather than using the value of the default property.
placeholder?: string
The placeholder text that appears in the input box for the parameter. If the placeholder property is not specified, the string representation of the default property is used instead.
placeholderAlways?: boolean
Whether the placeholder should always be displayed, even when something has been entered in the text box. (The usual behavior is to blank the placeholder as soon as there is input.) description?: string
Additional explanatory text about the parameter to display.
hideDescription?: boolean
If this property is specified as true, the description will appear as a tooltip that pops up when the parameter's control in the UI is hovered. Otherwise, the description will be (always) shown adjacent to the the control.
visibleDependency?: string

If this property is specified, the value of the parameter whose name is given by the visibleDependency property will determine whether or not the control for this parameter is visible in the UI. The idea is that the setting for one parameter may (or may not) make the value of another parameter irrelevant. If visibleDependency is set, then just one of the visibleValue or visiblePredicate properties must also be set to determine when this parameter will in fact be shown.

For example, if this parameter is 'backgroundColor' but it should only be displayed in the UI if the 'mode' parameter has the value 'color' (instead of, say, 'greyscale'), then on this parameter set the visibleDependency property to 'mode' and the visibleValue property to 'color'. On the other hand, if 'backgroundColor' should only be displayed when 'mode' is not 'greyscale' (instead of, say, 'rainbow' or 'pastels'), then still set visibleDependency to 'mode' but set the visiblePredicate property to

(dependentValue: string) => dependentValue !== 'greyscale'

Note that parameters with a visibleDepenency setting will be displayed with a distinctive appearance, when they are visible.

Another common use for the visibleDependency property is to make one or more parameters visible only if a checkbox corresponding to some other BOOLEAN parameter is checked. This feature allows you to show a core set of parameters at first, and allow the user to check a box to reveal additional, more detailed controls.

visibleValue?: unknown
If the visibleDependency property is specified, gives the value for the parameter named by visibleDependency which will cause this parameter to be displayed. Note that visibleValue only matters if the visiblePredicate property is not specified.
visiblePredicate?: (dependency: never) => boolean
If the visibleDependency property is specified, then this parameter will only be visible in the UI if the function given as the visiblePredicate property of this parameter returns true when called with the value of the parameter named by the visibleDependency property. Note that the never type above simply means that the argument to the visiblePredicate function may have any type.
level?: ParamLevel
An integer giving the hierarchical level of the parameter; this value is used to determine aspects of the layout of the parameter entry area in the UI such as its indentation, spacing, and/or border. Currently only parameter levels 0 ("top-level") and 1 ("subordinate") are defined. If this property is not specified, a level of 1 is used if the parameter has a visibleDependency, and level 0 is used otherwise.
symbols?: readonly string[]
If the type property is ParamType.FORMULA, this property gives the list of predefined symbols (variables and function symbols) that are allowed to occur in the formula. The entity using the resulting MathFormula will have to supply the values of those symbols when it calls computeWithStatus() on the MathFormula.
validate?(value: RealizedPropertyType[PT], status: ValidationStatus): void

This method, if it is defined, acts as an additional validity check on input values of the parameter. It must take a possible value of the parameter (that has been entered in the UI), and update the supplied status with any errors or warnings based on that value for the parameter. For example, if the speed parameter with type equal to ParamType.NUMBER must be positive and if the visualization may take too long to update if the speed is bigger than 16, then its validate method might look like

    validate: function(value: number, status: ValidationStatus) {
        if (value <= 0) status.addError('must be positive')
        else if (value > 16) {
            status.addWarning('when larger than 16, display may lag')
        }
   }

Note that if a required condition on a parameter can be captured in this sort of validation function, it is better to use this facility rather than check the condition later on in the associated entity's code. This way the error is caught earlier, with better feedback to the user, and can prevent your Sequence or Visualizer code from wasting time on useless inputs.

As a technical note, validate methods should generally be regular
JavaScript functions as opposed to "arrow functions," as they are called
with the this-context set to the entity (usually Sequence or Visualizer)
on which this parameter resides, so that the validate method may use
other data (but not other parameter values) of the entity in its
checks.
updateAction?(newValue: string, oldValue: string): void
This method, if it is defined, will be executed whenever the parameter takes on a new valid value, although it is called with the previous and newly-updated string forms of the parameter, not the realized values, since this method is called before all of the parameters of the entity have been fully validated (although this one parameter is guaranteed to be valid. Like the validate method, is is called with its this-context set to the entity (usually Sequence or Visualizer) on which this parameter resides.