A shorthand language for hydra
  • TypeScript 100%
2025-10-30 09:56:35 +01:00
src Fix parsing error 2025-10-30 09:56:35 +01:00
.gitignore Initial commit 2025-10-21 13:56:13 +02:00
basil.grammar More hydra defaults 2025-10-27 21:36:49 +01:00
package.json Initial commit 2025-10-21 13:56:13 +02:00
pnpm-lock.yaml Initial commit 2025-10-21 13:56:13 +02:00
Readme.md Add top level await 2025-10-26 20:35:31 +01:00
tsconfig.json Initial commit 2025-10-21 13:56:13 +02:00

Basil "documentation"

Also see the announcement blog post.

Basic Syntax

Basil is a syntax sugar language on top of JS. It is currently used to compile to hydra code.

Quick example Table

Basil JS
Function Calling osc 20 osc(20)
Chaining inline osc 20 # color 1 0 0 osc(20).color(1, 0, 0)
Chaining new lines osc 20
color 1 0 0
osc(20).color(1, 0, 0)
Sub chains osc 20 # add (noise 20) osc(20).add(noise(20))
lambdas rotate (> fft # * 2) rotate(() => fft() * 2)
real js:rotate(() => fft().mult(2))
Array syntax [4 5] [5, 6]
Array with functions Notice the sub chain!
([4 5] # smooth # fast 2)
[5, 6].smooth().fast(2)
JS-literals rotate <: () => fft(0,1) * Math.sin(time) :> rotate( () => fft(0,1) * Math.sin(time))
Await await (loadScript "http://...") await loadScript("http://...")

More in Depth explanations

Function calling

In Basil, function calls are written as functionName arg1 arg2 ...

Note: the space between the Arguments are required. No commas!

Some examples:

osc 20

rotate 0 .4

Chaining

Basil is a chain based language. Chains can be written either inline using # or a new line:

osc 20 # rotate 10

osc 20
rotate 10

Because lines get chained automaitically you need to have 2 new lines to separate different chains.

You cannot have both a new line and a # between to functions. (yet? todo?)

Sub Chains

Sub chains are written in ().

Basil:

osc 20 # add (noise 20)


osc 20
add (noise 20 # mod (osc 2))
out o1

The same in Native JS:

osc(20).add(noise(20))

osc(20)
    .add(noise(20).mod(osc(2)))
    .out(o1)

Lambdas

There are 2 ways of writing lambdas in Basil. The native way is using (> ). For the JS-literlay wat see the next section.

Under the Hood lambdas are parsed as sub-chains, and then get a () => prefix.

Basil:

osc 20
rotate (> fft # * 2)

Note: This is the "equivalent" JS. the real output looks a bit different.

Native JS:

osc(20)
    .rotate(() => fft() * 2)

The real JS looks like this:

osc(20)
    .rotate(() => fft().mult(2))

The * functions get aliased to mult, and then to get this working in nudel Number.mult() is overwritten on the Number prototype :pssst:

Arrays

Arrays are written as [1 2 3]

To use functions on arrays, use the sub chain syntax:

osc ([5 6] # smooth # fast 2)

JS:

osc([5, 6].smooth().fast(2))

Await

basil currently only has top-level awaits. it feels like a function in Basil:

await (loadScript "http://...")

JS-literals

In order to just do native JS, you ca souround your code with <: >

<: const a = bla :>

<: console.log("lol") :> 

osc 20 # rotate <: () => fft(0,1) * Math.sin(time) :>
const a = bla

console.log("lol")

osc(20).rotate(() => fft(0,1) * Math.sin(time))

Aliases

Lots of functions are aliased in basil, to make it more conscise.

This is a selection for now, see src/basil.ts for the full list.

alias real
o osc
rot rotate
rs 1 rotate 0 1
x scrollX
xs 1 scrollX 0 1
y scrollY
ys 1 scrollY 0 1
s shape
k kaleid
l luma
c color
h hue
n noise
+ add
- sub
* mult
/ diff
mod modulate
modScale modulateScale
modS modulateScale
modRotate modulateRotate
modRot modulateRotate
modR modulateRotate