About Us

Bulletpoint StarImulus® is a technology focused design + interactive agency.

In addition to our client services we also have a few products in the works. Our office is always filled with chatter and this blog is an outlet for our creative energy, rants and ideas.

Podium

Stacks!
Imulus built a task management solution that finally works for teams. It's a life saver, learn more at usestacks.com.

Featured Project

Dec26

“What’s Next in Web Design” Rebuttal

I recently read an article titled “What’s Next in Web Design.” The conclusion of the article states:

“Better interaction design, less graphic design. Better user experience, less debates about taste. Faster technology, more reliable design standards.”

What I find interesting is I’ve been seeing the opposite in web trends. With the introduction of more web friendly fonts and more flexibility in development, web design is starting to look more and more artistic and refined. Designers are able to explore their artistic roots with illustration, sketching, painting, etc.

When you look at a site that is so beautifully designed, it just makes you feel good. It’s the intangibles that can make a difference. Things that click tracking, heatmaps, and analytics can’t measure. I also find it interesting that, yes, of course the author is arguing the benefits of minimalist web design. Look at their site. Almost as minimalistic as it gets.

Minimalist design style has its place in web design, but it is far from the end-all for web design. Sites like Apple have been so successful because:
1. Their web design matches their brand style
2. They are able to display big, beautiful photography and not every company can afford that level of photography.
3. The amount of information they have packed into their website demands a simplistic design style in order not to overwhelm their audience.

While I agree that a design that is too cluttered and flowery can be extremely frustrating when I am looking for something specific, but why must it be one or the other? That is the challenge of web design: creating a web experience. Combining form and function so they work together seamlessly.

Would you hire an architect to design a building that meets the needs of keeping you warm and a roof over your head but is a plain box? No. You hire an architect to create something beautiful but still functions as a well structured building.

Bottom line, the minimalist approach works, but not for everyone, and not as often as many people think. Personally, I am seeing more creativity and interesting visuals than something flat and boring but usable. Pairing usability and beauty is a web designer’s job. So rather than casting off graphic design as unnecessary, I foresee it becoming more and more crucial.

Dec20

Beyond the Mouse: The Future of Computer Interaction

Having used computers for almost 30 years, and as a designer of interfaces, I often wonder what’s next. The mouse had been declared dead year ofter year, yet they continue to reign supreme. The recent videos from Microsoft have prompted a lot of discussion and there are often stories about the latest ideas in interface design. Many of these, including the Microsoft vision often champion a Minority Report like interface where the user manipulates an interface in front of them through touch or gestures. The Microsoft videos have tons of this type of interaction. While this is really cool to look at and may actually come to pass for certain applications, I don’t foresee anything like this for the typical desktop user being effective.
minority-report
The simple reason is laziness. Well, that may be a little harsh. It’s really a matter of muscle fatigue. Touch screen interfaces while very effective on phones and tablets have a serious flaw when it comes to traditional desktop work. Imagine having your arms constantly extended in front of you touching your screen for everything that you now use a mouse for. By the end of an 8 hour day you would be unable to lift your arms. If you put the screen down on the desk to alleviate the stress on your arms than you end up with a strained neck from looking down all day.
ms1
The reason keyboards and mice have been around for so long with little change is because they work. They allow the user to rest their arms on the desk and use very little muscular effort to interact with the computer. Any replacement for this arrangement must meet this need. I do see merit and opportunity in touch and gesture interfaces on the desk as an input for an upright screen. This still allows the user to look straight ahead and rest their arms on the desk, yet may allow for a more customized and varied system for input and manipulation. This type of system is explored in the Microsoft video and aspects are seen in ideas like Mouseless and the EXOpc.
ms2
The major advantage of this system is that it allows the interface to change according to the needs of the user and the context of the work they are doing. The options available when a user is working in Photoshop could be completely different from what would be available in Microsoft Word. And while touch interfaces are useful, they really won’t reach their potential until they gain a tactile element. A desktop that was adaptable and tactile would offer a much better experience for users and might finally spell the end for the venerable mouse. Until that day comes, mice will continue to inhabit the desks of the world.

Dec9

Reserved usernames to avoid vanity URL collision

