I run a mastodon bot at It posts some crunchy lookin' art every hour. Following is an explanation of how it works.

Actually generating the images (

#!/usr/bin/env bash

size=1000x1000 # this could be any ratio, of course, it's just the size I wanted it to generate
name=$(cat /proc/sys/kernel/random/uuid).png # random filename
# could change the values of the above variables to $1 and $2, so that the script could be invoked like "./ 1280x720 mycoolart.png"

# this function generates an image that's just one random color. it generates hex triplets in a very silly way!
random_square () {
    convert -size $size xc:white -fill "#$(for i in {1..6}; do hex=$hex$(shuf -n 1 -e 0 1 2 3 4 5 6 7 8 9 a b c d e f); done; echo $hex; hex=)" -opaque white $1

random_square color1.png; random_square color2.png # we need two randomly colored squares. (though I guess they wouldn't be squares if you set $size to something else)
convert -size $size xc: +noise Random random.png # here's where the randomness comes in -- an image that's just randomly colored pixels
convert color1.png color2.png random.png -composite $name # I actually don't fully understand what happens in this step but basically the two colored squares get smooshed together in a random way
blur_sigma=$(shuf -n 1 -e {5..50}); blur_radius=$(shuf -n 1 -e {5..50}) # more silly random number generation
convert -blur ${blur_radius}x${blur_sigma} $name $name # now the image gets blurred a random amount, to soften out the noise and create some orderly blobs
echo sharpening... # all those other steps execute pretty quickly, but the sharpening takes a bit so I want to know when it's doing it
for i in $(seq $(shuf -n 1 -e {5..20})); do cpulimit -l 10 -fq -- convert -sharpen 0x$(shuf -n 1 -e {1..20}) $name $name; echo did round $i; done # now it gets sharpened too much (but by a random amount), which is the effect that made me want to do this in the first place! (cpulimit prevents it from taking up server resources -- this is a very computationally heavy process.)
mv $name ~/sharpenart/ # it's important for the bot that there be a directory that only includes the output images
echo done.

Run the generation script periodically (

#!/usr/bin/env bash

while true; do
    backlog=$(ls ~/sharpenart | wc -l) # so this is where the bot gets silly

    if [ $backlog -lt 25 ]; then # it basically checks if 24 or fewer images (i.e. a day's worth) and if there is it generates 24 more (another day's worth)
    for i in {1..24}; do # there doesn't really need to be that many images at one time but w/e
    echo backlog contains $backlog images
    echo checked at $(date)
    sleep 1h

Post those images! (

#!/usr/bin/env bash

while true; do
    echo $(date) # because why not
    file=$(ls | shuf -n 1) # this script is run in ~/sharpenart, to be clear
    toot post -m $file # toot is set up beforehand to post to, of course
    trash $file # doesn't need to be trash, could be rm. but w/e
    sleep 1h # of course this bot doesn't post Every Hour On The Hour because "toot" takes a few seconds to run


Don't you just love "$(seq $(shuf -n 1 -e {5..20}))"?

There are some silly design decisions here (starting with the choice of language), but hey, whatever, I'm not a Real Programmer and it basically works.