zedgui is a small C99 embedded GUI framework for MCU, bare-metal, RTOS, small LCDs, and SDL2 desktop simulation. It borrows proven ideas from object trees, events, styles, and themes, but keeps the first version intentionally small and readable.
V4.0 records the AI Embedded UI Studio foundation as a platform status checkpoint:
AI Brief -> AI Handoff Packet -> Designer Model -> JSON DSL -> C CodeGen -> MCU Port Template
It is not a stable production release claim. The implemented baseline is the core runtime, basic JSON DSL loader, basic zedgui C CodeGen, SDL2 demo source path, generated-C syntax/build smoke path, and basic part/state style API. Real hardware validation, complete Designer UX, production multi-target CodeGen, AI quality pipeline validation, and export package hardening remain pending.
include/: public C API.src/core/: object pool, object tree, events, input, refresh.src/core/zed_layout.c: minimal row/column layout with padding, gap, align, and flex grow.src/draw/: pixels, lines, rectangles, rounded rectangles, text, bars, switches, clipping.src/style/: style and theme definitions.src/widgets/: panel, label, button, bar, switch.ports/: MCU display/input integration templates.simulator/sdl2/: SDL2 display/input port and PC demo.examples/simple_demo/: reusable demo UI creation code.tools/: Designer model, CodeGen, resources, performance, export, Studio, and stabilization checks.tests/: non-SDL smoke targets for generated C.
The core library does not include SDL2 headers. SDL2 is only used by simulator/sdl2.
The V3.1 architecture notes are in:
docs/ARCHITECTURE.md
docs/RELEASE_CHECKLIST.md
docs/RELEASE_STATUS.md
docs/RELEASE_HISTORY.md
docs/platform/V4.0_AI_EMBEDDED_UI_PLATFORM.md
The default CMake path is core-only and does not require SDL2:
cmake -S . -B build_core -DZED_BUILD_SDL2_SIMULATOR=OFF
cmake --build build_core
ctest --test-dir build_coreRecommended options:
- The SDL2 simulator is opt-in. If
simulator/SDL2-2.0.12exists, the commonSDL2-devel-2.0.12-mingw.tar.gzpackage is a MinGW package, so configure with a MinGW compiler:
cmake -S . -B build-mingw -G Ninja -DCMAKE_C_COMPILER=gcc -DZED_BUILD_SDL2_SIMULATOR=ON
cmake --build build-mingwIf your default generator is Visual Studio, this MinGW SDL2 package cannot be linked by MSVC. Install an MSVC SDL2 development package or build with MinGW.
- Install SDL2 with vcpkg:
vcpkg install sdl2
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%/scripts/buildsystems/vcpkg.cmake -DZED_BUILD_SDL2_SIMULATOR=ON
cmake --build build- Or install SDL2 development package manually and expose it through
CMAKE_PREFIX_PATH.
Debian/Ubuntu:
sudo apt install libsdl2-dev cmake build-essential
cmake -S . -B build -DZED_BUILD_SDL2_SIMULATOR=ON
cmake --build buildFedora:
sudo dnf install SDL2-devel cmake gcc
cmake -S . -B build -DZED_BUILD_SDL2_SIMULATOR=ON
cmake --build build./build/simulator/sdl2/zedgui_sdl2_demoOn Windows, run:
build\simulator\sdl2\Debug\zedgui_sdl2_demo.exeor the matching Release path for your generator.
Run the architecture and example contract scan:
python tools/test/zed_v31_scan.pyBuild the non-SDL generated-C smoke target:
cmake -S . -B D:/tmp/zedgui_v31_smoke -DZEDGUI_BUILD_SDL2_DEMO=OFF -DZEDGUI_BUILD_MCU_RGB565_SIM=OFF -DZEDGUI_BUILD_EXAMPLE_SMOKE=ON
cmake --build D:/tmp/zedgui_v31_smoke --config DebugThis target compiles and runs examples/simple_demo/demo_ui_generated.c without SDL2.
The default CMake configure path is core-only and does not require SDL2:
cmake -S . -B build_core
cmake --build build_core
ctest --test-dir build_coreEnable SDL2 previews explicitly when the host has a compiler-compatible SDL2 package:
cmake -S . -B build_sdl -DZED_BUILD_SDL2_SIMULATOR=ONOn Windows, the bundled simulator/SDL2-2.0.12 package is MinGW-oriented. Leave SDL2 simulator builds disabled for the default MSVC CMake Tools configure, or install an MSVC-compatible SDL2 package.
V4.0 uses the same stabilization scan and adds release-asset coverage for the platform docs and Studio manifest. Treat these as checkpoint checks, not proof of production readiness:
python tools/test/zed_v31_scan.pyRepresentative performance checks:
python tools/perf/zed_perf_analyze.py examples/simple_demo/demo_ui.json --spi-mhz 40
python tools/perf/zed_perf_analyze.py examples/widget_gallery/widget_gallery.json --spi-mhz 40
python tools/perf/zed_perf_analyze.py examples/templates/industry/energy_inverter/ui.json --spi-mhz 40AA and alpha are compile-time optional:
cmake -S . -B D:/tmp/zedgui_v41_fast -DZEDGUI_BUILD_SDL2_DEMO=OFF -DZEDGUI_BUILD_MCU_RGB565_SIM=OFF -DZEDGUI_BUILD_EXAMPLE_SMOKE=ON -DZEDGUI_USE_ANTIALIAS=OFF -DZEDGUI_USE_ALPHA_BLEND=OFF
cmake --build D:/tmp/zedgui_v41_fast --config Debug
cmake -S . -B D:/tmp/zedgui_v41_aa -DZEDGUI_BUILD_SDL2_DEMO=OFF -DZEDGUI_BUILD_MCU_RGB565_SIM=OFF -DZEDGUI_BUILD_EXAMPLE_SMOKE=ON -DZEDGUI_USE_ANTIALIAS=ON -DZEDGUI_USE_ALPHA_BLEND=ON
cmake --build D:/tmp/zedgui_v41_aa --config DebugThe runtime macros are:
#define ZED_USE_ANTIALIAS 0
#define ZED_USE_ALPHA_BLEND 0Use docs/designer/v4.1_aa_preview.md for SDL2, Studio, and MCU switching notes.
The repository includes a Code::Blocks project for the local MinGW SDL2 package:
simulator/codeblocks/zedgui_sdl2_demo.cbp
Open this file in Code::Blocks and select a GNU GCC / MinGW compiler. The project expects:
simulator/SDL2-2.0.12/x86_64-w64-mingw32
Build the Debug or Release target. The post-build step copies SDL2.dll into:
simulator/codeblocks/bin/Debug
simulator/codeblocks/bin/Release
If Code::Blocks reports missing gcc, install the Code::Blocks MinGW bundle or configure Settings -> Compiler -> Toolchain executables to point to your MinGW-w64 installation.
Call one of these before creating widgets:
zed_theme_set(zed_theme_light());
zed_theme_set(zed_theme_dark());
zed_theme_set(zed_theme_blue_tech());
zed_theme_set(zed_theme_industrial());The demo uses zed_theme_blue_tech() by default.
V0.2 adds a small layout layer for MCU-friendly automatic positioning:
zed_obj_set_layout(card, ZED_LAYOUT_COLUMN);
zed_obj_set_padding(card, 16, 16, 18, 14);
zed_obj_set_gap(card, 16);
zed_obj_set_align(card, ZED_ALIGN_START, ZED_ALIGN_STRETCH);Supported layout modes:
ZED_LAYOUT_NONE
ZED_LAYOUT_ROW
ZED_LAYOUT_COLUMNSupported alignment values:
ZED_ALIGN_START
ZED_ALIGN_CENTER
ZED_ALIGN_END
ZED_ALIGN_SPACE_BETWEEN
ZED_ALIGN_STRETCHThe layout pass runs inside zed_timer_handler() before drawing. Objects without a layout keep their manually assigned coordinates.
V0.3 adds a small dirty-area refresh path. Core setters call zed_obj_invalidate() automatically, and the refresh handler redraws only dirty clips:
void zed_refr_invalidate_area(const zed_area_t *area);
void zed_refr_invalidate_full(void);Display drivers can optionally implement region flushing:
static void lcd_flush_area(const zed_area_t *area, void *user_data);
disp.flush_area = lcd_flush_area;
disp.flush = lcd_flush_done;If flush_area is NULL, zedgui still renders dirty clips into the framebuffer and calls flush() once. The SDL2 port uses this fallback because it presents a full texture.
V0.4 exposes zed_font_t and adds a small BDF converter:
python tools/fontconv/zed_fontconv.py tools/fontconv/samples/demo_5x7.bdf D:/tmp/zed_font_demo.c --name zed_font_demo_5x7Current converter limits:
- monochrome BDF input
- fixed-width output
- font height up to 8 pixels
- ASCII range 32-126 by default
Generated fonts can be attached through styles:
extern const zed_font_t zed_font_demo_5x7;
zed_style_t label_style;
zed_style_init(&label_style);
label_style.font = &zed_font_demo_5x7;
zed_obj_set_style(label, &label_style);V0.5 adds a minimal image asset format and PPM converter:
python tools/imgconv/zed_imgconv.py tools/imgconv/samples/status_led.ppm D:/tmp/zed_img_status_led.c --name zed_img_status_ledCurrent converter limits:
- PPM
P3andP6input - RGB888 output
- no alpha channel
- no compression
Generated images can be drawn directly:
extern const zed_image_t zed_img_status_led;
zed_draw_image(ctx, 10, 10, &zed_img_status_led);zed_img_t is provided as a short alias for zed_image_t, intended for generated UI/resource code.
The runtime does not decode PNG/JPEG. Conversion happens on the PC, and the MCU draws simple C arrays from flash.
- Core headers and sources do not include or call SDL2. SDL2 remains isolated in
simulator/sdl2. - Core headers and sources do not use
malloc,calloc,realloc, orfree. The SDL2 simulator allocates its PC framebuffer in the port layer. - Dirty-area refresh uses a small fixed list controlled by
ZED_MAX_DIRTY_AREAS; overflow merges areas into one larger redraw region. - Layout changes invalidate the owning layout container only when child geometry changes, which avoids stale pixels without forcing continuous redraw.
- The public model types
zed_obj_t,zed_style_t,zed_layout_t,zed_font_t, andzed_image_t/zed_img_tare stable enough for the next JSON DSL and C CodeGen pass.
V0.6 adds a minimal JSON DSL loader. It is dependency-free, allocation-free, and maps directly to the current C API:
static zed_event_cb_t resolve_event(const char *name)
{
if(strcmp(name, "onClick_start") == 0) return on_start_clicked;
return NULL;
}
zed_dsl_resolver_t resolver = {
.event_cb = resolve_event,
.font = NULL,
.image = NULL,
};
zed_obj_t *screen = NULL;
zed_dsl_load_json(json_text, &resolver, &screen);Supported concepts:
- stable object
id/varnames for future CodeGen - event names such as
onClick_start - resource names such as
"font": "6x8_default"and"image": "status_led"reserved for CodeGen pos,size,layout,padding,gap,align_main,align_cross- widget fields:
text,value,checked,muted,hidden,disabled
The schema reference is in:
docs/dsl/v0.6_schema.md
The CodeGen compatibility table is in:
docs/dsl/v0.6.1_field_compat.md
The parser is intentionally small. In V0.6, each widget object should put type before fields that need an object instance.
V0.7 adds a PC-side C generator for JSON DSL files:
python tools/codegen/zed_codegen.py examples/simple_demo/demo_ui.json D:/tmp/zed_demo_generated.c --function zed_demo_generated_createThe generator emits C99 that uses public zedgui APIs:
- parent objects before child objects
- stable variable names from
varorid zed_obj_set_id()calls for object lookup/debugging- empty event callback stubs
externdeclarations for font/image resources
The CodeGen notes are in:
docs/codegen/v0.7_codegen.md
The V0.7.1 CodeGen review is in:
docs/codegen/v0.7.1_review.md
V0.8 adds lightweight part/state style overrides without dynamic allocation:
zed_obj_set_part_style(btn, ZED_PART_MAIN, ZED_STATE_PRESSED, &pressed_style);
zed_obj_set_part_style(bar, ZED_PART_INDICATOR, ZED_STATE_NORMAL, &indicator_style);
zed_obj_set_part_style(sw, ZED_PART_KNOB, ZED_STATE_NORMAL, &knob_style);Supported part slots:
ZED_PART_MAIN
ZED_PART_INDICATOR
ZED_PART_KNOBSupported main-state override slots:
ZED_STATE_NORMAL
ZED_STATE_PRESSED
ZED_STATE_DISABLED
ZED_STATE_CHECKEDButtons use pressed/disabled styles, bars use main/indicator styles, and switches use main/checked/knob styles. The default theme still works when no override is provided.
V0.8.1 defines the JSON DSL and CodeGen contract for these overrides. DSL objects may use a styles array:
{
"type": "button",
"id": "start_btn",
"styles": [
{ "part": "main", "state": "pressed", "style": "styles.button.primary_pressed" }
]
}CodeGen maps the logical style resource name to a valid C symbol and emits:
extern const zed_style_t styles_button_primary_pressed;
zed_obj_set_part_style(start_btn, ZED_PART_MAIN, ZED_STATE_PRESSED, &styles_button_primary_pressed);The runtime JSON loader is intentionally not a complex style loader. Application-owned C style resources remain the source of truth for generated UI code. The detailed contract is documented in:
docs/style/v0.8.1_style_dsl_codegen_contract.md
Implement zed_disp_drv_t for your LCD:
static void lcd_set_pixel(int x, int y, zed_color_t color, void *user_data);
static void lcd_fill_rect(const zed_area_t *area, zed_color_t color, void *user_data);
static void lcd_flush(void *user_data);
zed_disp_drv_t disp = {
.hor_res = 320,
.ver_res = 240,
.user_data = lcd_ctx,
.set_pixel = lcd_set_pixel,
.fill_rect = lcd_fill_rect,
.flush_area = lcd_flush_area,
.flush = lcd_flush,
};
zed_disp_register(&disp);Feed touch/key input through zed_input_proc(). The core never calls SDL2 directly.
V0.9.0 adds a board-neutral MCU port template:
ports/mcu_template/zed_port_mcu.h
ports/mcu_template/zed_port_mcu.c
examples/mcu_demo/
docs/PORTING_MCU.md
The template demonstrates:
- RGB565 framebuffer storage.
- Dirty rectangle flushing through
zed_disp_drv_t.flush_area. - Optional partial-buffer copying for LCD drivers that need packed rectangles.
- Touch/key polling that feeds
zed_input_proc(). - Generated C UI integration without SDL2 and without runtime JSON parsing.
Generate UI C on the PC, then add the generated file to the MCU project:
python tools/codegen/zed_codegen.py examples/simple_demo/demo_ui.json generated_ui.c --function zed_demo_generated_createThe MCU application calls zed_demo_generated_create() after registering the display driver.
V1.0 freezes the first end-to-end workflow:
JSON DSL -> SDL2 Preview -> C CodeGen -> Generated C Demo -> MCU Port Template
The workflow release note is in:
docs/V1.0_WORKFLOW_RELEASE.md
V1.2 adds optional software alpha blending:
zed_draw_pixel_opa(ctx, x, y, color, 128);Display drivers can implement get_pixel for true source-over blending. Rounded rectangles can opt in to 2x2 edge coverage with:
style.ext_flags |= ZED_STYLE_FLAG_ANTIALIAS;V1.3 adds a PC-side designer project format:
*.zedui.json
Validate or convert it with:
python tools/designer/zed_designer_model.py validate examples/simple_demo/demo_project.zedui.jsonV4.0.2 records the current Designer foundation as a Python CLI model tool. Its intended verification path is project validation, from-dsl, and to-dsl conversion, plus proof that exported DSL can be passed to tools/codegen/zed_codegen.py. In this environment the Python command chain was not verified because process spawning repeatedly failed with windows sandbox: spawn setup refresh. It is not a full visual editor.
V1.4 adds a dependency-free static HTML prototype:
tools/studio/index.html
Open it directly in a browser; no npm install, server, or backend is required. It opens .zedui.json, previews the UI on a canvas, displays the object tree, runs basic validation, and exports runtime/codegen JSON DSL.
Current limits:
- No drag-and-drop editing.
- No full property panel editing.
- No undo/redo.
- No integrated SDL2 launch.
- No direct CodeGen execution inside Studio.
- No production-ready Designer yet.
See docs/DESIGNER.md for current Designer model notes and limitations.
For the Studio beta workflow, use:
docs/STUDIO_USAGE.md
docs/V5.0_PRODUCTION_DESIGNER_BETA.md
examples/studio_demo_project/
V2.3 expands the embedded widget set and adds:
examples/widget_gallery/
The gallery covers image-capable controls, icon buttons, checkbox, radio, list, tab, popup/msgbox, slider, spacer, separator, and custom-widget hooks.
V2.4 adds resource manifest generation:
python tools/resourcegen/zed_resourcegen.py examples/resources/demo_resources.json D:/tmp/zed_resourcesIt emits resources.h, resources.c, and resources_stats.json for MCU integration planning.
V2.5 adds runtime counters and a PC-side estimator:
python tools/perf/zed_perf_analyze.py examples/widget_gallery/widget_gallery.json --spi-mhz 40V2.6 can generate basic UI code for multiple targets:
python tools/codegen/zed_multitarget_codegen.py examples/simple_demo/demo_ui.json D:/tmp/ui_lvgl.c --target lvglV2.7 exports MCU project skeletons:
python tools/export/zed_project_export.py examples/simple_demo/demo_ui.json D:/tmp/zedgui_exportV3.0 defines the product foundation for zedgui Studio:
examples/studio/zedgui_studio_project.json
tools/studio/studio_manifest.json
It ties AI handoff, Designer projects, resources, events, CodeGen, MCU export, and performance analysis into one workflow.
V3.1 is an engineering review stage. Its scope is to verify the existing V3.0 workflow rather than add new hardware ports, new Designer features, or expanded multi-target CodeGen.
Primary checks:
- Core/runtime remains SDL2-free, heap-free, and file-system-free.
core,studio,designer,codegen, andportsboundaries remain explicit.- JSON DSL, Designer Model, and CodeGen supported widgets/themes stay aligned.
- Generated example C is reproducible from committed JSON DSL.
- Non-SDL generated-C smoke builds are available through CMake.
V2.0 adds a local AI handoff workflow:
AI Brief -> AI Handoff Packet -> Designer Model -> JSON DSL -> C CodeGen -> MCU Port Template
Start from:
examples/simple_demo/ai_ui_brief.md
examples/simple_demo/ai_workflow.zedai.json
The runtime stays C99 and does not depend on AI services.
V0.9.1 adds an SDL2-hosted MCU rendering simulator:
simulator/mcu_rgb565_sim/
It uses the MCU port template, RGB565 framebuffer storage, dirty-area flush_area updates, and generated C UI. SDL2 is only the PC presentation shell; the zedgui display path is the MCU-style RGB565 path.
The version roadmap is maintained in:
ROADMAP.md
Platform checkpoints and partial stages:
- V3.1: Stabilization and engineering review.
- V3.2: Real hardware validation package documented; real-board validation remains pending.
- V3.3: Industry template library examples exist; production validation remains pending.
- V3.4: Resource and performance analysis tooling exists; MCU measurements remain pending.
- V3.5: Multi-target CodeGen hardening is documented / partial.
- V3.6: AI generation quality workflow is documented / pending validation.
- V3.7: Designer experience is prototype / partial.
- V3.8: MCU project export package is partial / pending hardening.
- V4.0: AI Embedded UI Platform checkpoint, not a stable production release.