Chuck McQuilkin

my writings, design experiements & code

Revenge of Analog Book Review

Posted by on Sep 23, 2019 in UX | No Comments

Back in April Austin’s UXPA book club read an except of The Revenge of Analog: Real Things and Why They Matter, by David Sax. It was an interesting choice for the group because UX professionals mostly focus on today’s technology or the tech of the future, not the technology of the past. The book reflects on today’s tech by comparing it to what came before. I ended up finishing the book, and afterward, I wrote a book review about the book published today on InMotion’s blog.

500 Albums Progressive Web Application

Posted by on Dec 13, 2018 in Code, UX, Web Design | No Comments

500 Albums is a simple mobile web app that I designed and built to practice design and development. The app helps me find good albums when I am at the record store. If you visit the link above on Android, you will see a banner with an “Add to Home Screen” button. On iOS, you can tap the export icon and swipe the bottom section to the left and tap the “Add to Home Screen” button to add the app to your phone’s home screen like a native app.

Apple pioneered web apps in 2009 by adding support in Safari for special meta tags and a cache.manifest file to control what data was cached as part of the web app, Google has recently released tools including Workbox that makes creating web apps using service workers easier and Lighthouse that rates how closely a progressive web app meets Googles’s new standards. Progressive web application an important part of last year’s I/o conference.

Web apps are interesting to me because they are built with HTML, CSS, and JavaScript which means that I can design and develop the app myself. I wanted a project that would need only one screen so it wouldn’t require designing or coding menus or managing routing. The finished product above is the result of a lot of designing and tinkering.

The project was also a chance to design an app icon and I created a variety of different versions before I landed on the one above. I added the icon to the iOS splash screens.

My initial idea was to design and build the simplest functional web app possible using HTML and CSS from another project. By using a fixed width for the list box I avoided designing breakpoints. I designed and coded a responsive version but ultimately decided against moving forward with it because the larger images hurt load times on mobile. I tried out a responsive version with filter buttons but decided against moving forward with that version because it would have required adding a lot more data to my data model (a single JSON file) or even adding a back-end so that there would be attributes to filter.

I started with an older Angular JS address book project. Then I refactored it into JSX and React to get more familiar with React. Then I refactored it into ES6/Babel to learn a little of the newer syntaxes.

I also adapted the design several times. I tried out more of a brutalist look and feel with a white background and black text. I also tried out two versions with larger album images, but I found that the designs with larger images performed poorly according to Lighthouse. A version with that used static HTML (No AJAX) and lazy-loaded the images with Javascript didn’t improve performance much.

Designing a simple web app got complicated. Now I know why the original 500 album list was paginated. Loading a few 20k images isn’t a big deal, loading 500 20k images is slow. I didn’t want to add pagination, so that meant that the images had to be small and optimized.

I found with Lighthouse that the React framework was one of the things that were slowing my little app down. I didn’t really need to use React in this project because all I was doing was fetching the list JSON, rendering the list HTML and filtering the list, all things that could be done with vanilla JavaScript. Then I discovered Preact which is a scaled down version of React created specifically for web applications. I also ran across an article that described measuring the baseline costs of javascript frameworks.

Performance and simplicity were the main reasons why I settled on a vanilla Javascript progressive web application for the final version.

Developing the idea for the project was almost as difficult as refactoring the code because I wanted to build something useful but avoid the temptation to add a new feature.  I own a copy of Rolling Stone’s 500 Greatest Albums of all time, but when I am at the record store (we still have those in Austin ❤ Waterloo), chances are I didn’t bring the book with me. This filterable list could be reused with different kinds of lists such as top 500 beers, top 100 TV shows or top 100 movies, top 500 podcasts, 500 easy to prepare recipes, etc.

The code for the final version is on Github, the other versions are on Codepen.

Design Sprints

Posted by on Jul 31, 2018 in Design, UX | No Comments
Design Sprints

I am a believer in kicking off product design initiatives with design sprints. The design sprint system will not work for every design problem but they are a great tool for condensing design thinking into an agile product development cycle. Design sprints encourage collaboration, draw out deep product knowledge hidden within the organization, build empathy for users, and create buy-in for a design direction by involving the key stakeholders and testing the end result.

