Skip to content

PyDevices/pydisplay

Repository files navigation

PyDisplay

Write your graphics code once. Run it everywhere Python runs.

Cross-platform display, input-event, and timer drivers for MicroPython, CircuitPython, and CPython.

DocumentationBrowser demoWokwi simulatorScreenshot gallery

active.py tiny_toasters.py
@peterhinch's active.py @russhughes's tiny_toasters.py

PyDisplay is the portable foundation layer for Python graphics. It gives you display drivers, unified input events, drawing primitives, fonts, palettes, and cross-platform timers behind a single API — so the same drawing code runs unchanged on a $4 microcontroller, on your desktop, in a web browser, and even inside a Jupyter Notebook.

It really does run everywhere

  • MicroPython — on microcontrollers, on Unix, on Windows, in the browser via PyScript, and in the Wokwi online simulator.
  • CircuitPython — on microcontrollers and on Unix.
  • CPython — on Unix, on Windows, and in Jupyter Notebook.

Develop and debug on your laptop with a mouse, then deploy the same code to a touchscreen on an ESP32 — no display rewrite, no input rewrite, no timer rewrite.

Build real GUIs on top of it

PyDisplay is the graphics, input, and timing backend for a growing family of projects. The sister projects lv_micropython_cmod, lv_circuitpython_mod, and lv_cpython_mod wire PyDisplay into LVGL for MicroPython, CircuitPython, and CPython respectively. That means you can build a polished LVGL application in pure Python — and you can even develop your LVGL apps interactively in a Jupyter Notebook, then run the identical code on a microcontroller.

It also drops straight in under Nano-GUI, MicroPython-Touch, russhughes-style TFT/st7789py apps, the bundled PyWidgets toolkit, or your own widget library.

Why you'll like it

  • One API, every platformframebuf-compatible drawing on MicroPython, CircuitPython, and CPython.
  • Unified input — touch, mouse, keyboard, keypad, rotary encoder, and joystick all arrive as the same PyGame/SDL2-style events.
  • Cross-platform timers — the multimer package gives you machine.Timer-style and asyncio timers on hosts that have neither.
  • Batteries included — 30 ready-made board configs, 60+ example scripts, a browser demo, and a Wokwi project.
  • Flexible install — full git clone, one-line MIP packages, or precompiled .mpy bytecode.

Alpha quality. APIs and docs are still evolving fast. Feedback and contributions are very welcome.


Contents

  1. Introduction 1.1 What PyDisplay is 1.2 What PyDisplay is not
  2. Portability — the single most important feature: where PyDisplay runs.
  3. Quick start 3.1 Try it in the browser — zero install. 3.2 Desktop (CPython) 3.3 MicroPython board
  4. Installation — clone, MIP, or precompiled packages.
  5. Architecture at a glance
  6. Ecosystem & sister projects — LVGL in Python, GUIs, Jupyter.
  7. Documentation map — where everything lives.
  8. Contributing
  9. Credits & license

1. Introduction

1.1 What PyDisplay is

PyDisplay is a foundation layer, not a GUI toolkit. It provides:

  • displaysys — display backends (BusDisplay, SDLDisplay, PGDisplay, PSDisplay, JNDisplay, FBDisplay) with a unified drawing API.
  • eventsys — a broker that turns touch, mouse, keyboards, keypads, encoders, and joysticks into uniform PyGame/SDL2-style events.
  • graphics — a portable framebuf-compatible drawing surface plus shapes, fonts, bitmap loaders, and Area helpers.
  • multimer — cross-platform periodic timers (sync, threaded, polled, and asyncio) with a machine.Timer-style API.

Use it directly for simple UIs, or as the backend for a full widget library.

1.2 What PyDisplay is not

  • Not a widget toolkit — no built-in buttons, sliders, or layout managers (use LVGL, Nano-GUI, or the bundled PyWidgets add-on).
  • Not a task scheduler — use multimer or asyncio for timing.

