Log In  

I've made a series of fonts for the PICO-8. Each font uses as few sprites and as little code as possible. An 'LS' version of a font uses Less Sprites at the expense of longer code.

TinyText: a lowercase font meant for use alongside the uppercase system font. Each character is just 3x4 pixels and aligns to the bottom of the system font, meaning lines of text are still 5 pixels tall and 3-pixel monospaced. The whole font uses just 5 sprites. Can fit 21 lines of text on-screen (the same as the system font).

TinyTextLS: the same font as TinyText but with just 4 sprites!

MiniText: a prettier lowercase font also meant for use alongside the uppercase system font. Character size varies and can hang below the writing line, meaning lines of text are now 7 pixels tall (but are still 3-pixel monospaced). The code is a bit longer, but the font still only uses 5 sprites. Can fit 16 lines of text on-screen.

MiniTextLS: the same font as MiniText but with just 3 sprites! [deprecated, see LRP's Mini]

LRP's Mini: the same font as MiniText but packed into just 2 sprites by LRP!! It also uses less code than MiniTextLS, so it's all-round better - use this one instead of MiniTextLS! Find it in the comments.

These fonts come with 3 text rendering functions, plus there's the system print, so we have:

  • print(str [x y [col]]) the system print function, which "PRINTS IN ALL CAPS".
  • printlower(str x y [col]) which "prints in all lowercase".
  • printfirst(str x y [col]) which "Capitalizes just the first word".
  • printevery(str x y [col]) which "Capitalizes Every Word".

3Text: this is a standalone font that replaces the system font for printing. Every character is just 3x3 pixels and the code is very short, but it uses 10 sprites and is the hardest one to read. Can fit 32 lines of text on-screen.

  • print3(str x y [col])
LRP's Mini   2      3Text       164      3Text       32
MiniTextLS   3      TinyText    245      TinyText    21
TinyTextLS   4      TinyTextLS  410      TinyTextLS  21
TinyText     5      MiniText    411      MiniText    16
MiniText     5      LRP's Mini  590      LRP's Mini  16
3Text       10      MiniTextLS  676      MiniTextLS  16

Cart #18802 | 2016-02-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Cart #18803 | 2016-02-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Cart #18804 | 2016-02-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Cart #18805 | 2016-02-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Cart #18806 | 2016-02-13 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA


Please feel free to use these for anything you like! I've tagged these with the CC license so people know immediately that they can use them, but I'm actually releasing the sprites and code under the zlib license. The zlib license is even more permissive than CC BY-NC-SA and basically means you can do whatever you want with them, but I can't be held liable. Attribution is not necessary, but I'd love to hear from you if you use them for anything!


Here's the TinyText font rendered, in TinyText 1.1 and in TinyTextLS:

Here's the MiniText font rendered, in MiniText 1.1 and in MiniTextLS:

And here's the 3Text font rendered and in 3Text (I haven't been able to do 3TextLS because of what seems to be a PICO-8 string parser error):

How the 'LS' versions work:

The Less Sprites versions use flipping and overlapping characters to reduce the number of sprites used, which requires a bit more code to setup and render.

The TinyTextLS sprites contain the following characters:


d, p and q are flipped versions of b; t is flipped from f; r is flipped from l; w is flipped from m; u is flipped from n.

The MiniTextLS sprites contain the following characters:


a overlaps d; b, p and q are flipped from d; i overlaps j; the dot of j overlaps the bottom left of s; n overlaps h; u is a flipped subset of h; t is a flipped subset of f; w is flipped from m; z is flipped from s.

Old versions:

While doing the LS versions of TinyText and MiniText I made small changes to the p and q characters, so I updated the original ones to match. Here are the first versions of TinyText and MiniText:

Cart #18768 | 2016-02-11 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Cart #18785 | 2016-02-12 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#18769 2016-02-11 15:27 ( Edited 2016-02-14 12:49)

This is awesome!! You didn't put the CC license on it though... Can we use it in our things or not?
Great job anyways!

P#18770 2016-02-11 16:24 ( Edited 2016-02-11 21:24)

Thanks. I'm releasing this under the zlib license, which is even more permissive than the CC BY-NC-SA license, so use away!

P#18773 2016-02-11 17:03 ( Edited 2016-02-11 22:03)

Pretty cool idea and nicely coded, but don't let a typograph see this :V
non-consistency in the n, k, or p-lines makes this pretty messy and hard to read. I'd suggest raising the height of letters like f or t by one, lowering the height of letters like r, n, v, u etc. by one, and maybe adding a descender height of 1 pixel for p, q, y, g etc. Further, why in the world would you make the small L and J look like that, 2 pixel width should be more than enough, if not one. I'd also cut the top right pixel of the e, but that's personal preference.

