Submission #7073: greysondn's SNES Mario Paint "Color-A-Dinosaur%" in 33:53.63

(Link to video)
Super Nintendo Entertainment System
Color-A-Dinosaur%
BizHawk 2.6.1
122219
60.0988138974405
1618
Unknown
Mario Paint (JU) [!].smc
Submitted by greysondn on 4/1/2021 9:01:05 AM
Submission Comments
What if - just hear me out - we could somehow play Color a Dinosaur on the SNES? The freeform creativity of such a game could - conceivably - unlock a brand new era of TAS creation previously unseen and unheard of in TASVideos history!
After scratching my head for a bit, I decided the best way turns out to be putting the images into Mario Paint. In this sense, Mario Paint essentially becomes Super Color-A-Dinosaur.
I present therefore what I hope will open a new category for Mario Paint SNES on TASVideos after viewing and notes: Color-a-Dinosaur%. The key objectives are recreating - and coloring - the unique pattern templates from Color-a-Dinosaur as stamps, some version of the fanfare jingle, and the 16 dinosaurs - and coloring them in clearly creative and fun ways.
This does, I've found out, turn out to be entirely possible. Assuming, of course, one is willing to do some legwork first.

Game objectives

  • Emulator used: BizHawk 2.6.1 (x64)
  • Fast where it counts, played for entertainment value where the zen of coloring is of more relevance.
  • Properly recreates previous runs on older hardware.
  • Properly empowers people playing back the TAS to color dinosaurs for themselves should they choose to take over from the recording at multiple points in time. (Now with sixteen colors, unique fill patterns, and no more flashing!)
  • Has extensive notes in a summary section for anyone who cares to do anything tool-assisted in Mario Paint in the future.
  • Tells the story of one brave, brave Sir Robin, who bravely ran away.
  • Demonstrates what the very edge of sanity looks like in the way only adherents of Discordianism can.
  • Is totally, like, just super chilled out by the time it's said and done, which is, like, the best reason to vote to publish.

Story Mode

After the story, run notes, afterword, and aftermath, you'll find summaries of my notes for other people who follow along in my footsteps later on. Those may actually be somewhat useful.
The multiple-year long process used to produce this TAS.

Obtain Sheet Music

Color a Dinosaur wouldn't feel authentic if we couldn't reproduce the iconic - and awful - "picture completed" jingle when our picture is completed somehow.
I am basically tonedeaf. This is a well known fact for anyone who has had the misfortune of listening to my "singing" at 3 in the morning as I walk home from across town.
Thankfully, some tools exist to help us.
We just have to:
  • Export the individual channels of the jingle audio.
  • Open them in a spectrograph and obtain the note pitches and durations
  • Awkwardly fumble out the BPM and meter because we're not good at all when it comes to musical theory, but guessing 4/4 and sliding the BPM until it lines up turns out to work well here. (300 BPM, by the way.)
  • Ask for help from someone else who has some decent grasp of musical theory to figure out the piece's key and - at the time, this was CompuCat, from the TASBot Labs Discord server. (Thanks for your help, CompuCat!)
  • Decide this is where we're stopping and send the sheet music to dwangoAC, for reasons I don't actually recall.
  • Completely forget we were even doing this and let approximately one year pass. Let life happen while this simmers on the back burner.
  • Try to locate the sheet music and fail, multiple times and multiple places, before ultimately finding the version sent to dwangoAC a year prior. (After messaging him to ask if he still has it laying around while he's at work - thank you for your patience and help, dwangoAC!)
  • Recreate the sheet music in MuseScore using the PNG version sent to dwangoAC.
Great! Following these simple and totally sane steps, you should now have a copy of the sheet music for Color a Dinosaur!

Get Sheet Music into Mario Paint

Now we have a new problem. The music sequencer in Mario Paint has five noteworthy properties.
  • It's only in the key of C Major, from the second G above middle C down to the B below middle C. There are no sharps or flats.
  • It only has staff for the treble clef. (That is, there is no bass clef at all.) This is covered in the first point, but needs stressed.
  • It has no idea what a sustain is, even for something as simple as defining a whole note versus a quarter note.
  • You can only place notes on the beat. Given that the two time signatures in Mario Paint are 3/4 and 4/4, this means that your notes must start on the quarter note.
  • It can only play one voice per pitch at a time, and a limited number of voices total at a time.
We can address each of these in turn.
  • Using MuseScore's tools, we can transpose music in the worst possible way - without knowing any musical theory whatsoever. So we transpose all the out of range notes on the treble clef into range. This turns out to mean transposing anything from the original song down a Major 6th on the treble clef. After doing this, we just completely discard the sharps and flats.
  • Again, we transpose, this time in a way so horrid that it could probably qualify as a crime. We realize that about an octave and a half is between the treble and the bass clef, so we just transpose it all up a major 16th - two full octaves. However, in order to match the change on the treble clef's transposition as closely as possible, we then have to transpose it upwards an additional Major 2nd. (Does this mean it totals a Major 18th? I don't think I want to know.) After doing this, we again completely discard the sharps and flats.
  • Note durations? Who needs 'em! Every first year piano student knows that you just hold down the sustain pedal and slap the keys! So, we just chuck them out and worry about the note's pitch.
  • This piece has eighth notes, so the next part gets a little hard. We basically half-ignore the measure divisions ingame and double up - a measure on the original sheet becomes two measures in Mario Paint.
  • We - thankfully - only need three voices. We have to make a judgement call on what notes to play if any conflicts happen - if memory serves, we only have one conflict, so this turns out to be not-that-hard.
