Architecture overview
This section is for contributors and anyone curious about the internals. The authoritative, detailed specifications live in the repository's spec/ directory; this page is the orientation map.
The one-paragraph version
Kog compiles standard TSX into JavaScript that targets a fine-grained signals runtime: component functions run once at mount, building LVGL widgets directly through a host interface of ~30 __kog methods (~70 functions including hw/flatlist/net), and every dynamic JSX expression becomes an effect subscribed to exactly the signals it reads. The app ships as precompiled bytecode running on MQuickJS, an embedded JS engine that executes precompiled bytecode in place from read-only flash. That property is what makes Kog fit on a bare, PSRAM-less ESP32. The native side is a portable C core: one task owning both LVGL and the JS engine, an event loop where LVGL's timer wheel also serves as the JS scheduler, and a hardware layer on a separate worker task. The same C core compiles into the desktop simulator (SDL) and the ESP32 firmware.
Layer diagram
Your app (TSX, hooks) packages: @kog/react, @kog/ui, @kog/hardware
──────────────────────────────
Compiler (Babel via esbuild) @kog/compiler: reactive-read rewriting,
tsc --noEmit gate JSX → host calls, Show/For lowering,
style interning, prop-ID interning
──────────────────────────────
Signals runtime (JS, tiny) @kog/runtime: $signal/$memo/$effect,
batching, ownership/disposal, show/forEach
──────────────────────────────
__kog host interface ~30 methods (~70 incl. hw/flatlist/net);
u16 IDs from kog-protocol
──────────────────────────────
Portable C core handle table, prop dispatch tables,
(kog_core, kog_bindings, kog_mquickjs) style interning, unified event loop, GC policy
──────────────────────────────
Ports kog_port_sdl + kog_hal_sim (simulator)
kog_port_web + kog_hal_sim (WASM simulator)
kog_port_esp + kog_hal_esp (ESP-IDF)
──────────────────────────────
LVGL v9 · MQuickJS · FreeRTOS/SDL
Key design decisions
- No VDOM on a retained-mode renderer. LVGL widgets already persist; diffing a virtual tree against them would duplicate state on the device with the least RAM. Fine-grained effects write straight to widget setters.
- One shared ID vocabulary.
kog-protocolgenerates both the C enums and the compiler's tables from one JSON file; its version is the ABI. No property-name strings ever cross the wire or live on the device. - One task owns the UI. JS and LVGL share a thread by construction, so application code cannot race the renderer; everything else (network, hardware buses) marshals in through queues.
- Bytecode-only devices. Apps are compiled to bytecode on the host and devices never parse app source, so they boot faster and need far less JS heap. (The parser is still linked on device, because the ROM stdlib exposes global
eval.) - The simulator is the runtime. Same C core, same engine, same dev protocol. Hardware is included too, via a virtual pin table. (During
kog dev, the simulator evaluates the JS bundle while a board receives precompiled bytecode.) - The engine behind one seam. All JS-engine API use is isolated in a single adapter. The engine (MQuickJS, which runs bytecode in place from flash) sits behind that stable seam, and everything above the
__koghost interface is engine-agnostic. (An earlier build used that seam to keep a second engine, quickjs-ng, swappable behindKOG_JS_ENGINE; Kog has since unified on MQuickJS and retired quickjs-ng.)
Spec index (repository spec/)
| Doc | Contents |
|---|---|
00-overview.md | Decision log and repo map |
01-language-semantics.md | Run-once semantics, transform rules, divergences |
02-compiler-pipeline.md | Build stages, ABI stamping |
03-host-interface.md | The __kog surface and C signatures |
04-native-runtime.md | Tasks, event loop, memory budgets, GC |
05-ota-versioning.md | Partitions, bundle format, signing, rollback |
06-boards.md | board.yaml schema, three-tier build |
07-hardware-io.md | HAL, pin registry, per-chip capability tables |
08-dev-server.md | Dev protocol, hot reload, discovery, flashing |
09-components-styling.md | Component surfaces, StyleSheet, navigation, FlatList contract |
10-roadmap.md | Post-v1: AOT tier, Fast Refresh, expanders |
11-web-simulator.md | The WASM simulator + in-browser docs playground |
12-web-flash-devlink.md | Browser flashing + the framed serial dev-link |
13-networking.md | Zero-import fetch/WebSocket/sockets/Wi-Fi across all targets |
16-rom-bytecode-inplace.md | MQuickJS: run bytecode in place from flash, deploy/relocation layout (draft) |