Cyril Beta 6: Language Reference

Daz
Cyril Live Coding
Published in
12 min readMay 10, 2016

--

This is the full list of commands available in Cyril Beta 6.

If you’re using Cyril version Beta 6 then the first thing you probably want to do is turn off Post Processing (until you need it). This is done by pressing COMMAND + Z together. You get better quality output (anti-aliased) without Post Processing, so things will look better if you turn it off initially. This will be fixed in a future version of Cyril.

Drawing simple shapes

Visuals in Cyril-beta6 are built from a few basic geometric primitives. The BOX, BALL, SPHERE, PEG, CONE, RECT, LINE, GRID.

Like most commands, the shapes have default arguments, usually ‘1’, so on it’s own ‘box’ will draw a cube with dimensions 1 x 1 x 1, like this…

If you specify one parameter it will use that for the width, height and depth:

Or specify the individual width, height and depth parameters:

Here are all the available basic shape commands:

box
box SIZE
box WIDTH, HEIGHT, DEPTH
ball
ball RADIUS
sphere
sphere RADIUS
peg
peg RADIUS, LENGTH
cone
cone RADIUS, LENGTH
rect
rect WIDTH, HEIGHT
line X1, Y1, X2, Y2
line X1, Y1
grid
grid SIZE

Ball and Sphere are two different ways of drawing a sphere. You can see the difference by either changing the level of detail used to draw them, or using the wireframe mode to see their construction:

You can alter the shape of balls and spheres by using the detail instructions. Balls are drawn as Icospheres and accept values <1 and up to 5. The default ballDetail is 2. Example:

Spheres are drawn using a different shape and need a detail level of 2 or more. For example:

Here’s examples of each primitive (basic shape):

Moving around

As you have seen in the examples above, shapes are draw at the current position. You change the current position by moving, rotating and scaling around 3D space. The commands are, MOVE, ROTATE, SCALE. There are a few versions of each command.

Both move and rotate have default versions that automatically animate their parameters. MOVE on it’s own will slowly move the current position left and right. ROTATE on it’s own will slowly rotate around the current position.

move // built-in sideways move animation
rotate // built-in rotation animation
box // draw a box

Notice how you get a different result depending on the order you move and rotate. This is because both commands continue from the current position. So, if you rotate then move you are moving in a different direction. If you move then rotate you are rotating from a different position. This example shows two boxes with the same rotation and move, the difference is the order of the commands:

Sometimes you need to save the current position so you can return to it later. Like in the previous example. The current position is saved by using the PUSH command, then you return with the POP command. You must have a matching number of push and pop commands in your program. It wont run if you don’t.

Here are all the MOVE commands:

move         // with default animation
move X // move along the X axis
move X,Y,Z // move in 3D space
move X,Y // move in current plane

Here are all the ROTATE commands:

rotate                 // rotate with default animation
rotate ANGLE // rotate around Z axis
// (i.e. in XY plane)
rotate ANGLE, X, Y, Z // quaternion rotation (specify angle and
// vector of rotation
rotate X, Y, Z // give 3 angles of rotation

There are two versions of the SCALE command:

scale SIZE       // scale same amount in all directions
scale X, Y, Z // scale different amount in x,y,z

Special Variables (Constants)

As far as your program is concerned these variables are special, and cannot be changed. They’re not ‘constant’ in the traditional sense that they never change, but that they are changed by Cyril outside of your program’s scope. They remain constant for each “frame” of animation.

You can use them to animate parameters to commands.

TIME     // the number of milliseconds since started 
SECS // the number of seconds since started
SLOW // a number that increases slowly
FAST // a number that increases a bit faster
FRAME // the number of frames since started
KICK // goes to 1 when KICK is detected in audio
SNARE // detects SNARE in audio
HIHAT // detects HIHAT in audio
PI // 3.141...
TWO_PI // PI * 2

You can reset the timers by pressing COMMAND + e

Beat detection registers

Cyril includes a really basic form of beat detection to use in your animations. It can give interesting results, but you might be better using the fft() function described later.

There are 3 beat detection constants, KICK, SNARE, and HIHAT. The value of these registers varies between 0 and 1. It’s 1 when a new beat is detected and fades to 0 based on the previously detected beat frame size. Here’s an example program that demonstrates their use:

Variables

As you have seen above, Cyril commands expect a certain number of parameters to be provided. You can provide numbers directly, or you can store the number in a variable and pass the name of the variable to the command.

