Thursday, 31 October 2019

Signs Your Website Feels More Like A Haunted House Than A Welcoming Home

Signs Your Website Feels More Like A Haunted House Than A Welcoming Home

Suzanne Scacca

When building a website or PWA, no one ever thinks, “I really hope my visitors run away in fear!” Yet, one wrong move could make a visit to your website seem like a nightmarish walk through a haunted house instead of an awe-inspiring tour of a new home.

To be clear, I’m not talking about dark color palettes or blood-red typography that might remind someone of something they’d seen in a horror movie. If those kinds of design choices make sense and don’t intrude on readability, go for it! What I’m talking about are those ominous feelings emitted by the design and content of a website — similar to the ones someone might feel when walking through a haunted house.

Dr. Frank T. McAndrew answered the question “What Makes a House Feel Haunted?” in an article on Psychology Today back in 2015. He explains:

“From a psychological point of view, the standard features of haunted houses trigger feelings of dread because they push buttons in our brains that evolved long before houses even existed. These alarm buttons warn us of potential danger and motivate us to proceed with caution.”

When a visitor shows up on your website, the last thing you want is for them to be wary of moving through it. You want your website to give off a welcoming and safe vibe; not one that makes visitors wonder what’s lurking around the corner.

So, today, I want to look at some ways in which a website might be giving your visitors the heebie-jeebies and what you can do to eliminate those haunted house-like elements from the experience.

Four Signs Your Website Feels Like A Haunted House

In a lot of ways, a website is like your home. You add comfortable furnishings to it. You make it feel warm and inviting. And you clean up before anyone comes over, so they’re not freaked out by the accumulated dust or clutter.

If you keep that in the back of your mind (i.e. your website = your home), you can avoid these scary missteps as you design websites (as well as PWAs and mobile apps) for your clients.

  1. It Feels Abandoned
  2. It’s Too Confusing
  3. It Looks Too Low Budget
  4. It Looks Unsafe

1. It Feels Abandoned

There’s a video game and movie called Silent Hill that’s based on Centralia, a real ghost town in Pennsylvania. Decades ago, there was a coal mine fire in the town that led to toxic conditions like the gas and smoke that billow up from the ground to this day.

It’s an element the video game designers and cinematographers latched onto when creating their own eerily abandoned setting for Silent Hill:

A still from the movie Silent Hill, featuring the toxic smoke that Centralia is known for.
A still from the movie Silent Hill, featuring the toxic smoke that Centralia is known for. (Source: GIPHY)

Eventually, Centralia was condemned due to the dangers posed by the fire and the resulting toxicity. Today, there are only a few residents who remain in town.

While there are some tourists who venture to Centralia out of curiosity, they don’t stay long. And why would they? The town is unlivable and it’s devoid of any meaningful experiences.

Your website may be sending similar signals if it’s:

  • Too simple in design,
  • Too outdated looking,
  • Devoid of useful content,
  • Seemingly uncared for,
  • Powered only by a basic chatbot,
  • Missing contact details or a working contact form.

The Blockbuster website (which I can’t believe still exists) is a good example of the kinds of signals a website might send to visitors if it were abandoned:

The Blockbuster website
The Blockbuster website has become nothing but a single landing page owned by DISH. (Source: Blockbuster) (Large preview)

The copyright on this website is from 2017, which is why the design of the site isn’t as bad as one might expect it to be. Even the mobile counterpart is responsive:

Blockbuster website on mobile
The nearly defunct Blockbuster still has a decent looking and mobile responsive website. (Source: Blockbuster) (Large preview)

That said, this website is nothing but a husk of what it once was in its heyday.

For example, this is what shows when someone clicks on “Blockbuster Store Location”:

BlockBuster location pop-up
The Blockbuster website advertises a location, but the pop-up leaves visitors with more questions than answers. (Source: Blockbuster) (Large preview)

If I had arrived at this site hoping to find a local video store to rent a movie from, I’d be confused by this pop-up. Does the store actually exist at 211 NE Revere Ave? What’s going to happen when I call the number? And why are they telling me I don’t have to leave the couch?

What DISH should’ve done when buying out Blockbuster is to take ownership of this domain, but then direct it to their own website. As it stands now, it feels as though there’s no one on the other side of this website and there’s no point in keeping it alive (much like the business itself).

It’s these kinds of questions and that eerie feeling of “What’s going on here????” that you want to keep your visitors from experiencing.

2. It’s Too Confusing

Another hallmark of a haunted house is excessive confusion. This is something that real-life serial killer H. H. Holmes mastered with his “Murder Castle”.

“This edifice became Holmes’ booby-trapped Murder Castle. The space featured soundproof rooms, secret passages and a disorienting maze of hallways and staircases. The rooms were also outfitted with trapdoors over chutes that dropped Holmes’ unsuspecting victims to the building’s basement.”

History.com

Interestingly, there is a term in the field of environmental psychology related to this particular quality of a space: legibility.

Essentially, if a space (like a home or a website) has clear pathways and a logical organization, it’s much easier for visitors to get oriented. Not only that, if a layout mirrors that of other spaces, it assists in recognizability and comfort. That sounds a lot like the legibility and navigability of a website, right?

Obviously, you don’t want your visitors to feel as though they’re going to get lost in your website or like they’re trapped within the walls of it. There are a number of things that could make them feel this way though:

  • Poor color contrasts,
  • Jarring typography or animations,
  • Excessively deep navigation without a trail of breadcrumbs,
  • Disappearing navigation,
  • Infinite scroll,
  • Incessant pop-ups and disruptions that won’t go away no matter how many times they’re dismissed,
  • An unclear or confusing call-to-action that makes them wonder what happens when they click it.

