Running out of RAM is the most common integration failure in embedded GUI projects. This page explains exactly where GUI memory goes, gives concrete numbers for a 320×240 display, and shows six techniques to shrink your footprint without sacrificing display quality.
Embedded GUI memory usage has three main components: framebuffer RAM (pixel storage for the display), widget state RAM (active widget objects and their properties), and asset RAM (decoded font glyphs and image data held at runtime). Of these, the framebuffer dominates. A 320×240 display at 16-bit colour (RGB565) requires exactly 153,600 bytes — 150 KB — for a single framebuffer. Double-buffering doubles this to 300 KB, exceeding the internal SRAM of most cost-effective MCUs entirely. Engineers typically discover this constraint during board bring-up, when the linker reports an overflow of the .bss or heap section.
Sparklet provides six independent techniques to address each component of memory usage — applicable individually or in combination depending on available hardware. The highest-impact single change (switching to partial buffer mode) reduces framebuffer RAM from 150 KB to as little as 6.4 KB — a 24× saving before any other optimisation is applied. For performance impact alongside memory optimisation, see Fix Slow Embedded GUI Performance. For per-platform RAM and Flash benchmarks, see Performance & Memory Benchmarks.
Consider an STM32F4 with 192 KB internal SRAM. A 320×240 RGB565 display needs 150 KB for a single framebuffer. That leaves 42 KB for the Sparklet core (~16 KB minimum), FreeRTOS task stacks (8–16 KB), RTOS kernel objects (~4 KB), and all communication and sensor buffers. The numbers do not add up with a naïve implementation — but they can with the right combination of the techniques on this page.
Each technique targets a different component of total embedded GUI memory usage — apply them independently or in combination for maximum savings.
The framebuffer is the single largest RAM consumer in any embedded GUI project. For a 320×240 RGB565 display, a full framebuffer requires 150 KB. The most impactful single change is switching to partial buffer mode — Sparklet allocates a strip buffer covering only a configurable number of scan lines and makes multiple renderer passes per frame, flushing each strip via DMA while computing the next.
Strip sizes and their framebuffer RAM costs for a 320-wide RGB565 display:
This 24× reduction is the single most impactful memory saving available. CPU overhead increases slightly due to multi-pass rendering, but hardware DMA transfers overlap with the next strip computation, keeping net throughput loss typically below 15%. Strip height is a single parameter in the Sparklet HAL initialisation call.

Dropping colour depth directly halves or quarters the framebuffer RAM requirement. Sparklet supports 8-, 16-, and 32-bit colour depths, configurable at build time without code changes. For a 320×240 display the framebuffer sizes are:
For most industrial LCDs and automotive TFTs, 16-bit colour is visually indistinguishable from 32-bit on the panel hardware. 8-bit is appropriate for medical status displays, simple HMIs, and greyscale e-paper panels. Combined with a 10-line partial buffer, 8-bit colour drops the total framebuffer RAM to 3.2 KB for a 320-wide display — enough to fit alongside a 16 KB Sparklet core on the smallest cost-effective MCUs.

Flash is often overlooked in the memory budget conversation. A single 24pt anti-aliased Unicode font covering the Latin character set can occupy 80–120 KB of Flash. A background image at full RGB565 resolution occupies width × height × 2 bytes — 150 KB for a 320×240 background alone. Two fonts and two background images can consume over 500 KB of Flash before any application code is included.
Sparklet compressed font format stores glyph data in a compressed binary format and decompresses on first use into the runtime glyph cache. This reduces the Flash footprint of font assets by 50–70% compared to uncompressed bitmap fonts. PNG image support allows background images to be stored as compressed PNG files in Flash — a 320×240 background that occupies 150 KB as raw RGB565 may compress to 15–40 KB as PNG. Decode is performed at render time with negligible overhead on Cortex-M4 and faster cores.

