Prototyping 3D Touch interactions

September 25, 2015

This is a guest article by George Kedenburg III and cross posted to Medium.

Like most of my designer friends, I recently went through my annual September ritual — new iPhone day. Usually, these new devices are just solid hardware updates, with some OS level goodies thrown in (like Siri or Notification Center). However, this year was a special one: Apple has #blessed us with an entirely new interaction paradigm in the form of 3D Touch. After playing with my 6S+ for a couple hours, and really feeling the level of nuance 3D touch affords, I was sold. My mind was on 🔥🔥🔥 with thoughts of all the crazy possibilities! But in order to really explore it deeply, I needed to figure out how to get this integrated with Framer.

– This is the part where you ooh and aah (gif via The Verge).

Heading home from work that day, I started in the most obvious place: Apple’s Developer Site. I quickly found what looked like exactly what I needed: “WebKit DOM Programming Topics: Responding to Force Touch Events.” I spent about a half an hour trying every different method to take advantage of Apple’s recommended “webkitmouseforce” events, but no luck. If their documented method for getting Force Touch events wasn’t working, I just assumed they we’re completely blocking Safari from all the 3D Touch fun.

– At this point it seemed pretty hopeless tbh.

Luckily, I’m not one to give up easily. As soon as I got home, I sat down at my desk, put on some thinking music, and dove deeper. After a lot of random finger mashing on my phone, roughly a bajillion console.log’s, and a little bit of luck, I had found the holy 3D grail.

– This one little line.

Surprisingly, Apple was actually using the standard (and well documented) Touch API to report pressure back to the client. Excited to share my findings with the Framer group, I quickly put together a little pressure sensitive demo.

Everyone loved it! But there was a problem.

I chose to build this specific demo because I had come across a big wall in my initial exploration—none of the touch events would fire on force pressure changes. The only continuously firing touch event (touchmove) responded to you moving your finger around on the screen. This worked great for something like a drawing app, but it made things where your finger doesn’t move, like the app action shortcut, impossible. I was about to be late for dinner with some friends, so I decided that figuring this out could wait.

The Next Day

I woke up in the morning and immediately jumped back in to solving the latency issue. I tried all sorts of off-the-wall solutions, and then finally at roughly 10:30am I found one that worked.

– What a time to be alive.

The solution was extremely hacky, but it worked flawlessly.

– This initial proof of concept is butter smooth

I was shocked at how simple the solution was. All I had to do was trap the Touch Event on touchstart, and manually keep pinging it inside an interval to get new force data. This is all the code needed for that proof of concept:

# basic setup of layers 
test = new Layer width: Screen.widthheight: Screen.height
circle = new Layer
forceValue = new Layer width: Screen.width
forceValue.html = "0" =
    textAlign: "center"
    lineHeight: forceValue.height + "px"
# make a holder for the current touch 
currentTouch = null
# on the beginning of a touch 
test.on "touchstart"(e) ->
    # trap the new touch event in currentTouch 
    currentTouch = e
# and at the end of the touch 
test.on "touchend"->
    # unset the currentTouch 
    currentTouch = null
# 100 times a second, check if there's touch in progress 
Utils.interval 1/100->
    # and if there is one 
    if currentTouch
        # ask for its latest force value 
        force = currentTouch.touches[0].force
        # and do something with it 
        forceValue.html = force
        newScale = Utils.modulate(force[0,1][1,5])
        circle.scale = newScale

Armed with a functional solution, I immediately got to work trying to replicate a system level interaction: the app shortcuts.

And after that, to complete the set, I built out the Safari peek/pop interaction. This was a little more involved than the app shortcut, requiring multiple actions depending on the pressure applied.

This whole experience really solidified my love for Framer. In a couple of hours, I was able to build a basic 3D Touch proof of concept, on the day this new technology launched to the world. Day one! I can’t stress that enough. I didn’t have to wait for Framer to ship an update unlocking this functionality. All I needed was a little bit of google-fu, my pre-existing Framer/JS knowledge, and some determination to figure it out.

And now, with these three demos, there is a solid foundation available for people who want to start exploring 3D Touch. Within a day of releasing this, Jordan Dobson has already taken my examples and wrapped them up in to a simple, drop-in module for anyone to use. I’m so excited to see what you all can build from this, and I’m definitely looking forward to this next generation of interactions.

Did you build something cool with 3D Touch and Framer? I’d love to see it! Give me a shout on Twitter.

Example Projects

Other Framer posts from George