2024-08-26 23:25:36 +02:00
# System library
2024-08-24 12:53:52 +02:00
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:
```haku
2024-09-01 18:54:38 +02:00
stroke
thickness : number
color : rgba
position : vec
-> scribble
2024-08-24 12:53:52 +02:00
```
The first element is always the function's name - in this case `stroke`.
2024-09-01 18:54:38 +02:00
Following this are `argumentName : argumentType` pairs, which describe the arguments that need to be passed to the function.
2024-08-24 12:53:52 +02:00
The last element is always the type of data this function produces.
2024-09-01 18:54:38 +02:00
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.
2024-08-24 12:53:52 +02:00
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.
2024-09-01 18:54:38 +02:00
(Currently there are no functions that accept any number of arguments, though.)
2024-08-24 12:53:52 +02:00
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.
```haku
2024-09-01 18:54:38 +02:00
stroke 1 1 1
2024-08-24 12:53:52 +02:00
```
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.
2024-09-01 18:54:38 +02:00
- `_` - special type used to signify that any value may be passed into the function.
2024-08-24 12:53:52 +02:00
- `()` - also known as _nil_, means _no value._
2024-09-01 18:54:38 +02:00
- `boolean` - either `False` or `True`. Indicates truth or falsehood, used in `if` conditions.
2024-08-24 12:53:52 +02:00
- `number` - a real number, with 32 bits of precision.
- `vec` - a 4-dimensional vector, composed of four `number`s.
- `rgba` - an RGBA color, composed of four `number`s.
2024-09-01 18:54:38 +02:00
- `\a -> r` - a function taking in the parameter `a` and returning `r`, as returned by `\x -> x` literals.
- `list t` - a list of values, where each value is of the type `t`.
2024-08-24 12:53:52 +02:00
- `shape` - a mathematical shape.
2024-08-27 14:13:03 +02:00
2024-09-01 18:54:38 +02:00
- `shapeLike` - anything that can be turned into a `shape` using `toShape`.
2024-08-27 14:13:03 +02:00
2024-08-24 12:53:52 +02:00
- `scribble` - something that can be drawn on the wall.
2024-09-01 18:54:38 +02:00
Additionally, the syntax `a | b` may be used to signify that one of the listed types is accepted or returned.
2024-08-24 12:53:52 +02:00
## Math
```haku
2024-09-01 18:54:38 +02:00
-
a : number
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`-`, when used in its unary form `-x`, returns the number `x` with the opposite sign.
2024-08-24 12:53:52 +02:00
```haku
2024-09-01 18:54:38 +02:00
+
a : number
b : number
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`+` adds two numbers together.
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
```haku
-
a : number
b : number
-> number
```
`-`, when used in its binary form `x - y`, subtracts two numbers from one another.
2024-08-24 12:53:52 +02:00
```haku
2024-09-01 18:54:38 +02:00
*
a : number
b : number
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`*` multiplies two numbers together.
2024-08-24 12:53:52 +02:00
```haku
2024-09-01 18:54:38 +02:00
/
a : number
b : number
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`/` divides a number by another number.
2024-09-07 15:39:29 +02:00
```haku
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 +∞.
```haku
abs
x : number
-> number
```
`abs` returns the absolute value of the given number.
If `x` is less than zero, returns `-x`.
Otherwise returns `x`.
```haku
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_.
```haku
pow
base : number
exponent : number
-> number
```
`pow` raises `base` to the given `exponent`.
```haku
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)`.
```haku
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`.)
```haku
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.
```haku
exp2
x : number
-> number
```
`exp2` is the exponential function `pow 2 x`.
```haku
log2
x : number
-> number
log10
x : number
-> number
```
`log2` is the logarithm base `2` of `x`.
`log10` is the logarithm base `10` of `x`.
```haku
hypot
x : number
y : number
-> number
```
`hypot` is the hypotenuse of the Pythagorean triangle with right angle-adjacent sides `x` and `y`.
```haku
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.
[trigonometric functions]: https://wikipedia.org/Trigonometric_functions
```haku
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.
[inverse trigonometric functions]: https://wikipedia.org/Inverse_trigonometric_functions
```haku
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.
```haku
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][].
[hyperbolic functions]: https://en.wikipedia.org/wiki/Hyperbolic_functions
2024-08-24 12:53:52 +02:00
## Logic
The following functions are used to compare values and work with `boolean`s.
```haku
2024-09-01 18:54:38 +02:00
!
a : _
-> boolean
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
If `b` is `()` or `False`, `not` returns `true`.
Otherwise it returns `False`.
2024-08-24 12:53:52 +02:00
```haku
2024-09-01 18:54:38 +02:00
==
a : _
b : _
-> boolean
!=
a : _
b : _
-> boolean
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`==` returns `True` if `a` and `b` are equal.
2024-08-24 12:53:52 +02:00
Whether two values are considered equal depends on their type:
2024-09-01 18:54:38 +02:00
- If the type of the two values differs, `False` is returned.
2024-08-24 12:53:52 +02:00
- If the two values are `number`s:
2024-08-27 14:13:03 +02:00
2024-09-01 18:54:38 +02:00
- If any of the values are `NaN`, `False` is returned.
- Otherwise `True` is returned if the two numbers have the exact same bit representation.
2024-08-27 14:13:03 +02:00
2024-09-01 18:54:38 +02:00
- If the two values are `vec`s, `True` is returned if each of their `number` components is equal to each other using the rules above.
2024-08-24 12:53:52 +02:00
- Likewise with `rgba`s.
2024-09-01 18:54:38 +02:00
- All other types of values use _reference_ equality - `True` is returned only if `a` and `b` are located in the same place in memory.
2024-08-24 12:53:52 +02:00
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.
2024-09-01 18:54:38 +02:00
`!=` returns `!(a == b)`.
2024-08-24 12:53:52 +02:00
```haku
2024-09-01 18:54:38 +02:00
<
a : _
b : _
-> boolean
<=
a : _
b : _
-> boolean
>
a : _
b : _
-> boolean
>=
a : _
b : _
-> boolean
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`<` returns `True` if `a` is less than `b`, and `<=` returns `True` if `a` is less than _or_ equal to `b`.
2024-08-24 12:53:52 +02:00
Order is only well-defined for numbers.
2024-09-01 18:54:38 +02:00
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.
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
`a > b` is the same as `b < a`.
`a >= b` is the same as `b <= a`.
2024-08-24 12:53:52 +02:00
---
2024-09-01 18:54:38 +02:00
Note that `and` and `or` are currently missing from this list, but are reserved keywords.
2024-08-24 12:53:52 +02:00
You can implement them using regular functions as a replacement.
```haku
2024-09-01 18:54:38 +02:00
boolAnd = \a, b ->
if (a)
if (b) True
else False
else False
boolOr = \a, b ->
if (a)
True
else
if (b) True
else False
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
2024-08-24 12:53:52 +02:00
## Vectors
```haku
2024-09-01 18:54:38 +02:00
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
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
Creates a new `vec` from one to four number values.
2024-08-24 12:53:52 +02:00
A `vec` always has four dimensions.
If any of the arguments are omitted, its corresponding dimension is initialized to zero.
```haku
2024-09-01 18:54:38 +02:00
vecX
v : vec
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
vecY
v : vec
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
vecZ
v : vec
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
vecW
v : vec
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`vecX`, `vecY`, `vecZ`, and `vecW` extract the individual components of a `vec`.
2024-08-24 12:53:52 +02:00
---
Note that mathematical operations are currently not defined for vectors.
You may define your own vector operations like so:
```haku
2024-09-01 18:54:38 +02:00
-- Vector addition
addv = \a, b ->
vec (vecX a + vecX b) (vecY a + vecY b) (vecZ a + vecZ b) (vecW a + vecW b)
-- Likewise for subtraction, multiplication, and division.
2024-08-24 12:53:52 +02:00
```
Note that haku-defined vector operations like these are more costly the more components they operate on.
Therefore, it's recommended to only define them for two dimensions, unless you really need more.
```haku
2024-09-01 18:54:38 +02:00
addv2 = \a, b ->
vec (vecX a + vecX b) (vecY a + vecY b)
2024-08-24 12:53:52 +02:00
```
## Colors
```haku
2024-09-01 18:54:38 +02:00
rgba
r : number
g : number
b : number
a : number
-> rgba
2024-08-24 12:53:52 +02:00
```
Creates a new `rgba` with the given color channels.
Note that unlike `vec`, all color channels have to be provided to form an `rgba`.
```haku
2024-09-01 18:54:38 +02:00
rgbaR
color : rgba
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
rgbaG
color : rgba
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
rgbaB
color : rgba
-> number
2024-08-24 12:53:52 +02:00
2024-09-01 18:54:38 +02:00
rgbaA
color : rgba
-> number
2024-08-24 12:53:52 +02:00
```
2024-09-01 18:54:38 +02:00
`rgbaR`, `rgbaG`, `rgbaB`, `rgbaA` extract color channels out of an `rgba`.
2024-08-24 12:53:52 +02:00
---
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.
```haku
2024-09-01 19:15:41 +02:00
-- This is how you can multiply two colors together.
2024-09-01 18:54:38 +02:00
mulRgba = \a, b ->
rgba (rgbaR a * rgbaR b) (rgbaG a * rgbaG b) (rgbaB a * rgbaB b) (rgbaA a * rgbaA b)
2024-08-24 12:53:52 +02:00
```
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.
```haku
2024-09-01 19:15:41 +02:00
-- NOTE: This example does NOT work correctly.
2024-09-01 18:54:38 +02:00
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
2024-08-24 12:53:52 +02:00
```
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:
- `∞` is clamped back to `1`.
- `-∞` is clamped back to `0`.
- any scribble with a `NaN` color is ignored.
Note that just like vectors, arithmetic operations on colors are currently not defined.
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:
```haku
2024-09-01 18:54:38 +02:00
stroke 128 #00000004 (vec 0 0)
2024-08-24 12:53:52 +02:00
```
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.
## Shapes
```haku
2024-09-01 18:54:38 +02:00
toShape
value : _
-> () | shape
2024-08-24 12:53:52 +02:00
```
Converts the given value to a shape.
- For `shape`, clones the shape that was passed in.
- For `vec`, returns a point `shape`.
- For anything else, returns `()`.
```haku
2024-09-01 18:54:38 +02:00
line
start : vec
end : vec
-> shape
2024-08-24 12:53:52 +02:00
```
Creates a line segment shape with the provided `start` and `end` points.
```haku
2024-09-01 18:54:38 +02:00
rect
position : vec
size : vec
-> shape
rect
x : number
y : number
width : number
height : number
-> shape
2024-08-24 12:53:52 +02:00
```
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`.
```haku
2024-09-01 18:54:38 +02:00
circle
center : vec
radius : number
-> shape
circle
x : number
y : number
radius : number
-> shape
2024-08-24 12:53:52 +02:00
```
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
```haku
2024-09-01 18:54:38 +02:00
stroke
thickness : number
color : rgba
shape : shapeLike
-> scribble
2024-08-24 12:53:52 +02:00
```
Creates a stroke scribble, which outlines the provided shape with a stroke of the given thickness and color.
Point shapes are drawn as squares, and `line` shapes have square caps at the line's endpoints.
```haku
2024-09-01 18:54:38 +02:00
fill
color : rgba
shape : shapeLike
-> scribble
2024-08-24 12:53:52 +02:00
```
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.