The real deliverable of a design sprint isn’t a prototype or a finished product, but a series of productive conversations and a changed mindset within a team. The book by Jake Knapp and the book by Richard Banfield, et al. helped me the most when I was preparing for my first design sprint at Pearson.

The magic really is in carefully time boxing key exercises that focus on the five stages, understanding, diverging, converging, and prototyping. The 5 step exercise was invented and popularized by Jake Knapp at Google Ventures, but it built upon the ideas of design thinking developed at IDEO and Stanford’s Design sprints also use several activities from Gamestorming by Dave Gray.

Design sprints can be adapted to shorter time-frames as needed. How Might We note, Facts and Assumptions and building a matrix of assumptions are the most important exercises to include in a design sprint. But it may make sense to add or replace some of the other exercises to meet the needs of the problem you are tackling. Gamestorming and the design kit websites below are great sources for alternate exercises.

Further Reading



Posted by on Jul 31, 2018 in UX | No Comments

A blog post about CSUN is long overdue. I attended CSUN last year in San Diego and it was eye-opening. I had attended Austin’s A11y meetup semi-regularly in the past, but until I had attended CSUN I had not realized how vast the world of accessibility is.

Innovations like Alexa and Google Assistant are mass-market products but also useful for making the digital world more accessible. Calculators that were designed digital-first like Desmos will likely improve math literacy over time by separating and eliminating the struggle to learn the calculator interface from the process of learning geometry or algebra.

Transformative technologies that can translate voice to text (Alexa, etc), Nemeth Braille to LaText (Pearson Equation Editor), and handwriting or speech to LaText (equatio by texthelp) are not only making learning accessible for everyone but changing the way all humans interact with computers.

Web Designer Depot Accessibility Article

Posted by on Jan 19, 2016 in UX, Web Design | No Comments

I wrote an article inspired by all that I have learned so far about accessibility on Web Designer Depot.

Patterns with Processing

Posted by on Sep 29, 2014 in Art, Code | No Comments

Over the last year or so I have been experimenting on and off with Processing, the programing platform for designers and artists. You can see the full potential of Processing in a book I recommend called Generative Gestaltung. But Processing doesn’t have to be used to create interactive prototypes or generative art. It can also be used to generate complex 2D patterns. The programs that created the images below are relatively easy to understand but still produce remarkable results.

Nested “for” loops were used in different combinations to create the patterns below. These programs (called processing “sketches”) create a set of x and y coordinates and replicate a line, shape or a pattern down and to the right across the x and y axis. In the Fish Scales image below the magic happens here:

for (int x = 0; x<=width; x+=20) // loop of x
  for (int y=0; y<=height; y+=20) // loop of y
     ellipse(x, y, 40, 40);

Above you will see “for” loops, one inside the other (with some extra code redacted). Basically a for loop sets a counter, tests for a condition, then iterates. The loop travels across the image, testing whether the sequence has have left the bottom or right edge of the image and adding new circles as it goes. I have linked the images of the Processing sketches to their authors (and code).

processing dot pattern Escher-like Processing Pattern Fish Scales Processing Pattern Plaid Processing Pattern Triangles Processing Pattern Truchet Processing Pattern Truchet Processing Pattern Truchet Processing Pattern Truchet Processing Pattern

Simply-List: iOS Web App with Local Storage

Posted by on Nov 15, 2013 in Code, Snippets, Web Design | No Comments

As Steve Jobs famously said, “Design is how it works.” The role of a Web designer increasingly requires some ability to write code because good design goes beyond appearances.

I built my own mobile web app to challenge myself to design a web app that would look and feel like a native iOS app. A todo list app makes a good beginner project. A warning, because my aim is targeting iOS it has not been designed to work on Firefox or IE:

Try Out Simply-List

Local storage is relatively new to the web, and a part of the HTML5 specification. It allows web applications to store more data on the client’s device than will fit in a cookie and retain it even if the user reloads the page. Local storage is currently supported by all major browsers except Opera Mini.

Apple’s HTML5 Offline Application Cache spec provides guidelines for creating offline web apps. Incorporating these guidelines into the web app mean that the app will not only store the user’s to-dos when they load the app in their browser but it will work when the user has no Internet connection. There are two main things that need are needed to make the app function offline on iOS. A link to a manifest file needs to be included at the top of the HTML document:

