# nano-gui gives a MicroPython display widgets without the RAM cost of input

> micropython-nano-gui is an MIT licensed MicroPython library of display-only widgets for displays whose driver is subclassed from FrameBuffer, covering small OLEDs, colour TFTs, ePaper and Sharp panels. It deliberately omits user input to stay small, and it publishes its own file manifest, fonts and driver documentation inside the repository rather than relying on a package index.

**peterhinch/micropython-nano-gui** — A lightweight MicroPython GUI library for display drivers based on framebuf class

- Repository: https://github.com/peterhinch/micropython-nano-gui
- Stars: 666 · Forks: 106
- Language: Python
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/peterhinch-micropython-nano-gui

## A GUI that draws and nothing else

nano-gui is a lightweight and minimal MicroPython GUI library for display drivers based on the FrameBuffer class. It is portable between a range of MicroPython hosts and display devices, and the supported technologies include small colour and monochrome OLEDs, colour TFTs, ePaper and Sharp units.

The key architectural constraint is stated early. The library provides a limited set of GUI objects, the widgets, for displays whose display driver is subclassed from FrameBuffer. Because the graphics primitives are supplied by the FrameBuffer class itself, the drivers can have minimal code.

That is the whole trick. Rather than implementing drawing primitives per panel, a driver only has to be a FrameBuffer subclass, and the widget code above it is identical across displays. The device driver document explains how to configure the library for a given display and MicroPython host by adapting a single small file, so porting to a new panel is a driver problem rather than a GUI problem.

The audience is an embedded developer with a small screen and a MicroPython board, an instrument panel, a sensor readout, a clock, a meter. The documentation gives a hint of the scale in the demos, an analogue clock, labels in two fonts, a meter on a small OLED, a level indicator that responds to how the board is tilted, and a seismograph style plot on an ePaper display.

One convention is worth noting because it will show up in the code you read. For historical reasons and to ensure consistency, the code and documentation use the American spelling of color.

## The widget set and what each one is for

The widget list is short, and each entry maps to a display need rather than to a GUI convention.

Label is dynamic text at any screen location, and the documentation notes that labels are shown in two fonts in the demo images. Meter is a vertical panel meter, and one of the demos runs it on a small OLED with the colours changing dynamically, low values green, intermediate yellow, high red. LED is a virtual LED of any colour, which is a way of drawing an indicator without inventing a graphics primitive. Dial and Pointer are the clock or compass style display of one or more pointers, and the level demo uses a vector arrow whose length and angle vary as the board is moved.

Scale is a linear display with a wide dynamic range, and the documentation describes it as capable of precision display of floats as a notionally very long scale moves behind a small window. Textbox is a scrolling text display with word wrap or clipping. Below those sits the drawing primitives section, so you can put arbitrary graphics on the screen when a widget does not fit.

There is also an optional graph plotting module, documented separately, for basic Cartesian and polar plots, and for real time plotting including time series.

Two of these exist because real instruments need them. A meter that changes colour is a different thing from a number, and a scale that slides behind a window is how you show a value with more precision than the screen has pixels. Neither is a general purpose GUI element, and both are the reason the library feels like it was written by someone who has built instruments.

## The display update mechanism and the ePaper problem

The documentation has a dedicated section on the display update mechanism, which is how updates are managed, and a separate one on ePaper displays, described as new developments in ePaper. There is also a subsection on monochrome displays and a slight gotcha with ePaper.

That gotcha is the kind of detail that decides whether a panel works at all, so it is worth understanding before you start. An ePaper panel holds its image with no power, which is the point of it, but it also means the update model is different from a lit display. The library treats ePaper as a distinct case rather than as just another FrameBuffer, and the section on user defined colors carries its own subsection for monochrome displays for the same reason, since a one-bit display cannot express the colour constants the rest of the library uses.

The scaling of the whole design follows from this. The library is display-only, and the documentation is explicit that it lacks provision for user input. The reason given for the separate input-capable library is that it comes at a cost of a substantially greater RAM requirement, while still supporting all the displays available to nano-gui.

