megacolorboy

Abdush Shakoor's Weblog

Writings, experiments & ideas.

Make your own generative pixel art in less than 100 lines of code

By modifying my old random pixel generator, I was able to generate a Space Invaders-esque pixel art.

Try it out!

Refresh the page to generate unique Space Invader-esque patterns as the results are unpredictable!

Generative art is a topic that still fascinates me because of the fact that you can produce something unique by just writing few (sometimes, more) lines of code. Especially, if it's self-generating art that makes use of fixed rules and a slight dash of randomness to produce unique results.

When it comes to writing code, it's quite straightforward. You come up with the rules and constraints and voila, you have something that works. Having said that, setting up rules for generative art can get quite tricky.

You might have read about my previous post about The Game of Life, it contains only four rules and each of them took a part in evolving the system through each generation. With generative systems like that, you can never predict the results as complex patterns will emerge due to it's randomness.

In my view, a combination of predictability and randomness is needed in order to create a good looking generative art.

Why you should explore it?

There could be many reasons, maybe you're bored, curious or passionate to learn something new. Who knows? Open up your editor and try it for yourself.

Exploring the craft of making generative art has allowed me to:

  • Gain different experiences โ€” It allows you to sharpen your algorithms & data structures and maybe even, learn a new technique.
  • Create something visually appealing โ€” A picture is equal to a thousand words.
  • Instant results that makes you feel good โ€” I mean, it's hard to explain but y'know what I mean, right?

Where to start?

Just like any other project, you just need:

  • An inspiration or an idea that you can work on.
  • The right kind of technology to use.

With today's article, I'll be showing you how I built a Space Invader-esque pixel art generator in JavaScript that makes use of the Canvas API.

Building a generator

I'd like to give a shout out to the person who built a twitterbot that generates random sprites using Python's Pillow image library.

I was inspired and I thought of writing it in JavaScript and as you can see above, it did turn out pretty well.

Here's the code for your reference and please read the comments to know how it functions:

// To store any used colors
var colorStack = [];

// Selected color palette
var colors = [
    '#30e3ca',
    '#ff5a5f',
    '#40514e',
    '#e4f9f5',
    '#40514e',
    '#e4f9f5',
    '#e4f9f5',
];

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');

var width = canvas.width;
var height = canvas.height;

function createSquare(squareDimensions, color, element, spriteDim) {
    const {squareX, squareY, squareWidth, squareHeight} = squareDimensions;

    // If it's a middle element, apply a color
    if (element == parseInt(spriteDim/2)) {
        ctx.fillStyle = color;
        ctx.fillRect(parseInt(squareX), parseInt(squareY), parseInt(squareWidth/squareX)+3, parseInt(squareHeight/squareY)+3);
    }
    // If it's the last element, then use the color that you saved previously
    else if (colorStack.length == element + 1) {
        ctx.fillStyle = colorStack.pop();
        ctx.fillRect(parseInt(squareX), parseInt(squareY), parseInt(squareWidth/squareX)+3, parseInt(squareHeight/squareY)+3);  
    }
    // Else, apply a color and save this for the last element.
    else {
        colorStack.push(color);
        ctx.fillStyle = color;
        ctx.fillRect(parseInt(squareX), parseInt(squareY), parseInt(squareWidth/squareX)+3, parseInt(squareHeight/squareY)+3);      
    }
}

function createInvader(invaderDimensions, spriteDim) { 

    var {posX, posY, invaderWidth, invaderHeight} = invaderDimensions;
    var squareSize = (invaderWidth - posX) / spriteDim;

    var cellPosition = 1;
    var element = 0;

    for(var y=0; y<spriteDim; y++){
        // Starts from the left side of the grid.
        // Think of it as something like this:
        // [-3,-2,-1,0,1,2,3]
        cellPosition *= -1;

        // First element
        element = 0;

        for(var x=0; x<spriteDim; x++) {
            squareX = x * squareSize + posX;
            squareY = y * squareSize + posY;
            squareWidth = squareX + squareSize;
            squareHeight = squareY + squareSize;

            // Pick a random color from the color palette
            var color = colors[Math.floor(Math.random() * colors.length)];

            var squareDimensions = {
                'squareX': squareX+2,
                'squareY':squareY+2,
                'squareWidth':squareWidth,
                'squareHeight':squareHeight,
            };

            // Create a square with a color and desired dimensions.
            createSquare(squareDimensions, color, element, spriteDim);

             // If it's the middle element or the starting element, 
             // then shift it's position to the leftmost.
            if(element == parseInt(spriteDim/2) || element == 0) {
                cellPosition *= -1;
            }

            element += cellPosition;
        }
    }
}

