---
description: "Parameter rules: reading/writing values safely, designing custom parameter pages, help text, sections, ordering, naming, ranges, and styles"
---
<!-- Generated by Embody/Envoy - Do not remove this comment -->
# Parameter Rules

## Reading and Writing Values

- **Always use `.eval()`** to get a parameter's current runtime value. `.val` only returns the constant-mode value.
- **Setting `.val` silently switches mode to CONSTANT** — destroys any active expression. Use assignment (`par.tx = 5`) only when you intend constant mode.
- **Toggle parameters** use `0`/`1` (not `"True"`/`"False"`). With `set_parameter`, pass `value="0"` or `value="1"`.
- **Explicit type conversion**: TD parameters remain TD objects internally. Convert with `int()`, `float()`, `str()` before passing to standard Python functions.

## Help Text

Every custom parameter MUST have `help` text set via `par.help = "..."`. Help text appears as a tooltip when users hover the parameter name in the dialog. Describe what the parameter controls and what its values mean.

- Good: `"Maximum number of rows displayed in the manager list. Set to 0 for unlimited."`
- Bad: `"Max rows"` (just restates the label)
- Unacceptable: no help text at all

In TDN files, include `"help": "..."` in the parameter definition. Embody exports and imports help text automatically.

## Section Breaks

Use `par.startSection = True` on the first parameter of each logical group. This draws a horizontal separator line above the parameter, visually grouping related controls.

In TDN: `"startSection": true` in the parameter definition.

## Parameter Ordering

Parameters appear in the order they are appended. Keep related parameters together and maintain a logical flow within each page:

1. Primary controls first (what users interact with most)
2. Secondary/advanced settings after
3. Read-only status/info parameters last

If reordering after creation, use `par.order` (accepts float values like `11.5` to insert between existing positions).

## Page Organization

Group parameters into pages by function. Use `comp.appendCustomPage('PageName')` — pages appear in creation order.

Common patterns:

| Page | Purpose |
|------|---------|
| Main / Settings | Primary configuration |
| Tags | Externalization tags, strategies |
| UI | Visual and display options |
| About | Version, build, author (read-only) |

## Naming

- First letter MUST be uppercase, rest lowercase letters and numbers only
- No underscores, spaces, or special characters
- Examples: `Speed`, `Maxrows`, `Autosave`, `Envoyenable`

## Style Selection

| Use case | Style | Notes |
|----------|-------|-------|
| On/off toggle | `Toggle` | Values are `0`/`1` |
| Fire-once action | `Pulse` | No persistent value |
| Enumerated choices | `Menu` | Set `menuNames` and `menuLabels` separately |
| Editable dropdown | `StrMenu` | Free-text input with suggestions |
| Numeric value | `Float` or `Int` | Set range properties (see below) |
| Text input | `Str` | Free-form string |
| File/folder path | `File` / `Folder` | Opens system dialog |
| Operator reference | `OP`, `COMP`, `TOP`, `CHOP`, `SOP`, `DAT`, `MAT` | Filtered by family |
| Section header | `Header` | Visual label only, no value |

## OP-Reference Parameter Values

Parameters that reference operators (Camera, Geometry, Lights, TOP, CHOP, SOP, DAT, MAT) follow the same rules as code — **never use absolute paths**. Use the shortest relative reference that resolves from the parameter's owner:

| Target location | Value format | Example |
|---|---|---|
| Sibling (same network) | Name only | `cam` |
| Child of self | `./child` | `./render1` |
| Up one level | `../name` | `../shared/lut` |

For references needing shortcuts or complex resolution, use expression mode instead of constant mode:

| Need | Expression |
|---|---|
| Parent shortcut | `parent.Scene.op('cam')` |
| Global shortcut | `op.Assets.op('texture1')` |

With `set_parameter`: use `value="cam"` for siblings, or `expr="parent.Scene.op('cam')"` for shortcut-based references.

## Numeric Ranges

For `Float` and `Int` parameters, configure the range:

| Property | Purpose |
|----------|---------|
| `min` / `max` | Minimum and maximum values |
| `clampMin` / `clampMax` | Whether to enforce min/max as hard limits (`True`) or allow values outside (`False`) |
| `normMin` / `normMax` | Slider range in the UI (what the slider covers visually) |

Example:
```python
p = page.appendFloat('Speed', label='Speed')[0]
p.default = 1.0
p.min = 0.0
p.max = 10.0
p.clampMin = True
p.clampMax = False    # Allow values above 10 via manual entry
p.normMin = 0.0
p.normMax = 5.0       # Slider covers 0-5, but values up to 10+ accepted
p.help = "Playback speed multiplier. 1.0 = normal speed."
```

## Read-Only Parameters

Use `par.readOnly = True` for status and informational parameters that users should see but not edit (version, build number, connection status).

## Defaults

Always set `par.default = value`. This enables "Revert to Default" in the TD parameter dialog and ensures TDN round-trips produce consistent results.

## Creating Custom Parameters

All `page.append*()` methods return a **ParGroup** (tuple-like), not a single `Par`. Index with `[0]` to get the `Par` object:

```python
page = comp.appendCustomPage('Settings')
pg = page.appendFloat('Speed', label='Speed')  # Returns ParGroup
p = pg[0]                                        # Get the Par
p.default = 1.0
p.help = "Playback speed multiplier."
p.startSection = True
```
