Standard library
The standard library is the set of functions that are always at hand, with no use or import: writing and reading on the console, waiting and measuring time, converting values, drawing random numbers, finding out which platform the program runs on and how much memory it uses. The global constants the compiler knows are here too.
They work the same on Windows and on the boards, except for what Platforms says.
Functions
| Function | What it does | Returns |
|---|---|---|
print(...), println(...) | Write their arguments on the console; println adds a line break at the end. | nil |
readLine() | Reads a line from the console. | String |
cls() | Clears the console. | nil |
ink(color), paper(color) | Change the color of the console's text and background. | nil |
pause(ms) | Waits ms milliseconds. | nil |
clock() | The milliseconds since startup. | Integer |
time(), time(format) | The date and time. | String |
chr(code) | The character of an ASCII code. | String |
int(x), float(x) | Convert a number or a boolean. | Integer, decimal |
type(x) | The type of a value. | Integer (a t* constant) |
randomize(seed) | Seeds the random numbers. | nil |
random(), random(max), random(min, max) | A random number. | Integer or decimal |
abs(x), round(x), sqrt(x) | Absolute value, rounding and square root. | Number |
vlenght(x, y) | The length of a vector. | Decimal |
len(x) | The length of a string, a list or a map. | Integer |
rgb(r, g, b) | A color in the 0xRRGGBB format. | Integer |
memUse(), memFree() | The memory the VM uses and the memory left free. | Integer |
platform() | Where the program runs. | Integer (an HW_* constant) |
vmerror() | Nothing useful in 0.9.7: always 0. | Integer |
encode64(text), decode64(text) | Encode and decode Base64. | String |
If you pass them an argument of another type, they throw ERR_TYPE_MISMATCH. With the wrong number of arguments, the program does not compile; cls, ink and paper say so when they run, with ERR_INVALID_ARG_NUMBER. Errors are covered in Errors and exceptions.
To end the program early there is exit: see exit.
Platforms
| Windows | ESP32 / ESP32-S3 | ESP32-P4 | ESP32-S31 | |
|---|---|---|---|---|
print, println | Write to the program's console. | Write to the serial port. | Write to the serial port. | Write to the serial port. |
readLine() | Reads from the console. | Gets nothing. | Gets nothing. | Gets nothing. |
cls() | Clears the console. | Sends the terminal code that clears the screen. | Sends the terminal code that clears the screen. | Sends the terminal code that clears the screen. |
ink(), paper() | Do nothing. | Send the terminal code of the color. | Send the terminal code of the color. | Send the terminal code of the color. |
clock() | Counts from when the VM started. | Counts from when the board started. | Counts from when the board started. | Counts from when the board started. |
time() | The PC's date and time. | Those of the board's clock. | Those of the board's clock. | Those of the board's clock. |
memFree() | Always 0. | The free internal RAM, without the PSRAM. | All the free memory, PSRAM included. | All the free memory, PSRAM included. |
platform() | 4 | 1 on the ESP32 and 2 on the S3 | 6 | 7 |
- What the program writes on a board shows up in the Output with Open Serial (see Your program on a board).
- Terminal codes (ANSI) are understood by a terminal program; the IDE's Output does not interpret them.
- For the board's clock to have the right time, the board needs WiFi and NTP: you turn them on in ESP32 Tools (see Display, sound, SD and network).
Console
print / println
print writes its arguments on the console, one after the other, with nothing between them. println does the same and adds a line break at the end; without arguments, println() just breaks the line. They take any number of arguments, of any type, and return nil.
var name = "Ann"
var points = 120
println("Player: ", name, " - points: ", points)
print("No line break, ")
println("and a line break")
println([1, "two", 3.5], " ", {"lives": 3})
Player: Ann - points: 120
No line break, and a line break
[1, two, 3.5] {lives: 3}
This is how they write each value:
| Value | How it comes out | Example |
|---|---|---|
| Integer | As it is. | 120 |
| Decimal | With just the digits needed so that, read back, it's the same number, and without decimals if it has none. | 0.1 comes out as 0.1, 0.1 + 0.2 as 0.30000000000000004, and 10.0 as 10 |
| String | Without quotes. | Ann |
Boolean and nil | With their name. | true, nil |
| List and map | With their elements; strings without quotes. | [1, two, 3.5], {lives: 3} |
| Struct | Its name and its fields. | Point{x: 1, y: 2} |
| Class instance | The name of the class. | Cat instance |
The error of a catch | Its name and its message. | ERR_KEY_NOT_FOUND: The given key was not present in the map. |
| Error value | Error and its number. | Error 9 |
- To write a decimal with fewer digits, convert it first with its
toString()method, which uses 15: withvar x = 0.1,println(x.toString())writes0.1. - The arguments are written as they are worked out. If one throws an exception, the ones before it have already come out, with no line break:
println("Price: ", prices[9])leavesPrice:written before the error. - To join texts into a single string, the string methods are in Strings.
readLine
readLine waits for you to type a line on the console and press Enter, and returns it as a string, without the line break.
print("Type your name: ")
var name = readLine()
println("Hello " + name + ", welcome!")
readLine() on the boardsIn 0.9.7, readLine() does not receive input over the serial port on the boards: the program waits forever. This happens to the examples that ask for data, such as CheckPrime or Palindromes. On Windows it works.
cls
cls clears the console.
cls()
On a board, it sends through the serial port the terminal code that clears the screen.
ink / paper
ink(color) changes the color of the text, and paper(color) that of the background, with a number from 0 to 15:
| Color | Name | Color | Name |
|---|---|---|---|
| 0 | Black | 8 | Dark gray |
| 1 | Blue | 9 | Light blue |
| 2 | Green | 10 | Light green |
| 3 | Cyan | 11 | Light cyan |
| 4 | Red | 12 | Light red (with ink, orange) |
| 5 | Magenta | 13 | Light magenta |
| 6 | Brown | 14 | Yellow |
| 7 | Light gray | 15 | White |
With any other number they do nothing. On a board, they send through the serial port the terminal code of that color: the colors show in a terminal program that understands it, not in the IDE's Output.
ink(4) // red text
println("This text is red")
ink(7) // back to light gray
paper(1) // blue background
println("Text with blue background")
paper(0) // back to the black background
ink and paper do nothing on WindowsIn 0.9.7, ink() and paper() change no color on the Windows console: the text always comes out in the console's colors. They give no error either.
Time
pause
pause(ms) stops the program for ms milliseconds. It only takes integers: with a decimal it throws ERR_TYPE_MISMATCH.
println("This message comes out now.")
pause(3000)
println("And this one, 3 seconds later.")
- While the pause lasts, the program does nothing else: whatever should fire in that time, such as a Timer callback, waits until it ends.
- Do not use
pausefor the pace of a game: useDisplay.fps(see Display).
clock
clock() returns the milliseconds since startup: on Windows, since the VM started; on a board, since the board started, and it keeps counting when the VM starts the program again. It is useful to measure how long something takes:
var start, finish, total_time
start = clock()
// Algorithm code would go here
finish = clock()
total_time = finish - start
println("The algorithm took ", total_time, " milliseconds")
time
time() returns the date and time in a string, in English, in this format: the day of the week, the month, the day, the time and the year.
time(format) returns it as you say in format: each code with % is replaced by a piece of data, and the rest is copied as it is. The most useful codes are in the table below.
println(time()) // Fri Nov 6 18:35:13 2026
println(time("%m/%d/%Y %H:%M")) // 11/06/2026 18:35
println(time("Today is %A")) // Today is Friday
(With the date and time of when you run it.)
| Code | What it gives | Example |
|---|---|---|
%Y | The year. | 2026 |
%y | The year, with two digits. | 26 |
%m | The month, from 01 to 12. | 11 |
%d | The day of the month, from 01 to 31. | 06 |
%e | The day of the month, with a space in front instead of the zero. | 6 |
%H | The hour, from 00 to 23. | 18 |
%I | The hour, from 01 to 12. | 06 |
%p | AM or PM. | PM |
%M | The minute, from 00 to 59. | 35 |
%S | The second, from 00 to 59. | 13 |
%A, %a | The day of the week, full or in three letters. | Friday, Fri |
%B, %b | The month, full or in three letters. | November, Nov |
%j | The day of the year, from 001 to 366. | 310 |
%u | The day of the week as a number, from 1 (Monday) to 7. | 5 |
%w | The day of the week as a number, from 0 (Sunday) to 6. | 5 |
%F | The date: %Y-%m-%d. | 2026-11-06 |
%T | The time: %H:%M:%S. | 18:35:13 |
%R | The hour and the minute: %H:%M. | 18:35 |
%% | A %. | % |
- The result can be up to 79 characters long. If it is longer, on Windows
timereturns an empty string. - On Windows, the date and time are the PC's. On a board, those of its clock (see Platforms).
% code that does not exist closes the VMOn Windows, time() with a code that does not exist, such as time("%Q"), closes the VM without any message. Use the codes in the table.
Conversion and types
chr
chr(code) returns the character of an ASCII code, in a one-character string. chr(0) returns the empty string.
var letter = chr(65)
println(letter) // A
var newline = chr(10)
print("Line 1" + newline + "Line 2")
It only works for the ASCII codes, from 1 to 127: with a higher one it gives a single byte, which is not an accented letter.
int
int(x) converts a decimal into an integer: it drops the decimal part (it truncates toward zero). It also converts booleans: true gives 1 and false, 0.
var decimal = 5.7
var integer = int(decimal)
println(integer) // 5
println(int(-5.7)) // -5
// Also works with booleans
println(int(true)) // 1
println(int(false)) // 0
It does not accept strings: int("7") throws ERR_TYPE_MISMATCH. To convert a string, use its toInt() method, for example text.toInt() (see Strings).
float
float(x) converts an integer or a boolean into a decimal. It does not accept strings: float("3.5") throws ERR_TYPE_MISMATCH. To convert a string, use its toFloat() method, for example text.toFloat().
var integer = 10
var decimal = float(integer)
println(decimal) // 10
// Useful for operations requiring decimal precision
var result = float(5) / float(2)
println(result) // 2.5
println writes 10 and not 10.0: a decimal without a decimal part comes out without it (see print / println).
type
type(x) returns an integer that says what type x is. Compare it with the t* constants:
func describe(v)
var t = type(v)
if (t == tInteger or t == tFloat) then
return "number"
elsif (t == tString) then
return "string"
elsif (t == tList) then
return "list"
end
return "something else"
end
println(describe(42)) // number
println(describe(2.5)) // number
println(describe("hello")) // string
println(describe([1, 2])) // list
println(describe(nil)) // something else
| Constant | Value | Type |
|---|---|---|
tBool | 0 | A boolean: true or false. |
tNil | 1 | nil. |
tInteger | 2 | An integer. |
tFloat | 3 | A decimal. |
tError | 4 | The error of a catch, or an error value from a function that failed. |
tMethod | 6 | A method of an instance kept in a variable, such as var m = cat.meow. |
tClass | 7 | A class. |
tFunction | 9 | A function or a lambda. |
tInstance | 10 | An instance of a class. |
tNative | 11 | A VM function. |
tString | 12 | A string. |
tList | 13 | A list. |
tMap | 14 | A map. |
tArray | 15 | An array. |
tFile | 16 | A file opened with File.open. |
tBitmap | 17 | A bitmap, such as the one Bitmap.load returns. |
tModule | 18 | A module, such as Display or Display.draw. |
tAbstract | 20 | An object of a module: a sprite, a GridMap, a Bytes, an LED strip… |
tEnumerator | 22 | An enum. Its values are integers: tInteger. |
- A struct gives 23, and the struct itself (its name, without creating anything) gives 24. They have no constant.
typeis a reserved word: you cannot name a variable that way.
Random numbers
randomize
randomize(seed) seeds the random number generator with an integer. With the same seed, random() always gives the same sequence: it is useful to repeat a game or a test.
randomize(12345) // Initialize with seed 12345
// Now random() will generate the same sequence each time
println(random(100)) // 67
randomize, always the same sequenceThe generator always starts with the same seed: if you don't call randomize, random() gives the same sequence on every run. To make it change, seed it with a value that differs each time, such as randomize(clock()). Right at startup clock() barely changes from one run to the next, so call it after something that depends on the user, such as waiting for a key press. randomize only accepts integers.
random
random gives a random number:
| Call | What it returns |
|---|---|
random() | Any 32-bit integer, negative ones too. |
random(max) | An integer from 0 to max, both included. |
random(min, max) | An integer from min to max, both included. The order does not matter: random(10, 1) is the same as random(1, 10). |
random(min, max) with decimals | A decimal between min and max. |
// An integer from 0 to 10
var a = random(10)
// An integer from 100 to 200
var b = random(100, 200)
// A decimal between 0.0 and 1.0
var c = random(0.0, 1.0)
// A decimal between -10.5 and 10.5
var d = random(-10.5, 10.5)
- With two arguments, both must be of the same type:
random(1, 2.5)throwsERR_TYPE_MISMATCH. - With a single decimal,
random(5.0)does not give any decimal: it gives one without a decimal part, from 0 to 5. For a decimal, userandom(0.0, 5.0).
Math
The other math functions, such as Math.floor or Math.sin, are in the Math module.
abs
abs(x) returns the absolute value of a number: the number without its sign. It returns an integer if x is an integer, and a decimal if it is a decimal.
println(abs(-5)) // 5
println(abs(8)) // 8
println(abs(-2.5)) // 2.5
round
round(x) rounds to the nearest integer. If the number is exactly halfway, it is rounded away from zero: round(3.5) gives 4 and round(-2.5) gives -3. The result has the same type as the number: given a decimal it returns a decimal (round(3.5) is 4.0, even though println shows it as 4).
var number = 3.14159265
var rounded_number = round(number)
println(rounded_number) // 3
println(round(3.5)) // 4
println(round(3.49)) // 3
println(round(-2.5)) // -3
sqrt
sqrt(x) returns the square root of a number, always as a decimal. With a negative number it throws no error: it returns NaN, the "not a number" value.
var x = 9
var result = sqrt(x)
println("The square root of ", x, " is ", result) // The square root of 9 is 3
println(sqrt(16)) // 4
println(sqrt(2)) // 1.4142135623730951
vlenght
vlenght(x, y) calculates the length of a 2D vector from its components: √(x² + y²). It returns a decimal. It is spelled this way, vlenght.
var length = vlenght(3, 4)
println(length) // 5
// Useful for calculating distances
var distance = vlenght(10.5, 20.3)
println("Distance: ", distance) // Distance: 22.854758804240312
Collections
len
len(x) returns the length of a string, a list or a map: the bytes of the string, the elements of the list or the pairs of the map.
// With strings
var string = "Hello world"
println(len(string)) // 11
// With lists
var list = [1, 2, 3, 4, 5]
println(len(list)) // 5
// With maps
var map = {"a": 1, "b": 2, "c": 3}
println(len(map)) // 3
- In a string it counts bytes: an accented letter counts as two.
len("café")gives 5. - It does not accept arrays: with one it throws
ERR_TYPE_MISMATCH. Use theirsize()method (see Lists, maps and arrays).
Colors
rgb
rgb(r, g, b) puts red, green and blue together, each from 0 to 255, into a color in the 0xRRGGBB format: the one used by draw.color and the other functions of Draw.
var orange = rgb(255, 128, 0)
println(orange) // 16744448
println(orange.toHex()) // FF8000
println(rgb(300, -5, 12.7) == rgb(255, 0, 12)) // true
A component above 255 stays at 255, a negative one at 0, and decimals are truncated.
System and memory
memUse
memUse() returns the bytes of memory the VM has reserved for the program at that moment.
var memory_used = memUse()
println("Memory used: ", memory_used, " bytes")
memFree
memFree() returns the bytes of free memory. On Windows it always returns 0. On a board, it counts differently depending on the chip: see Platforms, and the memory of each board in Memory and limits.
var free_memory = memFree()
println("Free memory: ", free_memory, " bytes")
How the VM frees memory, in the GC module.
platform
platform() returns an integer that says where the program runs:
| Value | Platform | Constant |
|---|---|---|
0 | Unknown platform | — |
1 | ESP32 | HW_ESP32 |
2 | ESP32-S3 | HW_ESP32S3 |
3 | Reserved | — |
4 | Windows | HW_WIN32 |
5 | Reserved | HW_WEB |
6 | ESP32-P4 | HW_ESP32P4 |
7 | ESP32-S31 | HW_ESP32S31 |
Rather than comparing against the number, use the constants: they read better.
var plat = platform()
if (plat == HW_ESP32 or plat == HW_ESP32S3 or plat == HW_ESP32P4 or plat == HW_ESP32S31) then
println("Running on an ESP32")
elsif (plat == HW_WIN32) then
println("Running on Windows")
else
println("Unknown platform")
end
Value 3 is reserved. It belonged to the old RISC-V VM for the K210 (Kendryte/Maixduino), which was retired when that chip was discontinued. It will not be reused for any new platform, so no program can ever receive that value. The HW_RISCV constant that named it no longer exists: if your code used it, replace it with whichever check applies. The RISC-V platforms JARU supports today are the ESP32-P4 (HW_ESP32P4) and the ESP32-S31 (HW_ESP32S31).
Value 5, HW_WEB, belongs to a VM for the browser, which 0.9.7 does not have: no program receives it.
vmerror
vmerror() should return the code of the last error, but it cannot tell you whether something failed.
vmerror() always returns 0In 0.9.7, vmerror() returns 0 even when there have been errors. To detect an error, use try and catch: see Errors and exceptions.
Base64 encoding
encode64
The encode64 function encodes a text string to Base64 format. It's useful for transmitting binary data in text formats or for encoding credentials.
var text = "Hello World"
var encoded = encode64(text)
println(encoded) // SGVsbG8gV29ybGQ=
decode64
The decode64 function decodes a Base64 string and returns the original text.
var encoded = "SGVsbG8gV29ybGQ="
var decoded = decode64(encoded)
println(decoded) // Hello World
Base64 is very useful for sending data through protocols that only support text, such as HTTP or MQTT.
use MQTT
// Example: encode sensor data to send over MQTT
var data = "temperature:25.5,humidity:60"
var payload = encode64(data)
MQTT.publish("sensors/data", payload)
Constants
The compiler knows them, and they can be used in any file without use:
| Constants | Value | What for |
|---|---|---|
HW_ESP32, HW_ESP32S3, HW_WIN32, HW_WEB, HW_ESP32P4, HW_ESP32S31 | 1, 2, 4, 5, 6 and 7 | What platform() returns. |
tBool … tEnumerator | From 0 to 22 | The types of type(). |
ERR_UNKNOWN … ERR_TIME_OUT | From 1 to 29 | The errors: see Errors and exceptions. |
LOW, HIGH | 0 and 1 | The levels of a pin: see GPIO. |
PI | π: println(PI) writes 3.141592653589793 | See Math. |
SQRT2 | √2: println(SQRT2) writes 1.4142135623730951 | See Math. |
Full example
It rolls a die 600 times, counts how many times each face comes up and measures how long it takes:
// With the same seed, the rolls are always the same.
randomize(2026)
var times = [0, 0, 0, 0, 0, 0]
var start = clock()
for (var i = 0; i < 600; i = i + 1)
var face = random(1, 6)
times[face - 1] = times[face - 1] + 1
end
var expected = 600 div 6
for (var f = 1; f <= 6; f = f + 1)
var n = times[f - 1]
println("Face ", f, ": ", n, " times (", abs(n - expected), " off)")
end
println("It took ", clock() - start, " ms")
Face 1: 100 times (0 off)
Face 2: 112 times (12 off)
Face 3: 109 times (9 off)
Face 4: 87 times (13 off)
Face 5: 97 times (3 off)
Face 6: 95 times (5 off)
It took 2 ms
The last line changes from one run to the next.
Pitfalls and known issues
- Without
randomize,random()always repeats the same sequence (see randomize). printlnwrites the digits the decimal has:0.1 + 0.2comes out as0.30000000000000004, because it isn't exactly 0.3. To show it rounded, usetoString()(see print / println).intandfloatdo not convert strings: usetoInt()andtoFloat().lencounts bytes in strings, and does not accept arrays.readLine()gets nothing on the boards (see readLine).inkandpaperdo nothing on Windows (see ink / paper).time()with a%code that does not exist closes the VM on Windows (see time).vmerror()always returns 0 (see vmerror).type()with an error value leaves the VM's stack out of place (see type).
All the known issues of JARU, together, are in Known issues.