Log In  

Cart #wobblepaint-6 | 2020-11-04 | Code ▽ | Embed ▽ | License: CC4-BY-NC-SA

Wobblepaint started as a secret cartridge in my 2019 Advent Calendar entry, but I think it's time for a proper release! This version has some extra controls and nicer, less crinkly wobble.


Your brush has a size, colour, pattern and shape that can be adjusted separately. There are 4 presets you can select and modify using keyboard shortcuts, or by clicking and dragging the top menu bar down to reveal a palette of attributes.


CTRL-Z, CTRL-Y (or S,F) to undo/redo
CTRL-C, CTRL-V to copy and paste between doodles
W,R to switch between doodles (or use the menu buttons)
TAB to toggle menu
Mouse wheel (or e,d) to change brush size
RMB to pick up a colour
RMB in menu colour palette to select secondary colour (used for patterns)
LMB+RMB in menu colour palette to set the background colour

To save all doodles, use the cartridge icon button in the pull-down menu.

Wobblepaint saves data to itself. To start a new wobble cart, type LOAD #WOBBLEPAINT from inside PICO-8 and then save it as something. The data storage is reasonably efficient so you can get around 20~100 doodles to a cart depending on complexity.

To save a gif to desktop, use the gif button to record a second of looping wobble. If you want to record multiple doodles (e.g. for an animation or story), press tab to hide menu, CTRL-8 to start a gif, W,R to flip through the doodles, and then CTRL-9 to save the gif.

Gamepad controls

Turn off the devkit input in the options menu ("turn off mouse") and use a gamepad:

LRUD to move the cursor
[X] to paint
[O] + L/R to undo/redo
[O] + U/D to adjust brush size
In the menu, [X] and [O] behave the same as LMB,RMB

Using Wobblepaint doodles in your cartridges

CTRL-C copies doodles in a text format that can be pasted into code (or bbs posts)

Paste the code from tab 5 into your cartridge to load and draw them:

str_to_mem(wobdat, 0x4300)
mywob = wob_load(0x4300)
function _draw()

Or alternatively, copy the binary data straight out of the spritesheet and use load_library (tab 2) to load all of the doodles into a table.


v1.5: fixed uneven frame times when recording gif and increased length to 2 seconds (was 1)

P#83422 2020-10-29 03:14 ( Edited 2020-11-05 07:20)

:: zep
P#83452 2020-10-29 10:23 ( Edited 2020-10-29 10:24)
:: Numzyx
P#83458 2020-10-29 15:04
P#83472 2020-10-29 21:24
:: cubee
P#83483 2020-10-30 05:55

+second palette 👀

BTW I had no idea CTRL+key and TAB had their own ORD values. Is there more information about that somewhere? Maybe a list? :)

