M Language Tutorial

Each M script consists of a fractal root element which contains two mandatory elements, orbit and color. The orbit element defines the algorithm to be used for computing the orbit for each point of the complex plane, or pixel of the screen if you prefer, and the color element defines the algorithm to be used for computing the color of the point or pixel. Each one of those elements have its own isolated variables scope, but we can export variables from orbit's scope to color's scope. Typically we export the right amount of variables required to compute the pixel's color.

fractal {
	orbit [...] [...] {
		...
	}

	color [...] {
		...
	}
}
						

The orbit element requires two list of parameters and it contains one or more trap elements, and not more than one of begin, loop, and end elements. The elements begin and end are optional. The element begin defines statements which are executed once at the beginning of the computation. The element end defines statements which are executed once at the ending of the computation. The element loop defines statements which are executed repeatedly until some conditions are met. The first list of parameters must contain two vectors <x,y> representing points x+yi of the complex plane. The second list must contains all state variables which need to be exported from orbit's scope to color's scope. The state variables are cached in memory to avoid recomputing all orbits when only color element changes. Beware of memory usage which might exceed the available memory for a large number of variables.

orbit [<-3.0,-1.5>,<0.0,1.5>] [x,n] {
	trap name [...] {
	}
	...

	begin {
		...
	}

	loop [...] (...) {
		...
	}

	end {
		...
	}
}
						

The begin element is optional and it might contain assignment statements, such as variable=expression, or if-else statements. The assignment statements can be used to declare new variables in orbit's scope. There are few implicit variables, x, w and n, which are declared and initialized automatically according to fractal's type, Mandelbrot or Julia/Fatou. The state variable x is initialized with the initial state or the current point, the constant w is initialized with the current point or Julia/Fatou constant, and n is always initialized with zero.

begin {
	y = |x|;
	z = <x>;
	...
}
						

The loop element is mandatory and it requires a list of parameters and a termination condition. The list of parameters must contain the initial value of index variable n and the number of iterations. The termination condition must contain a logical expression which is used to terminate the iteration loop. The loop terminates when the confition is true or when n is equals to the number of iterations. In addition, the loop can be terminated using a stop instruction. The loop must contain assignment statements, such as variable=expression, or if-else statements. The assignment statements can be used to declare temporary variables which will be visible only in loop's scope.

loop [0,100] (|x| > 2) {
	x = x * x + w;
	...
}

loop [0,200] (|x| > 4) {
	q = 2.5;
	x = x ^ q + w;
	...
}
						

The end element is optional and it might contain assignment statements, such as variable=expression, or if-else statements. The assignment statements can be used to declare temporary variables. After all statements are executed, the final value of variables which are declared in state variables parameters list of orbit element are cached and then exported to color's scope.

end {
	q = y + z;
	t = sin(n * pi / 10 + q);
	...
}
						

The trap element is optional, it requires a list of parameters and it must contain a sequence of commands. The list of parameters must contain the initial location of trap in the complex plane. The commands define the shape of a polygon in the complex plane which can be used in any expression to test if a complex number belong to the area delimited by the polygon. Command's parameters must be constant, we can't use variables or expressions.

CommandDescription
MOVETO(p)Move origin using absolute destination p=<px,py>
MOVEREL(d)Move origin using relative distance vector d=<dx,dy>
LINETO(p)Add line using absolute destination p=<px,py>
LINEREL(d)Add line using relative distance vector d=<dx,dy>
ARCTO(p1,p2)Add arc using absolute destination p1 and control point p2
ARCREL(d1,d2)Add arc using relative distance vector d1 and control vector d2
QUADTO(p1,p2)Add quad curve using absolute destination p1 and control point p2
QUADREL(d1,d2)Add quad curve using relative distance vector d1 and control vector d2
CURVETO(p1,p2,p3)Add spline curve using absolute destination p1 and control points p2 and p3
CURVEREL(d1,d2,d3)Add spline curve using relative distance vector d1 and control vectors d2 and d3
CLOSEClose polygon connecting last point to initial point
trap circle [<0,0>] {
	MOVETO(<1,0>);
	ARCTO(<1,1>,<0,1>);
	ARCTO(<-1,1>,<-1,0>);
	ARCTO(<-1,-1>,<0,-1>);
	ARCTO(<1,-1>,<1,0>);
}

trap rectangle [<0,0>] {
	LINETO(<0,1>);
	LINETO(<1,1>);
	LINETO(<1,0>);
	LINETO(<0,0>);
}

trap triangle [<0,0>] {
	MOVETO(<0,1>);
	LINETO(<1,0>);
	LINETO(<-1,0>);
	CLOSE;
}
						

The color element requires a list of parameters and it contains not more than one init element, and one or more of palette and rule elements. The list of parameters must contain a tuple (a,r,g,b) representing four color components, or a hexadecimal number #AARRGGBB representing a 32bits integer value, or a hexadecimal number #RRGGBB representing a 24bits integer value.

color [(1,1,1,1)] {
	init {
		...
	}

	palette {
		...
	}
	...

	rule (...) {
		...
	}
	...
}
						

The init element is optional and it might contain assignment statements, such as variable=expression, or if-else statements. The assignment statements can be used to declare new variables in color's. The color's scope contains implicit state variables which are imported from orbit's scope. Those state variables usually contain all the information required for computing the pixel's color.

init {
	y = |x|;
	z = <x>;
	...
}
						

