# Laser Expression Editor

This guide will cover the basics of the Laser Projector expression editor and how to use its various functions! It's an exciting guide filled with drama, betrayal, brotherhood, power, and other names for sadness.

# Brief Overview

The laser expression editor allows you to write math expressions to control the projection pattern on the laser projector.

# Expression Reference

## Outputs

The outputs are the parameters that control the look and behaviour of each individual beam. This includes where they point at, as well as their colours. Be sure to define each of the following outputs in your expressions.

Output | Description |
---|---|

x' | The output horizontal coordinate of the laser beam, ranging from -100 (left) to 100 (right). |

y' | The output vertical coordinate of the laser beam, ranging from -100 (down) to 100 (up). |

h | The beam hue, ranging from 0° to 360°. This value is wrapped, so the value is always remapped to this range. 0 means red, 120 means green, and 240 means blue. All values inbetween are interpolated, so you can pick any colour in the spectrum. |

s | The beam saturation, ranging from 0 to 1. 0 results in a white beam, and 1 results in a fully saturated colour. |

v | The beam value (brightness), ranging from 0 to 1. 0 results in the beam being invisible, and 1 results in a fully visible beam. |

## Inputs

These are parameters that you can feed into the output expressions. Some of the parameters give an indication of which laser beam it is, while others can be used to cause the beams to move dynamically.

Input | Description |
---|---|

x | The input horizontal coordinate taken from the projection base (shape or grid), ranging from -100 (left) to 100 (right). |

y | The input vertical coordinate taken from the projection base (shape or grid), ranging from -100 (down) to 100 (up). |

index | The unique number associated with the current beam. The index on the first beam is 0, and the last beam equal to the number of beams minus 1. |

count | The total amount of laser beams in the current projection. In most shapes this is equal to 32. |

fraction | This is equal to the index of the beam divided by the total amount of beams. |

pi | 3.14159265358979323846264338327950288419716... |

tau | Two times pi. Useful for quickly converting radians per second to Hertz, when using functions such as sin(), cos(), and tan(). |

time | The current time, in seconds, on the local system (your computer). |

projectionTime | The time, in seconds, since the expression was activated. |

projectionStartTime | The local time, in seconds, when the expression was activated. |

## Functions

Function | Description |
---|---|

sin('angle') | Returns the sine of 'angle'. |

cos('angle') | Returns the cosine of 'angle'. |

tan('angle') | Returns the tangent of 'angle'. |

asin('float') | Returns the arcsine of 'float'. |

acos('float') | Returns the arccosine of 'float'. |

atan('float') | Returns the arctangent of 'float'. |

atan2('x', 'y') | Returns the arctangent of 'y'/'x' with consideration for divide-by-zero edge cases. |

sqrt('float') | Returns the square-root of 'float'. |

min('a', 'b') | Returns the smaller value of 'a' or 'b'. |

max('a', 'b') | Returns the larger value of 'a' or 'b' |

floor('float') | Returns the value 'float' rounded down to the nearest whole number less than 'float' |

ceil('float') | Returns the value 'float' rounded up to the nearest whole number greater than 'float' |

round('float') | Returns the value 'float' rounded to the nearest whole number. |

abs('float') | Returns the absolute value of 'float' ('float' < 0 ? -'float' : 'float'). |

rand() | Returns a random number between 0.0 and 1.0. |

if('float', 'a', 'b') | Returns 'a' if 'float' is 1 or greater otherwise returns b. |