function main() {
    var spriteDim = 7;
    var numberOfInvaders = 15;
    var invadersSize = parseInt(width / numberOfInvaders);
    var padding = parseInt(invadersSize / spriteDim);

    for(var x=0; x<numberOfInvaders; x++) {
        for(var y=0; y<numberOfInvaders; y++) {
            var posX = (x * invadersSize) + padding + 2;
            var posY = (y * invadersSize) + padding + 2;
            var invaderWidth = posX + invadersSize - (padding * 3);
            var invaderHeight = posY + invadersSize - (padding * 3);

            var invaderDimensions = {
                'posX': posX,
                'posY': posY,
                'invaderWidth': invaderWidth,
                'invaderHeight': invaderHeight
            };

            createInvader(invaderDimensions, spriteDim);
        }
    }   
}

main();

Well, I won't say that is a perfect solution but hey, it works and yes, it doesn't take a lot of code to achieve something like this.

Explanation

I'll try my best to explain how this whole thing works.

First, you need to initialize a <canvas> DOM element of the desired width and height. Then in the main() function, you determine the size of each invader by specifying the number of invaders and dividing it with the width of the canvas. These values will then be used to determine the coordinates for each invader.

Second, the function createInvader() follows nearly the same process as the main function except that the coordinates for each pixel is determined by calculating the width of the invader and subtracting it's x position divided by the dimensions of each invader.

Third, as you can see in the function createSquare(), it contains 3 simple rules in which all of them draws a square with a color but with an emphasis that each invader has a symmetrical pattern.

The code looks deceptively simple but achieving this complexity did take a lot of trial and error and a little bit of simple calculus ๐Ÿ˜‚.

Conclusion

Generative art might be something that you may not need to explore but it's quite fun and you may never know what you might be able to produce by combining both code and visuals.

Hope you liked reading this article.

Stay tuned for more! ๐Ÿค˜

Built a new static site generator using Python 3.7

Thought of giving it some new upgrades and finally decided to open-source it.

Since 2019, I always used a custom static site generator for the website. The previous one was written in Python 2.7 but ever since Python decided to sunset it, I decided to rewrite it using Python 3.7.

Unlike the previous one, it's quite flexible and I thought of giving it some new features that would help me maintain it with ease.

The new features I have added are:

  • A neat CLI to build the entire site or certain parts of the website
  • Able to switch between different templates
  • Archive mode
  • Pagination
  • Generates RSS Feeds and JSON files

Why rewrite it again?

Over the past few months, I didn't really maintain my blog and when I visited the old codebase, I realized it wasn't flexible and it didn't have many features and it was slow, too.

Recently, I got new ideas of building different sections for the website and thus, is why I had the motivation to rewrite everything and make it modular and flexible enough to build a powerful yet simple custom static site generator.

Have a look

I have decided to open-source my static site generator on my GitHub repository and I'm having plans of writing a new documentation for it, so that if people are interested, they could contribute or use it for their own personal uses.

Conclusion

If you've been following my blog posts, you may know that I have a knack of displaying JavaScript widgets on some of my previous blog posts. Well, I've decided to rewrite all of those widgets, one-by-one, using ReactJS and hopefully, write more tutorials for each of them.

Hope you liked reading this article.

Resolve the "General error: 1835 Malformed communication packet" error

This happened like two days ago, when one of the client sites went down. Upon inspecting the error logs, I found this:

SQLSTATE[HY000]: General error: 1835 Malformed communication packet

If you got the same error as the one above, don't worry, it's not your fault. According to this forum, a recent MariaDB update introduced a new bug for PHP versions < 7.3 that uses PDO and MySQL connectors. You can easily resolve this by simply upgrading it to PHP 7.3.

