Investigation of a tech stack for a future project
JavaScript 29.5%
C++ 29.0%
Rust 19.6%
CMake 17.1%
Just 3.2%
HTML 1.2%
Thrift 0.4%
12 1 0

Clone this repository

https://tangled.org/jonas.tngl.sh/hmi-stack https://tangled.org/did:plc:bgslv45eubr4gvkfwjd5kv7s/hmi-stack
git@knot.greitemann.dev:jonas.tngl.sh/hmi-stack git@knot.greitemann.dev:did:plc:bgslv45eubr4gvkfwjd5kv7s/hmi-stack

For self-hosted knots, clone URLs may differ based on your setup.

Download tar.gz
README.md

HMI Stack Demo#

This project demonstrates a modern tech stack for building a Human-Machine Interface (HMI) that can be deployed as a web application.

Overview#

The stack consists of three main components:

  1. HMI Server - A C++ service using Apache Thrift for RPC, running on TCP
  2. Directory Agent - A C++ WebSocket proxy that enables web and firewall-friendly access
  3. HMI Client - A Rust/egui application compiled to WebAssembly

Architecture#

The server communicates with clients via Apache Thrift. For web deployment and firewall accessibility, a WebSocket proxy (directory_agent) forwards client connections to the backend services over plain TCP.

┌─────────────┐         ┌─────────────────┐         ┌─────────────┐
│   Web       │   WS    │  Directory      │  TCP    │   HMI       │
│   Browser   │────────▶│  Agent          │────────▶│   Server    │
│   (WASM)    │  (8080) │  (proxy)        │  (9090) │             │
└─────────────┘         └─────────────────┘         └─────────────┘
        │
        ▼
┌────────────────────┐
│  Vite Dev Server   │
│  + WASM + Thrift   │
└────────────────────┘

Client Architecture (Rust/egui + WASM)#

The HMI Client uses Rust with egui for the UI, compiled to WebAssembly:

  • Rust/egui: UI framework compiled to WASM
  • wasm-bindgen: Rust-JavaScript interop
  • Thrift (JavaScript): Handles Thrift networking via WebSocket in the browser
  • Vite: Build tool and dev server

Getting Started#

Prerequisites#

  • C++ compiler with C++23 support
  • CMake 3.28+
  • Conan 2.x
  • Node.js 18+ with npm
  • just command runner
  • Apache Thrift CLI (optional - only needed if modifying hmi.thrift)
  • Rust toolchain with wasm32-unknown-unknown target
  • wasm-bindgen CLI

Build#

Full build (server + client):

# Install all dependencies
just install-deps

# Configure C++ build
just configure

# Build everything (server + embedded web client)
just build

Note: Run just codegen only after modifying hmi.thrift to regenerate the Thrift bindings.

Quick rebuild (after code changes):

just build

Server only:

just conan
just configure
just build

Client only:

just client-deps
just client-wasm
just client-build

Run#

# Terminal 1: Start the Thrift server
./server/build/Release/hmi-server

# Terminal 2: Start the directory agent (serves both WebSocket proxy and embedded web client)
./server/build/Release/directory_agent

# Open browser: http://localhost:8080/hmi/9090

The directory agent serves the embedded web client at:

  • http://localhost:8080/hmi/9090 - serves index.html with WASM client
  • http://localhost:8080/assets/* - serves static assets (JS, WASM)

The client connects to the WebSocket proxy at ws://localhost:8080/hmi/9090.

Production Build#

The production build embeds the web client assets (HTML, JS, WASM) directly into the directory_agent executable, so no separate server is needed for the web frontend.

# Build - this automatically builds the client and embeds it
just build

# Run - directory_agent serves both the API proxy and the web UI
./server/build/Release/directory_agent

Clean#

# Remove all build artifacts (keeps generated Thrift code)
just clean

Key Technologies#

  • Apache Thrift: Interface definition language and RPC framework
  • Vite: Next-generation frontend build tool
  • Rust/egui: UI framework compiled to WebAssembly
  • wasm-bindgen: Rust-JavaScript interoperability
  • Boost.Beast: C++ WebSocket library (Boost.Asio)
  • C++23: Modern C++ with coroutines