Documentation / Start here

Core concepts

The dozen words everything else is written in, and what each one turns into on the device.

The designer has a small vocabulary and uses it consistently. This page defines each term once, says where it lives in the interface, and what it turns into in the generated project. The pages that follow assume it.

Project

A project is one JSON document holding everything: the name, the LVGL version, the theme, the hardware, the screens, the assets, the filesystem settings, the variables, the automations and the export options. It autosaves to your browser's localStorage on every change, so a reload never loses work - but that copy is per-machine. File > Save to account stores it on the server, which is what makes it openable elsewhere, and File > Download project file writes the same document as a .json you can keep in version control.

Old projects are migrated when opened: fields added to the application after a project was saved are back-filled with their defaults, so a design from months ago opens cleanly.

Screens

A screen is a top-level LVGL object the size of the panel. A project has at least one, and a cap per plan - three without an account, five on the free plan, thirty on Pro - applied when you add one: a guest is asked to sign in, a free account is offered Pro. Each becomes its own ui_<Name>.c with a ui_<Name>_screen_init() function, and ui_init() creates them all and loads the first. A screen has two settings of its own: Temporary, which frees it from RAM when it is unloaded and re-creates it on the next load, and Don't export screen function for a screen you intend to hand-write.

Widgets

A widget is an LVGL object on a screen - a button, a label, a chart. In the project it is a node with a type, a name, a position, parameters, styles, events and bindings, and it may contain child widgets. The widget catalogue lists all twenty-one; each one's parameters are the setters LVGL offers for that type, and the generator emits exactly the calls those parameters correspond to.

The name matters more than it looks: it becomes the C identifier ui_<Name> declared in ui.h, which is how your own code in ui_events.c reaches the object. Two widgets on one screen cannot share a name, and the validator says so.

Position and alignment

A widget's X and Y are offsets from an alignment anchor on its parent, exactly as lv_obj_align() understands them - not absolute coordinates. A widget aligned Center with X=0, Y=0 is in the middle of its parent whatever size the parent is. Dragging on the canvas keeps the anchor and rewrites the offsets, so a design keeps its alignment intent through a drag. Position and layout has the details and the flex and grid options.

Parts and states

LVGL styles an object per part (a slider has a Main, an Indicator and a Knob) and per state (Default, Pressed, Checked, Focused, Edited, Disabled). The Inspector's Style settings section has a Part and a State selector, and every property you set is stored under that pair. Only the properties you change are stored; everything else is the LVGL default theme, which the canvas approximates. That sparse storage is what keeps the exported C free of redundant setters. Styles covers it.

Events and actions

An event is a trigger on a widget (Clicked, Value changed, Screen loaded, Swipe left and so on) with a list of actions to run: change screen, set a flag, increment a slider, play an animation, set a variable, call a function of yours. The generator writes one ui_event_<Name>() handler per widget with events and registers it with lv_obj_add_event_cb(). Events and actions.

Hardware

The hardware block describes the board: MCU, graphics library, whether PSRAM is enabled, the display (controller, bus, pins, resolution, rotation, colour order, backlight), the touch controller (or a rotary encoder, button pad or keypad), and then the things beyond the panel - extra buses, peripherals on them, I/O extenders, analog inputs and digital I/O. A board preset fills in the first group in one go; the second group is yours and survives a change of preset.

Every pin is validated against the chosen MCU: whether it exists, whether it is input-only, whether it is a strapping or flash pin, and whether something else already uses it. Two devices sharing a named I2C or SPI bus is legitimate and is not flagged; two unrelated signals on one GPIO is an error.

Variables

A variable holds one value - a Float, an Integer or a Boolean - and the firmware refreshes it on a schedule. Its source is where the value comes from: a peripheral channel (the BME280's temperature), an analog input, a digital input, a constant, or nothing at all when it is only ever written by events. A formula converts the raw reading: raw * 9 / 5 + 32, map(raw, 0, 4095, 0, 100), or something that references other variables by name. Variables are what bindings and automations read.

Bindings

A binding connects a variable to one property of one widget: its text (with a printf format, a prefix and a postfix), its value, whether it is checked, its selected index, whether it is hidden, its colours, its opacity, or a push onto a chart series. A binding on a control such as a slider or a switch can run the other way too - Widget → variable or Both ways - so touching the widget writes the variable, which other bindings and automations then see.

Automations

An automation is an event raised by the hardware rather than by a finger: on startup, every interval, when a digital input changes or is held, when an analog value crosses a threshold, or when a variable changes. It runs the same action list a widget event does, plus the hardware actions - set a variable, drive a digital output, write to a peripheral, refresh the inputs now.

Assets

An asset is an image. You import a PNG, JPEG, GIF, WebP or BMP; the browser decodes it and the server packs it into LVGL's binary image format at export, in the colour format you choose per image. By default images are written to data/ and flashed to the board filesystem (SPIFFS, LittleFS, FFat or an SD card); an image can instead be compiled into the firmware as a C array. Images and fonts.

Generation

A generation is one build of a project's complete source, done on the server. It is the one metered thing in the application. A build that fails validation is never counted, and downloading the zip of a build you have just run is part of the same generation. Everything else - designing, styling, wiring, previewing, saving, opening - is free and unlimited. Accounts and limits.

The generated project, in one paragraph

The .ino brings up the backlight, the panel and the touch controller, initialises LVGL with a partial draw buffer, calls ui_init() to build your screens and app_init() to start the data layer, then loops on app_poll() and lv_timer_handler(). lcd_pins.h holds every pin and timing value as a #define. hardware.cpp owns the buses and devices and caches their readings; app_logic.cpp owns the variables, bindings and automations. Everything under ui/ is regenerated on every export except ui_events.c, which is yours. Export goes file by file.