Introduction
My childhood consisted of a lot of arcade games. My Dad introduced me and my brother to MAME back in around 1999 with a bunch of ROMs he managed to get. Me and my brother would use MAME32 (or MAMEUI32) as a frontend to select games and play them. It was the first experience with emulation I ever had.
One of the games that me and my brother played a bunch was Block Block. As kids, we never really finished the game. But now, 27 years later, we kind of went back to playing games like this and it became a weekly tradition to beat them. I set up a custom arcade "machine" that auto-records demo files so we can go back and upload videos to the DERPG YouTube channel for archival's sake. Here's a tweet about it, actually:
my emulation machine of choice is the Mac Mini. when family wants to play something, I boot this machine up. probably the best $500 i spent.
— Claıre 🌺 (@iDestyKK) April 28, 2025
a Raspberry Pi 4 is a close second choice, pictured sitting next to the Mac Mini in a Pironman 4 case. pic.twitter.com/sAz7hEP6TP
my emulation machine of choice is the Mac Mini. when family wants to play something, I boot this machine up. probably the best $500 i spent.
— Claıre 🌺 (@iDestyKK) April 28, 2025
a Raspberry Pi 4 is a close second choice, pictured sitting next to the Mac Mini in a Pironman 4 case. pic.twitter.com/sAz7hEP6TP
So yeah, we take our arcade games decently seriously. But we played so much of Block Block that I began to wonder what an optimal run would look like. Given it's one of the very few arcade games we play that doesn't run at a fixed pace, surely it's possible to have an optimal playthrough. That's where a TAS would come in. But we aren't doing that here. I want to take all of the runs of Block Block that we have, find the fastest runs of each level, and slap them all together into a single video, automatically. How do I do that? Well, let's get into it.
How Block Block works
Block Block is very simple. One or two players take down 50 fixed levels of blocks Arkanoid-style. I get the feeling Block Block is Capcom's attempt at an Arkanoid game. There are powerups. The player's "mallet" can expand in size. The ball can pierce through targets. There are multiple opportunities for extra lives. However, you are also penalised for the ball hitting the mallet too much.
Given the style of the game, each level can have an optimal path that clears out blocks more efficiently than other paths. Obviously, two players will clear out levels twice as fast. Occasionally, an "EXIT" will pop up which, when hit, will auto-complete a level for you. This is purely RNG-based. A truly optimal play would involve getting as many "EXIT"s as possible.
The Spreadsheet
I am going for a video where the fastest runs of each level, based on all runs, is shown. For instance, we played the game 20 times between 2024-2025. That is 20 runs of all 50 levels. Take the fastest run of level 1 and put it into the video. Take the fastest run of level 2 and do the same. And so on for all 50 levels.
Obviously, this requires a spreadsheet. I decided to use Google Sheets for convenience. After that, I painstakingly went through every single video and got the exact timestamps for the beginning and ending of each level. You can do this on YouTube via:
document.querySelector("video").currentTime
The spreadsheet looks like this:
|
|
As you can see, there are two pages to the spreadsheet. The first page is where the times are punched in. The second page is for export as CSV. Because we are going to write up a Bash script to comb through the data and encode video. More on that later. The spreadsheet auto-computes the fastest runs of each level and gives the date. It is also expandable, so I can make future iterations of this compilation video for 2026 runs, 2027 runs, and so on.
CSV Export
As mentioned up above, I export the second page of the spreadsheet to CSV. This has all of the auto-computed values for optimal plays, as well as the dates of the recordings where it happened. This is more than enough information to jump to a video file, seek to the moment the level starts, and extract the level clip. Here is what part of the CSV looks like:
File,Start,Delta
2025/11/16,46.035054,25.800285
2024/12/15,67.239091,32.622161
2024/12/01,138.326376,27.72129
2024/12/08,165.559408,31.066394
2025/06/29,222.330936,20.272769
This is the first 5 levels out of 50. To see the full file, check this out: data.csv.
Preparing Replay files and videos
At DERPG, there is no such thing as a delete button. We keep all footage. The format that these arcade demo files are stored is in a replay format. These files are very small. Though I also store separate audio tracks for me and my brother's microphones as an MKA file. I package everything up into a TAR.XZ and archive that. We can always go back to those replays and generate video to upload to YouTube or use for projects like this. This is what we call a "Master".
I am not going to get into the technical details of how the archive works. Just know we take the replay file, as well as backed up NVRAM, play back the gameplay, and tell MAME to export a video. Then we magically have a video file to work with. That gives us this:
Now we have the CSV, as well as all videos to comb through. Let's move on to the next step.
Automating Video Splicing and Concatenation
I am an automation person. I refuse to use a video editor to do things. Sure, we could technically read the spreadsheet, import all 20 videos into a video editor, and cut at the appropriate spots. Join them together, export, and upload. But that is just not how I do things. We are going to do this the FFmpeg way. In other words, I am going to write up a way to automatically cut the videos at the correct spots, and then join them all together.
The Basics
Let's start with the CSV file. Here's the first 5 levels again for reference:
File,Start,Delta
2025/11/16,46.035054,25.800285
2024/12/15,67.239091,32.622161
2024/12/01,138.326376,27.72129
2024/12/08,165.559408,31.066394
2025/06/29,222.330936,20.272769
Given the video files are named with the date and timestamp baked in, we can extract the date from the CSV file and use auto-completion to find the correct video file. Here is an example where I take a line from the CSV and "convert" it to the appropriate video file:
UNIX> ls -1 *"$(echo "2025/11/16,46.035054,25.800285" | sed 's/^\(.*\)\/\(.*\)\/\(.*\),.*,.*$/\1-\2-\3/')"*".mkv"
[2025-11-16 - 21 24 59] blockr1.mkv
Alternatively, sed 's/^\(.*\),.*,.*$/\1/;s/\//-/g' also works.
Either way, we got our video file. Now we need to hack up a script to comb
through all of the videos. In FFmpeg, you can cut videos precisely via:
ffmpeg -i "VIDEO.MKV" -ss TIME_START -t TIME_DELTA ...
So the first level in that spreadsheet would be...
ffmpeg -i "[2025-11-16 - 21 24 59] blockr1.mkv" -ss 46.035054 -t 25.800285 ...
For encoding settings, as per
"Frame jumping on a YouTube video",
uploading a YouTube video encoded via libx265 results in frame skipping. So
we will resort to libx264. Other settings include CRF 17, slow
preset, and yuv420p10le pixel format, as 10-bit encodes on
8-bit content somehow compresses better.
The Script
Here is my script which will take a data.csv, as well as the
20 videos in the same directory and make the final video for upload:
#!/bin/bash
mkdir level_clips
rm -f "level_clips/concat.txt"
# Read all lines into array
lines=()
{
while IFS= read -r line; do
lines+=("$line")
done
} < data.csv
# Go through every line and process
for ((i=1; i<${#lines[@]}; i++)); do
line="${lines[$i]}"
# Extract CSV information
date="$(echo "$line" | sed 's/^\(.*\)\/\(.*\)\/\(.*\),.*,.*$/\1-\2-\3/')"
time_start="$(echo "$line" | sed 's/^.*,\(.*\),.*$/\1/')"
time_delta="$(echo "$line" | sed 's/^.*,.*,\(.*\)$/\1/')"
# Grab the video file based on the date
F="$(ls -1 *"$date"*".mkv" | head -n 1)"
# Process via FFmpeg
ffmpeg \
-i "$F" \
-ss "$time_start" \
-filter_complex "[0:v]scale=-2:4320:flags=neighbor[out]" \
-map '[out]' -map 0:a \
-c:v libx264 -crf 17 -preset slow -pix_fmt yuv420p10le \
-c:a flac -compression_level 12 -sample_fmt s16 \
-t "$time_delta" \
"level_clips/segment_level${i}.mkv"
# Add to FFmpeg concat file
echo "file 'segment_level${i}.mkv'" >> "level_clips/concat.txt"
done
# Stitch all videos together
ffmpeg \
-f concat -safe 0 -i "level_clips/concat.txt" \
-map 0 -c copy \
"final.mkv"
I do need to explain. I read all lines into an array intentionally. For some reason, variables were being tampered with when I streamed the lines in. It was skipping videos and I didn't feel like debugging it. Anyway, I feel like the script is fairly straight-forward. It goes through every line in the CSV, finds the video, extracts the specific moment. Finally, it joins all 50 segments at the last step via FFmepg's concat mode.
Conclusion
This was a rather short blog post. And a very simple "production procedure". I plan to release "semi-optimal" playthrough videos of Block Block yearly from now on. Just to see how much we improve over the years. This'll go until we eventually stop playing Block Block, I guess. I hope you learned something about Bash or FFmpeg through this post as well. Though I didn't make this as educational as I probably could have.
To close out the post, here is the final video:
In a normal, average run of Block Block, we would spend 50-60 minutes playing. This optimal run is 28:05. Makes you wonder if it's possible to legitimately do this without segmentation. But until I see a TAS, I'm satisfied with this for now.