If you are a musician who has read that and is now hyperventilating, congratulations! You now have a fundamental understanding of the unique joy and excitement that Color-a-Dinosaur brought into the hearts of children in the late 80s! (Also, I'm half-sorry about the sustain pedal joke.)
The jingle we now have is almost - but not quite - entirely unlike the original. Being derived from the original NES jingle by someone who can only be described - after reading the above notes - as "likely mentally unhinged", it's deemed perfectly in the spirit of the game and becomes the 16-bit completion jingle for the purposes of this TAS.
We then experiment with this and playing it alongside the projection mode for images, and decide to delay the song two measures so there is enough time to "turn out the lights", as it were, and display our masterpieces in a style befitting the original, complete with slightly awkward delay.

Obtain Images

After that foray into madness, the date is 22 March 2021, and this part is remarkably easy by comparison.
Open Color-A-Dinosaur and capture screenshots of each of the images. Number them from 1 to 16, in reading order. Having done so, clean them up (remove the pencil and lefthand junk), observe that the images approximate to some size on an 8x8px tile grid (216x192), and crop them to that size.
While you're here, at least grab the fill patterns. The colors don't necessarily matter so much in this case; after all, part of the point of making it 16-bit is expanding the color palette. (And I'm not sure how we even begin to recreate that flashing thing the original game has going on without some sort of total control or hack.)
Redesign the fill patterns to fit 16x16 pixels. Then realize they were already 16x16, you were just seeing a 14x14 window onto the pattern. Reconsider your life choices and how they led to this exact point for a moment before moving forwards.
At first this may seem a waste of time. However, Mario Paint features a stamp editor, which will permit you to make 16x16 stamps to decorate images with. If you floodfill using one of those stamps, it actually lays it out as a flood filled pattern. (Granting, this is mostly being done for authenticity to original, and not from sheer necessity.)
Call it a good time for a break because you're tired and it's 6:02 in the morning. And because you're talking about yourself in the second person.

Prepare Images

Now that it's 4:02 in the evening on 22 March 2021, we can work on preparing those images.
We're first faced with what seems to be some kind of paradox: the SNES can output larger images, and yet our display with the smallest paintbrush is effectively only 124x84. (Reminder: Our images are around 216x192.)
This seems like some kind of oversight. Why can't you do single pixels? Pondering this at lengths and doing some research leads us to realize that you can create a single pixel stamp and use that to paint images in.
So that's what we do.
As the smallest brush was 2x2 pixels and we now have a 1x1 pixel brush, we've effectively doubled what our apparent resolution is. So then our apparent resolution is now 248x168. Still a little short, but maybe we can wedge the images in there?
So we cut the image area frame and proceed to use GIMP to place them behind it, do a little touch up, and find out that we can - in fact - *maybe* fit the images into the frame.
We also discover:
  • The baseplane on image #5 isn't actually straight, so we can clean that up.
  • The baseplane on image #6 is slanted, and likely meant to represent a slope, but because there's not enough detail to it, we can go ahead and straighten it out, too.
  • Image #7, same adjustment. I'm going to stop posting the pictures, it's pretty easy to check if you feel a need.
  • Image #8, the same adjustment but... On top of this, it's actually too tall to put onto our canvas. This is a good time to take a deep breath and once again consider what we're doing with our lives. If we leave a very small gap at the bottom and top so that those backplanes are singular spaces (so that floodfill works as expected), we will require the image to be 14 pixels shorter. We very carefully select 14 rows, by hand, with some content awareness around them, remove them, and then gently tweak the resulting image to be at least comparable to the original.
  • Image #9, thankfully just barely fits after that mess, and has the usual backplane adjustment.
  • Image #10 is actually fine.
  • Image #11, backplane adjustment.
  • Image #12, just fine.
  • Image #13 needs the usual backplane adjustment and is too tall, needs to lose 11 rows. I didn't feel like high-effort this time, not to mention how content dense this one is, so a different strategy to #8 was employed. First, we remove the entire background - the white fill in the back plane. Then, we separate several objects and relocate them.
    • The sun being moved to a new layer and moved down, along with the top spike being moved to a new layer and moved down, gives us 6 pixels. Halfway there for basically nothing!
    • The jawline up being separated from the body, and then moving the body to a new layer, and then moving it up gives us the remaining five pixels well enough.
    • The body move makes the third spike from the top - the highest flopped over one - a bit cramped, so we move it to its own layer and then move it along the dinosaur's spine until it looks "good enough".
    • And then, of course, we fill in the backplane with a new layer of white, and flatten the image for export.
  • Image #14, just the backplane adjustment.
  • Image #15 fits fine. The backplane, for once, is clearly meant to be curved. I don't feel like dealing with it, so I straighten it out to match the region in front of the dinosaur's front legs.
  • Image #16 is just fine.
At that, we've managed to prep all 16 original images to be imported into Mario Paint.

Taking Inventory ("Intermission")

We have something for the jingle, we have the fill patterns, and we have the images.
All we need to do now is actually import all of them into the game.
Mario Paint's mouse controls work something like a plotter; when the button is held, it draws on the current coordinate. When the button is released, it stops drawing. The same sort of can be said for the game's stamp patterns. Really, the entire control dynamic for the game is summarizable this way.
Therefore, the best script for this is a relative-positioned plotter.
Some experimentation shows that we can go quite fast, but if we go faster than 1 pixel at a time while drawing, we'll draw a dotted line with our stamp.
The next task is to write a script that can solve the fastest route from point to point as a series of mouse inputs for us, and to design a plotter script of sorts that can take a black and white image and convert it into a rapid series of inputs.
My usual tool being the Python programming language for such tasks, we'll use the PILLOW image editing library and examine the game's data instead of fighting with this.
The plotter script, if it has the ability to just wait some number of frames, could very nearly generate our entire TAS for us with some careful work and planning. And, of course, experimentation.
So first we get a feel for how the game responds to inputs, then we write the script.
But before that, we call it a day for this. It's 5:01 in the afternoon and we've done a good amount of work for one day on this. There's a need to make spaghetti.

Understanding Game's Inputs

Now that it's 5:17 PM on 23 March 2021, and our companion has brought home turkey subs and that most sacred of love currencies - french fries - along with an energy drink, it's time to fight with this.
The (original) SNES Mouse has three sensitivity settings, all set by software. If you're interested in the nitty-gritty, that can be seen here on the NESdev Wiki: https://wiki.nesdev.com/w/index.php/Mouse#Sensitivity
Looking at the sensitivity scaling, we can immediately realize that a direct mapping from the mouse value to an integer is likely at the base sensitivity setting. The question rapidly goes from "how does it behave?" to "where is the limit?"
Utilizing RAM search and floundering about rather aimlessly, we come up with a slew of addresses which look promising for the data points we need. At a best guess, here is my RAM Watch chart after playing around with the music earlier and playing around with positioning and the stamps a bit now:
0004DCws0WRAMCursor Screen X
0004DEws0WRAMCursor Screen Y
0 S_1
000226bu0WRAMCursor Canvas X
000227bu0WRAMCursor Canvas Y
0 S_1
0000A9bh0WRAMSomething to do with Instrument?
000E8Dbbh0WRAMActual selected instrument
000EB5bh0WRAMSomething to do with instrument?
0 S_1
00298Cbu0WRAMSpecial Stamp Editor Pixel 0, 0
00298Ebu0WRAMSpecial Stamp Editor Pixel 1, 0
0029AAbu0WRAMSpecial Stamp Editor Pixel 15, 0
0029CCbu0WRAMSpecial Stamp Editor Pixel 0, 1
002D6Abu0WRAMSpecial Stamp Editor Pixel 15, 15
0004D1bu0WRAMStamp Current Color?
001124bu0WRAMStamp Current Color?
Aside: That's just my watch file's contents. I've reformatted it for this document's presentation.
Whether what are marked as screen and canvas coordinates actually represent that is a bit sketchy. It's unclear in some ways, which is readily apparent by loading that watch and moving the mouse inside the canvas. Nonetheless, moving a single pixel on the screen adjusts those values by one pixel, so it's enough for our purposes.
Now we just use the virtual pad to send controlled inputs and draw a single pixel, and we find out the way the mouse is read doesn't resolve to anything totally clear for me, personally.
It would appear that any time the mouse is moved, the "actual" move takes place the next frame or (rarely) two frames later. Any time the button is clicked, it can take as many as three frames to read.
Button clicks are inconsistent. Moves can be inconsistent.
The best cleanup seems to be to wait three frames after a mouse move, five after a button click, for best response. By this, I mean that move wait wait wait (next) is correct, as well as click wait wait wait wait wait (next) is correct. (Consecutive moves seem okay; consecutive clicks I'm unsure but there's not many circumstances where clicking the mouse twice consecutively makes sense anyway.)
Around this time, I went looking for anyone who had done *any* work on Mario Paint before me. This led me to Alden, which - after reviewing their forum history, led me to this forum topic:
Alden evidently did their work with SNES9x, lua, and patience. WOW! Here's their page on that:
That forum topic is worth review just for problems that I have to solve in the process of this. Although I was - until this moment - unaware of such work, it's worth examining it for a view of people who walked this before me. (It's safe to assume I've at least skimmed that topic going forwards in these notes.)

Examining that Forum Thread

So I've covered it, here's the commentary on some of that thread:
Quoting Alden (27 August 2008)
Making these was about as close to "by hand" as you could get without actually drawing it yourself. I leave the heavy lifting to premade solutions and sort of dangle them together. I start by finding an image, cropping and resizing to a size that will fit (about 245x165). Convert to a black-and-white-pixel-only bitmap (this step usually took a bit of tweaking to get a decent final image). This first part is all done "by hand", but finally I run the image through a script that converts it into a monster string of 1's and 0's. And double finally, I run that string through another script that paints the picture, pixel by pixel. (And yes, the scripts are in two different languages :S I'm lazy.)
YOWZA!
The general method "works" and essentially is a variant on a plotter, but having the plotter external to the emulator likely would work better for the sake of sanity and time. Generally we talk about how it's impossible to understand a game's code well enough to create external tools, but this isn't exacty true; where the rules are rigidized enough, we can do so. (We do this, for example, at stellar distances where a signal round trip takes minutes to hours! The rigidized rules there being real world physics, generally.)
Quoting bisqwit
For generating a natural looking method of drawing the edges you could apply a floodfill style algorithm. Just follow the edges in the direction that is in the same color and has the least angular change, and when you hit a dead end (a point that has no surrounding pixels that are yet to be traced), choose another yet unprocessed intersection / edge (preferably one that is closest to where you stopped) and repeat, until you have traced all the edges. When choosing another point to trace, try to choose one in the same color; and if none are remaining, then choose a different color.
I had been pondering a plotter, but this would be something comparable to a space filling strategy. I had actually looked into space filling curves as an approach, but the mathematics of cramming a fractal into a design's space are beyond me.
It's worth noting that any method which minimizes time not spent drawing is going to do better overall on time. By extension, bisqwit's notes there are probably a winner.
Quoting bisqwit
When drawing the edges, estimate the width of the brush needed, and draw on the center of the edge.
Bisqwit expands on this premise for a ways in the thread.
I'm not going to take this up, but it's likely worth examination. Probably whether or not this saves time is image dependent, but solving for the brush placement is a bit much for me this instant, and I don't believe it will help me Color-a-Dinosaur!
Quoting bisqwit
For the floodfill, you should research on the algorithm used by the game to perform the floodfill, and choose a floodfill point that is fastest by the game to perform.
If there's time, I'll check into this. I'm not optimistic on my time here. (Post-production note: This does appear to carry some validity, but there was a deadline and not time to investigate. Future people in this category may find some gains there with some patience and work.)
Quoting bisqwit
When you feed the game a delta of 1, it is safe to assume that the cursor moves by 1 pixel. However, when you feed a delta of 20, the cursor might move by 15 pixels, or 40 pixels, or 0 pixels, depending on how it is programmed. This makes it very difficult to predict where your cursor is, and more importantly, to predict what kind of input you need to generate to place the cursor in some specific location.
So they had realized in 2008 what I'm fighting with this instant, in a completely different emulator. The mouse's data doesn't corrospond directly to what is programmed in game. Working out how that's distinct is necessary to establish anyhting resembling sanity.
Quoting bisqwit
Mouse events, including movements, are ignored when the game is busy. Such as after setting a pixel, or after clicking an icon.
Yes, this seems to hold. Wish I had found this topic much sooner. Question for someone else later: Is there a good way to establish what the "busy" state is in the game? An address or anything that doesn't require guesswork?
Quoting bisqwit
Clicking something for 1 frame does not register. Clicking for 2 frames usually is enough.
I'm finding 3 frames to be virtually bullet proof. We can extrapolate this to be a feature of the game's logic, not the emulator they were using.
Quoting bisqwit
Occasionally the game forces your cursor to some position on screen. For example, when you click "save" on the custom cursor editor. Your input generator must be aware of this fact, or you'll experience a desync.
Comparatively true. If we do it as a plotter, we just call a halt and move on the plotter's coordinates. In effect, moves sent to the game and moves in the plotter are distinct; this way if the game moves us, we can move the plotter to match. (I had already essentially planned this, just to be able to take control and give it back arbitrarily.)
Quoting Alden
I was using memory address 7E0226 and 7E0227 to track where the game thinks the cursor is
Those corrospond to what I've called cursor canvas positions in my watch file.

Returning to Movement Analysis

Let's assume that x and y are treated the same, as their vectors are essentially equivalent relative to real world motion in the SNES mouse.
We can gather some insight, then, by just moving the mouse itself.
The sensitivity settings appear, on their face, to be a lie. This is slightly perplexing - if they don't actually change anything in the mouse's reading, what do they do?
I pondered this for some time before it occurred to me to try selectively adding and removing frames from input sequences. Essentially, I created an arbitrarily large sequence of inputs that was:
  • start in a fixed position
  • move right ten pixels
  • delay x frames
  • click in our new position for y frames
  • delay x frames
  • move right 10 pixels
  • delay x frames
  • click in our new position for y frames again
  • delay x frames
  • move right 10 pixels
  • delay x frames
  • click in our new position for y frames again
  • delay x frames
  • move left 3 pixels for z frames - until we're back at the start. (Theoretical fastest is ten frames)
I read that as "total frames" = 6x + 3y + z + 3.
Although not exhaustive, this should start to give some insight into the game's logic for input processing, regardless.
The question is what the values are for X, Y, Z for each input setting. So I tested that. I also tested delaying and not delaying a few frames before the entire shebang to see if there was an even/odd reliance. Almost immediately I started to notice, while on 1 star/Tortoise, that the hold duration of a click changes how long I need to wait before I'm allowed to move.
So if we assume that's the case, then just evaluating the tortoise speed, we get:
X Y Z Total
7 1 10 58
6 2 10 55
5 3 10 52
4 4 10 49
3 5 10 46
2 6 10 43
1 7 10 40
0 8 10 37*
asterisk denotes a failure in some way
Note that I'm very bad at math, so the exact figures should be checked. I am reasonably sure about the relative three frame savings as we go down, though.
In the last case, a slur results. A single pixel to the left during the return gets drawn. This seems to imply that values of:
x 1
y 7
z 10
Are ideal here.
 
In human terms, this means:
 
  • Perform x/y movements of the mouse without any delay between them.
  • Hold the left button for a total of at least seven frames any time you click it
  • Wait a frame between movement and mouse holds, both before and after.
 
Moving the mouse while holding left mouse button is subject to the same timing requirements - the only difference is that the pause is replaced by continuing to hold the left mouse button. In layman's terms, hold the mouse button for eight frames before trying to move it while drawing. (Yes, I tested this.)
Hare shows some weird properties:
X Y Z Total
1 7 10 40*
1 7 11 41
1 6 11 38*
2 7 10 46
asterisk denotes a failure in some way
Essentially, the most reliable option is likely 2/7/10, but is six frames slower than tortoise! Slow and steady wins the race, indeed!
And the cheetah? Same issue. 2/7/10 or it's unreliable.
I felt like, at this point, maybe I had botched this somehow and went back to test the tortoise again, just to check. Even after doing it on cycle after itself several times, it seems to hold fine.
I don't understand why. At all.
Still, this tells us - now - that for reliability, not much can beat the tortoise.
All data with the tortoise had been done early on - each input to 11, and testing x + y movement together.
Despite being far from glamourous, the test footage can be found as proof of when this was done, I suppose. Or at least proof of when it was no later than.
I had wanted to sleep at 4:34 in the morning (24 March), but that didn't work out. So while I did take a break for a few hours, it's 7:35 and I can't sleep because this image is bugging me.
I charted the input delta for the x coordinate to the ingame result for x coordinates from that picture.
Input Ingame
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
>10 10
This seems to hold for inputs on y axis as well.
7:46 AM. I'm going to try sleeping now that I've done that bit of work that was bouncing around my head.
And now it's 25 March 2021 at 12:41 in the morning. It was meatloaf day. Beyond that, I'm just back to work after playing some Evoland 2 with my companion.
At this point, only two pieces of data are missing, both of which there's some access to.
The first is where we are in the game's coordinates, which are reflected in WRAM addresses from my watch file, in that first segment, anyway:
0004DCws0WRAMCursor Screen X
0004DEws0WRAMCursor Screen Y
0 S_1
000226bu0WRAMCursor Canvas X
000227bu0WRAMCursor Canvas Y
I'm just going to call those `4DC`, `4DE`, `226`, and `227` for short.
`226` and `227` Do seem to be strictly the canvas. If we wanted just a straight plotter for the canvas, they'd work reasonably well. However, because we do want the entire screen, they're not going to work out. So we can ignore them.
`4DC` and `4DE` look promising. They have minimum and maximum values I'll get to momentarily, but they seem to be unreliable for motion at the extremes. So in practice approximately 8px of distance towards their apparent edges is unreliable.
After starting the below chart, I worked out why. Basically, if a movement would make the cursor go past the limit, it's ignored. So any point up to the limits is reliable if you're only travelling 1 pixel a frame, but if you're travelling 10 pixels a frame, then effectively you can only guarantee up to 10 pixels away from it. In turn, this seems to make it be some arbitrary distance it stops - in reality, it's stopped such that whatever speed you're trying to go doesn't exceed the boundary from the present position. (Hopefully that makes sense.)
I also discovered that stamp placement is a little finicky on the right hand side, leading to the idea of a stamp with a pixel in the center or top right (instead of the top left). I tried both of these, and decided that a stamp towards the middle would likely be best. When you exit the canvas region, the frame turns black; when you enter it, the frame turns red; some experimentation led me to which pixel would always be drawable in the canvas region at the moment it was activated. (I spent some time tweaking a stamp and making note here.) If the stamp's drawing space coordinates go from (0, 0) at the top left to (15, 15) at the bottom right, that would be (8, 8) - I doubt this to be coincidental. Investigation of several tools shows that they align on the same coordinates for the canvas, and sliding out of the canvas with this stamp doesn't result in any displacement of the cursor graphics.
4DC = Screen X
4DE = Screen Y

As signed 2-byte ints
4DC 4DE
Canvas Min 4 28
Canvas Max 251 195
Min -16 8
Reliable Min -6 18
Max 271 215
Reliable Max 261 205
Essentially, this gives us one of the two pieces of data. The other one isn't quite so interesting; we mostly just want to know how TASStudio encodes mouse inputs, basically, as we can copy/paste to strings from it.
The correct input configuation for this game is a mouse in the first port and a controller in the second port. (The second port controller can be used for a few pushbutton things.) So that's what my inputs should match, roughly.
So, let's do four frames:
  • x+2
  • y+4
  • left click
  • right click
And see how that looks.
Copy/paste from Tasstudio:
|..|    2,    0,..|............|
|..|    0,    4,..|............|
|..|    0,    0,l.|............|
|..|    0,    0,.r|............|

Save as a Macro:
... I couldn't? This is when I discovered I'd been running Bizhawk 2.4.3, and had to take some time to update and fix settings all the way into 2.6.1.
I was, essentially, completely unamused. Especially upon finding that the issue was still present, likely due to testing (and support) of macros for the SNES mouse.
So I'm stuck copy/pasting into TASStudio and doing it by hand. Still, knowing this, I now have everything I need to write a plotter for this game. So now it's time to do that, I suppose.

The Plotter - Basics

A very, very basic plotter should have the ability to:
  • Drop Pen (draw on the paper)
  • Lift Pen (stop drawing on paper)
  • Make relative moves
  • Move to a specific location in the fastest line
Other features are essentially built on these. I'd like my plotter to have just a very few extra features:
  • Click - essentially, drop the pen for seven frames, then lift it.
  • Right-click - same thing, but right mouse button.
  • Pause - wait some number of frames, give no meaingful output.
  • Jumpto - change the internal coordinates without moving the pen itself (for example, if Mario Paint teleports our cursor for us).
I will build one last feature on top of this, but one thing at a time.
(Please note that the files as are have been omitted for the sake of sanity in the increasing length of this publication, but will be provided at the end.)
The time it took to get a basic plotter down stole most the night, and that's quite alright. Between that and reading manuals, it's now 8:52 in the morning on 25 March 2021, and I'm going to get some rest now.

Plotting Images

I rolled out of bed around 3:30 PM, 25 March. It's about 5:36 PM as I write this. (Incidentally, happy birthday, Caley!)
Now that we have a plotter, the next step is to draw images with it. This requires PILLOW and a few assumptions.
If I wanted to take the time, I could arrange a stack of pens and then define their rules such that each pen corrosponded to a color. Code could conceivably be written to swap the pens out.
It just sounds like too much effort for this project with time steadily running down. So instead I'm going to just assume some basic preprocessing can be done.
  • The plotter isn't responsible for selecting the correct pen.
  • The plotter isn't responsible for erasing the contents of the screen when there's more than just an empty space.
  • The plotter is only responsible for printing a 1 bit image to the screen, starting with where it is "right now", essentially. Ideally as quickly as possible, but we'll settle for "at all" first.
This code is straightforward. Given that we already have the code to do the functions described in the previous section, we can make use of the PILLOW library and just read the pixels off one at a time. A very naive - but working - solution is as easy as traversing X and Y and clicking in each position. So that's how we'll start.
Preparing images can look many ways, but the simplest start is just exporting them fullsize with everything non-necessary screened off. (Because white means "don't draw" to our plotter, this essentially means leaving those regions white.)
As I stated, it's quite possible to do this very naively. The first algorithm just traverses the X and Y in the image, and moves the pen accordingly.
(NB: A better and more complete version of the code will be presented towards the end of this document.)
Testing that gave me a series of results that I'm not the proudest of.
Essentially, due to the oddities - I think - in how the stamp draws, there's an offset of about 10 x and 11 y I didn't account for. So my drawing was done offset. This is easy to fix - we just add the offset as a property we can adjust in the plotter, then make use of it when drawing the image.
But most painful is just how slow this actually is The last input is on frame 17302. There's sixteen of these! And I still have to put in the redone jingle and actually play it and color these images in between! AGGGGH!
It's 9:33 PM and I've not eaten. The next step will be optimizing this algorithm. I have a few thoughts - and will give a bit of credit where it's due on that front - but one thing at a time. I'm going to take a break, joke with my companion, and dump the video of this being made.

Optimizing Plotting Images

It's 10:28 PM on 25 March 2021 (and still, happy birthday for about an hour and a half more, Caley) and it's time to talk about optimizations.
I'm going to start by repeating the quote from Bisqwit earlier.
Quoting bisqwit
For generating a natural looking method of drawing the edges you could apply a floodfill style algorithm. Just follow the edges in the direction that is in the same color and has the least angular change, and when you hit a dead end (a point that has no surrounding pixels that are yet to be traced), choose another yet unprocessed intersection / edge (preferably one that is closest to where you stopped) and repeat, until you have traced all the edges. When choosing another point to trace, try to choose one in the same color; and if none are remaining, then choose a different color.
I don't like the method as described, but what I'm going to do is likely influenced by having seen that message. So credit where credit is due: thank you bisqwit for inspiration here.
The following things need done to the plotter to optimize it considerably:
  • The offset needs added to the plotter's code. That's not hard at all; just need to remember to do it.
  • Any next-pixel that is 10 or fewer pixels away can be jumped straight to when the pen is down (Mario Paint won't draw the pixels in between.)
  • Preference should go essentially from closest pixel to furthest pixel, although certain types of routing would still be faster.
  • An actual intelligent search algorithm for pixels and a checklist of some sort needs to be maintained. The best I've got is Djikstra's Algorithm over the list of pixels. Slight bonus - I can in fact use the Manhattan distance as the heuristic cost here, so that should help just a little - namely in that I don't need to keep a running cost total anywhere.
It took me two hours and several attempts, but that certainly does work significantly better. I wound up just writing my own data structure that can search itself properly to handle the problem. Given the sheer amount of gains, I've decided this will be the final algorithm for this submission.
The final input to draw the first image - correctly, in the correct place, even - is now 3180. Compare that to the first algorithm (which finished on frame 17302) and I've made tremendous gains by optimizing that code for the several features given above.
It may still be possible to make other optimizations, but I'll leave that to someone else. I'm quite content with this lot, personally.
It's now 1:12 in the morning, 26 March 2021. The next task is actually assembling the TAS itself. I'm going to dump a demo video of this algorithm in action and call it a night.

Homage, Stamps

It's 11:25 AM on the 26th of March 2021, and I'm going to carry on.
I don't necessarily want to do all the fill patterns from the original game, I just want to have the pattern templates in Mario Paint for people who may wish to play around with this at some point.
I did want to reference a couple of the NES runs while I'm doing this. Specifically, Deign's Stegosaurus run and Adelikat's Pterodactyl run. In order to do so, I'll need the fill patterns they each use.
But first! There are 15 stamp pattern slots avaialble for users to save/load from in Mario Paint. I need 1 for the single pixel brush, which leaves me with 14. I want to leave 1 for people who play with this to swap into/out of, so now we're down to 13. Color-a-Dinosaur features 9 pattern bases, which means that I'm left with just 4 free.
Let's see what adelikat and Deign use before freaking out.
No lie, I did start to freak out here. That's because, at first glance, they're using a total of some 7 patterns - or perhaps 5. Well, the work is documented in this image:
I think - I'm not sure yet - that the Special Stamp Editor obeys much the same rules as the normal editor. So we just need to know literally every hit box, then to build out the stamps on those hitboxes.
I've been gathering this data the entire time. Here's what I have as I hit this point:
I don't find the next bit too terribly interesting. Just lay out the patterns on that hitbox grid such that there will be 1 pixel of input for every cell. Some degree of routing can still be done here; knowing that gaps of 10 or fewer pixels can be drawn without lifting our pen means we should probably just gravitate for the center of cells unless there's a gap we can close up somehow.
While doing this, I took the liberty of rearranging their planned order on the bar, too. There's no serious significance - mostly just what seemed to make more sense to me. The single pixel brush I need for plotting, the 9 pattern bases, the 4 for the homage pieces, and then the blank one.
It takes me approximately 30 minutes to get them all together. Most of that is due to my poor ability to remember strings of numbers and having to flip between two images in GIMP, as opposed to anything particularly hard about it.
I'm not sure if those will require the offset, and I'll still have to route color selection, saving, and clearing (loading a blank one?) by hand. Still, this does mean most of that routing will now handle itself. Next is routing the music input.

Music Routing

Essentially, I don't care much about this section. There are likely going to be a million ways I miss to optimize this, but I think the best I can do is just to know where the hitboxes are for specific sounds and route that. Mostly.
Being said, we can make at least a few intelligent choices, if we just look at the sheet. I've entitled this "We Colorin'", and I guess it's something like the world's worst remix in terms of mechanisms used to produce it at this point. The original started on the first measure; the version during the TAS will be input, as previously discussed, on the third measure forwards.
The first three things that should leap out are:
  • There are four symbols to be placed on the sheet
  • The dog only exists at the beginning of the sheet; the end marker only exists at the end of the sheet.
  • The tempo will need set
I think the best ordering is likely to be:
  • Going start-to-end, input all notes for the aeroplane.
  • At the end, input the end marker.
  • Going end-to-start, input all notes for the gameboy.
  • Going start-to-end, input all notes for the dog.
  • Fix the tempo and anything else, in likely no significant order other than from right-to-left (as the exit button is on the left and we can plan to start on the right).
  • Exit.
With that, this entire TAS's preplanning is done. But really. The rest can be figured out as I go along.

Assembling the TAS

  • 0: To start the game, we need to click on Mario. So let's just move to the right and click him as soon as possible. (This was already done in the videos I was doing tests in anyway, so recycling!)
  • 361: There's a very short animation that plays before loading the canvas; let's just click as soon as possible to exit it. (This was already done in the videos I was doing tests in anyway, so recycling!)
  • 500: Having gotten this far for free, I decide to take a nap at 1:30 PM on 26 March 2021. Although I'm awake sooner, I don't get any further until at least 4:25 AM on 27 March 2021. (Happy Birthday, Abel!)
  • 510: As soon as the game loads, I think the best option for how to proceed is to input the music. So that's what I proceeded to do. Part of that process was experimenting to see where collision boxes were.
  • 530: First frame I can input anything approaching reliably. Apparently. And then 531 is ignored. And then 532 forwards seems fine. ... What?
  • 728: I'm not overly convinced that there's anywhere I can horizontally hit the aeroplane that's going to be faster, because I still have to move the staff to the right. So it's just one stop on my way from left to right across the screen.
  • 744: I will take the nearest point on the arrow, however. While clicking in the bar gives us an entire screen worth of jumping (7x clicking the arrow), at some point moving back and forth across the screen loses any benefit that gives us, especially for such a short composition. I think that's a full measure's distance, but experimentation by someone who actually has time and talent for this with a proper composition is warranted.
  • 777: I hadn't examined my own sheet music when I wrote that, and it shows. The gap after this single note on the third measure is long enough to click into that space I just taked about.
  • 900: Seven clicks is 56 frames. Surely the loss to movement for four notes isn't going to be that bad?
  • 995: If I'm allowed to say, I'm surprised how fast that much went, honestly. Around 1/3 through composing the song already.
  • 1007: The end marker seems to have slightly different collision from the rest. No real matter, but worth noting.
  • 1029: Decided that I was going to go ahead and do the last screen of notes for the gameboy, since that seemed to go well for the aeroplane, which means that the horizontal click location barely matters as long as I don't have a dangling frame with fewer than ten pixels of movement.
  • 1222: And just like that the gameboy is done. On to the dog!
  • 1262: Looking ahead, I have just the tempo to fix, and two more dog notes to input. They will be on opposite sides of the screen. I think speed favors handling the tempo right now, so I go ahead and do so.
  • 1282: Turns out you're allowed to hit the tempo every other frame.
  • 1328: That's the last note. Now to exit the music editor. All things considered, I think that was fairly quick. 701 to 1328 is... 627 frames! SERIOUSLY?!? TEN AND A HALF SECONDS?!? ... So I watched it and... well, it's certainly fast anyway. So fast I couldn't follow it despite knowing how it was put together O.o Sorry, I've just... never done something this involved before. I genuinely expected that to take so, so much longer and be the second most boring part of this run.
  • 1517: Now we're in the Stamp Creator. By way of comparison, the time from the last note to here was approximately 1/3 the time it took to assemble that entire song. Anyway, not very exciting, any of this, really. My plotter script gets to take over drawing, and I handle saving and loading.
  • 1554: Quite the time to find two errors in a script you're counting on working, eh? (Github commit.)
  • 1555: Bad when you fail to get it all the first time, eh? (Github commit.)
  • 1581: It turns out that this can be a single frame click, but reliability gets wonky quickly if you do that.
  • 1608: Same problem. Could be a single frame click, but then it wants to be unreliable for some reason.
  • 1624: Sometimes, my script fails to buffer its very first instruction, which means I never receive it... and I don't really understand why this happens. It just seems to throw it away or something. Thankfully, more often than not, this is just a pair of tens, so I can just punch it in by hand if things are off by exactly ten.
  • 1629: I just found out that the Save and Load signs are clickable. Thankfully, I think it's been caught before it would have required a fix.
  • 2672: There's a number of errors I'm having to handle by hand here. I think it's in the script.
Status:
x    : 78.0
offX : -20
y    : 16
offY : 20
lmb  : False
rmb  : False
buf  : 0

> moveto 220 120

[... output here then...]

> status

Status:
x    : 220.0
offX : -20
y    : 120.0
offY : 20
lmb  : False
rmb  : False
buf  : 0
The actual position ingame is 210 110.
I'm not sure why. Still, short misses like this are, as I said, solvable by hand. It's when we get to coloring dinosaurs I may have to stop and fix it.
Or just go back to that first one I tested. One of those.
  • 2744: Saved by the fact the cell is still empty. Color-a-Dinosaur does not want to be ran anymore, is what I'm starting to gather here.
  • 2957: Of course, Stamp 5 would have to go perfectly, to attempt to restore some degree of faith, however false.
  • 3003: Literally just realized there's a clear button at the bottom. Wasn't on my screenshot because it doesn't load with the background. Woops. Not fixing it, but I will make use of it.
  • 3028: Yeah, that's an instant gratification button. Dag nabbit.
  • 3042: Clicking clear turns out to require 15 empty frames before drawing again. Still, minus movement to and from up top, that probably gains a few frames all the same.
  • 4772: So we do all the cyan patterns, then the cyan and red, then all the red patterns. Although this sees us saving out of order, it does save a little time over swapping colors back and forth.
  • 6730: It's been nine hours or so nonstop of coloring dinosaurs. It's now 10:53 AM on 27 March 2021, and I'm calling it a day for this project for now. (Happy Birthday again, Abel!)
  • 6772: It's 3 AM on 28 March 2021. Get excited, we about to start actually drawing (and coloring) dinosaurs.
  • 6867: Abel says "One, two, better not sue..." at times like this. I usually just shout "TONDA GOSSA!"
  • 9175: I just can't quite seem to get over how well that really works. Now to route, uh, Deign's coloring choices. I'm thinking cyan, red, cyan dotted, red dotted for pathing.
  • 9266: For the sake of time constraints for publication deadline, I'm just guessing on routing these regions.
  • 9552: I mean, yes, it runs fast, but production is slow. I've decided to speed things up by going ahead and inputting the remaining images with my plotter, as well as the code to display things. That way, if things go horribly wrong somehow, I can always come back to that version and resync it. (It's the 28th, I figure I have just today and tomorrow to get this completed, based on how much there is to proofread and edit here and my slow internet speed for the preview upload.) Basically, I built a macro starting from the frame one clicks the bottom right button all the way to drawing again... and then built out the plots for the individual images just after that. (Oddly enough, I can make quite alot of guarantees safely as a part of that O.o.)
  • 9552: I have no idea how long I've been at it, but I have basic plottings of all the images in the TASStudio project now. Hopefully those don't desync too hard. I still want to try to color all these, but at least now I can guarantee they all make it, at minimum, into the final video. It's 7:20 AM 28th March 2021, I'm going to get some rest for now.
  • 9552: I'm up, I'm up. 2:54 AM 29th March 2021. So, what I'm hoping is that putting in parts of coloring this only requires checking the location (and brush/top panel state) it's at after I'm done, setting it there, and then rolling forwards. In order to help with that (and possibly resyncing, I've marked where everything starts, ends in the TAS that matters (and locked markers to input so they move as I insert/delete frames). In the meantime, let's just carry on as though that will totally happen. (Weird side effect, I no longer need the plotter script if I've done this correctly. Everything is already plotted out. Probably keep it handy just to plot long moves, however. I'm lazy.)
  • 9754: That eyelid. Ugh. Why? Also, was it a separate object in the original? Anyway, after much distraction, I'm actually making forwards progress.
  • 9913: I'll talk about this move in just a moment.
  • 9922: That move, specifically, is a bit weird. The input was sort of randomly ignored and/or clamped by the game itself in places. I think this matches the best possible for it, although it may be possible to remove some inputs as "ignored anyway" or "not helping". (I routed that using my plotter and it failed harder than usual.)
  • 10120: Remember - I'm routing this via rapid guesswork under time pressure, and I'm not doing much twice right now to test due to that time pressure. So the right toe comes first because I think the slightly higher position on the middle toe might potentially save a frame here; otherwise, it probably didn't matter at all and was up to me anyway.
  • 10205: At this point, any segment not rapidly routed by the plotter or copy/pasted as a macro is probably done by hand using a controller. (For the curious, before this, I had 1338 rerecords.)
  • 11251: And there we have it! Deign's masterpiece recreated in Mario Paint! ... Just being honest, probably just replacing it with purple here would have been better. And perhaps "not only". Maybe on a CRT this would have looked better?
  • 11252: Anyway, I started to remove the empty frames and fix a lot of small things, but it kept causing major desyncs. I don't have time to investigate the pileon effect for every time I want to delete 2 or 3 frames, so I'm afraid it has to stay the way it is for now. (Obviously this is lost time, but if you were going to read this entire thing and actually approve this ridiculousness, this is far from the first issue in how it was produced.)
  • 11254: The "display and play jingle + erase" macro was initially assembled by hand to be pretty well perfect. Close enough to be intimidating anyway. You can find my notes down below about the major timesaving findings. It runs to about 12137.
  • 11747: I might have cut the end of that too soon. Although the jingle is definitely over, there are the aesthetics of letting that last note sink into someone's awareness. (Due to the lack of delay, it almost seems like the lights come up slightly before the jingle is over. Feel free to check the objective timing frame by frame!)
  • 12076: I literally just guessed at the fastest way to clear the screen here. Others may actually be faster. (For sufficiently small images, just using the eraser itself will be fastest!)
  • 12166: This bit was originally written for when I stopped at 9552 to plot all the images. So I had to resync it because the state was wildly out of line. Fun, fun.
  • 12196: And we're back on track again.
  • 14779: Spinosaurus. Although many depictions were easy to find on the net, the one I liked most was in shades of green with this strange green-to-red-to-white fade on the spines, plus black dots, and the underbelly was white. Since I can't do the strange design on the spines, I'll just do them in some weird patterning with plenty of green (and hopefully red) in it. But once again, I just focused on coloring it. So better times are definitely possible, even for the same design. In fact, I went so far as to unpause the game at half speed to record this segment.
  • 18917: Back on track for the display/erase cycle. I think he looks charming. I mean, personally. Really! (Or she!) But it's 8:34 AM and I have to make my companion breakfast, so hold that thought and stop my work timer.
  • 19828: And 9:31 AM. A desync happens here. A proper fix would have set the brush and then let it run starting at the top of the image, but I'm under time pressure, like I said, so I'm just going to return to the spot the plot is done from once I've got that sorted out again.
  • 19933: And we should be back on track.
  • 22217: And now we color this... Brontosaurus. Littlefoot? ... Littlefoot.
  • 23747: Back to erasing and drawing the next one. By selecting the stamp before letting this run, I save myself some labor time resyncing all the way until it's time for me to color again. A few thousand frames I don't have to do any more work in.
  • 26912: As it turns out, this is "Viktor", an original dinosaur created for this game. There were three of these. And I'm not having any luck at all finding a coloring guide so... time to be a bit creative with this.
  • 30349: And just like that, four of our dinosaurs have been colored. On to the next. But first! It literally just occurred to me to start keeping a list of which patterns I've used, woops!
  • 31263: I'll never get through all these patterns. There are legitimately too many for how little art I have to work on.
  • 33309: Triceratops... Cera? Cera.
  • 36454: I think that actually gives her some degree of justice, actually. Certainly not perfect, but a decent work of art.
  • 39512: It's Vinnie, another original dinosaur made just for this game with no coloring guide!
  • 43566: I mean, I think he's rather charming, personally. But regardless, that's another one down, ten more to go.
  • 47009: Ah, yes! The Pterodactyl, the best ending in the original game. I'd be sadly put upon if I didn't take the analogue to the historic run on TASVideos for this version of Color-a-Dinosaur.
  • 47496: Sequence breaking was established as part of this edition. A nice fringe benefit of being one to help create it, I suppose.
  • 47824: Careful manipulation of input cycling maximizes entertainment value, especially in the exploratory literature accompanying the run before you.
  • 48167: I tried to ask the original dev his thoughts on this maneuver, but he never got back to me with any meaningful answer. I mean, sure, when IGN contacts a dev, they have some time to comment on a speedrun, but when I contact them, they're all like "Who are you? How did you get in my house? No, I'm not a game developer!"
  • 48427: And there you have it. Just like that, we've recreated an absolute treasure originally created by adelikat.
  • 51711: "Crested Dinosaur". I'm not sure if it's original or an actual creature, but I am sure this is going to be another fun one.
  • 58428: Duckbill... Ducky? Ducky.
  • 65323: Vern, because of course I missed at least one original dinosaur when I checked the list. This is rather exciting!
  • 71425: Crested Duckbill. They put... a lot of crests and duckbills, by volume, into that game, didn't they? I'mma just start using the colors I've not used yet haphazardly to help check them off. It's not really possible to make sane art anymore with what I've got left, I don't think.
  • 77337: Vera, another original dinosaur for the original game. Interestingly, in the manual's coloring book, she's not holding the twig/branch. Otherwise it doesn't matter too terribly much; she still just gets the next colors on the palette.
  • 84014: I managed to make Vera sort of work... this is Mini Stegosaurus. See if I can do it twice, eh?
  • 90228: Probably Tyrannosaurus Rex? The image here is quite different from the one in the manual.
  • 95733: Torosaurus. I thought I was doing horrible on time, but honestly, I'm doing okay looking at the space between images. I know it probably doesn't feel that way watching it, and it certainly doesn't feel that way recording this at 1/4 speed and less at times.
  • 102037: Protoceratops. Also the last dinosaur to color!
  • 117356: Deign seems to be the first one to do the Color-a-Dinosaur NES run. Adelikat has the Pterodactyl run. Lord Tom references it in his SMB3 Total Control TAS. CompuCat helped more than a year ago as this is published with the music transcription for the fanfare from Color-a-Dinosaur. TASVideos.org was useful for the data in the forum posts. (I had to capitalize "ORG" to avoid a decender from the "g" getting lost.) dwangoAC and the AGDQ TASBot block seem to have captured the attention of quite a lot of people - he played Lord Tom's SMB3 TC there. Abel & Dove gave up considerable amounts of time with me - including part of Abel's birthday - for me to work on this TAS. And of couse - we always appreciate the viewers. [...] The last dinosaur, here on the credits page, is an upscale from Lord Tom's TC TAS. Enjoy it, as coloring it gives a bit of time to read the credits, essentially, which is more the goal here than coloring it is.
  • 122218: I was afraid that if anyone reencoded, they'd cut too quickly from the end frame, so a single frame of input with what I hope are special looking numbers exists way out here to conclude the take.
It is 2:16 PM on 29 March 2021, and finally - FINALLY - this project is completed.

Afterword

You may have already guessed this had nothing to do with me coloring a dinosaur. Actually, as far as I'm concerned, my work could conceivably have been done with just the jingle, the stamps, and the lineart for the 16 dinosaurs cycled through. This makes it possible to save the game and get a saveram image that has the dinosaur you'd like and stamp templates on it. (You can always discard the extra four if you'd like - the ones in color at the end of the stamp line - and you can always use the templates to build out patterns similar to the original and save them in any slots you've decided you don't need.)
Had I stopped there, we'd have saved about 12 minutes, I think. It didn't seem right, however; I wanted to at least give shoutouts to Deign, Adelikat, and Lord Tom - and I felt the best way was by recreating their works.
Everything after that was just falling into the zen of coloring, honestly. I don't regret it, but I regret that I ran so short on time that I couldn't do it proper justice for every single image. Maybe a later version will run faster and have better coloring. If I ever do a later version - and certainly others are welcome to pick it up and roll with it.
I hope you enjoyed this. The last year or so has really worn down my spirits - some deservedly, some not deservedly - and I think everyone just needed something that was absurd and overcommitted to its own premise. I genuinely hope this made you smile.z

Aftermath

The original version of this document - written in markdown - has 13963 words. There were 1618 rerecords. The final video has 122219 frames.
The amount of time spent on this project appears to be approximately 54 hours 30 minutes. ( https://imgur.com/TY6h2AZ ) Much of the timekeeping is done in the open in this document itself.

Notes from the Mario Paint Manual

Many people may not have the manual handy, so I'm including this little section here of snippets from the manual just to summarize some key data points that are assumed throughout this document to be known.

Controls

Left Mouse Button
Clicking the left mouse button will allow you to select various icons, advance through the color palette, and draw with the tools in Mario Paint. (Manual, Pg 3, "Click")
Right Mouse Button
The right mouse button pauses the game in Gnat Attack and allows you to move backwards through the color palette. (Manual, Pg 3, "Click")
A single right click will bring you to the stamp pallette from the default palette, as opposed to going through the entire list. Saves at least 20 frames, probably more.

Hints from Professor Paint

Draw slowly with the small pen to avoid drawing broken lines. (Manual, Pg 7, "Small, Medium, and Large Pens")
In some ways, that seems like a dead hint about the jumps-to-position thing with the pens and stamp.
The small pen tip makes a line that is two squares wide on the stamp gird. Try making a stamp that only uses one square of the stamp grid. Once you've saved it to your database, click on the Mario icon and draw with this ultra fine dot. This should help you draw lines in areas that require a lot of detail. You can also create an eraser using the same procedure with a single white dot. (Manual, Pg 13, "Save")
So it turns out the award for first discovering that trick goes to... The manual itself. The game itself literally tells you in its manual.

Notes from the Mario Paint Player's Guide

I don't know why a painting game has a player's guide, but it exists. I don't necessarily assume any of this to be known, it's just interesting to see laid out.

Color Palette

A page of the color palette effects can be found on page 13 of the players guide. Or here, clipped from there:

Song Editor Sound Effect Chart

The chart of sounds for the song editor appears on page 69 of the player's guide. Or, again, here:

If You Wonder

The rest is just filler, and stamp patterns, and songs on the composer, and artwork done in the game. Also projects you could do like a video greeting on an old VCR. Also a profile and small gallery for an artist who won an art competition.
There is some neat stuff in there, don't get me wrong. I just don't think it's going to be very useful for people trying to do a comparable speedrun.

The Collected and Organized-ish Notes

A decent number of these are in the above document, but they're a proper mess to track down. Figure that's the long research notes as a story and this is the shorter version, in a lot of ways. Be sure to also read the notes from the manual and the player's guide up above.

The Majority of the Game

  • The mouse speed labelled tortoise/one star seems to be the most reliable for consistency. No appreciable speed gains come from changing this setting.
  • The two axises of the mouse are largely independent of one another. So moving 1 pixel max to keep drawing actually means you can move 1 in the x-axis and 1 in the y-axis simultaneously, for example.
  • The maximum distance you can move in one frame is 10px - on each axis.
  • The most reliable and fastest (overall) clicking seems to come from a click of exactly seven frames, with a one frame break (of no inputs) on either side. (If you need to move while holding, hold eight frames before attempting to move.)
  • If you click something and wonder if it activated (without waiting several hundred frames to find out), if it requires loading something, see if the cursor animation stops on frame advance of just a few frames. Typically when the game is "busy", the cursor animation stops. (This is most evidenced going from scene-to-scene such as from the main paint canvas to the music editor.)
  • The game's boundaries seem to be inconsistent throughout the game for mouse motion, but a basic view is that x ranges from -16 to 271 and y ranges from 8 to 215. If you plan to run this game, be ready to constantly adjust your expectations (and input) as coordinates you can reach on one screen become unreachable on another for no clear reason.
  • If you build inputs and they're tempermental or seem wrong despite being the correct inputs for what you're trying to achieve (like moving a set distance), try inserting delays before/after and sometimes even in between somewhere. The game's logic is not very clear in when it's busy, and a high-value asset for TASing this game would be figuring out a reliable indicator outside "woops, didn't work, let me rewind and put in delay frames".

Fast Start

  • First valid frame for input: 131
  • First frame to click Mario: 263, only need to click one frame. Optimal position: Probably (228, 172) if you plan to do stamps. (The position is retained to the main game's screen.)
  • First frame to skip workout animation: 364, only need to click one frame.
  • First frame to start input in main game: 530. Input will be ignored on 531 and then work seemingly fine from 532 onwards. One extra frame of input, essentially.

Canvas / Main Game

  • Your canvas size is 248x168.
  • The top pane can be swapped in reverse order using the right mouse button. (This lets you go backwards just one step to reach stamps from the start.)
  • For distances greater than 1 (in either axis) while holding the mouse button, positions in between the start and end points won't be drawn. You can utilize this to jump gaps in art without lifting the mouse button (which easily saves at least 8 frames any time you can pull it off).
  • You can flood fill patterns! Doing so simply tiles them across the area you're trying to flood, with boundaries determined by the flood fill itself.
  • Going from inside a pane, you can reach further towards the inside of the screen and still activate things on the pane than if you try the same thing from outside a pane. The game seems to have a certain "most recent context" awareness.
  • The necessary delay after a seven frame click of the bottom right button (swapping the bottom pane) appears to be at least 12 empty frames before the next input, as opposed to just one.
  • The first frame input that matters again after starting a floodfill (if you don't cancel it) is the last frame the brush is oriented straight vertically.

Song Editor

  • Going from the main canvas to the Song Editor, if you did a seven frame click on the song editor button (main canvas screen) and the last frame holding left button is 575, the first frame your input will be read again (now inside the song editor) is 701 ... that's 126 franes later.
  • Going from the Song Editor to the Main Canvas, if you did a seven frame click on the exit button (Song Editor screen) and the last frame holding left button is 1346, the first frame your input will be read again (now inside the main canvas screen) is 1505 ... that's 159 franes later.
  • A single frame click is actually enough to place notes (apparently), but due to the lag frames, you don't gain any time here over a seven-frame click. Bummer, that. Can still minimize your input somewhat.
  • Regarding the scroll scrollbar - a click inside the bar itself is worth the same as clicking the equivalent arrow 7 times.
  • The end marker seems to have different collision locations from the instruments for some odd reason.
  • Adjustments to tempo can have clicks every other frame.
  • Only supports the key of C Major
  • Only Treble clef, ranging from the second G above middle C down to the B below middle C.
  • No sharps, no flats
  • Only time signatures are 4/4 and 3/4, but you can fake multiples of it somewhat by adjusting your tempo.
  • Notes can only be placed on the beat.
  • Notes cannot be sustained.
  • Only one voice per pitch can be played at a time.
  • Only three voices can be played at a time.

Special Stamp Creator

  • If you used a seven frame click to open the special stamp creator from the main canvas screen, then by the time you release the click it's already loaded and reading input again.
  • Going from the Special Stamp Creator to the Main Canvas, if you did a seven frame click on the exit button (Special Stamp Creator screen) and the last frame holding left button is 6695, the first frame your input will be read again (now inside the main canvas screen) is 6744 ... that's 49 franes later.
  • The area for a stamp is 16x16 pixels.
  • There are 15 slots available for use by the player to save/load stamps from.
  • When you click "Save" or "Load" in the Special Stamp creator, it sets your cursor's Y to 16 and leaves your X alone.
  • Clicking "Save" can be a single frame click, but it doesn't seem to be very reliable for timing input afterwards. Likewise, clicking a cell to save can be a single frame click, but isn't reliable for input timing afterwards. (Likely the same is true of "Load".)
  • The "sign" for "Save" and the "sign" for "Load" are both clickable. This makes the collision space far higher and to the left than it would be otherwise.
  • Clicking "Clear" requires 15 frames before you can start drawing again, although you can start moving sooner at least.

Animation Land

  • Opening it, fastest input leaves 3 blank frames after seven frame click.
  • Exiting it, fastest input leaves 26 blank frames after seven frame click.
  • Going into step 3, after you click it to load, you have some frames of input. Seven frame click + 1 frame delay and we're left with... apparently 40 frames that it's still taking mouse input, which should be enough to at least position the mouse for inside step 3, no matter what you want to do. After that, it's the first frame after the lag block, so it's easier to just see visually than count.
  • Also, while in step 3, you can move the mouse while the lights are out.
  • Exiting step 3, after 7 frame click, first read input is... 10074... 10270... 196 frames later.

Watch File

Coordinate standard should be Screen X and Y, and that standard is used in this document.
SystemID SNES
0004DC	w	s	0	WRAM	Cursor Screen X
0004DE	w	s	0	WRAM	Cursor Screen Y
0	S	_	1		
000226	b	u	0	WRAM	Cursor Canvas X
000227	b	u	0	WRAM	Cursor Canvas Y
0	S	_	1		
0000A9	b	h	0	WRAM	Something to do with Instrument?
000E8D	b	h	0	WRAM	Actual selected instrument
000EB5	b	h	0	WRAM	Something to do with instrument?
0	S	_	1		
00298C	b	u	0	WRAM	Special Stamp Editor Pixel 0, 0
00298E	b	u	0	WRAM	Special Stamp Editor Pixel 1, 0
0029AA	b	u	0	WRAM	Special Stamp Editor Pixel 15, 0
0029CC	b	u	0	WRAM	Special Stamp Editor Pixel 0, 1
002D6A	b	u	0	WRAM	Special Stamp Editor Pixel 15, 15
0004D1	b	u	0	WRAM	Stamp Current Color?
001124	b	u	0	WRAM	Stamp Current Color?

Plotter Code

  • I'm not sure if I'll be providing support for this code longer term or not. I did chuck it into my github, however, so I guess it's there if I ever change anything or people want to poke around it. Hopefully I remember to set it to public on April 1. https://github.com/greysondn/mario-paint-plotter
  • This is mostly self-documenting, although especially the REPL should be straightforward enough. Remember to check status before large or important operations and make sure it matches your ingame data. (The repl has a handwritten help command.)
  • You may need an offset in several circumstances. It's advised to create a test image, check it against what you wanted in game, and set the offset accordingly.
  • There are definitely bugs that I didn't have time to iron out. Many moves suffer from off-by-one errors; large moves suffer from missing a single frame.
  • It is fairly apparently that faster routes exist. They are essentially a travelling salesman problem with a fixed start and end point in most cases. Solving those generally requires brute force.

Notes Specific to This "Category"

Which is to say, notes specific to doing Color-a-Dinosaur in Mario Paint.
  • Image 8 and Image 13 must be resized.
  • After extensive work on this TAS that I feel qualifies me as a subjective (and perhaps only relative) expert on the topic, I've concluded that - contrary to Nach's judgement comment on submission #3543 - watching paint dry is actually more entertaining than Color-A-Dinosaur on the NES.

Random Notes

AKA "I couldn't find any good way to categorize these"
  • Remember that what you see is slightly delayed; what matters is where the game thinks the cursor is, not necessarily where it's shown to be.
  • Regards that previous link, Gimp is a free and open source image editor. You can get it here: https://www.gimp.org/

Advancements Others Could Make

  • I don't think this is the fastest the stamps and images can be drawn. The pathfinding algorithm I've used is set to just find the nearest valid target to color - not to route all the targets at once. This is a travelling salesman problem - and I've very little doubt, just on the sheer number of possible routes this provides, that I'm sub-optimal for a solution to the larger case every time I start drawing something here. (At some point, you have to accept it's good enough.)
  • Even if one maintains the exact same coloring plans as I did, the routing there is trash. So definitely gains could be made there.
  • It's clear the floodfill is at least filling space differently depending on where I click. Whether this translates to something that can actually be manipulated to save time remains to be seen; however, it should be investigated throughouhly.
  • If we knew exactly when the game is going to ignore input - some RAM address or some checkable condition - we'd be able to route an entire run by providing only the inputs to a special LUA script and letting it put in the spaces for when the game ignores input. It's therefore EXTREMELY VALUABLE to identify when the game is ignoring input.
  • The plotter script I wrote has errors that need fixed. It's like a little adorable broken chibi-robo just doing everything it can for me here, but I fear other people may not be so patient with its shortcomings.
  • Many small oversights and missed opportunities likely exist in this TAS - for example, I went with reliability for clicking, but possibly faster clicking could be done. I let the script I wrote route drawing for me, but there are more optimal solutions (try routing some of the stamps better for a starter). Eventually time pressure made it all but impossible to route well at all. Things like this could definitely be improved upon.
  • I don't expect us to ever get serious about this, but "just in case..." ... If we are remotely serious about this task - and while it's somewhat boring to watch, it does present very interesting optimization problems that have some application in the larger scheme of TASing - then we need to standardize what the run expectation actually is. I think that a good set of conditions is actually: input a jingle (which the community will have to agree on), input the single pixel stamp, the unique pattern templates into stamps from Color-A-Dinosaur, input the four necessary stamps to recreate Deign and Adelikat's works, draw & present & erase the 16 dinosaurs - with the exception of the Stegosaurus and the Pterodactyl, which must also be colored matching the old patterns with the relevant stamps. Doing so would end up demonstrating almost every task in the game and present the interesting routing problems of drawing all the dinosaurs and still provide ample time to stop the game and take over to do things on one's own, although it will not include beating Gnat Attack a tedious 16 times for all the trophies. (And note that my credits screen is omitted, although I do think some version of Lord Tom's dinosaur should be included somehow.)

It's time to go

Au revoir

But you may shout "Encore!"

That's all there is. There isn't
any more.

Samsara: pretend i wrote JUDGING in mario paint, i'm kinda in the middle of a claim spree right now and i can't slow down
Samsara: The run was pretty well-received, however many (including the author) have pointed out noticeable mistakes in the input, alongside slow-ish pacing because of the gimmick (that not everyone understands in the first place). I think there's definitely room for a good Mario Paint playaround on the site, and most people seem to agree with that, so I'm rejecting this in favor of a possible new version coming in the future.
Last Edited by adelikat on 11/6/2023 1:42 AM
Page History Latest diff List referrers