125 lines
4.5 KiB
Plaintext
125 lines
4.5 KiB
Plaintext
# haku
|
|
|
|
haku is a little scripting language used by rakugaki for programming brushes.
|
|
Here's a brief tour of the language.
|
|
|
|
## Your brush
|
|
|
|
Your brush is a piece of code that describes what's to be drawn on the wall.
|
|
|
|
For example, the default brush:
|
|
|
|
```haku
|
|
(stroke
|
|
8
|
|
(rgba 0 0 0 1)
|
|
(vec 0 0))
|
|
```
|
|
|
|
This is the simplest brush you can write.
|
|
It demonstrates a few things:
|
|
|
|
- The brush's task is to produce a description of what's to be drawn.
|
|
Brushes produce *scribbles* - commands that instruct rakugaki draw something on the wall.
|
|
|
|
- This brush produces the `stroke` scribble.
|
|
This scribble is composed out of three things:
|
|
|
|
- The stroke thickness - in this case `8`.
|
|
- The stroke color - in this case `(rgba 0 0 0 1)`.
|
|
Note that unlike most drawing programs, rakugaki brushes represent color channels with decimal numbers from 0 to 1, rather than integers from 0 to 255.
|
|
- The shape to draw - in this case a `(vec 0 0)`.
|
|
|
|
- Vectors are aggregations of four generic decimal numbers, most often used to represent positions in the wall's Cartesian coordinate space.
|
|
Although vectors are mathematically not the same as points, brushes always execute in a coordinate space relative to where you want to draw with the brush, so a separate `(point)` type isn't needed.
|
|
|
|
- Vectors in haku are four-dimensional, but the wall is two-dimensional, so the extra dimensions are discarded when drawing to the wall.
|
|
|
|
- haku permits constructing vectors from zero two four values - from `(vec)`, up to `(vec x y w h)`.
|
|
Any values that you leave out end up being zero.
|
|
|
|
- Note that a brush can only produce *one* scribble - this is because scribbles may be composed together using lists (described later.)
|
|
|
|
I highly recommend that you play around with the brush to get a feel for editing haku code!
|
|
|
|
## More complicated brushes
|
|
|
|
To make our brush more complicated, we can make it produce _multiple_ scribbles instead of just one.
|
|
To do that, we'll aggregate our scribbles into a _list_:
|
|
|
|
```haku
|
|
(list
|
|
(stroke 8 (rgba 0 0 1 1) (vec (- 4) 0))
|
|
(stroke 8 (rgba 1 0 0 1) (vec 4 0)))
|
|
```
|
|
|
|
A list allows us to say, "I'd like this brush to draw this, this, and this."
|
|
Of course, we are not limited to two elements only.
|
|
Here we'll use the `circle` function instead of `vec` to draw outlined circles.
|
|
|
|
```haku
|
|
(list
|
|
(stroke 1 (rgba 0 0 0 1) (circle (- 8) 0 8))
|
|
(stroke 1 (rgba 0 0 0 1) (circle 8 0 8))
|
|
(stroke 1 (rgba 0 0 0 1) (circle 0 (- 8) 8))
|
|
(stroke 1 (rgba 0 0 0 1) (circle 0 8 8)))
|
|
```
|
|
|
|
But the moment we'll want to change any one of these values, such as the color... we'll have to edit _every_ single occurrence of it!
|
|
|
|
To solve this, we can use a definition, or _def_ for short.
|
|
We'll replace our literal colors with a shared def:
|
|
|
|
```haku
|
|
(def color (rgba 0 0 0 1))
|
|
|
|
(list
|
|
(stroke 1 color (circle (- 8) 0 8))
|
|
(stroke 1 color (circle 8 0 8))
|
|
(stroke 1 color (circle 0 (- 8) 8))
|
|
(stroke 1 color (circle 0 8 8)))
|
|
```
|
|
|
|
And now we can control the color of the entire brush, without having to copy and paste it everywhere!
|
|
|
|
You can try doing this to the other `stroke` parameters, too - try creating a def `thickness` for the stroke thickness, `distance` for distance from the mouse, and `radius` for the radius of the circles.
|
|
|
|
## Repeating
|
|
|
|
At this point, we may be happy with this implementation.
|
|
But what if we want to draw four of these shapes, with different colors, next to each other?
|
|
|
|
This is where _functions_ come in.
|
|
|
|
A function allows us to store a piece of code for later, and give it some _parameters_, that'll be filled into the resulting value whenever the function is used.
|
|
|
|
```haku
|
|
(def circles
|
|
(fn (color x y)
|
|
(list
|
|
(stroke 1 color (circle (- x 8) y 8))
|
|
(stroke 1 color (circle (+ x 8) y 8))
|
|
(stroke 1 color (circle x (- y 8) 8))
|
|
(stroke 1 color (circle x (+ y 8) 8)))))
|
|
|
|
(circles (rgba 0 0 0 1) 0 0)
|
|
```
|
|
|
|
## Limits
|
|
|
|
The wall is infinite, but your brush may only draw in a small area around your cursor (~500 pixels.)
|
|
Drawing outside this area may result in pixels getting dropped in ugly ways, but it can also be used to your advantage in order to produce cool glitch art.
|
|
|
|
You can see this in action by setting the brush size to something really large:
|
|
|
|
```haku
|
|
(stroke
|
|
1000
|
|
(rgba 0 0 0 1)
|
|
(vec))
|
|
```
|
|
|
|
Additionally, haku code has some pretty strong limitations on what it can do.
|
|
It cannot be too big, it cannot execute for too long, and it cannot consume too much memory.
|
|
It does not have access to the world outside the wall, so you cannot use it to fire network requests or read the user's input in uncontrolled ways.
|