Number variables store a single number. Cyril also has color variables which behind the scenes store 3 numbers, as a color is made up of red, green, and blue components.

To assign a value to a variable use the colon ‘:’ symbol. Some programming languages use the ‘=’ symbol for assignment. Cyril reserves this to express equality and prefers a symbol that clearly differentiates an assignment command:

w: 2          // set variable w to value 2
box w, 1, 1 // draw a box with size 2,1,1
#red: #ff0000 // create a #red variable
color #red // set the current color to #red
box // draw a red box

Cyril also allows you to create ‘palette’ variables which have special functionality for grouping and selecting colors.

palette $fire
50 #ffff00
50 #ff0000
end

A color palette is a list of HEX colors with weights. A palette spreads the colors out along a line from 0.0 to 1.0 and then you can find a color from inside the palette using the lerp function:

color lerp($fire, 0.5)

The second value given here should be between 0 and 1. The weights decide how much of the spectrum from 0 to 1 each color takes up.

Control structure

Things get a bit more interesting when you don’t just run a series of commands in order. Cyril has various control structures to repeat instructions, or conditionally execute blocks of commands.

The most simple example is to repeat a block of commands a certain number of times. This is achieved using the ‘DO’ command, for example:

do 4 times
// this block of code will run 4 times
end

Sometimes you want to keep a counter of how many times the block of code has been run. You could do this with ‘DO’ like this:

i: 0
do 10 times
// some commands using i as variable
i: i + 1
end

Cyril provides a ‘FOR’ loop that increments the counter automatically. So, the previous example is equivalent to:

for i: 0 to 10 step 1
// some commands using i
end

Sometimes you want decide if a command runs or not. Like most imperative languages, Cyril provides an ‘IF’ command for this. It has two forms. You can use it before a command to make it conditional, or you can use it to wrap a block of commands:

if x < 10 ...if x < 10
...
end

If you want more control over how many times a block of code is run you can use the full ‘WHILE’ loop. But, be careful not to create infinite loops as you can very easily crash Cyril using this. Here’s an example…

i: 10
while i > 0 do
i: i - 1
end

Animation commands

Do something sometimes, but not at other times:

blink 100 100
...
end

Animate using an alternating set of options:

anim 100
...
next 100
...
next 100
...
end

You can have as many steps in your animation as you like.

Particles

A particle is a special type of control structure. The commands inside the particle block get run multiple times, but outside of the current frame. In a way it’s a bit like launching another thread as a separate program that continues to run once per frame. A particle is created with a ‘health’ of 1. It is reduced by the DECAY amount until it reaches 0 when it dies (stops running).

Warning: You can easily launch millions of particles and cause Cyril to slow down to the point where it’s unusable.

A particle system is included and is started by defining a particle block:

particle a
...
end

This creates a particle emitter at the current position, that launches particles in the direction of the current translation matrix, with velocity a.

An optional acceleration can also be provided, in which case the x, y, and z components of the acceleration are provided as extra values in the particle instruction:

particle a, x, y, z
...
end

The inner block of the particle definition becomes the particle script and is used to draw the particle as it travels away from the position it was emitted from.

DECAY: 0.1

You can use the HEALTH variable inside the particle definition to find the current state of the particle.

color #ff0000, map(HEALTH, 0, 1, 0, 255)

The heath variable is a number between 0 and 1. In the above example the range 0–1 is mapped to valid alpha transparency values, which are 0–255.

Math Expressions

All the standard maths operations you would expect from a programming language…

a: a + 1
a: 100 - 50
a: 10 / 10
a: 10 * 10
a: 1000 % 10

Plus binary operators for doing tests in conditionals…

a < b
a <= b
...etc

Color

When your Cyril program is run the background is set to the current background color. Every drawing command uses the current foreground color. You set the colors using the BACKGROUND and COLOR commands. There are several versions of each, that accept different types of color.

A color with one parameter it is interpreted as a shade of gray. If you provide two parameters then the first is the gray, second is alpha (level of transparency).

A color with 3 values is interpreted as an RGB value. If you provide 4 values then it is a full RGBA color. I.e. the first 3 are color parts and the last value is the amount of transparency (alpha).

You can use color values as HEX, with 3 parts, or values between 0 and 255.

background #000000color #ff0000
color 255, 0, 0
color 255, 0, 0, 255
color #ff0000, 150