As we continue to add support for more languages on our tech support management application, Support Details, one thing we’ve considered is how vanity URLs will impact the introduction of new features. In the short future we plan to add support for custom accounts, so it made sense to compile a list of usernames we’d reserve out of the gate to avoid collision in the future.

Here’s our running list:


reserved_usernames = [
	# Companies we'd love to have use our service
	# so we'll reserve them to be safe
	'supportdetails',
	'support-details',
	'stacks',
	'imulus',
	'github',
	'twitter',
	'facebook',
	'google',
	'apple',

	# Generic reserved words
	'about',
	'account',
	'activate',
	'add',
	'admin',
	'administrator',
	'api',
	'app',
	'apps',
	'archive',
	'archives',
	'auth',
	'blog',
	'cache',
	'cancel',
	'careers',
	'cart',
	'changelog',
	'checkout',
	'codereview',
	'compare',
	'config',
	'configuration',
	'connect',
	'contact',
	'create',
	'delete',
	'direct_messages',
	'documentation',
	'download',
	'downloads',
	'edit',
	'email',
	'employment',
	'enterprise',
	'faq',
	'favorites',
	'feed',
	'feedback',
	'feeds',
	'fleet',
	'fleets',
	'follow',
	'followers',
	'following',
	'friend',
	'friends',
	'gist',
	'group',
	'groups',
	'help',
	'home',
	'hosting',
	'hostmaster',
	'idea',
	'ideas',
	'index',
	'info',
	'invitations',
	'invite',
	'is',
	'it',
	'job',
	'jobs',
	'json',
	'language',
	'languages',
	'lists',
	'login',
	'logout',
	'logs',
	'mail',
	'map',
	'maps',
	'mine',
	'mis',
	'news',
	'oauth',
	'oauth_clients',
	'offers',
	'openid',
	'order',
	'orders',
	'organizations',
	'plans',
	'popular',
	'post',
	'postmaster',
	'privacy',
	'projects',
	'put',
	'recruitment',
	'register',
	'remove',
	'replies',
	'root',
	'rss',
	'sales',
	'save',
	'search',
	'security',
	'sessions',
	'settings',
	'shop',
	'signup',
	'sitemap',
	'ssl',
	'ssladmin',
	'ssladministrator',
	'sslwebmaster',
	'status',
	'stories',
	'styleguide',
	'subscribe',
	'subscriptions',
	'support',
	'sysadmin',
	'sysadministrator',
	'terms',
	'tour',
	'translations',
	'trends',
	'unfollow',
	'unsubscribe',
	'update',
	'url',
	'user',
	'weather',
	'webmaster',
	'widget',
	'widgets',
	'wiki',
	'ww',
	'www',
	'wwww',
	'xfn',
	'xml',
	'xmpp',
	'yaml',
	'yml',

	# Top 50 languages by speaking population
	'chinese',
	'mandarin',
	'spanish',
	'english',
	'bengali',
	'hindi',
	'portuguese',
	'russian',
	'japanese',
	'german',
	'wu',
	'javanese',
	'korean',
	'french',
	'vietnamese',
	'telugu',
	'chinese',
	'marathi',
	'tamil',
	'turkish',
	'urdu',
	'min-nan',
	'jinyu',
	'gujarati',
	'polish',
	'arabic',
	'ukrainian',
	'italian',
	'xiang',
	'malayalam',
	'hakka',
	'kannada',
	'oriya',
	'panjabi',
	'sunda',
	'panjabi',
	'romanian',
	'bhojpuri',
	'azerbaijani',
	'farsi',
	'maithili',
	'hausa',
	'arabic',
	'burmese',
	'serbo-croatian',
	'gan',
	'awadhi',
	'thai',
	'dutch',
	'yoruba',
	'sindhi',

	# Country TLDs
	'ac',  # Ascension Island
	'ad',  # Andorra
	'ae',  # United Arab Emirates
	'af',  # Afghanistan
	'ag',  # Antigua and Barbuda
	'ai',  # Anguilla
	'al',  # Albania
	'am',  # Armenia
	'an',  # Netherlands Antilles
	'ao',  # Angola
	'aq',  # Antarctica
	'ar',  # Argentina
	'as',  # American Samoa
	'at',  # Austria
	'au',  # Australia
	'aw',  # Aruba
	'ax',  # and
	'az',  # Azerbaijan
	'ba',  # Bosnia and Herzegovina
	'bb',  # Barbados
	'bd',  # Bangladesh
	'be',  # Belgium
	'bf',  # Burkina Faso
	'bg',  # Bulgaria
	'bh',  # Bahrain
	'bi',  # Burundi
	'bj',  # Benin
	'bm',  # Bermuda
	'bn',  # Brunei Darussalam
	'bo',  # Bolivia
	'br',  # Brazil
	'bs',  # Bahamas
	'bt',  # Bhutan
	'bv',  # Bouvet Island
	'bw',  # Botswana
	'by',  # Belarus
	'bz',  # Belize
	'ca',  # Canada
	'cc',  # Cocos (Keeling) Islands
	'cd',  # Democratic Republic of the Congo
	'cf',  # Central African Republic
	'cg',  # Republic of the Congo
	'ch',  # Switzerland
	'ci',  # Côte d'Ivoire
	'ck',  # Cook Islands
	'cl',  # Chile
	'cm',  # Cameroon
	'cn',  # People's Republic of China
	'co',  # Colombia
	'cr',  # Costa Rica
	'cs',  # Czechoslovakia
	'cu',  # Cuba
	'cv',  # Cape Verde
	'cx',  # Christmas Island
	'cy',  # Cyprus
	'cz',  # Czech Republic
	'dd',  # East Germany
	'de',  # Germany
	'dj',  # Djibouti
	'dk',  # Denmark
	'dm',  # Dominica
	'do',  # Dominican Republic
	'dz',  # Algeria
	'ec',  # Ecuador
	'ee',  # Estonia
	'eg',  # Egypt
	'eh',  # Western Sahara
	'er',  # Eritrea
	'es',  # Spain
	'et',  # Ethiopia
	'eu',  # European Union
	'fi',  # Finland
	'fj',  # Fiji
	'fk',  # Falkland Islands
	'fm',  # Federated States of Micronesia
	'fo',  # Faroe Islands
	'fr',  # France
	'ga',  # Gabon
	'gb',  # United Kingdom
	'gd',  # Grenada
	'ge',  # Georgia
	'gf',  # French Guiana
	'gg',  # Guernsey
	'gh',  # Ghana
	'gi',  # Gibraltar
	'gl',  # Greenland
	'gm',  # The Gambia
	'gn',  # Guinea
	'gp',  # Guadeloupe
	'gq',  # Equatorial Guinea
	'gr',  # Greece
	'gs',  # South Georgia and the South Sandwich Islands
	'gt',  # Guatemala
	'gu',  # Guam
	'gw',  # Guinea-Bissau
	'gy',  # Guyana
	'hk',  # Hong Kong
	'hm',  # Heard Island and McDonald Islands
	'hn',  # Honduras
	'hr',  # Croatia
	'ht',  # Haiti
	'hu',  # Hungary
	'id',  # Indonesia
	'ie',  # Republic of Ireland  Northern Ireland
	'il',  # Israel
	'im',  # Isle of Man
	'in',  # India
	'io',  # British Indian Ocean Territory
	'iq',  # Iraq
	'ir',  # Iran
	'is',  # Iceland
	'it',  # Italy
	'je',  # Jersey
	'jm',  # Jamaica
	'jo',  # Jordan
	'jp',  # Japan
	'ke',  # Kenya
	'kg',  # Kyrgyzstan
	'kh',  # Cambodia
	'ki',  # Kiribati
	'km',  # Comoros
	'kn',  # Saint Kitts and Nevis
	'kp',  # Democratic People's Republic of Korea
	'kr',  # Republic of Korea
	'kw',  # Kuwait
	'ky',  # Cayman Islands
	'kz',  # Kazakhstan
	'la',  # Laos
	'lb',  # Lebanon
	'lc',  # Saint Lucia
	'li',  # Liechtenstein
	'lk',  # Sri Lanka
	'lr',  # Liberia
	'ls',  # Lesotho
	'lt',  # Lithuania
	'lu',  # Luxembourg
	'lv',  # Latvia
	'ly',  # Libya
	'ma',  # Morocco
	'mc',  # Monaco
	'md',  # Moldova
	'me',  # Montenegro
	'mg',  # Madagascar
	'mh',  # Marshall Islands
	'mk',  # Republic of Macedonia
	'ml',  # Mali
	'mm',  # Myanmar
	'mn',  # Mongolia
	'mo',  # Macau
	'mp',  # Northern Mariana Islands
	'mq',  # Martinique
	'mr',  # Mauritania
	'ms',  # Montserrat
	'mt',  # Malta
	'mu',  # Mauritius
	'mv',  # Maldives
	'mw',  # Malawi
	'mx',  # Mexico
	'my',  # Malaysia
	'mz',  # Mozambique
	'na',  # Namibia
	'nc',  # New Caledonia
	'ne',  # Niger
	'nf',  # Norfolk Island
	'ng',  # Nigeria
	'ni',  # Nicaragua
	'nl',  # Netherlands
	'no',  # Norway
	'np',  # Nepal
	'nr',  # Nauru
	'nu',  # Niue
	'nz',  # New Zealand
	'om',  # Oman
	'pa',  # Panama
	'pe',  # Peru
	'pf',  # French Polynesia
	'pg',  # Papua New Guinea
	'ph',  # Philippines
	'pk',  # Pakistan
	'pl',  # Poland
	'pm',  # Saint-Pierre and Miquelon
	'pn',  # Pitcairn Islands
	'pr',  # Puerto Rico
	'ps',  # Palestinian territories
	'pt',  # Portugal
	'pw',  # Palau
	'py',  # Paraguay
	'qa',  # Qatar
	're',  # Réunion
	'ro',  # Romania
	'rs',  # Serbia
	'ru',  # Russia
	'rw',  # Rwanda
	'sa',  # Saudi Arabia
	'sb',  # Solomon Islands
	'sc',  # Seychelles
	'sd',  # Sudan
	'se',  # Sweden
	'sg',  # Singapore
	'sh',  # Saint Helena
	'si',  # Slovenia
	'sj',  # Svalbard and  Jan Mayen Islands
	'sk',  # Slovakia
	'sl',  # Sierra Leone
	'sm',  # San Marino
	'sn',  # Senegal
	'so',  # Somalia
	'sr',  # Suriname
	'ss',  # South Sudan
	'st',  # São Tomé and Príncipe
	'su',  # Soviet Union
	'sv',  # El Salvador
	'sy',  # Syria
	'sz',  # Swaziland
	'tc',  # Turks and Caicos Islands
	'td',  # Chad
	'tf',  # French Southern and Antarctic Lands
	'tg',  # Togo
	'th',  # Thailand
	'tj',  # Tajikistan
	'tk',  # Tokelau
	'tl',  # East Timor
	'tm',  # Turkmenistan
	'tn',  # Tunisia
	'to',  # Tonga
	'tp',  # East Timor
	'tr',  # Turkey
	'tt',  # Trinidad and Tobago
	'tv',  # Tuvalu
	'tw',  # Republic of China (Taiwan)
	'tz',  # Tanzania
	'ua',  # Ukraine
	'ug',  # Uganda
	'uk',  # United Kingdom
	'us',  # United States of America
	'uy',  # Uruguay
	'uz',  # Uzbekistan
	'va',  # Vatican City
	'vc',  # Saint Vincent and the Grenadines
	've',  # Venezuela
	'vg',  # British Virgin Islands
	'vi',  # United States Virgin Islands
	'vn',  # Vietnam
	'vu',  # Vanuatu
	'wf',  # Wallis and Futuna
	'ws',  # Samoa
	'ye',  # Yemen
	'yt',  # Mayotte
	'yu',  # Yugoslavia
	'za',  # South Africa
	'zm',  # Zambia
	'zw'   # Zimbabwe
]

