Trying to understand Sprites in TFT_eSPI

Hi there,

I’m trying understand the Sprites in the TFT_eSPI library. The sample code I am trying below does not show the red color rectangle. Anyone could highlight what I am doing wrong here. Or if my understand and usage of Sprites here is wrong.

Btw, example tft_graphicstest_ine_lib in the TFT_eSPI library is working.

WhatsApp Video 2025-11-09 at 20.57.44_aadd468c.mp4 optimize output image

#include <TFT_eSPI.h> 

TFT_eSPI tft = TFT_eSPI(); 
TFT_eSprite spr_parent    = TFT_eSprite(&tft);
TFT_eSprite spr_child1    = TFT_eSprite(&tft);
TFT_eSprite spr_child2    = TFT_eSprite(&tft);

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);

  spr_parent.createSprite(320, 170);
  spr_parent.setSwapBytes(true);

  spr_child1.createSprite(320, 50);
  spr_child1.setSwapBytes(true);

  spr_child2.createSprite(320, 120);
  spr_child2.setSwapBytes(true);

  spr_child1.fillSprite(TFT_BLACK);
  spr_child1.fillRect(0, 0, 320, 50, TFT_YELLOW);

  spr_child2.fillSprite(TFT_BLACK);
  spr_child2.fillRect(0, 0, 320, 120, TFT_RED);

  spr_child1.pushToSprite(&spr_parent, 0, 0); 
  spr_child2.pushToSprite(&spr_parent, 0, 50);

  spr_parent.pushSprite(0, 0);
}

void loop() {
}

Read_User_Setup Serial monitor output;

TFT_eSPI ver = 2.5.43
Processor    = ESP32
Frequency    = 240MHz
Transactions = Yes
Interface    = SPI
Display driver = 9341
Display width  = 240
Display height = 320

MOSI    = GPIO 23
MISO    = GPIO 19
SCK     = GPIO 18
TFT_CS   = GPIO 15
TFT_DC   = GPIO 2
TFT_RST  = GPIO 4
TOUCH_CS = GPIO 5

Font GLCD   loaded
Font 2      loaded
Font 4      loaded
Font 6      loaded
Font 7      loaded
Font 8      loaded
Smooth font enabled

Display SPI frequency = 40.00
Touch SPI frequency   = 2.50

This is my LCD.

and if you try

#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr_parent = TFT_eSprite(&tft);
TFT_eSprite spr_child1 = TFT_eSprite(&tft);
TFT_eSprite spr_child2 = TFT_eSprite(&tft);

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);

  spr_parent.createSprite(320, 170);
  spr_parent.setSwapBytes(true);
  spr_parent.fillSprite(TFT_BLACK);

  spr_child1.createSprite(320, 50);
  spr_child1.setSwapBytes(true);
  spr_child1.fillSprite(TFT_BLACK);
  spr_child1.fillRect(0, 0, 320, 50, TFT_YELLOW);

  spr_child2.createSprite(320, 120);
  spr_child2.setSwapBytes(true);
  spr_child2.fillSprite(TFT_BLACK);
  spr_child2.fillRect(0, 0, 320, 120, TFT_RED);

  spr_child1.pushToSprite(&spr_parent, 0, 0);
  spr_child2.pushToSprite(&spr_parent, 0, 50);

  spr_parent.pushSprite(0, 0);
}

void loop() {}

➜ the parent sprite spr_parent is explicitly filled with a background color (TFT_BLACK ) before pushing the child sprites

(The children are drawn into the parent sprite, so the parent acts as a canvas. If the parent is uninitialized, its undefined content could possibly interfere with the children when the parent is finally pushed to the screen).

thanks for the reply, I did try your code, but still I do not see the red rectangle.

OK and with this, do you see anything

#include <TFT_eSPI.h>

TFT_eSPI tft = TFT_eSPI();
TFT_eSprite spr_parent = TFT_eSprite(&tft);
TFT_eSprite spr_child1 = TFT_eSprite(&tft);
TFT_eSprite spr_child2 = TFT_eSprite(&tft);

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);

  spr_parent.createSprite(320, 170);
  spr_parent.setSwapBytes(true);
  spr_parent.fillSprite(TFT_BLACK);

  spr_child1.createSprite(320, 50);
  spr_child1.fillSprite(TFT_BLACK);
  spr_child1.fillRect(0, 0, 320, 50, TFT_YELLOW);

  spr_child2.createSprite(320, 119); // <<<== smaller height 
  spr_child2.fillSprite(TFT_BLACK);
  spr_child2.fillRect(0, 0, 320, 119, TFT_RED);

  spr_child1.pushToSprite(&spr_parent, 0, 0);
  spr_child2.pushToSprite(&spr_parent, 0, 51); 
  spr_parent.pushSprite(0, 0);
}

