LVGL ESP32 Simulator
БесплатноНе проверенHeadless LVGL simulator for ESP32 UI development that compiles C code, renders PNG screenshots, and exports widget trees without physical hardware.
Описание
Headless LVGL simulator for ESP32 UI development that compiles C code, renders PNG screenshots, and exports widget trees without physical hardware.
README
MCP (Model Context Protocol) server that gives Claude visual feedback when writing LVGL UI code for ESP32. It compiles C code snippets in a headless LVGL simulator on Windows and Linux, captures a PNG screenshot and a JSON widget tree, and returns them through the MCP protocol. No hardware, no flashing, no SDL window needed.
┌─────────────┐ stdio (JSON-RPC) ┌──────────────────┐
│ Claude Code │◄───────────────────────►│ MCP Server │
│ (client) │ │ (Node.js) │
└─────────────┘ └────────┬─────────┘
│ compile + run
┌────────▼─────────┐
│ LVGL Simulator │
│ (headless C) │
│ → PNG + JSON │
└──────────────────┘
Quick start (npm)
npm install -g lvgl-mcp-server
The simulator binary is downloaded automatically from GitHub Releases during install.
Add to your Claude Code config (.claude/settings.json or global settings):
{
"mcpServers": {
"lvgl-simulator": {
"command": "npx",
"args": ["lvgl-mcp-server"]
}
}
}
Done. Claude now has lvgl_render, lvgl_render_full, lvgl_inspect, and other LVGL tools.
Prerequisites
The prebuilt binary ships for Windows x64 and Linux x64. To build the simulator from source you need a C toolchain, CMake, and a build generator.
Windows
| Tool | Version | Notes |
|---|---|---|
| Windows | 10/11 x64 | No WSL required |
| Visual Studio Build Tools | 2019+ | Only the C/C++ build tools workload (cl.exe) |
| CMake | 3.16+ | Included with ESP-IDF or install separately |
| Ninja | 1.10+ | Included with ESP-IDF or install separately |
| Node.js | 18+ | For the MCP server |
If you have ESP-IDF installed, CMake and Ninja are already available.
Linux
| Tool | Version | Notes |
|---|---|---|
| Linux | x64 | Any modern distribution |
| gcc or clang | recent | C compiler (cc by default; override with CC) |
| CMake | 3.16+ | Build configuration |
| Ninja or Make | any | Ninja preferred; falls back to Unix Makefiles |
| Node.js | 18+ | For the MCP server |
On Debian/Ubuntu, install the build dependencies in one line:
sudo apt install build-essential cmake ninja-build
Setup from source (alternative)
If you prefer to build from source instead of using npm:
1. Clone
Windows (PowerShell):
git clone --recursive https://github.com/jaklys/Lvgl-mcp-esp32.git
cd Lvgl-mcp-esp32
Linux (bash):
git clone --recursive https://github.com/jaklys/Lvgl-mcp-esp32.git
cd Lvgl-mcp-esp32
If you already cloned without --recursive:
git submodule update --init --recursive
2. Build everything
The setup script validates tools, builds the simulator, and builds the MCP server.
Windows (PowerShell):
powershell -ExecutionPolicy Bypass -File scripts/setup.ps1
Or build manually:
# Simulator (opens a VS Developer Command Prompt internally)
scripts\build.bat
# MCP server
cd mcp-server
npm install
npm run build
Linux (bash):
# Full setup: validate tools, build simulator, build MCP server, print config snippet
./scripts/setup.sh
Or build just the simulator:
# Simulator (uses cc by default; Ninja if available, else Make)
./scripts/build.sh
# MCP server
cd mcp-server
npm install
npm run build
3. Configure Claude Code
Windows:
{
"mcpServers": {
"lvgl-simulator": {
"command": "node",
"args": ["C:/Users/YOUR_USER/path/to/Lvgl-mcp-esp32/mcp-server/dist/index.js"]
}
}
}
Linux:
{
"mcpServers": {
"lvgl-simulator": {
"command": "node",
"args": ["/home/YOUR_USER/path/to/Lvgl-mcp-esp32/mcp-server/dist/index.js"]
}
}
}
Replace the path with your actual project location. Forward slashes work on Windows too.
You can also set the project root explicitly if the auto-detection doesn't work:
{
"mcpServers": {
"lvgl-simulator": {
"command": "node",
"args": ["/home/YOUR_USER/path/to/Lvgl-mcp-esp32/mcp-server/dist/index.js"],
"env": {
"LVGL_PROJECT_ROOT": "/home/YOUR_USER/path/to/Lvgl-mcp-esp32"
}
}
}
}
Usage
Once configured, Claude has access to these MCP tools:
lvgl_render — Render a code snippet
The main tool. Send LVGL C code and get back a screenshot. Your code runs inside a create_ui() function with a screen variable (lv_obj_t*) already available:
Use lvgl_render to show a button with a label:
lv_obj_t *btn = lv_button_create(screen);
lv_obj_set_size(btn, 200, 50);
lv_obj_center(btn);
lv_obj_t *label = lv_label_create(btn);
lv_label_set_text(label, "Click Me!");
lv_obj_center(label);
Returns:
- PNG screenshot of the rendered UI
- JSON widget tree with full style information (see JSON output format)
- Render time
You can override the resolution per-call:
Use lvgl_render with width=320 height=240 and code:
lv_obj_t *label = lv_label_create(screen);
lv_label_set_text(label, "Small display");
lv_obj_center(label);
lvgl_render_full — Render a complete C file
For complex UIs with multiple functions, helper code, or custom includes. The file must define void create_ui(void):
#include "lvgl.h"
static void build_header(lv_obj_t *parent) {
lv_obj_t *header = lv_obj_create(parent);
lv_obj_set_size(header, lv_pct(100), 50);
lv_obj_set_style_bg_color(header, lv_color_hex(0x003a57), 0);
lv_obj_t *title = lv_label_create(header);
lv_label_set_text(title, "My App");
lv_obj_set_style_text_color(title, lv_color_white(), 0);
lv_obj_center(title);
}
void create_ui(void) {
lv_obj_t *screen = lv_screen_active();
lv_obj_set_flex_flow(screen, LV_FLEX_FLOW_COLUMN);
build_header(screen);
lv_obj_t *body = lv_label_create(screen);
lv_label_set_text(body, "Content area");
lv_obj_set_flex_grow(body, 1);
}
lvgl_inspect — Get the widget tree
Returns a JSON representation of every widget: type, position, size, computed styles, plus widget-specific data (label text, slider value/min/max, checkbox state, etc.).
Use lvgl_inspect on the last rendered UI
Example output:
{
"type": "lv_obj",
"x": 0, "y": 0, "w": 800, "h": 480,
"styles": {
"bg_color": "#ffffff", "bg_opa": 255,
"text_color": "#212121", "text_font_size": 16,
"border_width": 0, "border_color": "#000000",
"radius": 0,
"pad_top": 0, "pad_bottom": 0, "pad_left": 0, "pad_right": 0, "pad_gap": 11,
"opa": 255
},
"children": [
{
"type": "lv_button",
"x": 300, "y": 215, "w": 200, "h": 50,
"styles": {
"bg_color": "#2196f3", "bg_opa": 255,
"text_color": "#ffffff", "text_font_size": 14,
"border_width": 0, "border_color": "#000000",
"radius": 12,
"pad_top": 11, "pad_bottom": 11, "pad_left": 20, "pad_right": 20, "pad_gap": 4,
"opa": 255
},
"children": [
{
"type": "lv_label",
"x": 56, "y": 14, "w": 87, "h": 21,
"text": "Click Me!",
"styles": { "text_color": "#ffffff", "text_font_size": 14, "..." : "..." }
}
]
}
]
}
lvgl_set_resolution — Change display size
Match your target hardware:
Use lvgl_set_resolution with width=320 height=240
Common ESP32 display sizes:
- 320x240 (2.4" - 2.8" ILI9341/ST7789)
- 480x320 (3.5" ILI9488)
- 800x480 (5" - 7" displays, default)
lvgl://api-reference — LVGL API cheat sheet
MCP resource with a quick reference for LVGL 9.5 widgets, styles, layouts, colors, and symbols. Claude can read this to write correct code without guessing.
JSON output format
Every widget node in the JSON tree includes:
| Field | Description |
|---|---|
type |
Widget class name (lv_obj, lv_button, lv_label, lv_slider, lv_bar, lv_arc, lv_switch, lv_checkbox, lv_dropdown, lv_textarea, lv_chart, lv_table, ...) |
x, y |
Position relative to parent (pixels) |
w, h |
Size (pixels) |
styles |
Computed style properties (see below) |
text |
Label text (for lv_label widgets) |
value |
Current value (for lv_slider, lv_bar, lv_arc) |
min, max |
Range (for lv_slider, lv_bar, lv_arc) |
checked |
State (for lv_checkbox, lv_switch) |
children |
Nested child widgets |
Style properties
Every node includes a styles object with computed (resolved) values:
{
"bg_color": "#2196f3",
"bg_opa": 255,
"text_color": "#ffffff",
"text_font_size": 16,
"border_width": 2,
"border_color": "#d4af37",
"radius": 12,
"pad_top": 10,
"pad_bottom": 10,
"pad_left": 20,
"pad_right": 20,
"pad_gap": 8,
"opa": 255
}
Colors are in #rrggbb hex format. Opacity values range from 0 (transparent) to 255 (opaque). Font size is in pixels.
Examples
The examples/ directory contains rendered output from the MCP server — PNG screenshots and corresponding JSON widget trees.
Note: these example renders were produced with LVGL 9.2 and may differ slightly when re-rendered with LVGL 9.5. The pre-2.0 example JSONs also use the old short widget type names (
obj,btn,label, ...) instead of the prefixed names (lv_obj,lv_button,lv_label, ...) emitted since LVGL 9.5.
Demo renders
| Screenshot | JSON | Description |
|---|---|---|
| 01-button-slider.png | JSON | Button + slider basic layout |
| 02-dashboard.png | JSON | Multi-card dashboard |
| 03-esp32-small.png | JSON | ESP32 status at 320x240 |
| 04-esp32-small.png | JSON | ESP32 status (alternate) |
E-BREW brewery control screens (real project)
All 8 screens from the E-BREW brewery controller rendered through the simulator at 800x480:
| Screenshot | JSON | Screen |
|---|---|---|
| ebrew-01-menu.png | JSON | Main menu (3x2 tile grid) |
| ebrew-02-overview.png | JSON | Overview (temperatures + controls) |
| ebrew-03-loading.png | JSON | Loading splash screen |
| ebrew-04-pump.png | JSON | Pump control |
| ebrew-05-control.png | JSON | Relay switches |
| ebrew-06-thermostats.png | JSON | Thermostat settings |
| ebrew-07-graphs.png | JSON | Temperature graphs |
| ebrew-08-sysinfo.png | JSON | System info |
How it works internally
- Claude sends C code via the
lvgl_rendertool - The MCP server wraps the snippet in a template (adds
#include "lvgl.h"andcreate_ui()boilerplate) - The wrapped code is written to
simulator/build/user_code.c - CMake incrementally recompiles only the changed file and links against the pre-built LVGL library
- The resulting simulator binary (
lvgl_sim.exeon Windows,lvgl_simon Linux) runs headless: initializes LVGL, creates a framebuffer display, callscreate_ui(), ticks the timer 10 times, then exports a PNG and a JSON widget tree - The MCP server reads the PNG, base64-encodes it, and returns it alongside the widget tree
Compilation uses MSVC (cl.exe) on Windows — via a temporary batch file that sets up the Visual Studio environment — and gcc/clang (cc by default) on Linux. Incremental builds only recompile the user code file (~1-2 seconds).
Project structure
Lvgl-mcp-esp32/
├── simulator/ Headless LVGL renderer (C)
│ ├── CMakeLists.txt Build config (Ninja/Make + MSVC or gcc/clang)
│ ├── lv_conf.h LVGL config (32bpp, all widgets, snapshot)
│ ├── main.c CLI: --width --height --output-png --output-json
│ ├── hal/
│ │ └── display_driver.c Framebuffer-only display (no SDL/window)
│ ├── export/
│ │ ├── screenshot.c Framebuffer → PNG (stb_image_write)
│ │ └── widget_tree.c lv_obj tree → JSON (with styles)
│ ├── templates/
│ │ └── user_code_wrapper.c Template for wrapping code snippets
│ └── lib/
│ ├── lvgl/ LVGL v9.5 (git submodule)
│ └── stb/stb_image_write.h PNG encoder (single header)
├── mcp-server/ MCP server (TypeScript)
│ └── src/
│ ├── index.ts Entry point, stdio transport
│ ├── tools/
│ │ ├── render.ts lvgl_render + lvgl_render_full
│ │ ├── inspect.ts lvgl_inspect + lvgl_get_styles
│ │ └── config.ts lvgl_set_resolution
│ ├── simulator/
│ │ ├── compiler.ts Invokes CMake/MSVC, manages user code
│ │ └── manager.ts Orchestrates compile → run → collect
│ └── resources/
│ └── api-reference.ts LVGL API cheat sheet
├── examples/ Example renders (PNG + JSON)
│ ├── 01-button-slider.* Basic widget demo
│ ├── 02-dashboard.* Multi-card layout
│ └── ebrew-01..08-*.* E-BREW brewery controller (8 screens)
├── .github/workflows/
│ ├── ci.yml CI: build + test on push/PR
│ └── release.yml Release: build + package on v* tag
├── scripts/
│ ├── setup.ps1 Windows: full setup (validate tools, build all)
│ ├── build.bat Windows: quick rebuild (simulator only)
│ ├── setup.sh Linux: full setup (validate tools, build all)
│ └── build.sh Linux: quick rebuild (simulator only)
└── README.md
Configuration
| Setting | Default | Location |
|---|---|---|
| LVGL version | v9.5.0 | Git submodule branch |
| Color depth | 32-bit (XRGB8888) | simulator/lv_conf.h |
| Display resolution | 800x480 | lvgl_set_resolution tool or CLI args |
| Available fonts | Montserrat 12, 14, 16, 20, 24 | simulator/lv_conf.h |
| All LVGL widgets | Enabled | simulator/lv_conf.h |
| Flex + Grid layouts | Enabled | simulator/lv_conf.h |
Troubleshooting
"CMake configure failed" — Make sure Visual Studio Build Tools are installed with the "Desktop development with C++" workload. The setup script looks for vcvarsall.bat in standard VS 2019/2022 paths.
"cl is not recognized" — The MCP server sets up the MSVC environment automatically via vcvarsall.bat. If you're building manually, run scripts\build.bat which handles this.
"cc: command not found" (Linux) — No C compiler is installed. Install the toolchain with sudo apt install build-essential (or the equivalent for your distribution). You can point the build at a specific compiler with the CC environment variable.
"ninja: command not found" (Linux) — Ninja is optional; the build falls back to Unix Makefiles. To use Ninja, install it with sudo apt install ninja-build.
Render takes >5 seconds — The first render after server start includes CMake configuration (~1s extra). Subsequent renders are incremental (recompile user_code.c only).
Wrong colors in PNG — LVGL uses XRGB8888 which is BGRA in memory on x86. The screenshot exporter handles the byte swizzle. If colors look wrong, check simulator/export/screenshot.c.
"ENOENT: no such file or directory" — The LVGL_PROJECT_ROOT environment variable may be needed. Set it in your MCP server config to the absolute path of the project root.
Author
Установить LVGL ESP32 Simulator в Claude Desktop, Claude Code, Cursor
unyly install lvgl-esp32-simulatorСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add lvgl-esp32-simulator -- npx -y lvgl-mcp-serverПошаговые гайды: как установить LVGL ESP32 Simulator
FAQ
LVGL ESP32 Simulator MCP бесплатный?
Да, LVGL ESP32 Simulator MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для LVGL ESP32 Simulator?
Нет, LVGL ESP32 Simulator работает без API-ключей и переменных окружения.
LVGL ESP32 Simulator — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить LVGL ESP32 Simulator в Claude Desktop, Claude Code или Cursor?
Открой LVGL ESP32 Simulator на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare LVGL ESP32 Simulator with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