It is a merged list of the recommendations from this Quora discussion, this list of country TLDs and
this list of languages

How to Contribute:
Gist: https://gist.github.com/1453705

Dec1

Powder: A Backbone-powered iPad webapp

Powder screenshot

Winter is upon us, and like many folks in Colorado we’re stoked to hit the mountains. Given the recent snowfall and our experimentation with HTML5 localStorage, it seemed natural to push it a bit further and do something fun.

Enter Powder, an HTML5 webapp for tracking the snow conditions at your favorite ski resorts.

Powder is an experiment using backbone.js to power an iPad webapp. On the client, Powder uses the browser’s native HTML5 localStorage mechanism to save the users’s preferences, the list of resorts the user chooses to track. On the server, Powder uses Sinatra to fetch and parse various snow/ski reports from http://onthesnow.com/ then serve it up as JSON to the browser.

The Stack

Powder is free and open source, hosted on GitHub. We’d love to have you join us in making Powder better. Feel free to fork the project and help us make a kickass iPad webapp.

Nov28

An Interesting Challenge

Last week we had a client call us with an interesting problem. They have a tradeshow kiosk they’d like to use to capture form data from users and collect it at the end of each day.

The challenge: the kiosk doesn’t have an internet connection and can’t run a webserver. It can display webpages, but only through an IE8 iframe.

