Skip to main content

Write Dart.
Run it on a microcontroller.

moth compiles a subset of Dart to compact bytecode and interprets it on the chip. The same language you use for Flutter, now blinking an LED — no second toolchain, no C.

Runs on ESP32-S3 · MIT licensed · v0.x, API unstable

blink.dart
void main() {
var led = 38;
pinOutput(led);

var on = false;
while (true) {
on = !on;
digitalWrite(led, on);
delay(500);
}
}
your terminal — with no board it opens the simulator
$ dart pub global activate mothc
$ moth run blink.dart
Launching blink.dart on /dev/cu.usbmodem21201

pushed in 174ms
r hot restart (recompile + push; state resets)
h this help q quit

Why moth

Not a code generator and not a lookalike syntax — a real interpreter running your compiled Dart on the microcontroller itself.

🦋

One language, both worlds

If you are learning Dart for Flutter, the board on your desk speaks it too. The for loop you already know, on a chip that costs a few dollars.

Runs without hardware

The simulator drives pins, I2C and UART against a virtual clock, so three seconds of blinking finish instantly. Buy the board later.

🔌

Arduino parity

digitalWrite, analogRead, PWM, tone, millis, servos, I2C with bulk reads, UART, and preferences that survive a reboot — the names match Arduino, so any tutorial translates line for line.

📦

A program, not a firmware image

Blink is 138 bytes of bytecode. Push a change over the USB cable and it is on the screen in well under a second — no reflashing. Paired WiFi pushes add ~2s deriving the pairing key (or cache it in MOTH_PUSH_KEY).

See it run

One unedited take: moth run, a device picker because two boards are plugged in, a color edit in the editor, and r — the panel is orange before the logs settle.

Touch is renderer-owned, so controls track a finger without the VM in the frame loop — a slider and a switch from examples/ui/controls.dart, pushed over the same running session:

Honest status

moth is early. Everything in the left column either runs in CI or was measured on the board; everything on the right is genuinely not built yet.

Working today

  • Strings, lists, classes, closures, garbage collection
  • Flutter-named widgets, setState, sliders, switches, and embedded images — 38fps at 466x466, measured on the board
  • moth run — picks up a connected board (or opens the simulator), streams its console, and r hot-restarts in ~173ms
  • moth create scaffolds a project your editor understands — autocomplete and error-checking on every built-in
  • Hot push over the USB cable or paired WiFi — no reflashing
  • Digital and analog I/O, PWM, tone, servos, I2C with bulk reads and writes, UART, NVS-backed preferences
  • Installs from pub: dart pub global activate mothc
  • Desktop simulator, golden tests, paint-cost budgets
  • ESP32-S3 with the Waveshare 1.75" round AMOLED — the verified board

Not yet

  • Interrupts and async
  • SPI
  • Enums, mixins, extensions, and capturing locals in closures
  • Scalable text and gradients
  • Network and vector images — Image embeds PNG/JPEG at compile time only
  • State-preserving hot reload — r is a hot restart (~173ms) and your state resets
  • Boards beyond the one above — other ESP-IDF targets are ports, not rewrites, but none is built or verified

Blink something in five minutes

dart pub global activate mothc, then moth create and moth run — a board is optional; without one it opens the simulator.