Hope this tip helps you out!

Find and remove duplicate lines using Regular Expressions

Open up your text editor and use the following RegEx pattern to find and remove the duplicate lines:

^(.*)(\r?\n\1)+$

I found this technique on Regular-Expressions.info and I'm going to quote their explanation over here:

The caret will match only at the start of a line. So the regex engine will only attempt to match the remainder of the regex there. The dot and star combination simply matches an entire line, whatever its contents, if any. The parentheses store the matched line into the first backreference.

Next we will match the line separator. I put the question mark into `\r?\n` to make this regex work with both Windows `(\r\n)` and UNIX `(\n)` text files. So up to this point we matched a line and the following line break.

Now we need to check if this combination is followed by a duplicate of that same line. We do this simply with `\1`. This is the first backreference which holds the line we matched. The backreference will match that very same text.

If the backreference fails to match, the regex match and the backreference are discarded, and the regex engine tries again at the start of the next line. If the backreference succeeds, the plus symbol in the regular expression will try to match additional copies of the line. Finally, the dollar symbol forces the regex engine to check if the text matched by the backreference is a complete line. We already know the text matched by the backreference is preceded by a line break (matched by `\r?\n`).

Therefore, we now check if it is also followed by a line break or if it is at the end of the file using the dollar sign.

The entire match becomes `line\nline` (or `line\nline\nline` etc.). Because we are doing a search and replace, the line, its duplicates, and the line breaks in between them, are all deleted from the file. Since we want to keep the original line, but not the duplicates, we use `\1` as the replacement text to put the original line back in.

Hope you found this tip useful!

Use node-sass to minify your CSS

If you want to turn your .scss files to minified .css files but without using Webpack or Gulp, just install the node-sass package using npm package manager and then run this on your terminal:

sass scss/style.scss css/style.css --style compressed

And now, you can use your style.css file on production! ๐Ÿ˜†

Hope you found this tip useful!

Create aliased class constants in Laravel

There are many ways to define constants in Laravel but I learnt a neat technique where you can define constants using an alias.

First off, create the following directory:

mkdir app/Constants

Next, create a file named MyConstants.php in the app/Constants directory and copy-paste the following code:

<?php
namespace App\Constants;

class MyConstants {
    const HELLO = 'hello';
}
?>

Then, go to the config/app.php file and define your new alias:

<?php
'aliases' => [
    // previously defined aliases...
    'MyConstants' => App\Constants\MyConstants::class,
]
?>

Lastly, execute the following commands to update your app's configuration:

php artisan config:clear
composer dump-autoload
php artisan config:cache

After that, you can use your new constants anywhere (Controllers, Models or Blades) like this:

<?php
echo MyConstants::HELLO;
?>

Learning this new technique helps me keep the code clean and makes it easier to trace the constants.

Hope you find this tip useful!

Rename a Git Branch

Using branches are one of the most powerful features of Git and becomes a part of the software development process.

Last night, I came across an issue where I created a new branch and committed my changes until the git tool rejected it because the branch was already created by someone else in the repository.

Luckily, I was able to resolve this issue by renaming my branch using git branch -m command.

Here's a short guide on how you can do that too!

1. Switch to the remote branch you want to rename

git checkout <your_old_branch>

2. Rename the current remote branch

git branch -m <your_new_branch>

Proceed to the next step, if you've pushed your old branch to the remote repository.

3. Push the renamed remote branch

git push origin -u <your_new_branch>

4. Delete the old remote branch

git push origin --delete <your_old_branch>

If you've come this far without any issues, you've successfully renamed your local and remote Git branch.

Hope you found this useful!

Import and Export MySQL database via Terminal

Sometimes, phpMyAdmin can be painful to use especially when you want to import/export a MySQL database.

If you're not afraid of using the Terminal, try these commands to save your time:

Import MySQL database

mysql -u username -p database_name < your_sql_file.sql

Before you run this command, please make sure that you've created the database_name schema in your database or else, you might get an error especially if the .sql file doesn't have a CREATE DATABASE statement.

Export MySQL database

mysqldump -u username -p database_name > your_sql_file.sql

This command will export your database with the file name your_sql_file.sql to your current path.

Hope this helps you out!