<html manifest="path/filename">

Add the following tags to instruct iOS to hide the status bar and tell iOS where to find the app’s startup and iOS icons:

<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta names="apple-mobile-web-app-status-bar-style"content="black"/>
<link rel="apple-touch-icon-precomposed" href="apple-touch-icon-precomposed.png" />

Some additional tags instruct iOS to hide the status bar and tell iOS where to find the app’s startup and iOS icon images. When the user saves the app to their home screen, it shows up there just like a native app. When the user launches the app, the startup screen fills the screen of their device while the app loads.

Creating the manifest file is not as complex as it may sound. A manifest file is just a text file that is served with the MIME type of “text/cache-manifest” and saved with a filename ending in “.manifest.” Here is an example:

# v20131109

# cache 


You can change the MIME type with your FTP program (or the command line). The manifest file is just a list of all the files your app needs to function offline.


The HTML structure is a container div surrounding a div for the todo list that contains a clear all button, header, and placeholder unordered list and an input form to add to the todo list. Simplicity is the goal so we omit an add button, instead an item will be added when the user exits the input field.


First we’ll create the function that runs the app (named Todos). This function will set most of the functions that will react to user input. The most important of these is the function below, bound to the change event on the input field (named description). This function will add whatever the user leaves in the form to the unordered list when the user exits the field and trigger the save function:

        $('#description').change( function() {
           var todo = $('#description').val();
           var listItems = $("#todos").children();
           var newID = listItems.length + 1;
           $('#todos').append("<li id='"+newID+"'><input id='checkbox"+newID+"'class='checkbox' type='checkbox'/><label for='todo"+newID+"'>" + todo + "</label><a class='delete-btn icon-cancel-7' id='delete-btn-"+newID+"'>Delete</a></li>");
           addSwipeTo("#todos li");
           return false;

The user’s input will be appended to the end of the list. The save function below will update local storage.

    var saveTodos = function() {
        $('li').each(function(i) {
            var todo = $(this).html();
            window.localStorage.setItem("ToDo:"+ (i+1), todo);

Creating a single save function means that this code won’t need to be re-written several times within the final app. All the local storage code will be within an if statement that checks whether the user’s browser supports local storage. The save function itself simply saves all the HTML content within each list item. Local storage can only save data in key value pairs. here we create a key by looping over the items in the list and adding “ToDo:” to the front of the incremental value (i) to avoid conflicts with any existing data in the user’s browser. The value corresponding to each key becomes the HTML content of each list item.


The appearance of the check mark and the strike-through effect are accomplished using CSS and an icon font. It’s a nice effect that I stumbled upon on CSS Deck. The CSS uses a :before pseudo-element to position an attractive blue check box over the default HTML checkbox (which is hidden) and a :after pseudo-element to cover the empty box with a check-mark icon when the user checks off an item. The description of the todo item is crossed off using the plain HTML strike-through property. The icon font from Fontello allows us to add a check-mark icon to checked off items without using a CSS sprite. Icon fonts are vectors so they will display at full resolution on any display without adjustments, they are also smaller than their CSS sprite equivalent. Fontello makes it easy to include icon fonts in web projects.

	.to-do-list input[type=checkbox] {
		cursor: pointer;
		position: relative;
		visibility: hidden;

The CSS above hides the HTML checkbox. The code below adds the custom checkbox icon after HTML checkbox and the strikethrough:

	.to-do-list input[type=checkbox]:checked:after {
                font-family: "todo";
                color: #999;
                font-size: 20px;
                font-weight: 100;
                /*absolutely positioned*/
                position: absolute; top: 0; left: 0;
		border: 2px solid #fff;
		color: #979797;
		content: '\e804';
	.to-do-list input[type=checkbox]:checked + label {
		color: #979797;
		font-weight: normal;
		text-decoration: line-through;

Mobile apps should support swipe gestures as well as tap/click equivalents. Luckily there are several libraries that allow us to detect swipe-events in mobile web apps. Here I use touch swipe to detect a generic right or left swipe gesture to show a delete button for over the swiped item. JQuery allows us to animate the appearance of the delete button. After the function has been defined it needs to be bound to the link items.

The delete button also uses our icon font for the “x” icon. The buttons already have event listeners and events attached to them in the ToDo function, shown below. When the user clicks on a delete button, the button’s parent list item’s ID is defined as a string, the ID is extracted from the end. We use slice here because we know the beginning of the list item’s ID will be prefixed with “todo” but we are not sure whether the ID will be one or two digits. We then search local storage for the item matching the ID and we remove it. The list item is then removed from the DOM with another JQuery animation. The complete JavaScript code is below:

(function() {
    //Enable swip to delete
    var addSwipeTo = function(selector) {  
            swipe:function(event, direction, distance, duration, fingerCount) {
                //console.log("You swiped " + direction );	
                if ( direction === 'left' || direction === 'right' ) {
                    (this).find('.delete-btn').animate({ opacity: 1, width: 'toggle' }, 200).addClass('open');
                } else { null }
            threshold:0 //Default is 75px, set to 0 so any distance triggers swipe
    var saveTodos = function() {
        $('li').each(function(i) {
            var todo = $(this).html();
            window.localStorage.setItem("ToDo:"+ (i+1), todo);
    addSwipeTo("#todos li");
    if (window.localStorage) {
        function retrieveToDos() {
            var i = 0;
            var k;
            if ( localStorage.length > 0 ) {
                for (i = 0; i <= localStorage.length; i++) {
                    k = localStorage.key(i);
                    if (/ToDo:d+/.test(k)) {
            } else {
                var isTouchDevice = function() {  return 'ontouchstart' in window || 'onmsgesturechange' in window; };
                if (isTouchDevice != 'true') {
                } else { null }
        } retrieveToDos();
        $('#description').change( function() {
           var todo = $('#description').val();
           var listItems = $("#todos").children();
           var newID = listItems.length + 1;
           $('#todos').append("<li id='"+newID+"'><input id='checkbox"+newID+"'class='checkbox' type='checkbox'/><label for='todo"+newID+"'>" + todo + "</label><a class='delete-btn icon-cancel-7' id='delete-btn-"+newID+"'>Delete</a></li>");
           addSwipeTo("#todos li");
           return false;
    } else {
        alert('your browser does not appear to support local storage');
    function ToDos() {
        var deletebtn = $('.delete-btn');
        deletebtn.css('opacity', 0);
        $('.delete-btn').live('click', function(e) {
            var str = $(this).attr("id");
            var id = str.charAt( str.length-1 );
            window.localStorage.removeItem("ToDo:"+ id);
            $(this).parent().animate({ opacity: 0.25, left: '+=50', height: 'toggle'}, 500);
        $(':checkbox').click( function() {
           var id = $(this).attr("id");
           if ($(this).is(':checked')) {
               $(this).attr('checked', 'checked');
               //console.log(id + ' is checked');
           } else {
               //console.log(id + ' is unchecked');
        $('#clear').click( function() {
            return false;
        addSwipeTo("#todos li");
    } // end ToDos function


HTML5 makes it possible to develop many different types of simple mobile apps using HTML, CSS, and JavaScript instead of Objective C or Java. For more info on how to Local storage check out the following:

How to use local storage for javascript

Refer to the following links to learn more about developing iOS web apps:


Offline Application Cache

A script is available below that generates an “add to home screen” reminder balloon to encourage repeat visitors to save the app on their device:

Add to Home Screen

Coffee Blog Post on RPA’s blog

Posted by on Feb 10, 2013 in Advertising | No Comments

In July I traveled to Costa Rica to attend a friend’s wedding. During the trip I was able to visit a coffee plantation. Ever since then I have thought about the visit whenever I fill my coffee cup at RPA. I wrote a short blog post about my experience on RPA’s culture blog.

Robert Egger

Posted by on Aug 6, 2012 in Design | No Comments

It’s always encouraging to hear a designer talk about what inspires them. Regardless of the field, design attracts people who are dedicated to making everything that they touch better.

Design ideas do seem to come directly from the experience of working with your hands, even if it just means sketching before heading to the computer.

Who killed the inactive button state? – Blog Post on UX Booth

Posted by on Jun 26, 2012 in UX | No Comments

A few weeks ago I was designing a web application that included a form. When it came time to design and spec the submit button and I realized that including an inactive (or disabled) state for submit button was not only unnecessary, but it would detract from the usability of the application. Please check out the blog post I wrote about inactive states on UXBooth.