Skip to main content

Architecture

mcujs is organized around replaceable boundaries: the JavaScript engine, host runtime, native bindings, firmware services, board support, and examples. Keep changes inside the narrowest layer that owns the behavior.

Layers​

LayerPathsOwns
JavaScript engine adapterjavascript/, host/engine.*, host/jerry_port.cJerryScript setup, evaluation, engine-facing helpers
Module systemhost/module_loader.*, host/bindings/require.cCommonJS resolution, JSON loading, module cache
Native bindingshost/bindings/JavaScript APIs for GPIO, PWM, I2C, SPI, ADC, filesystem, HID, display, process, board helpers
Firmware servicessrc/boot flow, REPL, USB CDC/MSC, filesystem integration, startup
Board supportboard/<board-id>/pin maps, flash size, feature flags, memory maps, Pico SDK board selection
Userland examplesexamples/reusable JavaScript demos and board-local drivers
Toolingbuild.sh, docker-entrypoint.sh, scripts/deterministic builds, release packaging, source verification

Engine boundary​

JerryScript is the current engine, but it should stay replaceable. New runtime behavior should not require board code to know JerryScript details. Prefer these boundaries:

  • Engine setup and raw jerry_value_t handling stay in javascript/, host/engine.*, and host/bindings/.
  • Firmware services expose C APIs that bindings can call.
  • JavaScript-facing APIs are documented as runtime contracts, not JerryScript contracts.
  • Dependency versions exposed through process.versions must match the Dockerfile and CMake compile definitions.

Board boundary​

Board configuration belongs in board/<board-id>/. Build and release tooling discovers supported board IDs from scripts/lib/boards.sh, then CMake includes board/<board-id>/board_config.cmake.

Keep board changes explicit:

  • Put pin and feature constants in board_config.h.
  • Put CMake board selection and compile definitions in board_config.cmake.
  • Add a memory map only when flash layout needs it.
  • Document examples and pin notes in Hardware and Boards.

Serial boundary​

USB CDC serial output must use \r\n. That applies to REPL output, errors, command responses, and any new native code that writes text to serial.

Example boundary​

Examples should preserve REPL recovery:

  • Use setInterval() and setTimeout() for demos and animation loops.
  • Avoid indefinite loops in top-level example code.
  • Print progress with console.log().
  • Stop long-running demos after a fixed duration when possible.

Release boundary​

Release artifacts are produced by scripts, not by hand:

  • scripts/verify-release.sh checks source metadata and docs coverage.
  • ./build.sh all --clean builds every supported board.
  • scripts/package-release.sh writes checksums and a manifest.
  • scripts/release.sh runs the full release flow.

This keeps the public release process reproducible and easy to review.