Wednesday, April 29, 2015

Automating Code Deployment with GitHub Webhooks and Node

Do you push a "pull" button?
I've been pushing updates to my webcomic's code repo on GitHub for over a year now. My workflow has gone something like this:
  1. Make code changes.
  2. Test locally.
  3. Push changes to GitHub.
  4. Log on to production server.
  5. Pull changes from GitHub.
I'm trying to automate steps 4 and 5. I'd like to have my production server automatically update itself whenever I push code to the "main" branch of the repository.

This week I've been experimenting with using GitHub's Webhooks to automate my code deployment. Webhooks are a cool idea - set one up on your repo and every time an event occurs (push, pull request, fork, etc.) GitHub will send you some data to a URL of your specification which describes the event. All you need is something to process the data!

I set myself up a simple Node application to process the data using the githubhook package. It was very easy to use.

var githubhook = require("githubhook");
var exec = require("child_process").exec;

var github = githubhook({
    port: 8082,
    secret: "your-secret-code"
});

// listen to push on github on branch master
github.on("push", function(repo, ref, data) {

    var branchName = ref.substring(ref.lastIndexOf("/")+1);
    if (branchName === "master") {

        var repoName = data.repository.name;
        if (repoName === "comic") {

            child = exec("/home/comic/update_comic.sh", function(error, stdout, stderr) {

                if (error !== null) {

                    var e = new Error("exec error: " + error);
                    console.log(e);

                } else {

                    console.log("pulled update for " + repoName);

                }

            });

        }

    }

});

// listen to github push
github.listen();

My application will listen on port 8082 for GitHub events, which will be HTTP POSTed in JSON format (when you select that option later). When setting up, the value for secret (line 6) is important. You'll want that to match the value you'll set up in GitHub. Once you create the object, specify callback functions for the events that interest you and start listening.

I am just looking for the "push" event. When that event happens, I check to make sure the push was to the master branch and that the repo was my comic (I might use this for other repos later). If both of those are true, I exec a script that will pull the updates and restart the app if necessary.

Once you have your app running, you can set up your GitHub repo with the Webhook. Just go to your repository page, and click on the Settings link. Then click on "Webhooks & Services" and then on the "Add webhook" button.

Now specify the URL where you are listening with the app. My URL happens to be http://caseyleonard.com:8082/github/callback. The port is obviously the same one I specified above, but the path of /github/callback is the default used by githubhook (you can change it if you want - see the docs). Set the Content Type to be "application/json" and type in the same value for Secret that you used in the app. If these don't match, GitHub will receive a 403 response code when it sends you data and your listener will not be called. You can also select which events of which you want to be notified. It defaults to just "push" which is fine for my use.

It's simple and it works for me, at least so far. The less time I spend updating the code for the comic, the more time I can spend making the comics themselves. Today is the last of the Canterbury Tales parody, a set which took me a very long time to create!

Monday, April 27, 2015

The Moral of the Story

If you've been reading Amphibian.com for the last week, you'll know that I've been doing a parody of the Canterbury Tales. Today's comic is the third story told by the frogs, and it happens to be Business Frog's tale.

Business Frog is a weird character for me. He wasn't part of my original comic idea (I created him just for this shirt I made for my brother), but he gets a lot of screen time in the comics (he was the central character in the 5-part Christmas poem and the star of my GitHub Game Off entry). He is also the most upbeat of all the frogs. I've only shown him frowning once, and that was more fear than sadness. And today his story is the only one to have a "real" moral. Like most of the tales told by Chaucer's pilgrims, there was some moral - but before today they've just been silly. I think I use Business Frog for the deep stuff as a contrast to the lack of moral integrity I see in the real business world. Business Frog learns and gets it right because I want business humans to learn and get it right.

Too often, humans get it wrong.

I don't have any cool code tricks to showcase today because last week I didn't do much coding. On Thursday I did something infinitely more important and adopted the foster child who's been living in my home for the past 2 and a half years. She is a wonderful child, now 15 years old, who's been hurt by a broken world and is on a slow road to recovery. I am responsible for her now, but in a sense we're all responsible for what happened to her. We live in a world where we see our leaders put profits before people and teach us that self-interest is the best interest. We celebrate financial success and absurd narcissism.

That's the kind of stuff I think about when I make a comic using a frog wearing a necktie. Actually, I think about that stuff pretty much all the time. It's just that sometimes I am making a comic using a frog wearing a necktie. Am I crazy?

Absolutely.

