Documentation / Designing

Spritesheets

One picture cut into frames on a grid, each frame named if you like, and named runs of them that a Sprite plays.

A spritesheet is an ordinary image on the Assets tab with one switch turned on. The designer cuts it into frames on a grid you set, and you can name each frame and make sequences of them: a walk, a jump, a shot. A Sprite shows one frame of the sheet at a time. Which frame or sequence is chosen by a press, an automation, a variable or the joystick. On the board the sheet is stored once, however many Sprites show it. Pro.

A spritesheet of a top-down green battle tank: eight rows, one for each way it faces - up, up-right, right, down-right, down, down-left, left, up-left - and six frames in each row: three with the tracks in different places, then the barrel kicked back with a big flash, a small flash, and a puff of smoke.
A sheet of 48 frames: a row for each of eight ways the tank faces, three frames of the tracks rolling and three of the shot.

Making one

  1. Add the picture on the Assets tab, as any image: PNG, JPEG, GIF, WebP or BMP. A sheet with transparency wants RGB565A8.
  2. Select it, and switch on Spritesheet. The designer makes a first guess from its shape (a strip of square frames is the commonest sheet there is) and draws the grid over the picture, a numbered cell for each frame.
  3. Set the grid. Cut by columns and rows works out a frame’s size; by a frame’s size works out how many fit. Margin is round the outside of the grid and Spacing between frames, in pixels, as sheet tools such as TexturePacker and Aseprite export them. Frames stops short of the grid’s last cells when the last row is not full; 0 is the whole grid.
  4. Click a cell to give that frame a name. Names are optional, and each must be different.
  5. Add the sequences under it.
The Assets tab with tank.png selected: Spritesheet ticked, the sheet with a magenta grid over it and every cell numbered 1 to 48, cell 4 picked, the line 48 frames of 40 x 40, 225.0 KB in the firmware, once, then Cut by columns and rows, Columns 6, Rows 8, Margin 0, Spacing 0, Frames 0.
The sheet on the Assets tab: its grid, its numbered frames, and what it costs.
Two sequences of the sheet: drive_up_right from frame 7 to 9 at 12 fps, over and over, and the start of drive_right.
Sequences: a name, the frames it runs from and to, how fast, and how it plays.

Its settings

SettingDefaultWhat it does
SpritesheetoffMakes the image a sheet. Off, it is a picture again, and its names and sequences are dropped.
CutBy columns and rowsOr by a frame’s size.
Columns, Rowsa guessHow the grid divides the picture. A frame’s size is what is left after the margin and spacing, divided by these.
Frame width, Frame heightthe picture’sWith by a frame’s size: as many frames as fit.
Margin, Spacing0Round the outside, and between frames, in pixels.
Frames0 (all)How many of the grid’s cells are frames, counted along each row from the top.
Name of framenoneClick a cell to name it. A Sprite can be told to show a frame by its name.
SequencesnoneEach has a Name, From frame and To frame (counted from 1), fps (1 to 100) and how it Plays: over and over; once, staying on its last frame and sending the Sprite’s Sequence finished event; or there and back, over and over. A sequence of one frame is a picture that stays.
Colour formatRGB565As for any image. Every frame is packed in it.

Frames are counted along each row from the top left, from 1. The Problems tab says when the grid does not fit the picture, when two frames or two sequences share a name, and when a sequence runs past the last frame.

On the board

A sheet is kept in the firmware, never on the filesystem: its Stored in says so, and a sheet set to the filesystem by hand is refused. The export lays the sheet out again as its frames one after the other, each a whole picture, in one array under ui/images/. Every frame is a small image descriptor pointing at its own part of that array, so showing another frame is giving the image another source: nothing is copied, and every Sprite on the sheet shares the one array. Margin and spacing are dropped, so the sheet costs a little less than its picture: width × height × 2 bytes a frame, or 3 with transparency. The tank above is 48 frames of 40 × 40 with transparency, 225 KB.

Because each frame is a whole picture of its own, a frame is drawn exactly as any image is, on LVGL 8 and 9 alike. A Sprite can be turned and scaled, but a sheet drawn facing each way (as the tank is) costs nothing at all to draw turned.

The MicroPython export writes the sheet as one file of the same bytes. It is read off the filesystem once, when the first Sprite on it is made, and kept in RAM (PSRAM on a board that has it). Each frame is a view onto it, never a copy. ESPHome has nothing a sheet of named frames fits, and a design with a Sprite is refused there with the reason.

Only a Sprite shows a sheet

An image that is a sheet goes to the board as its frames, so there is no whole picture of it for anything else to show. The Image, Image Button and background pickers leave sheets out, and the Problems tab says when a widget still names one. To show the whole sheet in an Image as well, add the picture a second time.

Example: a battle tank driven by a joystick

The sheet above, on a 3.5-inch board. A Joystick drives the tank round a pen in eight directions with its tracks rolling, and FIRE plays the shot. Everything is the designer’s own; there is no code of your own.

  1. Make tank.png a spritesheet of 6 columns and 8 rows. Its 24 sequences are drive_up … drive_up_left (the three track frames of each row, 12 fps, over and over), fire_up … (the three shot frames, once) and rest_up … (each row’s first frame).
  2. Drop a Joystick and bind its X, Y and Angle out to joyX, joyY and joyAngle.
  3. Drop a Sprite in a panel, choose tank.png, and bind its X and Y to tankX and tankY and its Sequence playing, by its number to seqNo.
  4. An automation every 20 ms sets moving to (joyX != 0 || joyY != 0), moves tankX and tankY with the stick, keeps dir at floor((joyAngle + 22.5) / 45) % 8 while it moves (0 is up, round clockwise), and sets seqNo to the fire, drive or rest sequence for that way.
  5. FIRE’s Pressed sets firing to 1, and the Sprite’s Sequence finished sets it back to 0.
A 320 x 480 screen titled BATTLE TANK: a sand-coloured pen with the tank in the middle facing up, a joystick bottom left and a red FIRE button bottom right.
The design on the canvas.

The other way in is the Play frames action, from any event: a key’s Clicked can play walk_left while a Set variable beside it moves the Sprite’s bound X, which is a Pac-Man in two actions.