The code itself is synchronous, but it is compatible with asyncio, and some demo programs illustrate that. A few device drivers use the native and viper decorators, which is a MicroPython compiler feature, so the source stays standard MicroPython apart from those driver files.

## Fonts, core files and a manifest instead of a package index

The repository does not follow the usual layout of a Python library, and that is deliberate.

Instead of a single importable package, the files are published as a manifest. The package.json in the repository root carries a urls array that maps each file to its location in the upstream GitHub repository, and the entries cover the core modules, the fonts and the widgets:

```json
  "urls": [
    ["gui/core/__init__.py", "github:peterhinch/micropython-nano-gui/gui/core/__init__.py"],
    ["gui/core/colors.py", "github:peterhinch/micropython-nano-gui/gui/core/colors.py"],
    ["gui/core/fplot.py", "github:peterhinch/micropython-nano-gui/gui/core/fplot.py"],
    ["gui/core/nanogui.py", "github:peterhinch/micropython-nano-gui/gui/core/nanogui.py"],
    ["gui/core/writer.py", "github:peterhinch/micropython-nano-gui/gui/core/writer.py"],
```

The font list is part of the same manifest, with Arial in three sizes, Courier, FreeSans and two bitmap fonts, and the widget list covers the dial, label, led, meter, scale and textbox modules.

Why do it this way? Because MicroPython devices rarely have a package manager, and copying a handful of files onto a board is the normal deployment model. The manifest lets the tooling fetch exactly the files needed, and the fonts are the part that matters for size, since a font is dead weight on a device that will not use it.

The rest of the tree is documentation-heavy, which suits a library whose main difficulty is hardware configuration rather than API design. There are DISPLAYS.md for the list of compatible and tested displays, DRIVERS.md for the device driver document, FPLOT.md for the plotting module, ASYNC.md, ADAFRUIT.md, IMAGE_DISPLAY.md, an extras directory with further widgets back-ported from micro-gui plus more demos, a drivers/ directory, and a setup_examples/ directory.

## Which boards it has actually been run on

The documentation is specific about the hardware it has been tested on, and that list is short enough to be useful.

It has been tested on Pyboard 1.1, Pyboard D, Raspberry Pi Pico and on the ESP32 reference board without SPIRAM. The ESP32 note matters, because adding SPIRAM changes the memory situation entirely, and the library is being used on the harder configuration.

Running on ESP8266 is possible, but with a condition that says a lot about the design. Frozen bytecode must be used, owing to its restricted RAM, and the documentation points to an appendix on freezing bytecode as the optional way to save RAM. Freezing compiles the modules into the firmware image, so they are not held in the filesystem heap at runtime, and on a device with very little memory that is the difference between the library fitting and not fitting.

Multiple displays on one target are supported, and the documentation attaches a warning to that: bear in mind the RAM requirements for multiple frame buffers. Each display has its own frame buffer, and on a microcontroller that is often the largest single allocation in the program.

The library also supports a round display, with a second appendix offering an alternative hardware check script for that case, and the change log records support for circular displays with the gc9a01 controller on 22 May 2024, a driver update for a 4.2 inch Waveshare ePaper display on 15 Mar 2023, and the addition of the sh1106 driver with a fix for SSD1306 colour compatibility on 12 Feb 2023.

## nano-gui against micro-gui and the touch libraries

The alternatives are named in the documentation, and the difference between them is one of scope and cost.

The direct alternative is micro-gui, the library supporting user input, which is by the same author and supports all displays available to nano-gui. The stated difference is memory: micro-gui comes at a cost of a substantially greater RAM requirement. For a device with a screen and no input, paying that for nothing is the mistake nano-gui exists to prevent.

For touch specifically, the documentation points to three separate projects: the official lcd160cr touch GUI, the RA8875 large display GUI, and the SSD1963 large display GUI. These are per-display touch implementations rather than one general library, which tells you something about how much of the work is panel specific.