Amphibian.com comic for 27 April 2015

Friday, April 24, 2015

Meetups are Better Than Meetings

I admit it, I don't work well in crowded and noisy areas. I can't set up my laptop at the coffee shop and get anything done. I like silence. Unlike many people, I can't focus when there is music playing. Does that make me strange? Probably. I need solitude to really accomplish much of anything.

Despite that, I went to a Meetup tonight in a local co-working space where I tried to work on an issue with my webcomic framework. There were lots of people around having lots of conversations. I frequently stopped what I was doing to talk to someone about what they were working on or what I was working on. Even though I didn't really get much done, it was still a positive experience.

Why? Because it exposed me to new people and new ideas outside of what is typical for me. For example, I have been curious for some time about algorithms that procedurally generate terrain in games, but I didn't know anyone who had actually worked on something like that. Tonight, I met someone who had made a game with randomly-generated areas and he told me about Perlin noise and how it is used. It was great!

So in this short post today I'd like to encourage you to find a similar group in your area and participate in it. Sites like Meetup.com are good places to look for them. If you can't find one near you, maybe you should start one!

In other news, my parody of the Canterbury Tales is still going at Amphibian.com. Today, Science Frog tells his story:

Amphibian.com comic for 24 April 2015

Wednesday, April 22, 2015

Simple DOM Collision Tracking

Back on the 15th, I had this awesome frog dodgeball game right in the third frame of my Amphibian.com comic. While today's Chaucer-inspired tale told in Middle English is amusing, it lacks the technical complexity of the dodgeball game. One of the many pieces that came together to enable a game inside a webcomic was simple collision detection between DOM nodes.

Frog Dodgeball
The comic frames, even in the dodgeball comic, are just "regular" DIV tags. I didn't use an HTML5 Canvas or anything like that. The frogs and balls are just IMG tags. To determine if a ball hits a frog, I had to come up with some reasonably efficient way of detecting the collision between two elements in the DOM and then taking some action based on a possible collision.

I used a class-based detection strategy similar to what I learned while using Crafty to make my entry for the GitHub Game Off 2015. Any element that should be checked for collisions with other objects should have the "collision" class applied to it. There isn't necessarily any special CSS associated with that class - it just has to be on the element. The element should also define a value for the field "collidesWith" that will be the name of another class. Only elements that have that class will be checked for collisions. I used a simple circle-based intersection formula for speed, so elements that can collide with other should define a value for the "collisionRadius" field as well. Finally, the elements should specify a function, hit, to be called if a collision is detected. The function will be passed an array of objects that are in collision.

Here is an example of how I set up the ball elements.

var ball = $('#ball');
var newBall = ball.clone()[0];

$(newBall).addClass("collision");

newBall.collisionRadius = $(newBall).width() / 2;
newBall.collidesWith = "frog";
newBall.hit = handleHit;

All balls are clones of a master ball element (line 2). I add the "collision" class, set the radius, specify what kinds of elements with which the balls collide, and specify the function to call if there is a hit. Here is an example of the handleHit function:

function handleHit(elemArray) {

    $(this).removeClass("collision"); // this ball won't hit anything else

    // make the element hit (assumes only 1 in this case)
    // semi-transparent for half a second
    $(elemArray[0]).css("opacity", "0.5");
    setTimeout(function() {
        $(elemArray[0]).css("opacity", "1");
    }, 500);

}

So that's the setup. But of course I had to add the collision-checking code to the comic framework. I already had a function that handled the animation, so I added a call to checkCollisions after each position update.

function checkCollisions() {

    $("img.collision").each(function(idx, elem) {

        if (elem.collidesWith) {

            var cx1 = Number($(elem).css('left').replace('px', ''));
            var ox1 = cx1 + ($(elem).width() / 2);

            var cy1 = Number($(elem).css('top').replace('px', ''));
            var oy1 = cy1 + ($(elem).height() / 2);

            var hits = [];
            $("img." + elem.collidesWith).each(function(idx2, elem2) {

                var cx2 = Number($(elem2).css('left').replace('px', ''));
                var ox2 = cx2 + ($(elem2).width() / 2);

                var cy2 = Number($(elem2).css('top').replace('px', ''));
                var oy2 = cy2 + ($(elem2).height() / 2);

                var distX = (ox2) - (ox1);
                var distY = (oy2) - (oy1);
                var magSq = distX * distX + distY * distY;
                if (magSq < (elem.collisionRadius + elem2.collisionRadius) * (elem.collisionRadius + elem2.collisionRadius)) {
                    hits.push(elem2);
                }

            });

            if (hits.length > 0 && elem.hit) {
                elem.hit(hits);
            }

        }

    });

}

