Tim Kjær Lange

GrabFood Design Lead

New File in Finder.app

January 9 · 2017

It's possible to create new folders in Finder.app, but creating files are not supported. I've created a Keyboard Maestro macro that lets you spawn new files at will:

If you're not familiar with Keyboard Maestro it's a tool similar to Automator, that allows you to create macros that can be triggered in a number of ways e.g. when a hot key is pressed. In this case I've mapped the "New File…" macro to ⌘⌥N.

Download the macro: New-File.kmlibrary

Comment on this article.

Running with Alexa Pt. 1

June 26 · 2016

TLDR: Learn a bit of Python and you can create a custom skill with Flask-ask in a breeze.

They yell down on us from their high horses: Designers shouldn’t code. Designers should pound the drum and developers should dance to the beat. Well, I've been dancing a secret proverbial tango with Python lately.

This is my first step outside of the Python Hello World sandbox. I recently came upon an Amazon Echo and I was curious to see if I could create my own skill. As much as I enjoy receiving flash briefings from NPR, I wanted to do more. I wanted Alexa to keep track of my daily run:

John Wheeler’s Flask-Ask framework makes it easy to create Alexa Skills. If you’re interested in creating your own skills I would highly recommend that you pony up the $15 and buy his Alexa tutorial videos. It’s an absolute bargain.

Creating the VUI flow

VUI is an acronym I learned last week, it stands for Verbal User Interface. Here's the VUI flowchart for the Run Log skill:

This is a simplistic VUI, but it will suffice for our proof-of-concept purposes.

Setting up the development environment

Follow John's tutorial to get up and running with Flask-Ask:

My IntentSchema and SampleUtterances are very simple for this proof-of-concept skill. I use Amazon's own AMAZON.DURATION slot type that makes it possible for the user to utter a workout duration and easy for us to parse that duration:

{
  "intents": [
    {
      "intent": "DurationIntent",
      "slots": [
        {
          "name": "duration",
          "type": "AMAZON.DURATION"
        }
      ]
    }
  ]
}

Response template

Let me a reveal a secret here: Alexa is not a personal assistant. Alexa is a voice terminal robot and we have to stand on the edge of the scene and feed her lines to create the illusion of dialogue. These lines live in the Jinja template:

welcome: "How long did your workout take?"

welcome_reprompt: "I did not catch that. How many minutes did your workout take?"

run_logged: "OK, I have logged {{ minutes }} minutes, {{ seconds }} seconds."

personal_best: "{{ minutes }} minutes, {{ seconds }} seconds. That is a new personal best. Congratulations tiger!"

personal_worst: "{{ minutes }} minutes, {{ seconds }} seconds. That is a new personal worst. Please up your game."

This is how the responses map to our VUI flowchart:

Adding some audio flavor

Plain text strings can get you a long way, but for more advanced speech features SSML is required. SSML is a markup language that is tailored to the creation of synthetic speech, it provides some impressive features like phonemic pronunciation. Very handy if you want to mention Arsenal's goal-keeper Wojciech Szczęsny in your skill.

I used the audio tag in my skill, to play a sad trombone when you log a personal worst and an upbeat sax riff if you log a personal best:

personal_best: <speak><audio src="https://s3-us-west-1.amazonaws.com/run-log/best.mp3" />{{ minutes }} minutes, {{ seconds }} seconds. That is a new personal best. Congratulations tiger!</speak>

personal_worst: <speak><audio src="https://s3-us-west-1.amazonaws.com/run-log/worst.mp3" />{{ minutes }} minutes, {{ seconds }} seconds. That is a new personal worst. Please up your game.</speak>

This proved more difficult than expected, Alexa doesn't take any old mp3. I had to encode the mp3 in ffmpeg using these parameters:

ffmpeg -i input.mp3 -b:a 48k -ar 16000 output.mp3

Skill logic

The logic lives in the alexa-runlog.py script. The launch decorator determines what Alexa should do when the skill is launched:

