Skip to main content

Architecture overview

This section is for contributors and the deeply curious. 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 ~10-function host interface, and every dynamic JSX expression becomes an effect subscribed to exactly the signals it reads. The app ships as precompiled bytecode running on quickjs-ng (parser removed on device); 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 doubles 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 ~10 functions; u16 IDs from kog-protocol
──────────────────────────────
Portable C core handle table, prop dispatch tables,
(kog_core, kog_bindings, kog_quickjs) style interning, unified event loop, GC policy
──────────────────────────────
Ports kog_port_sdl + kog_hal_sim (simulator)
kog_port_esp + kog_hal_esp (ESP-IDF)
──────────────────────────────
LVGL v9 · quickjs-ng · FreeRTOS/SDL

Load-bearing 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-protocol generates 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; devices don't ship a JS parser — smaller, faster to boot, smaller attack surface.
  • The simulator is the runtime. Same C core, same bytecode, same dev protocol — hardware included, via a virtual pin table.

Spec index (repository spec/)

DocContents
00-overview.mdDecision log and repo map
01-language-semantics.mdRun-once semantics, transform rules, divergences
02-compiler-pipeline.mdBuild stages, ABI stamping
03-host-interface.mdThe __kog surface and C signatures
04-native-runtime.mdTasks, event loop, memory budgets, GC
05-ota-versioning.mdPartitions, bundle format, signing, rollback
06-boards.mdboard.yaml schema, three-tier build
07-hardware-io.mdHAL, pin registry, per-chip capability tables
08-dev-server.mdDev protocol, hot reload, discovery, flashing
09-components-styling.mdComponent surfaces, StyleSheet, navigation, FlatList contract
10-roadmap.mdPost-v1: AOT tier, Fast Refresh, expanders