If the kiosk had a net connection we’d build a static form to post the data to a remote webservice. But that’s out. If the kiosk could run a webserver we’d build a simple webapp to handle the data locally. But that’s out, too.

We decided to solve the problem by saving the data to localStorage. localStorage is a key-value store built into most modern browsers, and a perfect mechanism for persisting simple form data. It has a minimal JavaScript API (setters and getters) via the window’s localStorage object that makes it really easy to work with.

Here’s how we did it:

We started by setting up a simple Storage class to interface with localStorage. This isn’t entirely necessary, but makes it easier to save and retrieve the data without having to parse/stringify on every transaction. (Yes, we love CoffeeScript.)


class Storage

  constructor: (@name)->
    @data = []

    # Check to see if the object already
    # exists in localStorage
    # If it does, grab the value
    # Otherwise, create a key in localStorage
    # with an empty array of data
    if localStorage[@name]?
      do @fetch
    else
      # We need to stringify the data as JSON
      # because it is stored as a string
      localStorage.setItem(@name, JSON.stringify(@data))

  # Pull the data out of localStorage and populate
  # the instance's @data array property
  # We need to parse the data as JSON
  # because it is stored as a string
  fetch: ->
    @data = JSON.parse(localStorage.getItem(@name))

  # Add an item to the instance's @data array and
  # re-save to localStorage
  add: (data) ->
    @data.push data
    localStorage.setItem(@name, JSON.stringify(@data))

Next, we set up a Form class to observe the form on the page and do some simple validation before finally committing it to a storage instance.


class Form

  constructor: (@$form, name)->
    @storage  = new Storage(name)
    @$fields  = $('input, textarea, select', @$form)

    @$form.submit (event) =>
      event.preventDefault()
      if @validate()
        do @save
        do @clear

  save: ->
    data = {}

    @$fields.each ->
      name  = $(this).attr('name')
      value = $(this).val()
      data[name] = value

    @storage.add data

  clear: ->
    @$fields.each ->
      $field = $(this)
      type = $field.attr('type')
      $field.val('') if type is 'text'

  validate: ->
    data = {}
    valid = true

    # Simple 'required' validation
    # Loop over each of the form fields
    # If the field is required, then check to see if it is blank
    @$fields.each ->
      $field = $(this)
      value = $field.val()
      required = $field.hasClass('required')
      if required and value is ''
        valid = false
        $field.addClass('invalid')
      else
        $field.removeClass('invalid')

    return valid

The client needed a means of retrieving the data, so we set up way to grab all of the data and render out a table with each of the entries.


class ResultsTable
  constructor: (@$table, name) ->
    @storage  = new Storage(name)
    @results = @storage.data
    $head_tr = $('<tr />')

    for field, value of @results[0]
      $head_tr.append $('<td />').text(field)

    $('thead', @$table).append $head_tr

    for result in @results
      $tr = $('<tr />')
      $tr.append $('<td />').text(value) for field, value of result
      $('tbody', @$table).append $tr

Finally, an example of how to pull it all together.

On the form page:


<form id="user-form" action="#">
  <input type="text" name="first_name" />
  <input type="text" name="last_name" />
  <button type="submit">Submit</button>
</form>

<script type="text/javascript">
  $(document).ready(function(){
    new Form($('form#user-form'), 'kiosk');
  });
</script>

On the results page:


<table id="results">
</table>

<script type="text/javascript">
  $(document).ready(function(){
    new ResultsTable($('#results'), 'kiosk');
  });
</script>

Given the constraints, we feel like this is great solution. Lucky for us, the browser environment was predictable and IE8 has support for localStorage. All in all, it was a fun experiment with localStorage.