@ask.launch
def launch():
    welcome_msg = render_template('welcome')
    return question(welcome_msg)

The intent decorator determines what happens after the user has replied with the run duration:

@ask.intent("DurationIntent", convert={'duration': 'timedelta'})
    '''
    Parsing and writing the duration to a CSV file…
    '''
    if(personal_best > duration):
        return statement(personal_best_msg)
    if(personal_worst < duration):
        return statement(personal_worst_msg)
    else:
        return statement(logged_msg)

Next steps

This is a crude prototype. There's many tasks to complete before the skill is ready for public consumption:

All to come in Running with Alexa Pt. 2.

Comment on this article.

Annotation markers

January 24 · 2016

I often find that I need to add annotation icons to a mockup, to explain what is going on.

I like Skitch's annotation style. The annotations stand out from the mockup - you're not in doubt what is the annotation and what is the actual mockup.

Annotation Markers (Sketch).
Annotation Markers (Axure library).

Comment on this article.

iOS installing animation

October 25 · 2015

iOS is full of interesting interaction animations, one of my favorites is the installing animation.

I've recreated the effect with CSS:

See the Pen iOS installing animation by Tim Kjær Lange (@timkl) on CodePen.

The approach is inspired by the work of Lea Verou. I'm reading her book CSS Secrets at the moment.

The first part of the animation is achieved by giving a SVG a stroke-width and then animating the stroke-dasharray.

The second part uses a radial-gradient background with a sudden color-stop. The background is scaled to encompass the entire square.

Comment on this article.

Lighten & Darken with LESS

May 25 · 2015

I had a LESS file full of color variables and it looked something like this:

@color-blue: #0070b9
@color-blue-dark: #003b7f
@color-blue-light: #0079c2
@color-blue-extra-light: #0080cb
@color-blue-xx-light: #9ee0ff
etc.

My need for additional color tints grew and so did the length of the variable names. Say hi to @color-blue-very-very-light! There was a another problem: if I wanted to change the hue of @color-blue I would have to change each and every tint.

An unsustainable situation. Today I found out that LESS (and Sass for that matter) has a lighten and a darken function. That means that I can have a master color (e.g. @color-blue) and use lighten and darken to create the tints:

See the Pen EjZRwN by Tim Kjær Lange (@timkl) on CodePen.

Comment on this article.

Sweet complexity

Jan 5 · 2015

It's hypnotic, to watch the guitarist move her hands over the fretboard. It's been a struggle for her, to achieve this man/machine symbiosis, but it was worth it.

Vim is a text editor, but it's not exactly MS Word. To say that Vim has a steep learning curve would be an understatement. Learning Vim is an investment, but it's an investment that pays fine dividents. Watching a Vim master type is like watching the guitarist pick chords.

As UX Designers we're all about ease-of-use, but who's going to invent the complex tools for tomorrows guitar heroes? Who's going to invent the next guitar, the next Vim?

I'm not arguing that complexity is a goal in itself, but neither is limiting complexity where it is needed.

Comment on this article.

Fischer Random Fun

Dec 5 · 2014

In the beginning it's all play. The designers of games are trying things out - having fun, creating. They invent throw-ins, castling and chequered flags. Slowly the games solidify, status quo creeps in, it's business as usual. That's why we can't have a special rule for diving in the penalty area, where you have to wear a ballerina outfit for the rest of the match.

The traditionalists are against ballerina outfits in football games. They want things to be like the last time we played - it was a 1-1 draw and John fell asleep in front of the TV. In another world 1500 years ago, someone woke up, had breakfast and invented chess. For two weeks chess was soft, like clay - nobody cared about memorizing opening variants. A five year old chess prodigy is reading up on the Sicilian right now, but she would have more fun playing Fischer Random Chess, where the pieces on the first row are shuffled. Pokemon figurine to B4 - checkmate!

Comment on this article.