Let’s look at an example.

How many of you would feel confident pursuing any of the paths (links) available to you on the ARNGREN website?

ARNGREN website
The ARNGREN website is littered with excessive links and not enough organization. (Source: ARNGREN) (Large preview)

This is what appears when you click on the “PEDALS” image/link in the top-middle of the ARNGREN home page:

ARNGREN category page
An example of one of ARNGREN’s product/category pages. (Source: ARNGREN) (Large preview)

As you can see, the “Index” disappears from the left, so the only option visitors have is to click the home page link or hit the browser “Back” button to depart from the path they’ve taken.

Then there’s the page itself which scrolls on and on, showing off more pictures of bicycles and scooters. There are occasional descriptions and links that appear, but it’s really nothing more than a painful rabbit hole to fall down:

ARNGREN text, links, and images
A disorganized and poorly designed page on the ARNGREN website. (Source: ARNGREN) (Large preview)

This website is exactly how I expect visitors of H. H. Holmes’ Murder Castle felt when they first stepped inside those confusing hallways or fell through one of his trap doors. There’s no rhyme or reason to any of the pages and it almost feels as dangerous to backtrack as it is to move forward.

If you’d like to avoid taking your visitors on such a harrowing journey, focus on creating a clear and open path that’s easy to traverse and to get off of when they want to.

3. It Looks Too Low Budget

It’s not just real haunted houses you want to avoid emulating. You should also steer clear of certain types of haunted house attractions.

I’m what you might call a horror addict. I watch scary movies all year long. I take haunted tours every time I visit a new city. And I spend a good chunk of the months of September and October going to haunted house attractions.

As you can imagine, I’ve seen some really impressive haunted houses, and I’ve seen some that are really poorly done.

This, for instance, is an encounter I had with a street actor at Halloween Horror Nights:

Halloween Horror Nights scare actor
That’s me trying not to giggle too hard at the Halloween Horror Nights scare actor. (Source: Halloween Horror Nights) (Large preview)

Although I have a slightly cowered stance, you can see that I’m laughing. That’s because I could see his face through the holes of his mask.

Now, this by no means is a low budget haunted house/Halloween event. And this actor deserves all sorts of kudos for walking around steamy hot Florida in that getup and on stilts, no less. But I will say that being there in the daytime where I could see through the mask did deflate my enthusiasm. It also had me wondering if the rest of the experience would be as disappointing. (For the record, it wasn’t.)

You definitely don’t want your visitors noticing flaws, odd design choices and other errors on your site. Then, wondering why the company behind it didn’t put more money into design and development.

If your website looks cheesy, overdone or like it was cheaply thrown together, you’re going to have a big problem on your hands. The rest of the web has set a very high bar for what a website should look like and how it should work. Fail to live up to those expectations and you’ll find that people will start to question the legitimacy or worth of the business behind it.

For instance, this is the website for Yale University’s School of Art:

Yale University’s art department website
This is the home page of the School of Art at Yale University. (Source: Yale University School of Art) (Large preview)

I thought it was a joke, that somehow I’d landed on someone pretending to be Yale University at yale.net instead of yale.edu. But I was wrong. This is the real website of the art department at the Ivy League university.

So, I dug a little further, hoping that somewhere on this subdomain would be an explanation of why this website sucked so much. This is what I found:

Yale School of Art web design
The Yale School of Art explains why their website / wiki looks the way it does. (Source: Yale University School of Art) (Large preview)

Let me point you to the most revealing parts of the explanation. First, they explain that this site is an open-source wiki:

It is a wiki, meaning that every graduate student, staff person, and faculty member of the School can change this website’s content or add to it at any time.

Next, they warn you that you may be shocked by what you see:

As you move through it you may, in consequence of such openness, encounter content that surprises you or with which you don’t agree. That will be the sign that this website reflects life in our institution in all its heterogeneous dimensions.

Considering the editor of this page used a negative review from Facebook as the repeating background image, there must be some inside joke here. In fact, when I looked into it further, it seems as though this school has had a tradition of scary web design choices as far back as 2010. So, they obviously know what they’re doing.

Here’s the thing though: even if you’re designing for someone with as well-known a reputation as Yale, building something that looks like it was thrown together in Paint back in 2001 is no way to go. There’s no exception for design this bad and I don’t think your visitors will be happy that you wasted their time either.

I realize this might help with the virality of a site, but it’ll do nothing for the credibility of it. All you’ll end up with is a few thrill seekers stumbling through in search of a good laugh or shock. What you need instead is visitors who feel comfortable and confident enough to convert.

4. It Looks Unsafe

The last thing that might leave people feeling unsettled is a lack of security (or at least the perception of none).

One of the things I often get asked by people who don’t like scary movies or going to haunted houses is:

“But aren’t you scared?”

Of course, I’m scared! I enjoy all of this horror stuff because I can do so safely from a distance. I know that the scare actors in a haunted house aren’t going to hurt me and I know that Michael Myers isn’t going to pop out of my TV screen and butcher me in the middle of the night. Plus, it’s a much more enjoyable way to get my cardio in without having to hit the treadmill.

A still of Michael Myers sneaking up on Laurie Strode in Halloween.
A still of Michael Myers sneaking up on Laurie Strode in Halloween. (Source: GIPHY)

I think for some people, though, they don’t have that same sense of security when partaking in activities like these, which is why they steer clear. And this is something you need to be extra careful about when it comes to your website. Specifically, be mindful of:

  • Installing SSL certificates on every website.
  • Using security badges at checkout.
  • Preventing 404 errors.
  • Fixing faulty contact forms.
  • Blocking spam in comment sections and forums.
  • Monitoring for server downtime.
  • Repairing the white screen of death.