The palette element is optional, it requires a name and it must contain one or more interpolation sequences. A sequence is defined as a list which contains range, length, and an optional interpolation function. A palette defines a table of colors which can be used to produce color values. The colors are generated interpolating color values from the inital value to the final value of the range, using a linear interpolation or a user defined interpolation function if present. The total size of the palette is equals to the sum of the length of all sequences. The colors can be defined as a tuple (a,r,g,b) representing four color components, or a hexadecimal number #AARRGGBB representing a 32bits integer value, or a hexadecimal number #RRGGBB representing a 24bits integer value.

palette MyPalette {
	[#FFFF0000 > #FFFFFFFF, 100];
	[#FFFFFFFF > #FF000000, 100];
	...
}

palette MyPalette {
	[(1,0,0,0) > (1,1,0,0), 200, sin(x)];
	...
}
						

The rule element is optional, it requires an activation condition and an opacity level, and it must contains either a single value or a tuple of three or four values. The values must be real numbers in interval [0,1]. The single value s is interpreted as tuple 1,s,s,s. The tuple with three values a,b,c is interpreted as tuple 1,a,b,c. The tuple represents four color components a,r,g,b. As special case, a rule may create a tuple directly from a palette using the notation name[i]. The initial value of a pixel's color is equals to background color declared in color element. The final color is computed applying all the active rules and composing the output of each rule sequentially according to the opacity level.

rule (n > 0) [0.8] {
	MyPalette[n]
}

rule (n > 0) [1.0] {
	c
}

rule (|x| > 4) [0.9] {
	r,g,b
}

rule (|x| > 4) [0.9] {
	a,r,g,b
}
						

A logical expression is an expression which has a boolean value, true or false. It might contains a contant, a variable, or a composition of logical operators and other expressions. We can use parenthesis to create nested expressions and control operators priority. There is one implicit boolean constant, julia, which is initialized according to the type of algorithm in use, false for Mandelbrot or true for Julia/Fatou.

OperatorDescription
x = ytrue if x is equals to y, false otherwise
x < ytrue if x is less than y, false otherwise
x > ytrue if x is greather than y, false otherwise
x <= ytrue if x is less than y or equals to y, false otherwise
x >= ytrue if x is greather than y or equals to y, false otherwise
x <> ytrue if x is not equals to y, false otherwise
x & ytrue if x is true and y is true, false otherwise
x | ytrue if x is true or y is true, false otherwise
x ^ ytrue if x is true and y is false or x is false and y is true, false otherwise
~xtrue if x is false, false otherwise
loop [...] (|x| > 2 | circle ? x) {
	...
}

init {
	if (|z| > 1 & |z| < 10) {
		...
	} else {
		...
	}
}

rule (|x| > 4) [...] {
	...
}

rule ((|x| > 4 & |x| < 8) | n > 10) [...] {
	...
}
						

An arithmetic expression has a numeric value, real or complex. It might contain a constant, a variable, a function, or a composition of arithmentic operators and other expressions. We can use parenthesis to create nested expressions and control operators priority. The type of the expression is statically defined according to the type of constants, variables, or functions used. There are built-in operators, functions, and constants which can be used in any arithmetic expression. We can declare a variable using the vector notation <x,y> or we can use the complex number notation x+yi, where x and y are constants or arithmetic expressions.

FunctionDescription
pha(x)Phase of x
mod(x)Modulus of x
mod2(x)Modulus ^ 2 of x
re(x)Real part of x
im(x)Imaginary part of x
cos(x)Cosine of x
sin(x)Sine of x
tan(x)Tangent of x
acos(x)Acosine of x
asin(x)Asine of x
atan(x)Atangent of x
log(x)Logarithm of x
exp(x)Exponential of x
sqrt(x)Square root of x
abs(x)Absolute value of x
ceil(x)Closet integer bigger than x
floor(x)Closet integer smaller than of x
FunctionDescription
pow(x,y)x ^ y
atan2(y,x)Atan2 of y and x
hypot(x,y)x ^ 2 + y ^ 2
max(x,y)if x > y x else y
min(x,y)if x < y x else y
square(x)Square signal of period 1
saw(x)Saw signal of period 1
ramp(x)Ramp signal of period 1
pulse(x,w)Pulse signal of period 1 and width w
time()Relative time in seconds
OperatorDescription
|x|Modulus of x
<x>Phase of x
x + yAddition x + y
x - ySubtraction x - y
x * yMultiplication x * y
x / yDivision x / y
x ^ yPower y of x
ConstantDescription
eEuler constant
piPythagoras constant
2pi2 * pi

Example #1

Mandelbrot set with two colors

Example #2

Mandelbrot set with simple gradient

Example #3

Mandelbrot set with binary decomposition

Example #4

Combine gradient with non linear function

Example #5

Derive color from modulus of state variable

Example #6

Derive color from phase of state variable

Example #7

Use opacity to compose rules

Example #8

Assign value to color component

Example #9

Assign value to alpha component

Example #10

Use expression to activate rule

Example #11

Use state variables in rule expression

Example #12

Use state variables in color expression

Example #13

Use simple orbit trap

Example #14

Use multiple orbit traps

Example #15

Mandelbrot set of z ^ m

Example #16

Mandelbrot set of z ^ q

Example #17

Mandelbrot set of sin(z)

Example #18

Mandelbrot set of cos(z)

Example #19

Mandelbrot set of exp(z)

Example #20

Newton-Raphson equation

Example #21

Magnetism equation I

Example #22

Magnetism equation II


Follow NextFractal on Facebook