FollicleScript Expressions

FollicleScript is FollicleFX's expression language for procedural hair control. Write simple expressions that are evaluated in real time on 100,000+ strands.

Quick Start

Click the ƒx button next to any parameter to open expression mode.

0.8                          # Constant value
rand(index)                  # Random 0-1 per strand
rand3(0.7, 1.0, index)      # Random in range per strand
lerp(0.5, 1.0, v)           # UV-based gradient
v > 0.5 ? 1.0 : 0.5         # Conditional

Variables

Strand Properties

| Variable | Description | Range | |----------|-------------|-------| | index | Strand index | 0 to count-1 | | count | Total strand count | — | | length | Strand length | World units | | maxLength | Maximum strand length in system | World units | | width | Strand width | World units | | t | Position along strand | 0 (root) to 1 (tip) |

Spatial Coordinates

| Variable | Description | Range | |----------|-------------|-------| | u | UV X coordinate | 0–1 | | v | UV Y coordinate | 0–1 | | x | World X position | World units | | y | World Y position | World units | | z | World Z position | World units |

Clumping

| Variable | Description | |----------|-------------| | clump_id | Clump index (when using Clumping modifier) |

Constants

| Constant | Value | |----------|-------| | pi | 3.14159... | | tau | 6.28318... (2π) | | e | 2.71828... |

Operators

Arithmetic

+ - * / ^ (or **) ()

Comparison

< > <= >= == !=

Returns 1.0 (true) or 0.0 (false).

Ternary

condition ? value_if_true : value_if_false

Functions

Random & Noise

| Function | Description | |----------|-------------| | rand(seed) | Deterministic random 0–1 | | rand3(min, max, seed) | Random in range [min, max] | | noise(x) / noise(x, y) / noise(x, y, z) | Smooth organic noise |

Math

| Function | Description | |----------|-------------| | abs(x) | Absolute value | | sqrt(x) | Square root | | pow(x, y) | Power | | exp(x) | e^x | | log(x) | Natural logarithm | | sign(x) | Returns -1, 0, or 1 | | mod(x, y) | Modulo | | min(a, b) | Minimum | | max(a, b) | Maximum |

Trigonometry

sin(x) cos(x) tan(x) — Input in radians.

Rounding

floor(x) ceil(x) frac(x)

Interpolation

| Function | Description | |----------|-------------| | clamp(x, min, max) | Clamp to range | | lerp(a, b, t) | Linear interpolation | | smoothstep(edge0, edge1, x) | Smooth S-curve | | select(cond, a, b) | If cond > 0 then a, else b |

Texture Sampling

map(u, v)    # Sample bound texture at UV coordinate

Custom Variables (Dynamic Sliders)

Use $varName syntax to create UI sliders automatically:

$base + rand(index) * $variation

This creates "base" and "variation" sliders that you can adjust in real-time. Up to 16 custom variables supported.

Common Patterns

Per-Strand Randomization

rand(index)                      # Random 0-1
rand3(0.8, 1.2, index)          # Random range
clamp(rand(index), 0.2, 0.8)   # Clamped random

Gradients

v                                # Bottom to top (0→1)
1.0 - v                          # Top to bottom (1→0)
u                                # Left to right
lerp(0.5, 1.5, v)               # Custom range gradient

Along-Strand Effects

t                                # Root to tip (0→1)
1.0 - t                          # Tip to root
lerp(1.0, 0.1, t)               # Taper
smoothstep(0.0, 1.0, t)         # Smooth taper

Center/Edge Falloff

1.0 - abs(u - 0.5) * 2.0        # Dense in center
abs(u - 0.5) * 2.0              # Dense at edges

Per-Clump Variation

rand(clump_id)                   # Random per clump
0.5 + rand(clump_id) * 0.5      # Clumps vary 0.5–1.0
clump_id % 2                    # Alternating clumps

Conditional Logic

v > 0.5 ? 1.0 : 0.5             # Top/bottom split
rand(index) * 0.5               # Per-strand variation
index < 100 ? 0.8 : 1.0         # First 100 strands different

Noise Patterns

noise(u * 10, v * 10)            # 2D organic pattern
noise(u * 5, v * 5, index)      # Per-strand noise
0.7 + noise(u * 3, v * 3) * 0.3 # Noise in range

Modifier-Specific Examples

Clumping — Per-Clump Tightness

rand3(0.6, 0.9, clump_id)

Frizz — Per-Strand Variation

rand(index) * 0.5

Cut — Random Trim (Keep 80–100%)

rand3(0.8, 1.0, index)

Cut — Remove 1–3% Per Strand

1.0 - rand3(0.01, 0.03, index)

Density — UV-Based

lerp(0.5, 1.0, v)

Width — Taper to Tips

lerp(1.0, 0.1, t)

Coil — Per-Strand Count Variation

5.0 + rand(index) * 3.0

Tips

  1. Use index for per-strand randomization — consistent, deterministic
  2. Use t for along-strand effects — 0 at root, 1 at tip
  3. Use clump_id for per-clump variation — all strands in a clump get the same value
  4. Clamp extreme valuesclamp(expr, 0.2, 0.8) avoids outliers
  5. Start simple — test with constants, add complexity gradually
  6. Custom variables for tweaking$varName creates real-time sliders
  7. Most parameters expect 0–1 — check the parameter's range

Performance Notes

  • Expressions are evaluated in real time on all strands simultaneously
  • Simple expressions (arithmetic, rand) are very fast
  • Complex expressions (noise, trig) are slightly slower
  • No practical limit on expression complexity