void loop() {}

(spr_child2 has a slightly smaller height and its push position starts at y = 51 instead of 50 so that we are not exceeding the parent sprite’s boundaries)

Are you sure there is enough ram in the ESP32? A 320 * 170 sprite with the default 16-bit color depth would take 108,800 bytes of ram.

Note the following from the github page https://github.com/Bodmer/TFT_eSPI#sprites :

On an ESP32 the workspace RAM is more limited than the datasheet implies so a 16-bit colour Sprite is limited to about 200x200 pixels (~80Kbytes), an 8-bit sprite to 320x240 pixels (~76kbytes). A 1 bit per pixel Sprite requires only 9600 bytes for a full 320 x 240 screen buffer, this is ideal for supporting use with 2 colour bitmap fonts.

1 Like

good point - I did not check the sizes.

Still the same.

make them way smaller. It's likely a memory full issue as pointed by @david_2018

so you mean to say that I should not use ESP32 with this sizes LCD?

I mean your sprites should not be that big or full color.
the link shared above states

Sprites by default use 16-bit colours, the bit depth can be set to 8 bits (256 colours) , or 1 bit (any 2 colours) to reduce the RAM needed. On an ESP8266 the largest 16-bit colour Sprite that can be created is about 160x128 pixels, this consumes 40Kbytes of RAM. On an ESP32 the workspace RAM is more limited than the datasheet implies so a 16-bit colour Sprite is limited to about 200x200 pixels (~80Kbytes), an 8-bit sprite to 320x240 pixels (~76kbytes). A 1 bit per pixel Sprite requires only 9600 bytes for a full 320 x 240 screen buffer, this is ideal for supporting use with 2 colour bitmap fonts.

One or more sprites can be created, a sprite can be any pixel width and height, limited only by available RAM. The RAM needed for a 16-bit colour depth Sprite is (2 x width x height) bytes, for a Sprite with 8-bit colour depth the RAM needed is (width x height) bytes. Sprites can be created and deleted dynamically as needed in the sketch, this means RAM can be freed up after the Sprite has been plotted on the screen, more RAM intensive WiFi based code can then be run and normal graphics operations still work.

1 Like

Did that and I can see the two color rectangles.

#include <TFT_eSPI.h> 

TFT_eSPI tft = TFT_eSPI(); 
TFT_eSprite spr_parent    = TFT_eSprite(&tft);
TFT_eSprite spr_child1    = TFT_eSprite(&tft);
TFT_eSprite spr_child2    = TFT_eSprite(&tft);

void setup() {
  tft.init();
  tft.setRotation(1);
  tft.setSwapBytes(true);

  spr_parent.createSprite(100, 100);
  spr_parent.setSwapBytes(true);

  spr_child1.createSprite(100, 50);
  spr_child1.setSwapBytes(true);

  spr_child2.createSprite(100, 120);
  spr_child2.setSwapBytes(true);

  spr_child1.fillSprite(TFT_BLACK);
  spr_child1.fillRect(0, 0, 100, 50, TFT_YELLOW);

  spr_child2.fillSprite(TFT_BLACK);
  spr_child2.fillRect(0, 0, 100, 50, TFT_RED);

  spr_child1.pushToSprite(&spr_parent, 0, 0); 
  spr_child2.pushToSprite(&spr_parent, 0, 50);

  spr_parent.pushSprite(0, 0);
}

void loop() {
}

so that confirms @david_2018's suspicion.

1 Like

thanks @david_2018 for pointing the core issue of my code.

May I ask, if I push an image for a Sprite that is 320x170, would that work?

the doc states

On an ESP32 the workspace RAM is more limited than the datasheet implies so a 16-bit colour Sprite is limited to about 200x200 pixels

so 320x170 is larger ➜ won't work

1 Like

thanks @J-M-L for this insight. I think all is clear to me now.

appreciate your help.

@david_2018 @J-M-L

I wonder, then how some of those projects done in youtube manages amazing graphics with an ESP32? what am I missing?

Would really depend on what kind of graphics you were displaying. You can draw shapes and print text directly to the display, although that may involve erasing portions of what is already on the screen. Could also be that the images are stored in flash memory and written to the display directly, instead of having to buffer through a sprite.

1 Like

If your board has psram activate it..

it’s under the tools menu option..

usually disabled be default..

sprites will use this extra ram automatically I believe..

good luck.. ~q

my understanding on this is very low, and I might have catch bits and pieces from here and there.

Would you kindly point me to a good tutorial for this pls.

thanks