       hubo.canvas.render()
 
       # Update FPS counter
-      stats.end();
-      stats.begin();
-
-    # GAH! What a horrible hack
-    window.updateModel = updateModel
-    setUpdateHook()
+      LIVE.stats.end();
+      LIVE.stats.begin();
+
+    # Deferred connection established callback
+    LIVE.connectionEstablished.done () ->
+      if (LIVE.use_socket)
+        LIVE.socket.on 'serial_state', (serial_state) ->
+          LIVE.serial_state = serial_state
+          # LED status indicator
+          LIVE.flashLED()
+          updateModel(serial_state)
 
     $('input[name="angle-source"]:radio').on 'change', () ->
       console.log('Radio Changed')
-      updateModel(window.serial_state)
+      updateModel(LIVE.serial_state)
 
     $('#fullscreen-button').on 'click', () ->
       if (document.webkitFullscreenEnabled)

    # Deprecated for now by server-side timeouts watching state.time.
    # Might still be needed to reestablish client connections at some point?
    # $('#fix-button').on 'click', () ->
    #   connectToServer()
    #   console.log('Resetting hubo-ach...')
    #   socket.emit('reset-ach',{jawn: true})

    $(document).on 'webkitfullscreenchange', () ->
      setTimeout(adaptCanvasSize, 500)

    # Update the rendering to reflect any changes to Hubo.
    c.render()
  , progress = (step, total, node) ->
    $("#load").html "Loading " + step + "/" + total
  )

    hubo.ft.HUBO_FT_L_FOOT.axis.position = new THREE.Vector3(-0.05,0,-0.11)
    # Place floor slightly below foot axis.
    c.render() # Needed to force foot axis matrix to update.
    LIVE.floor.position.z = hubo.ft.HUBO_FT_L_FOOT.axis.localToWorld(new THREE.Vector3(0,0,-0.01)).z
    # # Looks like the wrists need some rotation too.
    # hubo.ft.HUBO_FT_R_HAND.axis.rotation.y = -Math.PI/2
    # hubo.ft.HUBO_FT_L_HAND.axis.rotation.y = -Math.PI/2

    updateModel = (serial_state) ->
      if (not serial_state? or serial_state == "")
        return

      state = JSON.parse(serial_state);
