Log In  


I'm working on a collection of 'retro' 8x8 repeating patterns.
Since the fillp() function only supports 4x4 px patterns, the nearest data format is using Custom Fonts (1bit per pixel, 8x8px).

I'm planning on something like this:


-- 97 'a' stonewall
poke(0x5600+(8* 97),
  14, -- ▒███▒▒▒▒
 230, -- ▒██▒▒███
 240, -- ▒▒▒▒████
 102, -- ▒██▒▒██▒
  15, -- ████▒▒▒▒
  95, -- █████▒█▒
 206, -- ▒███▒▒██
 224  -- ▒▒▒▒▒███

-- 98 'b' picket
poke(0x5600+(8* 98),
   0, -- ▒▒▒▒▒▒▒▒
  34, -- ▒█▒▒▒█▒▒
 102, -- ▒██▒▒██▒
 255, -- ████████
 102, -- ▒██▒▒██▒
 102, -- ▒██▒▒██▒
 255, -- ████████
 102  -- ▒██▒▒██▒

-- ...


and then to render the pattern,

print "\014aaabbb"
print "\014aaabbb"
-- etc.

Request for feedback:
(esp. @Heracleum, @dw817) ~ Is this reasonable?
Is there a more appropriate data type / graphics method?

Many thanks,

P#118960 2022-10-12 17:43

why not sprite data?

P#118963 2022-10-12 19:54

@merwok - Thanks for the feedback. Can the sprite data be stored as compactly (1 bit per pixel)?
I was going to put together a helper function to dump all characters to the screen and then memcopy() from screen to sprite memory ...then use of the sprite area is optional...?

P#118970 2022-10-12 20:27 ( Edited 2022-10-12 20:34)

Hi @aced, you can certainly write your own.

One of the very early carts I wrote demonstrates 1-bit saving of images. However with all the advanced Pico-8 has made since this could likely really be a lot smaller code. Also it is not slow. I use flip() to slow down the drawing. If you take that out it runs quite quickly.


There is also the one-off as seen in P8SCII which truly does display an 8x8 1-bit image.


P#118980 2022-10-12 21:57 ( Edited 2022-10-12 23:17)

Thanks @dw817. I'm not sure what you mean by "write your own"?
I'm very new to the world of PICO-8, so really want to use the API / standards that exist in the community. It seems the Custom Font is the only native way to store 1bpp images. I've played with the one-off characters, but as these patterns are normally repeated, it's better to store them once (as a 'font') so they can be reused multiple times.

Please shout if this seems odd!?... I'd love a solution that's copy&paste simple~ so perhaps writing directly to the sprite sheet is what is expected?... On other platforms I have code snippets that can be quickly added to your project, providing the graphics resource, with minimal chance of breaking existing code.

Again, thanks for your comments.

P#119019 2022-10-13 00:30

Hi @aced.

By writing your own, let me see ...

Just to toss this in the air. Regarding storing and drawing one-off images from the sprite sheet.

Now writing to the spritesheet a true 1-bit 8x8 pixeled image to begin with is a bit of work but can be done. DRAWING back the sprites is pretty speedy though.

Cart #oo2spr-1 | 2022-10-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Here now, load that up, examine the sprites.


Notice there are 2-sprites. One of which takes 8-bytes, the other of which takes 32-bytes. The 1st sprite is the 1-bit image. The 2nd sprite is the true 4-bit image you can change and edit in the spritesheet.

And of course that math could be worked out where a single 1-bit 8x8 sprite occupies two sprite pixels 16x1 yielding a true 8-bytes.

Oh, and one other thing and actually all you guys need to know this.

Using cstore() by itself in your code will automatically HARD CODE whatever POKEs and memory changes you have made to your spritesheet, Maps, SFX, and Music to your code as if you had drawn and written it yourself. Self-modifying code ! :)

P#119024 2022-10-13 01:23 ( Edited 2022-10-13 17:23)

Example of writing an image to sprite sheet ~


-- 97 'a' confettilarge
poke(0x5600+(8* 97),
cstore()--store as sprite 0

The code is trivial, I'm just not sure how useful this approach is?

P#119047 2022-10-13 15:46 ( Edited 2022-10-13 16:08)

What you have is pretty good, @aced. Most interesting 8x8 pattern BTW. May I borrow that for future carts, please ? I can see that developing all kinds of interesting floor patterns.

Now how would you write the code for reading from the sprite-table to the custom character set ?

P#119049 2022-10-13 17:12 ( Edited 2022-10-13 17:24)

Thanks @dw817! Really grateful for the positivity :-)
All the patterns at 8x8.me are public domain / CC0 - free to use.

The idea (for all platforms) is that either the code snippets can be copied & pasted and have minimal impact on the user's existing code, or, the whole file can be import-ed and used as a library resource.

I've struggled the most with the PICO-8 platform, to separate (1) storing the bitmap data and (2) blitting the data (which the user should be free to decide). Currently the two are conflated, which is why it doesn't feel 'good' to me...

Re. writing the custom characters ~
To manage hundreds of images, the code will be automagically generated with a bash script.
It's just a question of deciding on the format that will be most useful to the community...

P#119052 2022-10-13 17:27

Oh how interesting, @aced ! Thanks for sharing the link. That should actually help a lot of artists and programmers.

I was also looking at your code and am a bit confused as to the "X" you have in the poke-set, which converts to 120:


Converts to: poke(0x5600,8,120,8,0,0)

What is the 120 for ? According to Pico-8 documentation that is the width for characters 128 and above ?

Looking at your bash script. Oy, I hope it's not that complex. Let me think, to convert a sprite to a custom character would be:

Cart #yokefafite-0 | 2022-10-13 | Code ▽ | Embed ▽ | No License

Please see code to where conversion takes place.

P#119056 2022-10-13 17:54 ( Edited 2022-10-13 17:59)

The x in ?"\^!5600⁸x⁸\0\0" is just a 1char padding as the value will never be used; it can be anything that minimises the total number of characters.

P#119063 2022-10-13 19:06

Thanks @merwok and @dw817 for feedback.
I have explored separating how the bitmap data is stored (as a table) and the blitting function.
This allows the user flexibility in how it's rendered, e.g. (1) to a custom font or (2) to the sprite sheet

confetti = {

-- blit option (1) to custom font, character 97 'a'
poke(0x5600+(8* 97), unpack(confetti))

-- blit option (2) to Sprite 0
for row=1,8 do
 for i=0,7,2 do
  x= confetti[row]>>i

While I prefer the spirit of keeping the data and rendering functions separate... it does result in an excess of code.
It seems brevity is the overriding philosophy of the PICO-8 platform. My original approach, using the built-in font rendering and writing to the sprite sheet, uses less characters and tokens. I don't think I could improve on that...
Unless method (2) be written in ~half the tokens...!?

P#119076 2022-10-13 23:32

I have pushed a 'draft' code sample: here.

Here's an example filling the sprite sheet (0 - 15) with the Bayer dither patterns -

#include dither.p8.lua
print"⁶c0ᵉabcdefghijklmnop"for i=0,7do memcpy(i*64,24576+i*64,64)end cstore()

I still welcome all feedback on coding style and approach.
Many thanks,

P#119151 2022-10-15 16:15

@merwok - just for you- I've added the ability to generate sprite sheets.

import dither.png

Is this what you had in mind...?
Obviously it will overwrite the first 32 sprites you may have created... :-/

P#119203 2022-10-17 01:01

oh I was just replying to your initial question by asking about storing the data in spritesheet instead of using font, I don’t need dither patterns as sprites myself. like you said the information density is different between sprites and font data, unless you use a technique to use all the bits (like https://8bit-caaz.tumblr.com/post/171458093376/layering-sprite-data)

P#119204 2022-10-17 01:44

[Please log in to post a comment]