There is a fourth option for the case where nano-gui is too small: draw on the frame buffer directly. The drawing primitives section exists for exactly that, and it is what you fall back to when a widget does not exist for what you need. The cost of that route is that you own the layout, the refresh behaviour and the ePaper update model.

The trade-off across all of these is the same one the library made at the start. nano-gui is small enough to run on constrained hardware and gives you a fixed set of widgets, and everything beyond that set, input, custom layout, exotic panels, is work you take on yourself.

## Maintenance, releases and the documentation layout

The administrative picture is modest. The licence is MIT, the primary language is Python, the repository is not archived, and the last push was on 2026-06-13. There are no GitHub releases, which is normal for a library that is installed by copying files rather than by a package index.

The README is a long document rather than a short one, and its table of contents shows the structure: an introduction with a change log, a description and a quick start section that can be run without actually installing the library, a quick install subsection, and a section on a performance boost. Then there is a files and dependencies section that breaks into core files, demo scripts, fonts and hardware setup examples, a dependencies section and a section on verifying the hardware configuration, with the instruction to check hardware first.

That last part is a fair summary of the project. The hard part is not the API, it is getting a driver and a panel configured correctly, and the documentation is organised around that reality rather than around the class list. The change log in the README is ordered by date, with the most recent entries at the top, and the entries are terse, one line each, which is the right shape for a change log that tracks driver compatibility more than features.

The project also hosts its own extra widgets in the extras directory, back-ported from micro-gui, with the stated aim of avoiding the main document becoming over long and daunting to new users.

## Conclusion

nano-gui suits an embedded project that drives a small OLED or ePaper panel from a MicroPython board and only needs to draw, not to receive touch or key input, and it is the wrong choice for a project with a touchscreen, where the documentation points to the touch GUI libraries instead. Before adopting it, check DISPLAYS.md for your panel and DRIVERS.md for your host, and read the RAM section for the ESP8266, where the library only fits if you freeze the bytecode.

## FAQ

### What is micropython-nano-gui?

It is a lightweight and minimal MicroPython GUI library for display drivers based on the FrameBuffer class, providing a limited set of widgets for small colour and monochrome OLEDs, colour TFTs, ePaper and Sharp displays. It is display-only and has no provision for user input.

### What widgets does nano-gui provide?

Label for dynamic text at any location, Meter as a vertical panel meter, LED as a virtual LED of any colour, Dial and Pointer for clock or compass style displays, Scale for a linear display with wide dynamic range, Textbox for scrolling text, plus drawing primitives and an optional graph plotting module for Cartesian, polar and real time plots.

### Which hardware has nano-gui been tested on?

Pyboard 1.1, Pyboard D, Raspberry Pi Pico and the ESP32 reference board without SPIRAM. Running on an ESP8266 is possible but requires frozen bytecode because of its restricted RAM, and multiple displays on one target are supported with a warning about the RAM needed for multiple frame buffers.

### How do I add user input to a nano-gui project?

nano-gui is display-only, so the documentation points to micro-gui, which supports user input and all the displays available to nano-gui, at the cost of a substantially greater RAM requirement. For touch, it lists separate projects for the lcd160cr, RA8875 and SSD1963 displays.

### How is nano-gui installed on a MicroPython board?

The repository publishes a manifest in its package.json that maps each gui/core, gui/fonts and gui/widgets file to its location in the upstream repository, so the tooling can fetch exactly the files a project needs and copy them onto the board, which is the normal deployment model for MicroPython devices with no package manager.

## Sources

- [Issues](https://github.com/peterhinch/micropython-nano-gui/issues)
- [License: MIT](https://github.com/peterhinch/micropython-nano-gui/blob/master/LICENSE)
- [peterhinch/micropython-nano-gui on GitHub](https://github.com/peterhinch/micropython-nano-gui)
- [README](https://github.com/peterhinch/micropython-nano-gui/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/peterhinch-micropython-nano-gui