P#18780 2016-02-12 07:15 ( Edited 2016-02-12 12:16)

Great work!

P#18782 2016-02-12 12:43 ( Edited 2016-02-12 17:43)

@Pizza thanks for the honest feedback. The inconsistency in TinyText was bugging me too but my goal was to keep every character 3x4 and have the bottom edge line up with the normal system font. I still think that's worthwhile but I thought I'd make a prettier font too, let me know if you think MiniText could be improved! I'm new to pixel art and fonts but thoroughly enjoying both, constructive feedback is great for improving :)

@UrbanMonk, thank you!

P#18786 2016-02-12 13:57 ( Edited 2016-02-12 18:57)

These are great. For a font that is designed to fit into the least space, I think the uneven ascenders and descenders on TinyText qualify as charming.

I notice that the lowercase e in your MiniText image doesn't match the cart. There is a single pixel above the loop in the image, but no pixel above the loop in the cart.

I wonder if you could save a full sprite in MiniText by using flip_x and flip_y to reuse the same graphics for b/d, p/q, m/w, u/n/e, s/z. In fact, you could also omit "a" by drawing the bottom 3x3 from "d", same for h/n.

P#18790 2016-02-13 00:40 ( Edited 2016-02-14 20:14)

Dunno if the MiniText font image was already there last time I looked and I just missed it, but it's looking much, much better than the other one. If you wanna have the bottom edge lined up with the normal system font I'd just move the characters with a descender up one pixel, the ones with ascender down, cut the rest and call it a font. Basically having one font that's a middle ground between the two is what I'd suggest.

P#18798 2016-02-13 12:00 ( Edited 2016-02-13 17:00)

@LRP good spot. I was debating that pixel on and off for a while, must have grabbed a pic from earlier. Thanks for suggesting the flip stuff, making the LS versions was pretty fun!

@Pizza MiniText wasn't there at first, it was just TinyText. I've since added the LS versions and 3Text as well. I'm not sure what you mean about making a middle ground, I don't see how it would still line up with the bottom edge of the system font?

P#18809 2016-02-13 15:10 ( Edited 2016-02-13 20:10)

I just finished my own attempt at MiniText2, which manages to squeeze all of the characters into just 2 sprites! I had to make one change, to the "y", but otherwise the characters are the same.

Edit: Updated cart. The "y" is fixed and you can now switch between sample text and a sprite guide with z/x.

Edit 2: Minor adjustments in the sprite layout to reduce the number of flips required.

Cart #18834 | 2016-02-14 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

P#18812 2016-02-13 15:16 ( Edited 2016-02-14 18:13)

Wow, 2 sprites is pretty crazy. I thought about trying to change the order of the characters to overlap them more efficiently, but I didn't think 2 sprites would be possible!
Your InitChar function is obviously much nicer than the way I was doing it, but the reason I was doing it that way was so that characters which don't have (e.g.) a DX value literally don't have one, instead of storing a 0. I was trying to limit memory usage, but I don't know if it actually made a difference and it might have made the code longer than necessary.

P#18814 2016-02-13 15:26 ( Edited 2016-02-13 20:26)

The 3x3 is actually surprisingly readable! Very nice. Me like.

P#18815 2016-02-13 15:45 ( Edited 2016-02-13 20:45)

I'm actually passing nil for default values (w=3, h=3, dy=0*, fx=false, fy=false), which I think means that those variables aren't set at all. I don't know a lot about lua memory management, though, so I might be wrong about that.

I thought about encoding the character parameters in a bitfield (a single integer per character) or something similar to save some tokens, but I decided it wasn't worth it for this demo.

  • dy moves characters up from the third pixel, so 3x3 sprites have dy=0, letters with full ascenders have dy=2, etc.
P#18821 2016-02-13 22:09 ( Edited 2016-02-14 03:09)

After some more manipulation, I managed to find a spot for the original lowercase y, so all of the MiniText2 characters should now match your original MiniText font. I updated the cart in my earlier post with this adjustment.

P#18827 2016-02-14 00:52 ( Edited 2016-02-14 06:17)

Big fan of the 3Text, now make a lowercase version of that in 3x3 :V

P#18829 2016-02-14 04:11 ( Edited 2016-02-14 09:11)

Nice one LRP, I love the sprite guide, very cool!

P#18831 2016-02-14 07:49 ( Edited 2016-02-14 12:49)

[Please log in to post a comment]