Let’s look at an example of a website that sends a number of red flags pertaining to security. This is RoadKill T-Shirts:

RoadKill T-Shirts website
This is the home page of the RoadKill T-Shirts website. (Source: RoadKill T-Shirts) (Large preview)

At first glance, you might think this e-commerce website is okay. The design is outdated, but it’s a low-end tee-shirt shop. Visitors can’t be expecting too much from the design.

But then you move over to your mobile device and realize it’s not responsive:

RoadKill T-Shirts not responsive on mobile
The RoadKill T-Shirts website is not mobile responsive. (Source: RoadKill T-Shirts) (Large preview)

That said, there may be some visitors who are able to look past these design missteps, especially if there’s a tee shirt decal they really want.

One of the first red flags that should stop them in their tracks though is the “Not Secure” notice in their browser window. Although there is a GoDaddy security seal at the very bottom of the checkout page, I’m not all that sure I’d trust that to protect my purchase as a consumer either.

RoadKill T-Shirts GoDaddy security seal
The RoadKill T-Shirts website includes a GoDaddy security seal at checkout. (Source: RoadKill T-Shirts) (Large preview)

Then, there’s the matter of the contact form. I was curious to see how secure users would feel about filling in contact information without submitting a payment, so I forced an error:

RoadKill T-Shirts contact form error
What the RoadKill T-Shirts contact form looks like when an error occurs. (Source: RoadKill T-Shirts) (Large preview)

I’m happy to see that the failure to fill in required fields triggered such a response. However, here’s what happens to the bottom of the form as a result:

RoadKill T-Shirts error on form
RoadKill T-Shirts error-filled contact form leads to a hidden “Submit” button. (Source: RoadKill T-Shirts) (Large preview)

Users can tab down to reveal the “Submit” button. However, what if your visitors don’t know that they can do that? They may just end up abandoning the form and the website altogether if something as simple as the contact form is so fraught with error.

There are a variety of ways a website might seem unsafe to visitors, so do what you can to fortify it on the backend and then provide trust marks on the frontend to put their minds at ease.

Wrapping Up

When a visitor enters your website, what do you want their first thought to be?

“Oh great! There’s the product I was looking for!”

Or:

“Hmmm… Maybe I should go back to Google and see if there’s a different place to buy this product from.”

There are so many ways to give your visitors pause when they visit a website. But if you start looking at your website like a home, you can avoid the common pitfalls that make a website feel more like a haunted house than a warm and welcome homecoming.

Smashing Editorial(ra, yk, il)

from Tumblr https://ift.tt/34h4dEX

Wednesday, 30 October 2019

Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 3)

Writing A Multiplayer Text Adventure Engine In Node.js: Adding Chat Into Our Game (Part 3)

Fernando Doglio

I first showed you how to define a project such as this one, and gave you the basics of the architecture as well as the mechanics behind the game engine. Then, I showed you the basic implementation of the engine — a basic REST API that allows you to traverse a JSON-defined world.

Today, I’m going to be showing you how to create an old-school text client for our API by using nothing other than Node.js.

Reviewing The Original Design

When I first proposed a basic wireframe for the UI, I proposed four sections on the screen:

(Large preview)

Although in theory that looks right, I missed the fact that switching between sending game commands and text messages would be a pain, so instead of having our players switching manually, we’ll have our command parser make sure it is capable of discerning whether we’re trying to communicate with the game or our friends.

So, instead of having four sections in our screen, we’ll now have three:

(Large preview)

That is an actual screenshot of the final game client. You can see the game screen on the left, and the chat on the right, with a single, common input box at the bottom. The module we’re using allows us to customize colors and some basic effects. You’ll be able to clone this code from Github and do what you want with the look and feel.

One caveat though: Although the above screenshot shows the chat working as part of the application, we’ll keep this article focused on setting up the project and defining a framework where we can create a dynamic text-UI based application. We’ll focus on adding chat support on the next and final chapter of this series.

The Tools We’ll Need

Although there are many libraries out there that let us create CLI tools with Node.js, adding a text-based UI is a completely different beast to tame. Particularly, I was able to find only one (very complete, mind you) library that would let me do exactly what I wanted: Blessed.

This library is very powerful and provides a lot of features we won’t be using for this project (such as casting shadows, drag&drop, and others). It basically re-implements the entire ncurses library (a C library which allows developers to create text-based UIs) which has no Node.js bindings, and it does so directly in JavaScript; so, if we had to, we could very well check out its internal code (something I wouldn’t recommend unless you absolutely had to).

Although the documentation for Blessed is quite extensive, it mainly consists of individual details about each method provided (as opposed to having tutorials explaining how to actually use those methods together) and it is lacking examples everywhere, so it might be difficult to dig into it if you have to understand how a particular method works. With that being said, once you understand it for one, everything works the same way, which is a big plus since not every library or even language (I’m looking at you, PHP) has a consistent syntax.

But documentation aside; the big plus for this library is that it works based on JSON options. For example, if you wanted to draw a box on the top right corner of the screen, you would do something like this:

var box = blessed.box({
  top: ‘0',
  right: '0',
  width: '50%',
  height: '50%',
  content: 'Hello {bold}world{/bold}!',
  tags: true,
  border: {
    type: 'line'
  },
  style: {
    fg: 'white',
    bg: 'magenta',
    border: {
      fg: '#f0f0f0'
    },
    hover: {
      bg: 'green'
    }
  }
});

As you can imagine, other aspects of the box are defined there as well (such as it’s size), which can perfectly be dynamic based on the terminal’s size, type of border and colors — even for hover events. If you’ve done front-end development at some point, you’ll find a lot of overlap between the two.