See the Architecture guide for the full mental model.

2. Portability

Portability is PyDisplay's headline feature. The same application code runs across every supported runtime and target:

Runtime Microcontrollers Unix / Linux Windows Browser Jupyter Notebook
MicroPython PyScript · Wokwi
CircuitPython
CPython

The right display backend is selected automatically: BusDisplay on MCUs, SDLDisplay or PGDisplay on the desktop, PSDisplay in PyScript, JNDisplay in Jupyter, and FBDisplay for CircuitPython framebuffer displays. Your code just imports board_config and draws.

Full details and per-platform notes: Portability & platforms.

3. Quick start

3.1 Try it in the browser (no install)

Open the live PyScript demo or the Wokwi simulator — both run real PyDisplay code in your browser with nothing to install.

3.2 Desktop (CPython)

git clone https://github.com/PyDevices/pydisplay.git
cd pydisplay/src
python3 -i path.py
>>> import pydisplay_demo

A display window opens (PyGame or SDL2, whichever is installed). See the Desktop CPython guide.

3.3 MicroPython board

import mip
mip.install("github:PyDevices/pydisplay/installer.py")
import installer   # runs the default install

Then pick a board config for your hardware and follow the ESP32 board guide.

4. Installation

Channel Format Best for
Full clone Entire repo Development, desktop, contributing
installer.py Source files One-shot setup on a MicroPython board
GitHub MIP Source .py Picking individual packages
micropython-lib MIP Precompiled .mpy Smallest footprint on device

Precompiled packages live in the PyDevices micropython-lib MIP index. See the installation overview to choose.

5. Architecture at a glance

   board_config.py          (selects + wires your hardware / platform)
        │
        ├── displaysys  ──►  display_drv   (draw: fill_rect, blit_rect, show, …)
        ├── eventsys    ──►  broker        (poll: touch / mouse / keys / encoder)
        ├── graphics                       (shapes, fonts, framebuf, Area)
        └── multimer                       (periodic + asyncio timers)
        │
        ▼
   your app  ·  LVGL  ·  Nano-GUI  ·  MicroPython-Touch  ·  PyWidgets
from board_config import display_drv, broker

while True:
    for event in broker.poll():
        ...  # handle touch, clicks, keys, encoder
    display_drv.fill_rect(0, 0, 10, 10, 0xF800)
    display_drv.show()

Full diagram and boot sequence: Architecture.

6. Ecosystem & sister projects

PyDisplay is the graphics, input-event, and timing backend for the wider PyDevices ecosystem:

Project What it adds
lv_micropython_cmod LVGL bindings for MicroPython, using PyDisplay for display and input.
lv_circuitpython_mod LVGL bindings for CircuitPython, backed by PyDisplay.
lv_cpython_mod LVGL bindings for CPython, backed by PyDisplay.

Because all three share PyDisplay as the backend, you can build an LVGL app in pure Python and develop it interactively in a Jupyter Notebook, then run the identical code on a microcontroller. See the LVGL guide and the Jupyter walkthrough.

PyDisplay also integrates with:

7. Documentation map

Everything lives in one place — the documentation site:

Topic Start here
First steps Getting started
Where it runs Portability & platforms
Core concepts Architecture, Displays, Events, multimer
Hardware Board configs
Examples Examples catalog
GUI libraries GUI integration
API API reference

8. Contributing

Fork, branch, and open a PR. See the Contributing guide and the open GitHub Issues. Roadmap items include EPaper displays, CircuitPython circup packages, end-user PyPI wheels, and more C bus drivers.

9. Credits & license

PyDisplay is released under the MIT License. Copyright © 2024 Brad Barnett.

Thanks to @peterhinch, @russhughes, and the Adafruit CircuitPython team for foundational work in the Python-on-microcontrollers community.

About

Display, touch and encoder drivers for MicroPython, CircuitPython and Python

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors