System library
haku comes with a set of built-in functions, called the system library. This is a reference for these functions.
Preamble: how to read this reference
Each function comes with a signature description. These descriptions read like this:
stroke
thickness : number
color : rgba
position : vec
-> scribble
The first element is always the function’s name - in this case stroke
.
Following this are argumentName : argumentType
pairs, which describe the arguments that need to be passed to the function.
The last element is always the type of data this function produces.
Function names which are made up of symbols instead of letters are operators.
Operators may have one or two arguments, where one argument corresponds to a prefix form -x
, and two arguments correspond to an infix form x - y
.
Note that this documentation lists a unary and binary operator of the same spelling as two separate functions, not overloads of a single function.
The argument name usually does not matter when calling the function - it is only used for documentation purposes.
The one exception is arguments called ...
, which signify that zero or more arguments can be passed to the function at that position.
(Currently there are no functions that accept any number of arguments, though.)
The argument type however is important.
If you try to use a function with the wrong type of value as its argument, it will fail with an error.
For example, consider a brush where we pass a number as stroke
’s color
and position
arguments.
stroke 1 1 1
This brush will fail to render, since stroke
expects an rgba
as its 2nd argument.
With that said, there are several types of values in haku that can be passed into, and returned by functions.
-
_
- special type used to signify that any value may be passed into the function. -
()
- also known as nil, means no value. -
boolean
- eitherFalse
orTrue
. Indicates truth or falsehood, used inif
conditions. -
number
- a real number, with 32 bits of precision. -
vec
- a 4-dimensional vector, composed of fournumber
s. -
rgba
- an RGBA color, composed of fournumber
s. -
\a -> r
- a function taking in the parametera
and returningr
, as returned by\x -> x
literals. -
list t
- a list of values, where each value is of the typet
. -
shape
- a mathematical shape.-
shapeLike
- anything that can be turned into ashape
usingtoShape
.
-
-
scribble
- something that can be drawn on the wall. -
reticle
- an interaction the user can make with the wall.
The syntax a | b
may be used to signify that one of the listed types is accepted or returned.
The following syntax:
{
A : t
B : u
}
is used for records—functions which take in a tag as a parameter, and return a value depending on what tag was passed.
In the case above, if A
is passed in a value of type t
is returned, and if B
is passed in a value of type u
is returned.
Passing in any other tag is an error.
Math
-
a : number
-> number
-
a : vector
-> vector
-
, when used in its unary form -x
, returns the number x
with the opposite sign.
When used on vectors, returns the same vector facing the reverse direction (the individual components are negated.)
This operation is not defined for colors, because it doesn’t make sense to have a color with negative RGBA values.
+
a : number
b : number
-> number
+
a : vector
b : vector
-> vector
+
a : rgba
b : rgba
-> rgba
+
adds two numbers, vectors, or colors together.
-
a : number
b : number
-> number
-
a : vector
b : vector
-> vector
-
a : rgba
b : rgba
-> rgba
-
, when used in its binary form x - y
, subtracts two numbers, vectors, or colors from one another.
*
a : number
b : number
-> number
*
a : vector
b : vector
-> vector
*
a : rgba
b : rgba
-> rgba
*
multiplies two numbers together.
When used on vectors, it scales them component-wise.
Likewise for colors.
/
a : number
b : number
-> number
/
a : vector
b : vector
-> vector
/
a : rgba
b : rgba
-> rgba
/
divides a number by another number.
When used on vectors, it divides them component-wise.
Likewise for colors.
floor
x : number
-> number
ceil
x : number
-> number
round
x : number
-> number
floor
, ceil
, and round
are rounding functions.
Each of them rounds a little differently:
-
floor
rounds towards -∞. -
ceil
rounds towards +∞. -
round
rounds half towards +∞.
abs
x : number
-> number
abs
returns the absolute value of the given number.
If x
is less than zero, returns -x
.
Otherwise returns x
.
mod
x : number
y : number
-> number
mod
is the modulo operation.
It returns the remainder of dividing x
by y
.
haku uses the Euclidean definition, which means the remainder returned by mod
is always non-negative.
pow
base : number
exponent : number
-> number
pow
raises base
to the given exponent
.
sqrt
x : number
-> number
cbrt
x : nunber
-> number
sqrt
returns the square root of the given number.
cbrt
returns the cubic root of the given number.
Other roots may be obtained using pow x (1 / base)
.
exp
x : number
-> number
ln
x : number
-> number
In the following functions, e
is the base of the natural logarithm (approximately 2.7128
.)
The e
constant (Euler’s number) is currently not exposed to haku source code; you have to define it yourself.
exp
is the exponential function pow e x
.
ln
is the natural logarithm (logarithm base e
of x
.)
expMinus1
x : number
-> number
ln1Plus
x : number
-> number
expMinus1
is pow e x - 1
, but accurate even when x
is close to zero.
ln1Plus
is ln (1 + x)
, but more accurate than if the operations are performed separately.
exp2
x : number
-> number
exp2
is the exponential function pow 2 x
.
log2
x : number
-> number
log10
x : number
-> number
log2
is the logarithm base 2
of x
.
log10
is the logarithm base 10
of x
.
hypot
x : number
y : number
-> number
hypot
is the hypotenuse of the Pythagorean triangle with right angle-adjacent sides x
and y
.
sin
x : number
-> number
cos
x : number
-> number
tan
x : number
-> number
sin
, cos
, and tan
are the trigonometric functions sine, cosine, and tangent.
Their argument x
is counted in radians.
asin
x : number
-> number
acos
x : number
-> number
atan
x : number
-> number
asin
, acos
, and atan
are the inverse trigonometric functions arc sine, arc cosine, and arc tangent.
Their argument x
is counted in radians.
atan2
y : number
x : number
-> number
atan2
is the angle between the positive X axis and a line that passes through (0, 0)
and (x, y)
.
Note the reverse argument order—y
comes first, due to atan2
being a convenience function over atan (y / x)
that is defined for all arguments.
sinh
x : number
-> number
cosh
x : number
-> number
tanh
x : number
-> number
asinh
x : number
-> number
acosh
x : number
-> number
atanh
x : number
-> number
sinh
, cosh
, tanh
, asinh
, acosh
, and atanh
, are the six hyperbolic functions.
Logic
The following functions are used to compare values and work with boolean
s.
!
a : _
-> boolean
If b
is ()
or False
, not
returns True
.
Otherwise it returns False
.
==
a : _
b : _
-> boolean
!=
a : _
b : _
-> boolean
==
returns True
if a
and b
are equal.
Whether two values are considered equal depends on their type:
-
If the type of the two values differs,
False
is returned. -
If the two values are
number
s:-
If any of the values are
NaN
,False
is returned. -
Otherwise
True
is returned if the two numbers have the exact same bit representation.
-
If any of the values are
-
If the two values are
vec
s,True
is returned if each of theirnumber
components is equal to each other using the rules above. -
Likewise with
rgba
s. -
All other types of values use reference equality -
True
is returned only ifa
andb
are located in the same place in memory. This more or less means that the values are considered equal if they are produced by the same call to a system function, in time.
!=
returns !(a == b)
.
<
a : _
b : _
-> boolean
<=
a : _
b : _
-> boolean
>
a : _
b : _
-> boolean
>=
a : _
b : _
-> boolean
<
returns True
if a
is less than b
, and <=
returns True
if a
is less than or equal to b
.
Order is only well-defined for numbers.
Other types may assume an arbitrary but consistent ordering - ()
may be less than True
, or it may not be less than True
, but this will not change between executions of the program.
a > b
is the same as b < a
.
a >= b
is the same as b <= a
.
Note that and
and or
are currently missing from this list, but are reserved keywords.
You can implement them using regular functions as a replacement.
boolAnd = \a, b ->
if (a)
if (b) True
else False
else False
boolOr = \a, b ->
if (a)
True
else
if (b) True
else False
Vectors
vec
x : number
-> vec
vec
x : number
y : number
-> vec
vec
x : number
y : number
z : number
-> vec
vec
x : number
y : number
z : number
w : number
-> vec
Creates a new vec
from one to four number values.
A vec
always has four dimensions.
If any of the arguments are omitted, its corresponding dimension is initialized to zero.
vecX
v : vec
-> number
vecY
v : vec
-> number
vecZ
v : vec
-> number
vecW
v : vec
-> number
vecX
, vecY
, vecZ
, and vecW
extract the individual components of a vec
.
Colors
rgba
r : number
g : number
b : number
a : number
-> rgba
Creates a new rgba
with the given color channels.
Note that unlike vec
, all color channels have to be provided to form an rgba
.
rgbaR
color : rgba
-> number
rgbaG
color : rgba
-> number
rgbaB
color : rgba
-> number
rgbaA
color : rgba
-> number
rgbaR
, rgbaG
, rgbaB
, rgbaA
extract color channels out of an rgba
.
haku uses RGBA values in a normalized 0
to 1
range rather than 0
to 255
, which may be unfamiliar if you’re coming from other image editing software.
This is because it’s easier to do math on normalized colors.
For example, consider multiplicatively blending two colors.
-- This is how you can multiply two colors together.
-- Note that the `*` operator works for colors, so you don't need to define this in your brushes.
mulRgba = \a, b ->
rgba (rgbaR a * rgbaR b) (rgbaG a * rgbaG b) (rgbaB a * rgbaB b) (rgbaA a * rgbaA b)
If haku represented colors using an 8-bit 0
to 255
range instead, to multiply two colors together, you would have to divide them by 255
to get them back into the correct range.
-- NOTE: This example does NOT work correctly.
mulRgba = \a, b ->
let red = (rgbaR a * rgbaR b) / 255
let green = (rgbaG a * rgbaG b) / 255
let blue = (rgbaB a * rgbaB b) / 255
let alpha = (rgbaA a * rgbaA b) / 255
rgba red green blue alpha
Note that haku does not clamp colors to the 0
to 1
range.
It is perfectly valid to have a color that is out of range or even NaN
, but when drawing scribbles:
-
any number less than
0
is clamped to0
. -
any number greater than
1
is clamped to1
. -
∞
is clamped back to1
. -
-∞
is clamped back to0
. -
any scribble with a
NaN
color is ignored.
Before scribbles are drawn to the wall, colors are converted to 8-bit integers for more efficient rasterization and storage. This means some loss of precision will happen, which may cause issues with brushes like this one:
stroke 128 #00000004 (vec 0 0)
If you try to to use this brush to fill up a single spot with black, you will notice that despite all the math suggesting so, the color will end up gray instead.
Lists
len
l : list _
-> number
Returns the number of elements in the given list (its len
gth.)
index
l : list t
i : number
-> t
Returns an element of the list, located at the given index i
.
The first element is located at index 0.
Indexing out of bounds is an error.
Shapes
toShape
value : _
-> () | shape
Converts the given value to a shape.
-
For
shape
, clones the shape that was passed in. -
For
vec
, returns a pointshape
. -
For anything else, returns
()
.
line
start : vec
end : vec
-> shape
Creates a line segment shape with the provided start
and end
points.
rect
position : vec
size : vec
-> shape
rect
x : number
y : number
width : number
height : number
-> shape
Creates a rectangle shape with its top-left corner at position
, with a given size
stretching from the top-left corner.
The alternative 4-argument version takes in the rectangle’s X/Y coordinates, width, and height as separate arguments instead of aggregating them into a vec
.
circle
center : vec
radius : number
-> shape
circle
x : number
y : number
radius : number
-> shape
Creates a circle shape, with its center at center
, with the provided radius.
The alternative 3-argument version takes in the circle’s center X/Y coordinates as separate arguments instead of aggregating them into a vec
.
Scribbles
stroke
thickness : number
color : rgba
shape : shapeLike
-> scribble
Creates a stroke scribble, which outlines the provided shape with a stroke of the given thickness and color.
Point shapes are drawn as circles, and line
shapes have round caps at the line’s endpoints.
fill
color : rgba
shape : shapeLike
-> scribble
Creates a fill scribble, which fills in the entire area of the provided shape with a solid color.
Since this requires the shape to have a surface area, this does not do anything when point and line
shapes are passed in.
Reticles
withDotter
cont : \{
To : vec
From : vec
Num : number
} -> scribble
-> reticle
The dotter is a reticle that allows the user to draw things on the wall directly under the mouse cursor.
Once the user makes the interaction (presses the left mouse button), cont
is called repeatedly with every movement of the mouse cursor, until the mouse button is released.
It’s not called a plotter since the dotter does not plot lines or curves; it only places dots under the mouse cursor.
During the interaction, cont
is called with a record containing the following fields:
-
To
- the current position of the mouse cursor -
From
- the previous position of the mouse cursor. May be equal toTo
if the user just pressed the mouse button. -
Num
- the number of timescont
has been called since the mouse cursor was pressed. Always greater or equal to0
.
Since the dotter reticle finishes immediately (there is no extra interaction the user needs to take after pressing the mouse button for the action to be taken,) cont
may only return a scribble; never another reticle.
The drawing area is a large, square, chunk-aligned perimeter around To
.