lerp(frac', 'a', 'b') | Interpolates between 'a' and 'b' using 'frac' (afrac + b(1-frac)). |

## Operators

Maths and logic. What more is there to say?

Operator | Description |
---|---|

= | Equal. Assigns the value of the right operand to the left operand. You can use this to declare your own variables. |

+ | Add. Returns the sum of the left and right operands. |

- | Subtract. Returns the left minus the right operand. |

* | Multiply. Returns the product of the left and right operands. |

/ | Divide. Returns the left divided by the right operand. |

^ | Exponent. Returns the left operand to the power of the right operand. |

% | Modulo. Returns the remainder of the left operand divided by the right operand. |

< | Less than. Returns 1 when the left operand is less than the right, otherwise returns 0. |

> | Greater than. Returns 1 when the left operand is greater than the right, otherwise returns 0. |

<= | Less than or equal. Returns 1 when the left operand is less than the right, otherwise returns 0. |

>= | Greater than or equal. Returns 1 when the left operand is greater than the right, otherwise returns 0. |

== | Equal to. Returns 1 when the left operand is equal to the right, otherwise returns 0. |

& | And. Returns 1 if both the left side and right side are true. |

| | Or. Returns 1 if either the left side and right side are true. |

! | Not. Returns 1 if the expression is false and 0 if the expression is true (inverts the value). |

# | Comment. Allows you to put plain text behind it, without getting compiled. |

# Example Expressions

## Simple sine wave

A sine wave is added to the vertical output component of the projector.

```
#wave parameters:
phase = tau*time; #wave movement (1 cycle per second)
frequency = 0.05; #wave width
amp = 10; #wave height
#output:
x' = x;
y' = y + amp * sin( frequency*x + phase );
```

## Blink

Scales the shape up and down instantaneously.

```
#cycle duration in seconds
rate = .2;
#wrap time to cycle duration (ramainder of time / rate)
wraptime = time % rate;
#'>' operator gives 1 if wraptime > rate/2, otherwise 0
isscaleddown = wraptime > rate/2;
#do scaling
scaledownamount = .5;
scale = 1 - isscaleddown * scaledownamount;
#output:
x' = x * scale;
y' = y * scale;
```

## Color Wheel

Changes the color of each laser based on its angle from center.

```
#atan2 returns the angle between 0,0 and y,x
#atan2's range is (-pi,pi], here we convert to (0, 1]
#we first divide by 'pi' to give us the range (-1, 1]
#then we add 1 to get (0, 2]
#finally, we divide by 2 to get (0, 1]
diskposition = ( 1+atan2(y,x)/pi ) / 2;
#scale diskposition by 360 for hue output:
colordisk = diskposition * 360;
#add time to get the disk rotating
#200time is a shortcut for 200 * time:
huerot = colordisk + 200time;
#output:
x' = x;
y' = y;
h = huerot;
s = 1;
```

## 3D Rotation

Rotates (x, y, z) by angles (rx, ry, rz)

You can use z' to simulate depth in any way you like.

```
#projector doesn't have a z value, make one up or set to 0
z = 0;
#rotation around each axis:
rx = time;
ry = time/2;
rz = time/4;
#cosine and sine values for each rotation axis:
cx = cos(rx);
sx = sin(rx);
cy = cos(ry);
sy = sin(ry);
cz = cos(rz);
sz = sin(rz);
#result vector:
x' = x*(cz*cy) + y*(cy*-sz) + z*sy;
y' = x*(-sx*-sy*cz+sz*cx) + y*(-sx*-sy*-sz+cx*cz) + z*-sx*cy;
z' = x*(cz*cx*-sy+sz*sx) + y*(-sz*cx*-sy+cz*sx) + z*cx*cy;
```

## Waving three-color flag

```
#first we define the three colors:
h1 = 0; s1 = 1; v1 = 1; #red
h2 = 0; s2 = 0; v2 = 1; #white
h3 = 240; s3 = 1; v3 = 1; #blue
#masks for each stripe:
mask1 = y > (100/3);
mask2 = (y < (100/3)) * (y > (-100/3));
mask3 = y < (-100/3);
#wave stuff:
angle = (time + fraction * 18) * tau;
#output:
x' = x + sin(angle) * 4;
y' = y + cos(angle) * 4;
h = h1 * mask1 + h2 * mask2 + h3 * mask3;
s = s1 * mask1 + s2 * mask2 + s3 * mask3;
v = v1 * mask1 + v2 * mask2 + v3 * mask3;
```

## Analog Clock

```
# Construct 3 linearly increasing waves, one for each hand
extent = (fraction % (1/3)) * 100;
# Convert the seconds to radians on a clock
angle = -floor(time) * pi * 2 ;
# Calculate the angle of each hand
secondAng = angle / 60 + pi/2;
minuteAng = angle / (60^2) + pi/2;
hourAng = angle / (60^2 * 12) + pi/2;
# Plot out the lines for each clock hand
secondX = cos(secondAng) * extent;
secondY = sin(secondAng) * extent;
minuteX = cos(minuteAng) * extent * .8;
minuteY = sin(minuteAng) * extent * .8;
hourX = cos(hourAng) * extent * 0.5;
hourY = sin(hourAng) * extent * 0.5;
# Choose the colors for each of the hands
secondH = extent;
minuteH = 100 + extent;
hourH = 200 + extent;
# Check if the current beam should be a part of the second, minute, or hour hand
isSecond = fraction < (1/3);
isMinute = if(isSecond, 0, fraction < (2/3));
# Select the position based on the criteria above
x' = if(isSecond, secondX, if(isMinute, minuteX, hourX));
y' = if(isSecond, secondY, if(isMinute, minuteY, hourY));
# And the same for the color
h = if(isSecond, secondH, if(isMinute, minuteH, hourH));
s = 1;
v = 1;
```

## Tornado

```
size = 500;
# Plot the tornado points in 3d
sidx = index * 0.15;
spin = sidx + (time / (sidx ^ 1.2)) * 50;
heightRand = (sidx ^ 0.6) * 10 -sin(sidx * 10000) * 8;
xp = cos(spin) * sidx;
yp = heightRand;
zp = sin(spin) * sidx + 500;
xp = xp + sin(sidx/10 + time) * 10;
zp = zp + cos(sidx/10 + time) * 10;
x' = xp;
y' = yp + 100;
z = zp;
x' = x' * size / z;
y' = y' * size / z - 145;
h = -time*100 + fraction*350;
v = 2.5 - z/300;
s = v;
```