My function iterates over all images that have the "collision" class. If those elements have a "collidesWith" defined, I get the X and Y coordinates for the center of the image. I'll need these for the collision check. Then I iterate over all the image elements that have the class specified by the "collidesWith" field and get their centers. The collision check starts on line 22. Basically, it makes two circles at the center-points of the images with the specified radii. A collision is detected if the circles overlap at all. If they do, I add that element to the hits array. At the end I call the hit function, passing the array, if there were any hits.

It all worked pretty well, and now I'll have it all ready for the next time I want to add a pointless game to a comic!

Amphibian.com comic for 22 April 2015

Monday, April 20, 2015

Using Your Own Custom Web Fonts

Olde Geoff coude telle a goode tale.
It is the month of April, and you know what that means. Yes! The Canterbury Tales! Geoffrey Chaucer's most famous work of Middle English literature was set in April near the end of the 14th century. I loved reading the Tales as part of my high school literature requirements and have never forgotten them.

As a tribute to Chaucer some 600+ years later, Amphibian.com will be written in the style of the Tales for the next week and a half. It starts out with an unnamed narrator meeting up with a group of frogs in an airport. They're all travelling to the Moscone Center in San Francisco for a conference and agree to tell each other stories to pass the time. In the Canterbury Tales, it was a group of pilgrims travelling to Canterbury. If you've never read Chaucer's original, you can find it here: The Canterbury Tales.

I say all that as an introduction to the real topic of the today's post - using your own custom fonts on web pages via CSS.

I had to do this for the comics to get a font that looked Middle English. The font I'm using is, oddly enough, named Canterbury. You may be familiar with using Google Fonts to add a custom font to web pages, but they don't actually offer one in the Middle English style. That's why I had to do it on my own. It's not hard to do, and is the same method used by Google Fonts and font-based icon utilities such as Font Awesome.

The first thing you need is a font. There are many places on the web to find fonts, but make sure you are adhering to the license agreement. Some are public domain, others you have to pay for, and some are provided under one of the Creative Commons licenses. Here are some popular font sources:

Besides just having a font, you need to have that font 4 different ways. Each browser has its own set of supported formats, so if you want complete functionality across all browsers you'll need to have the font in EOT, SVG, TTF, and WOFF formats. You can usually find fonts in TTF or OTF formats. What if you don't have the rest? There are some free utilities on the web that can convert to the other formats for you. I used Font2Web but Font Squirrel has a similar service that I used once in the past.

Once you have all those font files, you need to define the font in your CSS. You do this with the @font-face declaration. In it, you give the font a family name and specify the URLs for the various file formats. Here is the CSS for the Canterbury font:

@font-face {
    font-family: 'Canterbury';
    src: url('../fonts/Canterbury.eot');
    src: url('../fonts/Canterbury.woff') format('woff'), url('../fonts/Canterbury.ttf') format('truetype'), url('../fonts/Canterbury.svg') format('svg');
    font-weight: normal;
    font-style: normal;
}

Note that if you use relative paths in the URLs, they are relative to the location of your CSS file. I keep my fonts in a directory named fonts which is sibling to my css directory.

Once you have your font defined, you can use it in styles by referencing the font-family name you gave it above.

.olde-text {
    font-family: 'Canterbury';
    text-align: left;
    font-size: 1.3em;
}

As you can see, it's not that hard to use your own custom fonts in web pages. It was easy to make my text use a Middle English font. What's not easy is reading Middle English and understanding what it means. But give it a try anyway in today's comic.

Amphibian.com comic for 20 April 2015

Friday, April 17, 2015

Publish/Subscribe with jQuery

The frog dodgeball thing from Wednesday's comic was probably more fun for me to create than it was to play. Embedding a simple game in a comic, even a SVG/CSS/JavaScript comic, was not the easiest thing to do. But I used some very effective design patterns to make it easier.

Not a Sub, a Pub/Sub
The comic has supported simple animations since the beginning, but for the game to work I needed to add a custom module to just that one comic which could take additional actions when the animation state changed. I certainly didn't want to tightly couple the general-purpose animation code to this one comic, and also I didn't want to duplicate the most of the animation code in this module just to add one feature. Since I may want to do similar things in the future as well, I wanted a solution that would be flexible.