Every widget type compiled into the Sparklet library adds static code and data overhead — even widget types your application never instantiates. Sparklet's build configuration supports feature-level inclusion: disable widget types not used in your application to reduce both Flash (code size) and RAM (static descriptor tables).
An application using only Button, TextArea, and ProgressBar can exclude Graph, Carousel, 3DWidget, and the 30+ other widget types entirely. Typical code-size saving per excluded widget type: 2–8 KB of Flash. Widget pooling (virtual scrolling) addresses heap fragmentation in list-heavy applications — Sparklet's ScrollView and ListView maintain a fixed pool of widget instances recycled as the user scrolls. For a 1000-item list, this reduces live widget RAM from 1000 × (widget size) to 10–15 × (widget size) — a 60–100× saving.
sparklet_config.h — one line per widget type to exclude
| Component | Typical Usage | Sparklet Minimum | Reduction Technique |
|---|---|---|---|
| Framebuffer RAM | 150 KB (single full frame) | 6.4 KB (10-line partial, 16-bit) | Partial buffer mode |
| Widget core RAM | 30–80 KB (all 36+ widget types) | ~16 KB (selective inclusion) | Feature flags in sparklet_config.h |
| Font assets (Flash) | 80–120 KB per font face | 20–40 KB (compressed) | Sparklet compressed font format |
| Image assets (Flash) | 150 KB per full-screen RGB565 image | 15–40 KB (PNG compressed) | PNG storage + decode-at-render |
| List widget RAM | 1000 × widget size (full list) | 12 × widget size (virtual scroll) | Widget pooling in ScrollView/ListView |
| Double-buffer overhead | +150 KB for tear-free display | 0 KB extra (dirty-region) | Dirty-region rendering avoids double-buffer need |
Sparklet's dirty-region renderer eliminates the need for a double framebuffer in most applications. Double buffering — two full framebuffers for tear-free display — is only necessary when full-screen transitions happen at high frame rates continuously. For typical embedded UIs where partial areas update incrementally, Sparklet's dirty-region rendering delivers tear-free output with a single framebuffer — saving 150 KB at 320×240 RGB565 compared to a naive double-buffered implementation. See Fix Slow GUI Performance for the full render pipeline explanation.
Flint UI Designer compresses all font and image assets at export time into Sparklet's binary format. Font glyph data is stored compressed and decompressed into a runtime glyph cache on first character use. PNG images are decoded from Flash at render time into a small decode buffer (5–10 KB). Together these two techniques reduce asset Flash footprint by 50–70% with no design workflow changes — assets are compressed automatically during the Flint export step. Flint's real-time asset size panel shows per-asset Flash consumption throughout the design phase so overruns are caught before building.
Sparklet's build system allows individual widget types to be excluded via feature flags in sparklet_config.h. Each excluded widget type removes its renderer, event handler, property descriptors, and static tables from the binary. An application that uses only 8 of Sparklet's 36+ widget types can exclude the other 28, reducing the library Flash footprint proportionally. Typical code-size saving per excluded widget type: 2–8 KB of Flash. The Flint UI Designer project defines which widget types are used — the build system validates that no excluded widget type is referenced. See the full catalogue at Widget Library.

For a 320-wide 8-bit display, a 10-line partial buffer requires 320 × 10 × 1 = 3.2 KB. At 16-bit depth this is 6.4 KB. This eliminates the full 150 KB framebuffer requirement entirely. The renderer makes 24 passes per frame (240 lines ÷ 10), each flushed to the SPI display controller via DMA. Strip height is configured in the Sparklet HAL init call — no other code change required.

Switching from 16-bit to 8-bit colour halves framebuffer RAM and is visually acceptable for status indicators, appliance panels, and simple HMIs. Sparklet's 8-bit renderer supports both palette-mapped colour (up to 256 colours) and greyscale modes. Palette selection is configured at project level in Flint. Combined with a 10-line partial buffer, total framebuffer RAM for a 320-wide display drops to 3.2 KB.

Including only the widget types used in the application reduces the Sparklet core RAM requirement substantially. For a simple status panel using Button, TextArea, ProgressBar, and ImageHolder, excluding the remaining 30+ widget types reduces the library to approximately 10–14 KB of Flash and 12–14 KB of RAM — well below the 16 KB minimum figure for an all-widget build.

Sparklet's render task stack requirement is 1–2 KB with a minimal widget tree. Allocating 2 KB for the Sparklet render task, 4 KB for the application task, and 2 KB for the RTOS idle task gives a total task stack budget of 8 KB — well within a 32 KB total RAM target alongside the Sparklet core and partial buffer. See RTOS Support for FreeRTOS integration details.
The highest-impact single change is switching from a full-screen framebuffer to partial buffer rendering. This alone reduces framebuffer RAM from 150 KB (320×240 RGB565) to as little as 6.4 KB — a 24× reduction. Combine this with 16-bit or 8-bit colour depth, compressed fonts exported by Flint, selective widget inclusion, and widget pooling for list-heavy UIs. Sparklet supports all of these natively — no external libraries or manual optimisation loops required.
Download the Sparklet evaluation binary and run it on your target MCU. The evaluation includes RAM and Flash usage reporting for your specific display resolution and widget set — concrete numbers before any licence commitment.