Everyone understands + - * /, but % usually surprises people who haven't done much coding before.
% is modulo. When you first learn to divide in primary school, and you do remainders, well, modulo is the remainder. That's it.
Ask a 10 year old kid '5 divided by 2' , they'll tell you '2, remainder 1'. In the same way, 5 % 2 = 1.
This is useful because it sets up loops; when the first and second number are the same, the remainder is 0. If you're doing modulo by 5 on an input that smoothly increases, like @ptnum or @Frame, you'll get a sawtooth waveform that goes 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4...
@P.y = @ptnum % 5;
Modulo works on fractional values too, so you can give it a float input, and smoothly varying float input like @Time, you still get a sawtooth pattern:
@Cd.r = @Time % 0.2;
Lots of effects involve setting up loops, modulo gives you an easy way to setup inputs or outputs that loop.
Making smooth things stepped via quantising
Go back to the usual trick of P.y based on distance to the origin:
float d = length(@P); d *= ch('scale'); @P.y = d;
The result is a smooth funnel shape. What we can do is make this steppy. Imagine we had slowly increasing fractional values:
1.0, 1.1, 1.2, 1.3, 1.4 ... 1.8, 1.9, 2.0, 2.1, 2.2, 2.3 ...
If we removed everything after the decimal place, you'd get this:
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3
Ie, the smoothly increasing original values are now stepped. But what if the original values are really small, say ranging from 0.001 to 0.003? If you remove values after the decimal point, it all goes to 0, thats no good. Similarly, if the values were between 1000 and 4000, it won't make much of a difference.
The trick is to multiply all the numbers by a factor to push the interesting values to the left of the decimal point, then remove stuff after the decimal point, then divide by the original number. If you put that steppy factor on a channel slider, you have an easy way to dial in the size of the steps. The vex function to remove stuff after the decimal point is trunc, short for truncate.
float d = length(@P); d *= ch('scale'); float f = ch('factor'); d /= f; d = trunc(d); d *= f; @P.y = d;
Faking trunc with a chramp
An equally valid way to get stepping is to draw in a stepped graph into a channel ramp. Whatever is more useful to you at the time. Just remember that you'll probably need 2 scaling functions, the first to bring your thing into a 0 to 1 range for the channel ramp, and a second to scale it to where you need the values to be after stepping.
float d = length(@P); d *= ch('pre_scale'); d = chramp('my_stepped_ramp', d); d *= ch('post_scale'); @P.y = d;