I wasn't able to record a gif via BBS, it says "saved on desktop" but the file doesn't show up anywhere (I'm using Windows 10)...

P#83496 2020-10-30 13:12
:: machi
P#83497 2020-10-30 14:00

Oh hey @machi ! I think you were on sheezyart ?? Not sure. I know we both share a mutual friend (shaddowkarate/newrem) though. I was darkscythe.

Great drawing!

P#83500 2020-10-30 15:22

@BoneVolt same here. The gif showed up on the left side of the bbs page, and I had to right click and "Save image as..." to download it. Maybe the save to desktop only works if you run the cart in standalone pico8.

P#83505 2020-10-30 15:55

@ianjsikes ooh, I didn't notice it before, thanks!

P#83506 2020-10-30 16:09

Happy Halloweenies

P#83508 2020-10-30 17:04 ( Edited 2020-10-30 17:12)
:: dimAI
P#83509 2020-10-30 17:12 ( Edited 2020-10-30 17:13)
:: machi

I never heard of Sheezyart, must be someone else, Im afraid :v

P#83513 2020-10-30 18:00
P#83518 2020-10-30 19:46
:: pilaf
P#83651 2020-11-03 08:04

How do i download the gifs ;-;

P#83737 2020-11-05 00:13
P#83739 2020-11-05 00:32

i made a little dandelion...
and a fatty bee, why not :3
and just to say, im here cuz of a brazilian youtuber called Goularte, and i loved this site!

P#83757 2020-11-05 01:32 ( Edited 2020-11-05 01:33)

I also watch that guy. He made a video about PICO-8? Cool.

P#83842 2020-11-06 03:02

Id just like to say that zep, youre such a wonderfull guy. The BBS has helped me so much, its just a great place thriving with creativity and amazing people, a place that you created alongside the community. I just want to say, thank you zep, we all love you! <3

P#83843 2020-11-06 03:25 ( Edited 2020-11-06 03:26)
:: Skykai
P#83855 2020-11-06 12:35

isso é bom!!!

P#83883 2020-11-06 23:21


P#83962 2020-11-08 00:45 ( Edited 2020-11-08 00:52)


P#83963 2020-11-08 00:46
P#83972 2020-11-08 10:06

Wow! I really enjoy reading Zep's carts source code because it teaches me some new tricks. But! This one has put me down... I can't figure out how the editor save the states and undo/redo them.

Could someone explain the basics about data compression and everything subject related and implemented in this cart?

P#84046 2020-11-09 16:50
:: kikito

@gcuellar The function doing the parsing is wob_load. Inside there, getval is used to extract numbers from memory, bit by bit. It does so by calling peek, which reads Pico-8 internal memory and returns it, but byte by byte. So sometimes the numbers read by getval require several bytes read (for example a number can take the last two bits from 1 byte and then the first 3 bits of the next byte).

Back into wob_load, the main thing it does is using getval to fill up a table called scn.

The first thing it does in order to do this is read the first 16 bits, which indicate the size of the scene in bits (variable dat_len). Then it reads the scene background color (4 bits) and stores it in scn.background_color.

Then it reads a bunch of "curves" using a loop which exists using the aforementioned dat_len var. Each curve has a bunch of properties, encoded as numbers (color, size, shape, etc). Some curves have "segments", which require an extra loop.

Curves are stored in the array part of scn, and segments are stored in the array part of each curve. So what you end up at the end is a scn table which looks like this:

scn = {
  background_color = 16,
  [1] = { -- first curve
    col = 15,
    shape = 3,
    [1] = { ... } -- first segment
    [2] = { ... } -- second segment

With this in mind, you can probably imagine how to undo works: it takes the last curve from scn, and puts it on another table called undo_stack.

"Redo" does the opposite - move the curve from undo_stack back to scn.

To load from a string, you first put that string into memory with this game's str_to_mem, and then read the memory.

The other interesting function is wob_draw, which is able to read the curves of a scn table and perform the relevant pico-8's functions. There is a table called funcs which is used to select how to draw every "shape", depending on the "shape number" of each curve. For example, shape number "0" (the first one in funcs is a circle). The functions read their parameters from the scn table. Each "curve" and "segment" end up calling the relevant pico-8 function or functions.

wob_draw is also in charge of doing the "wobbly effect" by altering the dots positions by random amounts. Picking the amounts involves doing something tricky with magic numbers, in the nrnd function.

With regards to "data compression"... I would call it "efficiency". Everything is stored as numbers, but they are densely packed to their size, with no wasted space. For example: consider the background color. In pico-8 there are only 16 colors. If you wanted the background color to be number 12, and stored that in plain text, you would need the character "1" followed by "2". That's 2 bytes/16 bits total. But by handling stuff in binary you can dedicate exactly the 4 bits you need for that, which "saves" 12 bits.

I hope it helps!

P#84610 2020-11-22 23:33 ( Edited 2020-11-22 23:38)

. @kikito Kudos for you, mate. Your explanation was very useful.


P#84651 2020-11-24 09:22

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2020-11-24 20:01 | 0.124s | 2097k | Q:91