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.

OutputDescription
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).
hThe 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.
sThe beam saturation, ranging from 0 to 1. 0 results in a white beam, and 1 results in a fully saturated colour.
vThe 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.

InputDescription
xThe input horizontal coordinate taken from the projection base (shape or grid), ranging from -100 (left) to 100 (right).
yThe input vertical coordinate taken from the projection base (shape or grid), ranging from -100 (down) to 100 (up).
indexThe 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.
countThe total amount of laser beams in the current projection. In most shapes this is equal to 32.
fractionThis is equal to the index of the beam divided by the total amount of beams.
pi3.14159265358979323846264338327950288419716...
tauTwo times pi. Useful for quickly converting radians per second to Hertz, when using functions such as sin(), cos(), and tan().
timeThe current time, in seconds, on the local system (your computer).
projectionTimeThe time, in seconds, since the expression was activated.
projectionStartTimeThe local time, in seconds, when the expression was activated.

Functions

FunctionDescription
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?

OperatorDescription
=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 );

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;
TOWER UNITE™ & © 2015-2024 PIXELTAIL GAMES LLC. Tower Unite and PixelTail Games are trademarks and/or registered trademarks of PixelTail Games LLC in the U.S. and/or other countries.