The point I’m trying to make here is that everything regarding the representation of the box is configured through the JSON object passed to the box method. That, to me, is perfect because I can easily extract that content into a configuration file, and create a business logic capable of reading it and deciding which elements to draw on screen. Most importantly, it will help us get a glimpse of how they’ll look once they’ve been drawn.

This will be the base for the entire UI aspect of this module (more on that in a second!).

Architecture Of The Module

The main architecture of this module relies entirely on the UI widgets which we’ll be showing. A group of these widgets is considered a screen, and all these screens are defined in a single JSON file (which you can find inside the /config folder).

This file has over 250 lines, so showing it here makes no sense. You can look at the full file online, but a small snippet from it looks like this:

"screens": {
        "main-options": {
            "file": "./main-options.js",
            "elements": {
                "username-request": {
                    "type": "input-prompt",
                    "params": {
                        "position": {
                            "top": "0%",
                            "left": "0%",
                            "width": "100%",
                            "height": "25%"
                        },
                        "content": "Input your username: ",
                        "inputOnFocus": true,
                        "border": {
                          "type": "line"
                        },
                        "style": {
                          "fg": "white",
                          "bg": "blue",
                          "border": {
                              "fg": "#f0f0f0"
                          },
                          "hover": {
                            "bg": "green"
                          }
                        }
                    }
                },
                "options": {
                    "type": "window",
                    "params": {
                        "position": {
                            "top": "25%",
                            "left": "0%",
                            "width": "100%",
                            "height": "50%"
                        },
                        "content": "Please select an option: \n1. Join an existing game.\n2. Create a new game",
                        "border": {
                          "type": "line"
                        },
                        "style": {
                        //...
                        }
                    }
                },
                "input": {
                    "type": "input",
                    "handlerPath": "../lib/main-options-handler",
                   //...
                }
            }
        }

The “screens” element will contain the list of screens inside the application. Each screen contains a list of widgets (which I’ll cover in a bit) and every widget has its blesses-specific definition and related handler files (when applicable).

You can see how every “params” element (inside a particular widget) represents the actual set of parameters expected by the methods we saw earlier. The rest of the keys defined there help provide context about what type of widgets to render and their behavior.

A few points of interest:

Screen Handlers

Every screen element has file property which references the code associated to that screen. This code is nothing but an object that must have an init method (the initialization logic for that particular screen takes place inside of it). Particularly, the main UI engine, will call that init method of every screen, which in turn, should be responsible for initializing whatever logic it may need (i.e setting up the input boxes events).

The following is the code for the main screen, where the application requests the player to select an option to either start a brand new game or join an existing one:

const logger = require("../utils/logger")

module.exports = {
    init: function(elements, UI) {
        this.elements = elements
        this.UI = UI
        this.id = "main-options"
        this.setInput()
    },

    moveToIDRequest: function(handler) {
        return this.UI.loadScreen('id-requests', (err, ) => {
            
        })
    },

    createNewGame: function(handler) {
        handler.createNewGame(this.UI.gamestate.APIKEY, (err, gameData) => {
              this.UI.gamestate.gameID = gameData._id
              handler.joinGame(this.UI.gamestate, (err) => {
                return this.UI.loadScreen('main-ui', {
                    flashmessage: "You've joined game " + this.UI.gamestate.gameID + " successfully"
                },  (err, ) => {
                    
                })
              })
            
          })
    },

    setInput: function() {
        
        let handler = require(this.elements["input"].meta.handlerPath)
        let input = this.elements["input"].obj
        let usernameRequest = this.elements['username-request'].obj
        let usernameRequestMeta = this.elements['username-request'].meta
        let question = usernameRequestMeta.params.content.trim()


        usernameRequest.setValue(question)

        this.UI.renderScreen()

         let validOptions =  {
             1: this.moveToIDRequest.bind(this),
             2: this.createNewGame.bind(this)
         }

        usernameRequest.on('submit', (username) => {

            logger.info("Username:" +username)
            logger.info("Playername: " + username.replace(question, ''))
            this.UI.gamestate.playername = username.replace(question, '')

            input.focus()

            input.on('submit', (data) => {
                let command = input.getValue()
                  if(!validOptions[+command]) {
                      this.UI.setUpAlert("Invalid option: " + command)
                      return this.UI.renderScreen()
                  }
                  return validOptions[+command](handler)
            })


        })
        return input
    }
}

As you can see, the init method calls the setupInput method which basically configures the right callback to handle user input. That callback holds the logic to decide what to do based on the user’s input (either 1 or 2).

Widget Handlers

Some of the widgets (usually input widgets) have a handlerPath property, which references the file containing the logic behind that particular component. This is not the same as the previous screen handler. These don’t care about the UI components that much. Instead, they handle the glue logic between the UI and whatever library we’re using to interact with external services (such as the game engine’s API).

Widget Types

Another minor addition to the JSON definition of the widgets is their types. Instead of going with the names Blessed defined for them, I’m creating new ones in order to give me more wiggle room when it comes to their behavior. After all, a window widget might not always “just display information”, or an input box might not always work the same way.

This was mostly a preemptive move, just to ensure I have that ability if I ever need it in the future, but as you’re about to see, I’m not using that many different types of components anyway.

Multiple Screens

Though the main screen is the one I showed you in the screenshot above, the game requires a few other screens in order to request things such as your player name or whether you’re creating a brand new game session or even joining an existing one. The way I handled that was, again, through the definition of all these screens in the same JSON file. And to move from one screen into the next one, we use the logic inside the screen handler files.

We can do this simply by using the following line of code:

this.UI.loadScreen('main-ui', (err ) => {
 if(err) this.UI.setUpAlert(err)    
 })

I’ll show you more details about the UI property in a second, but I’m just using that loadScreen method to re-render the screen and picking the right components off of the JSON file using the string passed as parameter. Very straightforward.

Code Samples

It’s now time to check out the meat and potatoes of this article: the code samples. I’m just going to highlight what I think are the small gems inside it, but you can always take a look at the full source code directly in the repository anytime.

Using Config Files To Auto Generate The UI

I’ve already covered part of this, but I think it’s worth exploring the details behind this generator. The gist behind it (file index.js inside the /ui folder) is that it is a wrapper around the Blessed object. And the most interesting method inside it, is the loadScreen method.

This method grabs the configuration (through the config module) for one specific screen and goes through its content, trying to generate the right widgets based on each element’s type.

loadScreen: function(sname, extras, done) {
        if(typeof extras == "function") {
            done = extras
        }

        let screen = config.get('screens.' + sname)
        let screenElems = {}
   
        if(this.screenElements.length > 0) { //remove previous screen
            this.screenElements.map( e => e.detach())
            this.screen.realloc()
        }

        Object.keys(screen.elements).forEach( eName => {
            let elemObj = null
            let element = screen.elements[eName]
            if(element.type == 'window') {
                elemObj = this.setUpWindow(element)
            }
            if(element.type == 'input') {
                elemObj = this.setUpInputBox(element)
            }

            if(element.type == 'input-prompt') {
                elemObj = this.setUpInputBox(element)
            }
            screenElems[eName] = {
                meta: element,
                obj: elemObj
            }
        })

        if(typeof extras === 'object' && extras.flashmessage) {
            this.setUpAlert(extras.flashmessage)    
        }


        this.renderScreen()
        let logicPath = require(screen.file)
        logicPath.init(screenElems, this)
        done()
    },

As you can see, the code is a bit lengthy, but the logic behind it is simple:

  1. It loads the configuration for the current specific screen;
  2. Cleans up any previously existing widgets;
  3. Goes over every widget and instantiates it;
  4. If an extra alert was passed as a flash message (which is basically a concept I stole from Web Dev in which you setup a message to be shown on screen until the next refresh);
  5. Render the actual screen;
  6. And finally, require the screen handler and execute it’s “init” method.

That’s it! You can check out the rest of the methods — they’re mostly related to individual widgets and how to render them.

Communication Between UI And Business Logic

Although in the grand scale, the UI, the back-end and the chat server all have a somewhat layered-based communication; the front end itself needs at least a two-layered internal architecture in which the pure UI elements interact with a set of functions that represent the core logic inside this particular project.

The following diagram shows the internal architecture for the text client we’re building:

(Large preview)

Let me explain it a bit further. As I mentioned above, the loadScreenMethod will create UI presentations of the widgets (these are Blessed objects). But they are contained as part of the screen logic object which is where we set up the basic events (such as onSubmit for input boxes).

Allow me to give you a practical example. Here is the first screen you see when starting the UI client:

(Large preview)

There are three sections on this screen:

  1. Username request,
  2. Menu options / information,
  3. Input screen for the menu options.

Basically, what we want to do is to request the username and then ask them to pick one of the two options (either starting up a brand new game or joining an existing one).

The code that takes care of that is the following:

module.exports = {


    init: function(elements, UI) {
        this.elements = elements
        this.UI = UI
        this.id = "main-options"
        this.setInput()
    },

    moveToIDRequest: function(handler) {
        return this.UI.loadScreen('id-requests', (err, ) => {
            
        })
    },

    createNewGame: function(handler) {

        handler.createNewGame(this.UI.gamestate.APIKEY, (err, gameData) => {
              this.UI.gamestate.gameID = gameData._id
              handler.joinGame(this.UI.gamestate, (err) => {
                return this.UI.loadScreen('main-ui', {
                    flashmessage: "You've joined game " + this.UI.gamestate.gameID + " successfully"
                },  (err, ) => {
                    
                })
              })
            
          })
    },

    setInput: function() {
        
        let handler = require(this.elements["input"].meta.handlerPath)
        let input = this.elements["input"].obj
        let usernameRequest = this.elements['username-request'].obj
        let usernameRequestMeta = this.elements['username-request'].meta
        let question = usernameRequestMeta.params.content.trim()


        usernameRequest.setValue(question)

        this.UI.renderScreen()

         let validOptions =  {
             1: this.moveToIDRequest.bind(this),
             2: this.createNewGame.bind(this)
         }

        usernameRequest.on('submit', (username) => {

            logger.info("Username:" +username)
            logger.info("Playername: " + username.replace(question, ''))
            this.UI.gamestate.playername = username.replace(question, '')

            input.focus()



            input.on('submit', (data) => {
                let command = input.getValue()
                  if(!validOptions[+command]) {
                      this.UI.setUpAlert("Invalid option: " + command)
                      return this.UI.renderScreen()
                  }
                  return validOptions[+command](handler)
            })


        })

        
        

        return input
    }
}

I know that’s a lot of code, but just focus on the init method. The last thing it does is to call the setInput method which takes care of adding the right events to the right input boxes.

Therefore, with these lines:

let handler = require(this.elements["input"].meta.handlerPath)
let input = this.elements["input"].obj
let usernameRequest = this.elements['username-request'].obj
let usernameRequestMeta = this.elements['username-request'].meta
let question = usernameRequestMeta.params.content.trim()

We’re accessing the Blessed objects and getting their references, so that we can later set up the submit events. So after we submit the username, we’re switching focus to the second input box (literally with input.focus() ).

Depending on what option we choose from the menu, we’re calling either of the methods:

  • createNewGame: creates a new game by interacting with its associated handler;
  • moveToIDRequest: renders the next screen in charge of requesting the game ID to join.

Communication With The Game Engine

Last but certainly not least (and following the above example), if you hit 2, you’ll notice that the method createNewGame uses the handler’s methods createNewGame and then joinGame (joining the game right after creating it).

Both these methods are meant to simplify the interaction with the Game Engine’s API. Here is the code for this screen’s handler:

const request = require("request"),
    config = require("config"),
    apiClient = require("./apiClient")

let API = config.get("api")
module.exports = {

    joinGame: function(apikey, gameId, cb) {
        apiClient.joinGame(apikey, gameId, cb)
    },

    createNewGame: function(apikey, cb) {
        request.post(API.url + API.endpoints.games + "?apikey=" + apikey, { //creating game
            body: {
                cartridgeid: config.get("app.game.cartdrigename")
            },
            json: true
        }, (err, resp, body) => {
            cb(null, body)    
        })
        
    }
}

There you see two different ways to handle this behavior. The first method actually uses the apiClient class, which again, wraps the interactions with the GameEngine into yet another layer of abstraction.

The second method though performs the action directly by sending a POST request to the correct URL with the right payload. Nothing fancy is done afterwards; we’re just sending the body of the response back to the UI logic.

Note: If you’re interested in the full version of the source code for this client, you can check it out here.

Final Words

This is it for the text-based client for our text adventure. I covered:

  • How to structure a client application;
  • How I used Blessed as the core tech for creating the presentation layer;
  • How to structure the interaction with the back-end services from a complex client;
  • And hopefully, with the full repository available.

And while the UI might not look exactly like the original version did, it does fulfill its purpose. Hopefully, this article gave you an idea of how to architect such an endeavor and you were inclined to try it for yourself in the future. Blessed is definitely a very powerful tool, but you’ll have to have patience with it while learning how to use it and how to navigate through their docs.

In the next and final part, I’ll cover how I added the chat server both on the back-end as well as for this text client.

See you on the next one!

Smashing Editorial(dm, yk, il)

from Tumblr https://ift.tt/2MVW9DM

Tuesday, 29 October 2019

Speed Up Your Website With WebP

Speed Up Your Website With WebP

Suzanne Scacca

(This is a sponsored post.) Spend enough time running websites through PageSpeed Insights and you’ll notice that Google has a major beef with traditional image formats like JPG, PNG and even GIF. As well it should.

Even if you resize your images to the exact specifications of your website and run them through a compressor, they can still put a strain on performance and run up bandwidth usage. Worse, all of that image manipulation can compromise the resulting quality.

Considering how important images are to web design, this isn’t an element we can dispose of so easily nor can we afford to cut corners when it comes to optimizing them. So, what’s the solution?

Here’s what Google suggests:

PageSpeed Insights WebP tips
PageSpeed Insights demonstrates how much storage and bandwidth websites stand to save with WebP. (Source: PageSpeed Insights) (Large preview)

Years ago, Google aimed to put a stop to this problem by creating a next-gen image format called WebP. You can see in this screenshot from PageSpeed Insights that Google recommends using WebP and other next-gen formats to significantly reduce the size of your images while preserving their quality.

And if .75 seconds doesn’t seem like much to you (at least in this example), it could make a big difference in the lives of your visitors, the people who sit there wondering how long is too long to wait. Just one less second of loading could make a world of difference to your conversion rate.

But is WebP the best solution for this problem? Today, we’re going to examine:

What is WebP?

Google developed WebP back in 2010 after acquiring a company called On2 Technologies. On2 had worked on a number of video compression technologies, which ended up serving as the basis for Google’s new audiovisual format WebM and next-gen image format WebP.

Originally, WebP used lossy compression in an attempt to create smaller yet still high-quality images for the web.

If .75 seconds doesn’t seem like much to you, it could make a big difference in the lives of your visitors, the people who sit there wondering how long is too long to wait.

Lossy Compression For WebP

Lossy compression is a form of compression used to greatly reduce the file sizes of JPGs and GIFs. In order to make that happen, though, some of the data (pixels) from the file needs to be dropped out or “lost”. This, in turn, leads to some degradation of the quality of the image, though it’s not always noticeable.

WebP entered the picture with a much more efficient use of lossy compression (which I’ll explain below) and became the much-needed successor to JPG.

You can see a great demonstration of this difference as KeyCDN compares the difference in file sizes of a compressed JPG vs. WebP:

KeyCDN compares original file size against compressed JPG and WebP
KeyCDN shows how five images differ in size between the original, a compressed JPG and a WebP. (Source: KeyCDN) (Large preview)

Notice how significant a difference this is in terms of file size, even after the JPG has been compressed to a comparable quality. As Adrian James explains here, though, you have to be careful with WebP compression.

“Compression settings don’t match up one-to-one with JPEG. Don’t expect a 50%-quality JPEG to match a 50%-quality WebP. Quality drops pretty sharply on the WebP scale, so start at a high quality and work your way down.”

Considering how much more file sizes shrink with WebP compared to JPG, though, that shouldn’t be too much of a sticking point. It’s just something to think about if you’re considering pushing the limits of what WebP can do even further.

Now, as time passed, Google continued to develop WebP technology, eventually getting it to a point where it would support not just true-color web graphics, but also XMP metadata, color profiles, tiling, animation, and transparency.

Eventually, Google brought lossless compression to WebP, turning it into a viable contender for PNG, too.

Lossless Compression For WebP

Lossless compression does not degrade image quality the way lossy does. Instead, it achieves smaller file sizes by removing excess metadata from the backend of the file. This way, the quality of the image remains intact while reducing its size. That said, lossless compression can’t achieve the kinds of file sizes lossy compression can.

That was until WebP’s lossless compression came along.

You can see some beautiful examples of how WebP’s lossy and lossless compression stands up against PNG in Google’s WebP galleries:

Google WebP Gallery comparison against PNG
The Google WebP Galleries show how PNG images compare in quality and size to compressed WebPs. (Source: Google) (Large preview)

If there’s any degradation in the quality of the WebP images, it’s going to be barely noticeable to your visitors. The only thing they’re really going to notice is how quickly your site loads.

What Are The Advantages Of Using WebP?

It’s not enough to say that WebP is “better” than JPG and PNG. It’s important to understand the mechanics of how WebP works and why it’s so beneficial to use over other file formats as a result.

With traditional image formats, compression always results in a tradeoff.

JPG lossy compression leads to degradation of the clarity and fineness of an image. Once applied, it cannot be reversed.

WebP lossy compression, on the other hand, uses what’s known as prediction coding to more accurately adjust the pixels in an image. As Google explains, there are other factors at work, too:

“Block adaptive quantization makes a big difference, too. Filtering helps at mid/low bitrates. Boolean arithmetic encoding provides 5%-10% compression gains compared to Huffman encoding.”

On average, Google estimates that WebP lossy compression results in files that are between 25% and 34% smaller than JPGs of the same quality.

As for PNG lossless compression, it does work well in maintaining the quality of an image, but it doesn’t have as significant an impact on image size as its JPG counterpart. And certainly not when compared to WebP.

WebP handles this type of compression more efficiently and effectively. This is due to the variety of compression techniques used as well as entropy encoding applied to images. Again, Google explains how it works:

“The transforms applied to the image include spatial prediction of pixels, color space transform, using locally emerging palettes, packing multiple pixels into one pixel and alpha replacement.”

On average, Google estimates that WebP lossless compression results in files that are roughly 26% smaller than PNGs of the same quality.

That’s not all. WebP has the ability to do something that no other file formats can do. Designers can use WebP lossy encoding on RGB colors and lossless encoding on images with transparent backgrounds (alpha channel).

Animated images, otherwise served in GIF format, also benefit from WebP compression systems. There are a number of reasons for this:

GIF WebP
Compression Lossless Lossless + lossy
RBG Color Support 8-bit 24-bit
Alpha Channel Support 1-bit 8-bit

As a result of this powerful combo of lossless and lossy compression, animated videos can get down to much smaller sizes than their GIF counterparts.

Google estimates the average reduction to be about 64% of the original size of a GIF when using lossy compression and 19% when using lossless.

Needless to say, there’s nothing that can beat WebP when it comes to speed while maintaining image integrity.

Acceptance Of WebP Among Browsers, Devices And CMS

As you can imagine, when WebP was first released, it was only supported by Google’s browsers and devices. Over time, though, other platforms have begun to provide support for WebP images.

That said, WebP still doesn’t have universal support, which can cause problems for web designers who use this image format by default.

Let’s take a look at where you can expect full acceptance of your WebP images, where you won’t and then we’ll discuss what you can do to get around this hiccup.

As of writing this in 2019, Can I use… has accounted for the following platforms that support WebP:

‘Can I Use’ data on WebP support
‘Can I Use’ breaks down which browsers and versions of those browsers provide support for WebP. (Source: Can I use…) (Large preview)

The latest versions of the following platforms are supported:

  • Edge
  • Firefox
  • Chrome
  • Opera
  • Opera Mini
  • Android Browser
  • Opera Mobile
  • Chrome for Android
  • Firefox for Android
  • UC Browser for Android
  • Samsung Internet
  • QQ Browser
  • Baidu Browser

The platforms that continue to hold back support are:

  • Internet Explorer
  • Safari
  • iOS Safari
  • KaiOS Browser

It’s not just browsers that are on the fence about WebP. Image editing software and content management systems are, too.

ImageMagick, Pixelmator and GIMP all support WebP, for instance. Sketch enables users to export files as WebP. And for software that doesn’t natively support WebP, like Photoshop, users can usually install a plugin which will allow them to open and save files as WebP.

Content management systems are in a similar spot. Some have taken the lead in moving their users over to WebP, whether they uploaded their files in that format or not. Shopify and Wix are two site builders that automatically convert and serve images in WebP format.

Although there are other platforms that don’t natively support WebP, there are usually extensions or plugins you can use to upload WebP images or convert uploaded ones into this next-gen format.

WordPress is one of those platforms. Drupal is another popular CMS that provides users with WebP modules that add WebP support. Magento is yet another.

It’s pretty rare not to find some sort of add-on support for WebP. The only example that I’m aware of that doesn’t accept it is Squarespace.

Challenges Of Converting And Delivering WebP

Okay, so WebP doesn’t have 100% support on the web. Not yet anyway. That’s okay. For the most part, we have some sort of workaround in terms of adding support to the tools we use to design and build websites.

But what do we do about the browser piece? If our visitors show up on an iOS device, how do we make sure they’re still served an image if our default image is WebP?

First, you need to know how to convert images into WebP.

Last year, front end developer Jeremy Wagner wrote up a guide for Smashing Magazine on this very topic. In it, he covers how to convert to WebP using:

  • Sketch,
  • Photoshop,
  • The command line,
  • Bash,
  • Node.js,
  • gulp,
  • Grunt,
  • webpack.

Any of these options will help you convert your PNGs and JPGs into WebPs. Your image editing software will only get you halfway to your destination though.

It’ll handle the conversion, but it won’t help you modify your origin server so that it knows when to deliver WebPs and when to deliver a traditional image format to visitors.

Some of these methods let you dictate how your server delivers images based on the restraints of your visitors’ browsers. Still, it takes a bit of work to modify the origin servers to make this happen. If you’re not comfortable doing that or you don’t want to deal with it, KeyCDN has a solution.

The Solution: Simplify WebP Delivery With KeyCDN

KeyCDN understands how important it is to have a website that loads at lightning-fast speeds. It’s what KeyCDN is in the business to do. That’s why it’s no surprise that it’s developed a built-in WebP caching and image processing solution that helps developers more easily deliver the right file formats to visitors.

What Is WebP Caching?

Caching is an integral part of keeping any website running fast. And WebP caching is only going to make it better. Essentially, it’s a form of content negotiation that takes place in the HTTP header.

It works like this:

Someone visits a website that has KeyCDN’s WebP caching enabled. The visitor’s browser sends an accept HTTP header as part of the request to the server with a list of asset types it prefers. But rather than go to the origin server (at the web host), the request is processed by the edge server (at KeyCDN). The edge server reviews the list of acceptable file types and sends a content-type header in response.

Here’s an example of how that might look:

curl -I 'https://ip.keycdn.com/example.jpg' -H 'accept: image/webp'
HTTP/2 200
server: keycdn-engine
date: Thu, 06 Jun 2019 08:29:50 GMT
content-type: image/webp
content-length: 56734
last-modified: Tue, 14 May 2019 23:36:28 GMT
etag: "5cdb50fc-1040a"
expires: Thu, 13 Jun 2019 08:29:50 GMT
cache-control: max-age=604800
x-ip: 1
x-ip-info: osz=56734 odim=700x467 ofmt=webp
x-cache: HIT
x-shield: active
x-edge-location: chzh
access-control-allow-origin: *
accept-ranges: bytes

An example of a content-type request that KeyCDN sends to browsers that accept WebP. (Source: KeyCDN)

So, for Google Chrome visitors, the content-type: image/webp would automatically be accepted and the cached WebP assets would be delivered to the browser.

For Safari users, on the other hand, the request would go unaccepted. But that’s okay. Your CDN will know which file format to send instead. In the first line in the example above, you can see that the original image format is JPG, so that’s the version of the file that would be delivered.

As you can see, there’s no need to modify the origin server or prepare multiple versions of your files in order to account for WebP compatibility. KeyCDN WebP caching handles all of it.

How Do You Use KeyCDN WebP Caching?

There are two ways in which KeyCDN users can take advantage of the WebP caching feature.

Image Processing Through KeyCDN

The first requires nothing more than flipping a switch and turning on KeyCDN’s image processing. Once enabled, the accept request header will automatically load.

You can, of course, use the image processing service for more than just WebP caching. You can use it to adjust the size, crop, rotation, blur, and other physical attributes of your delivered images. But if you’re trying to simplify your image delivery system and simply want to speed things up with WebP, just enable the feature and let KeyCDN do the work.

WebP Caching Through Your Origin Server

Let’s say that you generated your own WebP image assets. You can still reap the benefits of KeyCDN’s WebP caching solution.

To do this, you’ll need to correctly generate your WebPs. Again, here’s a link to the guide that shows you how to do that.

It’s then up to you to configure your origin server so that it only delivers WebPs when accept: image/webp is present. KeyCDN provides some examples of how you’ll do this with Nginx:

# http config block
map $http_accept $webp_ext {
    default "";
    "~*webp" ".webp";
}

# server config block
location ~* ^(/path/to/your/images/.+)\.(png|jpg)$ {
    set $img_path $1;
    add_header Vary Accept;
    try_files $img_path$webp_ext $uri =404;
}

KeyCDN demonstrates how you can modify the origin server with Nginx to deliver your own cached WebP assets. (Source: KeyCDN)

And with Apache:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP_ACCEPT} image/webp
    RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
    RewriteRule ^(path/to/your/images.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>

<IfModule mod_headers.c>
    Header append Vary Accept env=REDIRECT_accept
</IfModule>

AddType image/webp .webp

KeyCDN demonstrates how you can modify the origin server with Apache to deliver your own cached WebP assets. (Source: KeyCDN)

Obviously, this option gives you more control over managing your image formats and how they’re served to visitors. That said, if you’re new to using WebP, KeyCDN’s automated WebP caching and image processing is probably your best bet.

An Alternative For WordPress And Magento Designers

If you design websites in WordPress or Magento, KeyCDN has plugins you can use to add WebP support and caching.

For WordPress, you’ll use KeyCDN’s custom Cache Enabler along with Optimus.

Cache Enabler plugin from KeyCDN
The Cache Enabler plugin offers delivery support for WebPs in WordPress. (Source: Cache Enabler) (Large preview)

Cache Enabler checks to see if your images have a WebP version. If it exists and the visitor’s browser supports it, that’s what it will deliver in the cached file. If it doesn’t exist, then it’ll simply turn to the JPG, PNG or GIF that’s there.

Magento developers have a simplified workaround for converting and delivering WebP, too. First, you’ll need to install the Webp extension. Then, you’ll have to configure the WebP binaries on your server.

Wrapping Up

There’s a reason why Google went to the trouble of developing a new image format and why more and more browsers, design systems and content management systems are supporting it.

Images can cause a lot of problems for websites that have otherwise been built to be lean and mean. If they’re not uploaded at the right size, if they’re not compressed and if caching isn’t enabled, your images could be the reason that your website’s speed is driving visitors away.

But with WebP, your website is sure to load more quickly. What’s more, there doesn’t need to be a tradeoff between image quality (or quantity!) in order to gain that speed. WebP efficiently compresses files while preserving the integrity of the image content.

If you’re really struggling to increase the speed of your website then WebP should be the next tool you turn to for help.

Smashing Editorial(ms, ra, il)

from Tumblr https://ift.tt/2orTcS9