Preview 0.1.0 · MBC v28

One app.Everyscreen.

Micro OS is a portable application layer for small devices. Write a restricted TypeScript app, compile it to versioned bytecode, and run the same binary on an ESP32-S3, a Mac, or in the browser — under a deterministic, capability-gated runtime.

ESP32-S3macOSWebAssemblyNo JavaScript engine
MICRO OS800 × 480 · RGB565
GT911 / CH422G8 MiB FLASH · 8 MiB PSRAM
MBC v2810,000 instr / handler0 JS engines

Not a framework. A contract between one app and every screen it runs on.

A framework asks the host to run your source. Micro OS asks the host to run a binary contract: a validated MBC image, a static UI tree, reactive state, and a default-deny list of host calls. The host supplies pixels, input and platform services. Nothing else crosses the line.

The core has no platform dependencies. That is why an 800 × 480 panel, a macOS window and a browser tab can share one runtime instead of three rewrites.

  • 01
    One binary Apps ship as MBC v28 — not source, not a bundle, not a WebView.
  • 02
    One runtime Events, state, bindings and patches live in a single Rust core.
  • 03
    One boundary Every side effect is a host call, checked against manifest capabilities.
  • 04
    Three hosts LVGL on metal, LVGL on desktop, DOM through WebAssembly.
28
MBC format version
versioned + CRC-32
10k
instructions per handler
hard budget
3×
supported hosts
metal · desktop · web
8
launcher slots
built-in + SD card

Small by construction.

Every constraint is load-bearing. No threads, no GC, no dynamic widgets, no ambient I/O — the surface is small enough to validate, test and reason about on a device that fits in your hand.

FormatMBC1

Bytecode, not a browser

The device never parses TypeScript. An MBC image carries constants, state, handlers, the UI tree, host-request descriptors and the manifest behind a CRC-32. Bad references and bad versions are rejected before frame one.

RuntimeBounded

10,000 instructions, then the host gets control

Every handler runs under a hard budget. Writes completed before exhaustion are committed, dirty bindings are flushed, and the queue keeps moving.

6,204EXAMPLE · 10,000
0illustrative
StatePatches

Reactive values, not a virtual DOM

The tree mounts once. Each binding records exactly which state slots it reads, so a write dirties only its subscribers and emits a patch for an existing node.

RenderOne tree

One UI tree, three renderers

The runtime emits LVGL objects, DOM nodes or native SDL-backed widgets through the same narrow port. Host chrome — the 40 px app bar, power state, back gesture — belongs to the host, not the app.

SecurityDefault deny

Permissions start empty

A manifest declares capabilities; the compiler rejects calls outside them and the runtime gates the host boundary again. There is no ambient filesystem, network or clock.

clockkvconfigstoragenetaudiojsondeviceos
InstallNo reflash

Drop an app on the card

Eight launcher slots. Built-in apps occupy the first ones; compiled .mbc files in /apps are scanned before Home and appended. A built-in id always wins a collision.

Built-in + SD card8 slots total

A straight line from source to pixels.

The compiler runs on the development host. The runtime runs on the device. Renderers only know how to paint a tree and apply a patch.

01 / SOURCE

app.ts

A restricted TypeScript subset with state, bindings and a declarative UI.

const count = state(0)
02 / COMPILE

microc

SWC parse, allow-list diagnostics, lowering, structural validation, encode.

MTS002 · host call denied
03 / SHIP

.mbc

Versioned image with CRC-32, validated again at load time, before execution.

MBC1 · v28 · 6.9 KiB
04 / RUN

micro-core

FIFO events, typed stack VM, state store, bindings, render patches.

10,000 instructions / handler
05 / PAINT

Host port

LVGL, SDL3 or DOM. Same tree, same patches, different pixels.

LVGL 9.5 · DOM
micro-ir · micro-vm · micro-core stay platform-freeOpen the full map

The whole app is one file.

No package graph, no bundler config, no runtime imports. One app.ts declares its manifest, mounts a tree and compiles to one artifact. The SDK is a type declaration, not an execution environment.

  • state / bind / ui.mount — no JSX, no hooks
  • capabilities declared once, enforced twice
  • MBC v28 artifact, CRC-32 validated
  • same source builds for native, Wasm and device
Read the quickstart
apps/counter/app.ts
const count = state(0);
const note = state("micro");

ui.mount(
  ui.column([
    ui.text("Counter Studio", {
      font: "uiSans", size: 18, lineHeight: 24,
    }),
    ui.text(bind(() => `Count: ${count.value}`), {
      size: 32, lineHeight: 40,
    }),
    ui.button("Add", {
      onClick: () => { count.value++; },
    }),
    ui.button("Reset", {
      onClick: () => { count.value = 0; },
    }),
    ui.input(bind(() => note.value), {
      placeholder: "type a note",
      onChange: (text) => { note.value = text; },
    }),
  ]),
);
TypeScript subset · compiled ahead of timeMBC1

The bytes are the demo.

These captures come from the Web Player: the same compiled MBC, the same Rust runtime, running in a browser tab. The UI is real; the board services are simulated.

micros / home
Micro OS home screen with Counter, Settings and momo in the launcher
HomeShell MBC · 8 slots
micros / counter
Counter Studio app running with Add, Reset and Double controls
CounterState + bind · MBC v28
micros / momo
momo vocabulary trainer dashboard with today's plan and streak
momoReal app · KV + sync
Captured from the browser host at 800 × 480See the app layer

A real app, not a hello world.

momo is a 墨墨-style vocabulary trainer written in the same restricted TypeScript. It keeps a per-word Ebbinghaus schedule, runs a four-step study loop and survives a reboot.

Up to five local users share one install, with namespaced KV and config. On macOS, the sync tab imports the active account's today queue through the native HTTP bridge, then enriches words with definitions and examples.

9review intervals
4study stages
5local users
10active word slots
Read the momo breakdown
momo study dashboard on a warm paper canvas with a daily goal and streak
momo · Web PlayerKV-backed · MBC v28

Design decisions, written down.

Short essays on the choices behind the runtime: why bytecode, why a hard budget, and how one UI tree survives three renderers.

02Runtime

The 10,000-instruction budget

What happens when an app handler runs away, why work is bounded per event, and how failure stays local to one app.

Oct 20, 2026·5 min
03Interface

A UI tree for three renderers

Static trees, reactive bindings and render patches: how one layout survives LVGL, SDL3 and the DOM without a layout engine.

Oct 14, 2026·7 min
Long-form notes from the buildAll notes

Quickstart

Build something
small.

Compile an app, open the native window, or run the Web Player. The first build takes a few minutes; later builds reuse the cache.

micros — zsh
$ npm install
$ npm run build:app
  microc → apps/*/dist/*.mbc
$ npm run demo
  Micro OS · native window · Home
# or the browser runtime
$ npm run dev:web