You can create color values from R, G, and B components. If you are familiar with HSB/HSV color systems you can create colors from the hue, saturation, and brightness components. This is useful for animating hue. It’s easier to fade between two colors on the HSB scale than doing it nicely in RGB.

Create a colour using RGB or HSV:

rgb(255, 0, 0)
hsv(255, 255, 255)
hsb(255, 255, 255) // either will work

You can also use named colors (like in CSS). For example:

color red
color cyan
color fireBrick

Create a color by mixing two other colors. The third value is the amount to mix. 0 gives the first color, 1 gives the second color, and a value between returns a mixture of the 2 colors.

#c: lerp(#ff0000, #ffff00, 0.5)

Return a mixed color from somewhere in a color palette:

#c: lerp($palette, 0.5)

Return a color from a palette. This doesn’t mix the colors but find the nearest color based on the weights provided when defining the palette:

#c: palette($palette, 0.5)

Solid Fill vs Wireframe mode

You can switch between wireframe and filled mode. Fill can optionally accept a color to set the current drawing color at the same time:

fill
fill #ffff00
fill #ff0000, 255

Switch to wireframe with stroke or noFill with an optional stroke size:

stroke 1
noFill

Color for stroke/wireframe mode is taken from the current color as set by the last color instruction.

Functions

Cyril uses functions to generate values. They are like commands, as they have built in functionality, but unlike a command, they return a value. It’s not possible in Cyril beta 6 to write your own functions unless you use C++. This will change in the next version of Cyril. But for now you’ve got these useful built-in functions:

// oscillate between 0 and 1 over specified period (ms)
i: wave(1000)
// trig functions
i: sin(PI)
i: cos(PI)
i: tan(PI)
// random number between 0 and X
i: rand(X)
// perlin noise, in 1D, 2D, and 3D
// noise is like random, but looks nicer
i: noise(A)
i: noise(A, B)
i: noise(A, B, C)
// map a number from one range to another
i: map(VALUE, A1, B1, A2, B2)
// fast Fourier transform (audio analysis)
// where BAND is between 0 and 31
i: fft(BAND)

Map Range

The map range function takes a number in one range, and maps it to another. This is useful if you have a number that varies between two values, but you want to use it to control a parameter that operates over a different range. For example, the HEALTH value of a particle varies between 1 and 0 but the alpha value of a color is between 0 and 255. You can map between the ranges, generating a version of the hotPink color that gets more transparent as the like this:

color hotPink, map(HEALTH, 0, 1, 0, 255)

Another mapping function is the LERP command. It’s short for ‘interpolate’. It returns a value between the first and second values provided. The third value defines how the two values are mixed. I.e. 0 returns the first value, 1 returns the second value, and 0.5 returns half way between. For example, this draws a semi-transparent pink box:

color hotPink, lerp(0, 255, 0.5)
box

Audio functions

There are 32 bands of processed audio available via the built-in FFT.

Lighting

You can move the position of the light (if you’ve got lighting turned on) using the LIGHT command. It takes an X, Y, Z position for new light position. You could even animate this:

light x, y, z

If you provide two color values, then the diffuse and ambient colors of the light will be changed. These are white by default, but you can get some nice color effects by drawing white objects and coloring them with the light:

light #ff0000, #ffff00

Tiling

A favorite among Cyril live coders. Use the TILE command to quickly repeat a block of commands in multiple locations. This works by ‘tiling’ the block of commands in 1D, 2D, or 3D space.

tile 3,3,3
box
end

Custom shapes

If you’re bored of the built in shapes, create your own.

You can draw any custom shape using the SHAPE command, it just takes a list of either 2d or 3d points:

shape
vert 0,0
vert 0,1
vert 1,1
end

You can also use 3D points, or use functions to calculate points:

shape
vert 0,0,0
vert 0,wave(1000),1
vert 0,1,1
end

Initialization of variables

Variables are often set and used inside frames:

x: 0.5
do 4 times
box x
x: x + 0.5
end

But you can also make use of variables across frames, if you just use the init command to initialize them the first frame:

init x: 0.5
box x
x: x + 0.5

In this example the box keeps growing until the timers are reset and the INIT code runs again (i.e. press COMMAND + e to reset timers).

Post Processing Effects

A separate page documents the post processing effects.

--

--

Daz
Cyril Live Coding

Geocities Developer Expert. Keywords: Angular, TypeScript, JavaScript, Cyril Live Coding, Functional Programming