3 languages in a trenchcoat
A questionable combination of JavaScript (in syntax), FORTH (in spirit) and MicroPython (in terms of scope and being a wild mix of weird and kinda cool).
Dear $deity, why?
- Hot code reloading on embedded without having to flash a whole new binary: especially on
esp32-idfimage size and thus turnaround time can be a bit of an obstacle. - Port Pixelblaze to Rust.
See it in action
this is the web app, JavaScript editor + live updated in-browser rendering of the code, alongside hot code reload sent to a no_std,no_alloc microcontroller

Features
-
extremely fast turnaround, no noticable delay between code change and web app/mcu update
-
Care has been taken to keep runtime platform, language and language dialect generic. This means:
- runtime: you can run
trenchcoaton a PC, a microcontroller, or in the browser. - language dialect: Pixelblaze-specific JavaScript extensions are factored out and don't pollute the standard JS namespace
- language: the virtual machine actually executing code is a language-agnostic stack machine, there just happened to be a JavaScript parser lying around. If you want to add, say, Python syntax support, you totally can! I won't! (Pull requests are welcome, though)
- runtime: you can run
Limitations
- Only a very minimal subset of JavaScript and Pixelblaze functionality is supported. You want
forloops? Maybe in the next release… - Extremely unoptimized! Also, basically no prior art has been considered so it's probably full of Arrogant Rookie™ mistakes.
- Parsing is not available on microcontrollers (so, no on-device REPL). The architecture allows implementing it, though.
- the existing
no_stdembedded apps don't use an allocator, which means a lot of wasted memory for static buffer headroom. Allocator support is implemented but not currently used. - The license needs to be piped through a lawyer.
Enough talking, how do I run this?
Right now the main focus lies on getting pixelblaze support to mature, so that's also what these instructions will focus on.
The general approach is:
- Pick a runtime (console/web/embedded) and compile JavaScript/Pixelblaze source to bytecode
- For embedded only: pick an update path - the web app uses inline compilation + HTTP to UART updates for hot code reload, but if you don't need that, you can also use the bundled
console-compilerto compile bytecode to disk (.tcbfor "TrenChcoat Bytecode" is a suggested file extension) and "somehow" have your firmware access it, e.g. viainclude_bytes! - Spawn an
Executor,start()it once and calldo_frame()as many times as you wish to produce LED colors. Onno_std"current time" needs to be advanced manually from some timer source (the example app reuses the frame task's scheduling interval).Executor::exit()is optional.
WeAct STM32F4x1 aka "USB-C pill", "black pill"
- you need a working hardware probe +
probe-runsetup. - the example app uses SPI2 on PB15 with 16 WS2812 LEDs. Most heavy LED lifting is done in the adjacent
f4-pericrate; you can also use SPI1+PB5 by using thespifeature instead of the defaultspi_alt.f4-perialso supports the SK9822/APA102 protocol if you prefer a more stable LED.
cd console-compiler
# rainbow melt is the only verified-working file at the moment
cargo run -- -f pixelblaze -i ../res/rainbow\ melt.js -o "../res/rainbow melt.tcb"
cd ../stm32f4-app
# probe-run is required
cargo rrb app
Espressif C3 (and potentially S2)
TODO, up next!
Raspberry Pi Pico
TODO, up next!
Browser
(a cool bear spawns from an adjacent universe)
cool bear: Browser? As in ... you're running a rudimentary JavaScript virtual machine ... in the browser ...
author, in straightjacket: you got that exactly right. With no performance-boosting offload support whatsoever!
On the bright side, we don't need a separate compilation step as part of our build. Because the compiler also runs in the browser, muahahaha
See main.rs for more details. Currently the web app is wildly inefficient (but still plenty fast), and also the editor permanently loses cursor position. WIP.
cargo install --git https://github.com/DioxusLabs/cli # their stable version seems broken atm
cd web-app
dioxus serve
$browser http://localhost:8080/
Acknowledgements
- Forth-ish VM inspired by forth-rs
- Abstract (
log/defmt) logging macros courtesy of dirbaio and whitequark - Cool Bear™ by fasterthanlime