What sets rakugaki apart from other drawing apps is that all drawing is done via a tiny computer program called _the brush._
Most drawing programs offer very customizable brushes, but rakugaki is unique in that the brushes are computer programs!
::: aside
The name _rakugaki_ comes from the Japanese word 落書き, which roughly translates to _scribbles_!
Japanese artists also sometimes use the abbreviation rkgk, which is where the website _rkgk.app_ comes from.
:::
The task of a brush is to take the strokes you make on the wall, and turn them into instructions on what should be drawn on the wall.
We call these instructions _scribbles._
You can edit your brush in the _brush editor_, which can be found in the top right corner of your screen.
Try fiddling with the code a bit and see what happens!
## The code
Brushes are written in rakugaki's custom programming language called _haku._
haku belongs to a family of programming languages known as _functional_ programming languages.
In these languages, instead of giving the computer direct instructions on what to do, we instead _declare_ what we'd like the computer to do by using various forms of data.
haku treats all sorts of things as data.
Numbers are data, shapes are data, colors are data, and of course, scribbles are also data.
The task of a haku program is to manipulate data to produce a _single scribble._
Theoretically, this would mean brushes are very limited.
After all, if we're only limited to drawing single scribbles, wouldn't that mean a brush can only draw a single shape?
But the magical part is that you can _compose scribbles together._
haku vectors however are a little more constrained, because they always contain _four_ numbers---this makes them _four-dimensional_.
We call these four numbers X, Y, Z, and W respectively.
Four is a useful number of dimensions to have, because it lets us do 3D math---which technically isn't built into haku, but if you want it, it's there.
For most practical purposes, we'll only be using the first _two_ of the four dimensions though---X and Y.
This is because the wall is a 2D space---it's a flat surface with no depth.
It's important to know though that vectors don't mean much _by themselves_---rakugaki just chooses them to represent points on the wall, but in a flat 2D space, all points need to be relative to some _origin_---the vector `(0, 0)`.
In brushes, this position is at the tip of the mouse cursor.
Note how it's parenthesized though---recall that function arguments are separated with spaces, so if we didn't parenthesize the `vec`, we'd end up passing `vec`, `0`, and `0` back to `stroke`---which is far from what we want!
That's quite a lot of copy-pasting for such a simple thing!
Luckily, haku has a solution for this: we can give a _name_ to a piece of data by using a _definition_, and then refer to that piece of data using that name we chose.
That's a lot nicer, isn't it---a template for our circles is neatly defined in a single place, and all we do is reuse it, each time with a different `radius`.
Parameters are the names we give to a function's arguments---for a function call `splat 8`, we need the function to have a name for that `8` datum that gets passed to it.
Note that a function can only have _one_ result, just like a brush can only have one scribble.
::: aside
One interesting thing you may have noticed with parameters, is that some system functions can accept varying numbers of them.
Such as `vec`, which can accept from zero to four.
This is called _function overloading_ and is somewhat common among programming languages.
It is also kind of controversial, because if a function if overloaded to do vastly different things depending on the number or type of data that is given to it, it can become quite hard to predict what it'll really do!
haku limits the use of overloading to system functions for simplicity---adding overloading would require introducing extra syntax, which would make the language harder to grok fully.
:::
Since these transparent circles are so much easier to draw now, let's make a few more of them!
We have to make _a lot_ of these circles, and we're still repeating ourselves.
There's less to repeat, but my brain can quickly recall only so many increments of 8.
::: aside
Seriously, 64 is my limit.
:::
I wonder if there's any way we could automate this?
### The Ouroboros
You know the drill by now.
We're programmers, we're lazy creatures.
Anything that can be automated, we'll automate.
But there doesn't seem to be an obvious way to repeat a bunch of values like this, no?
Well, there isn't.
At least not in a continuous list like that, yet.
But remember how lists can nest?
What we _could_ do is define a function that constructs a list out of a circle, and then a call back to _itself_, which will then construct another list out of a circle and a call back to itself, so on and so forth...
Until some threshold is reached, in which case we just make a single circle.
The first part is easy to do: haku allows us to define a function that calls itself without making any fuss.
haku doesn't let our code run indefinitely, and that's precisely what would happen in this case.
Also, it used an important word in that error message: *recursion.*
This is what we call the act of a function calling itself.
Sometimes people say that a function calls itself _recursively_, which sounds redundant, but it clarifies it's to achieve _iteration_---the act of executing the same code repeatedly, over and over again.
Anyways, we need some way to make the function _stop_ calling itself after some time.
For that, there's another piece of haku magic we can use: `if`.
`if` will execute a bit of code and pass on its result if a condition is found to be true.
Otherwise, it will execute a different bit of code.
We call this act of switching execution paths _branching_.
Try this out---change the `radius`, and observe how your brush changes color once you set it beyond 16:
- `<` is a function that produces `true` if the second argument is a smaller number than the first argument.
Truth and falsehood are data too, and are represented with the values `true` and `false`.
- We need three arguments to execute an `if`: the condition, the data to use when the condition is `true`, and the data to use when the condition is `false`.
What's magical about an `if` is that _only one branch is executed_.
In a function call, all arguments will always be calculated.
An `if` only calculates the argument it needs to produce the result.
This allows us to use it to prevent unbounded recursion in our `airbrush` example.
All we have to do is specify the size, and the code does all the magic for us!
Obviously, it's not really shorter than what we started with when we were listing all the circles manually, but the beauty is that we can control all the parameters trivially, by editing single numbers---no need for copy-pasting stuff into hellishly long lists.
But the airbrush still looks super primitive.
Let's try increasing the fidelity by doing smaller steps!
Looks good as a single dot, but if you try drawing with it... it's gray??
## Limits of the wall
Unfortunately, we don't live in a perfect world... and neither is rakugaki a perfect tool.
What's happening here requires understanding the internals of rakugaki's graphics engine a bit, but bear with me---I'll try to keep it simple.
As much as haku works on 32-bit real numbers, due to on-disk storage and memory considerations, rakugaki renders things in an 8-bit color space.
Therefore, unlike haku, it can only represent color channels from 0 to 255, with no decimal point.
There's Red 1 and Red 2, but no Red 1.5.
::: aside
haku uses a standard representation of real numbers in the computer world, better known as IEEE 754 floating point.
This standard has its quirks, such as `NaN`---a value that is *N*ot *a* *N*umber, in a standard representation for real numbers.
Huh.
What's even funnier is that `NaN` is not equal to anything, even itself.
_Huh._
And what's _even_ funnier is that `NaN` infects anything it touches with itself.
One plus `NaN` is `NaN`.
It's like an error flag that propagates across your calculations, with no context as to what went wrong, and when.
I gotta make the appearance of `NaN` a hard error in haku someday.
:::
Now let's consider what blending colors does.
Most commonly, colors are blended using _linear interpolation_---which is essentially, you draw a straight line segment between two colors in the RGB space, and take a point across that segment, at the alpha value---where an alpha of 0 means the starting point, and an alpha of 1 means the ending point.
Mathematically, linear interpolation is defined using this formula:
```
lerp(a, b, t) = a + (b - a) * t
```
What we're doing when blending colors, is mixing between a _source_ color (the wall), and a _destination_ color (the brush) on each channel.
Since the operations are the same across all four color channels, we'll simplify and only look at Red.
But due to this reduced precision on the wall, we have to convert from a real number between 0 and 1, to an integer between 0 and 255 at _every rendering step_, with each splat of the brush rendered to the wall.
Consider that we're drawing circles of opacity 0.01 every single time.
Now let's look what happens when we try to blend each circle on top of a single pixel...
But remember that we have to convert that down to an integer between 0 to 255---rakugaki does this by removing the decimal part.
::: aside
This is known as _truncation_.
It is not the same as rounding!
For negative results, it gives different results: `floor(-1.5)` would be `-2`, while `trunc(-1.5)` is `-1`.
:::
So for the next step, we'll be interpolating from `2`, and not `2.55`...
```
lerp(2, 255, 0.01) = 4.53
lerp(4, 255, 0.01) = 6.51
lerp(6, 255, 0.01) = 8.49
lerp(8, 255, 0.01) = 10.47
...
```
I think you can see the pattern here.
This continues until around 52, where the decimal point finally goes below zero, and now we're incrementing by one instead.
```
...
lerp(52, 255, 0.01) = 54.03
lerp(54, 255, 0.01) = 56.01
lerp(56, 255, 0.01) = 57.99 -- !!
lerp(57, 255, 0.01) = 58.98
...
```
...and at one point, we get to this:
```
lerp(153, 255, 0.01) = 154.02
lerp(154, 255, 0.01) = 155.01
lerp(155, 255, 0.01) = 156
lerp(156, 255, 0.01) = 156.99 -- !!
```
Truncating 156.99 will get us to 156 again, which means we're stuck!
This precision limitation is quite unfortunate, but I don't have a solution for it yet.
Maybe one day.
For now you'll have to construct your brushes with this in mind.
## And more limits
There are more limits on top of this, which stem from haku's design.
Since it's running _your_ code on _my_ server, it has some arbitrary limits set to prevent it from causing much harm.
haku code cannot be too long, and it cannot execute too long.
It cannot consume too much memory---you cannot have too many definitions, or too many temporary values at once.
There are also memory usage limits on "heavyweight" data, such as functions or lists.
Basically, don't DoS me with it ^^'
I'm not specifying the precise limits here, because the app will show these to you in the future.
There's no point in documenting them if you can't inspect your brush's resource usage easily.
## Have fun
With that said, I hope you can have fun with rakugaki despite its flaws.
You may want to check out the [system library reference](/docs/system.html) now, to know what else you can do with the language---this little introduction barely even scratched the surface of what's possible!