Recently we announced our decision to shift from our proprietary BRAWL bytecode to embrace WebAssembly (WASM). WASM is becoming a global standard, and standardization matters when building technology that needs to be secure, interoperable, and future-proof.
We are proud to share that we’ve not only made a transition decision - we’ve done it by building our own WASM runtime from scratch, purpose-built for resource constrained microcontrollers.
A Extremely Lightweight Runtime
When we announced our shift to WebAssembly, we faced a clear choice: utilize an existing open source engine, or start from scratch. We chose the harder path, since we like challenges and also want to fully understand the implementation - in doing so, we created something that is uniquely suited for microcontroller environments.
Why Build Our Own Runtime?
Most WebAssembly engines are designed with desktops or high-end embedded Linux systems in mind. They assume megabytes of memory, operating systems, and in some cases, JIT compilation. They typically do not focus on a bare-metal microcontroller with only a few kilobytes of SRAM.
By writing our runtime from the ground up in C, we could:
- control every byte of the memory usage on the device
- control the opcode surface - focus on WebAssembly MVP (1.0)
- avoid hidden assumptions - we understand every line of code!
- guarantee determinism - essential for IoT and safety-critical environments
How Big Is The WASM Runtime?
Our runtime is surprisingly small given what it implements:
- ~12,000 lines of C - cleanly documented source
- ~46 KB flash overhead for the runtime - compared to a trivial Arduino sketch
- ~14 KB RAM overhead - adjustable based on requirements
That means a fully compliant WASM virtual machine can fit comfortably in the flash and SRAM of many microcontrollers on the market, leaving space for actual applications. We also chose an Arduino UNO R4 WiFi to demonstrate our runtime as it is a typical microcontroller that is available on the market.
How Reliable Is The WASM Runtime?
Code size alone is meaningless without validation and compliance. That is why testing and ensuring compliance to the WebAssembly MVP (1.0) standard was a major focus:
- we have almost 12,000 test cases
- the majority are derived from WAST, the official test suite
- we have also added hundreds of handcrafted edge cases
We can confidently claim our runtime is 100% compliant to WebAssembly MVP (1.0) specification.
DEMO: Arduino UNO R4 WiFi
We like to show that things work, proof is in the pudding as they say - we utilized the Arduino UNO R4 WiFi, powered by the Renesas RA4M1 microcontroller, specifically to demonstrate the capabilities of the WebAssembly runtime - providing host functions to create a demo that actually does something visual.
- MCU: Arm® Cortex®-M4F @ 48 MHz
- flash: 256 KB
- SRAM: 32 KB
- Onboard LED Matrix: 12x8
Arduino Sketches: LEDBounce_I32.ino and LEDBounce_F32.ino for Arduino UNO R4 WiFi.
We re-created a nice demo we saw on hackster.io demonstrating balls bouncing around the Arduino UNO R4 WiFi's LED Matrix. We have implemented two variants, one using I32 (fixed point 16:16) and the other F32 (floats) - depending on weather the target microcontroller has an FPU or not.
What It Means in Practice
On Arduino, there’s no operating system, no filesystems - just a microcontroller and simple peripherals. We kept our runtime MVP-pure (no custom opcodes), and exposed device features through set of hardware specific host functions (WASM imports); keeping the VM small and portable, while interacting directly with hardware like the Arduino UNO R4’s 12x8 LED matrix.
As an example, the WASM target for Arduino UNO R4 WiFi provides these host functions:
;; LED matrix lifecycle (import "brawl:device/matrix" "begin" (func $begin)) (import "brawl:device/matrix" "on" (func $on (param i32))) (import "brawl:device/matrix" "off" (func $off (param i32))) (import "brawl:device/matrix" "autoscroll" (func $autoscroll (param i32))) (import "brawl:device/matrix" "clear" (func $clear)) (import "brawl:device/matrix" "play" (func $play (param i32))) (import "brawl:device/matrix" "next" (func $next)) (import "brawl:device/matrix" "sequenceDone" (func $sequenceDone (result i32))) ;; pixel/sequence I/O (import "brawl:device/matrix" "loadFrame" (func $loadFrame (param i32 i32 i32))) (import "brawl:device/matrix" "loadPixels" (func $loadPixels (param i32 i32 i32))) (import "brawl:device/matrix" "loadSequence" (func $loadSequence (param i32 i32))) (import "brawl:device/matrix" "renderFrame" (func $renderFrame (param i32)))
The runtime resolves the host functions (WASM imports) by name (namespace + function), validates the types at load time, and binds them to real functionality on the device. A WASM call is just a direct, bounds-checked jump into the host device, as if it was a native application.
The Developer Experience
From a developer’s perspective, working with our runtime is straightforward: you write your logic in WebAssembly text format (WAT), compile it to standard WASM bytecode, and then let our runtime execute it on the device. Instead of coding directly against Arduino libraries, you target a small set of imported host functions that abstract the hardware (like the LED matrix).
WebAssembly also opens up the opportunity for developers to use high level languages such as C, Rust, JavaScript, Go and many more - while being able to compile into a universal bytecode that can potentially be deployed anywhere bring a true "write one, run anywhere" experience.
This means the same WASM module can run unmodified on any board that provides those imports. Looking ahead, we are extending our lifecycle management platform to support WASM as a first-class deployment format. Just like with our native microcontroller updates today, developers will soon be able to deliver and update WASM bytecode over the air - securely, seamlessly, and at scale.
Recognizing Our Interns
While this runtime has been project led internally, it would not have reached this milestone as quickly without the help of two talented interns who joined us through the Absolute Internship program.
Luis Daniel Filorio Luna and Maria Renee Ramos Valdez holding Arduino plug-and-make kits
"Luis Daniel Filorio Luna" and "Maria Renee Ramos Valdez" - Computer Science and Engineering students at "Instituto Tecnológico de Estudios Superiores de Monterrey" have worked hands-on with our team and assist in building our test framework and producing real examples to make this project a reality.
They have directly shaped the reliability of our WASM runtime. For us, internships are more than a learning opportunity for students; they are a way to bring new energy, ideas, and perspectives into our every day to day work work. This project is living proof of that.
We also want to recognize Absolute Internship for the professionalism and global reach they bring. By managing the logistics and matching us with interns who had the right skills and mindset, they enabled us to focus on innovation while ensuring the program ran smoothly.
This collaboration is something we’re proud of, and we look forward to continuing it in future projects.