I decided to use the Publish/Subscribe Pattern. A derivative of the Observer Pattern, a Publish/Subscribe model allows me to completely decouple the event generator (my animation code in this case) from any other components that may wish to take action on certain events (the game code).

The Publish/Subscribe pattern has three parts:

  1. the publisher (creates the events)
  2. the subscriber(s) (want to be notified of events)
  3. the controller (takes events from publishers to subscribers).


My animated comic objects will publish events at certain points in their animation cycles. It doesn't matter if no one is subscribed to those events or if 100 other objects are subscribed. The general contract is that the subscriber says to the controller, "call my notify method when event X happens" and the publisher says to the controller, "event X just happened" the controller will pass the message on to every subscriber by calling the notify method. The publisher doesn't have any idea who is subscribed.

Fortunately, jQuery provides the controller. In jQuery-speak, this system is called custom events. Basically, the .trigger(event) method on jQuery objects invokes a controller that notifies any other objects that may be subscribed to that particular event on that object.

Consider the following example.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Pub/Sub</title>
</head>

<body>

  <p id="publisher">I have something to say.</p>

  <p id="target">Nothing here.</p>

</body>

<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>

<script>

$(function() {

    // subscribe to events named "myEvent" from #publisher
    $("#publisher").on("myEvent", function(event, data) {

        $("#target").html(data.text);

    });

    // using setTimeout to simulate an asynchronous event
    setTimeout(function() {

        var myData = {
            text: "This is my event text"
        }
        // publish a "myEvent" event, with some custom data
        $("#publisher").trigger("myEvent", [myData]);

    }, 5000);

});

</script>

</html>

As soon as the page is loaded, it sets up a subscriber function to "myEvent" events that may come out of the P element named "publisher." I used setTimeout to simulate an asynchronous event that may happen sometime on your page. When it does, the "publisher" publishes its "myEvent" along with some data. The subscriber function is called, and the P element named "target" changes its contents to be whatever was provided as data.

If you execute this code yourself, you'll see that the text "Nothing here" is replaced by "This is my event text" after 5 seconds.

I used this pattern on IMG tags to have them publish events at certain points in their animation cycles, so I am now able to make comic-specific code that can take special actions on general-purpose animations. All I had to do was add a single line with a call to .trigger() to my animation function! That means comic-cell games will now be even easier for me to create! There will be more!

But not today. It's just a normal comic with a little animation.

Amphibian.com comic for 17 April 2015

Wednesday, April 15, 2015

Sounds Good

Today's comic was a lot of fun to create. If you haven't seen it yet, go there right away. You won't regret it. It's much more entertaining than this blog.

If you're still reading, it means you've either already looked at the comic or you just ignored my advice in the first paragraph. Let's move on.

So the third frame in the comic is a frog dodgeball game. Every time you click (or touch) it launches a ball at the frogs. If they get hit, their agility score goes down. It's really pointless. But still, throwing red balls at frogs as they hop past is strangely entertaining.

There's a lot of good programming topics that came up while I was making it. I added animation event emitters so that I could use a listener pattern for the frogs' paths. I added animation that changes the image of an object as it moves around on the screen. I added collision detection that uses jQuery selectors. All good stuff.

Creative Commons Licensed Sounds
But the one thing I would like to mention here today is where I get the sound effects. The sound the page makes when you successfully hit a frog is the same sound I used in my GitHub Game Off 2015 game entry for when Business Frog gets hit by an apple. I got it and all my other sound effects from Freesound.org.

Previously, I've mentioned how I sometimes get SVG clipart from OpenClipart.org. Freesound is like the same thing, but for sounds. All of the sound effects on Freesound are licensed under one of the Creative Commons license agreements. Many completely free, having been donated to the public domain. Most are licensed by Attribution, which means you just need to give credit to the creator. There are vast amounts of sound effects that are perfect for the kinds of small web-based games that I like to create.

You'll need to create an account in order to download the sounds, but you can listen to them right on the web until you find the perfect one. Unlike with OpenClipart, I'm not really capable of creating any kind of audio files that anyone would want - so I don't upload my own work. But if you do make your own sound effects, by all means share them! The world will be a better place for it!

One final thought. The sound files on Freesound.org tend to come in a variety of formats. Typically I need them in .mp3 or .ogg format for my games. I've found Audacity to be a great tool for my simple audio conversion and editing needs.

Here's another link to that comic, in case you missed it.

Amphibian.com comic for 15 April 2015