diff --git a/hsqml-morris.cabal b/hsqml-morris.cabal
--- a/hsqml-morris.cabal
+++ b/hsqml-morris.cabal
@@ -1,10 +1,10 @@
 Name:          hsqml-morris
-Version:       0.1.0
+Version:       0.2.0.0
 Cabal-version: >= 1.10
 Build-type:    Simple
 License:       BSD3
 License-file:  LICENSE
-Copyright:     (c) 2012 Robin KAY
+Copyright:     (c) 2012-2013 Robin KAY
 Author:        Robin KAY
 Maintainer:    komadori@gekkou.co.uk
 Stability:     experimental
@@ -25,12 +25,13 @@
         Morris.Board
     Build-depends:
         base       == 4.*,
-        containers == 0.4.*,
-        directory  == 1.1.*,
-        network    == 2.3.*,
+        containers >= 0.4 && < 0.6,
+        deepseq    >= 1.2 && < 1.4,
+        directory  >= 1.1 && < 1.3,
+        tagged     >= 0.4 && < 0.8,
         OddWord    == 1.0.*,
-        hsqml      == 0.1.*
+        hsqml      == 0.2.*
 
 Source-repository head
     type:     darcs
-    location: https://patch-tag.com/r/komadori/hsqml-morris
+    location: http://hub.darcs.net/komadori/hsqml-morris
diff --git a/qml/morris.js b/qml/morris.js
--- a/qml/morris.js
+++ b/qml/morris.js
@@ -73,18 +73,24 @@
     var d = isPlayerAI(game.player);
     if (d > 0) {
         if (0 == aiMove.length) {
-            var move = game.getAIMove(d);
-            for (var j=move.count-1; j>=0; j--) {
-                aiMove.push(move.elem(j));
-            }
+            game.aiReady.connect(aiReadyCallback);
+            game.startAI(d);
         }
-        if (0 != aiMove.length) {
+        else {
             selectTarget(aiMove.pop());
         }
     }
     else {
         updateTargets();
     }
+}
+
+function aiReadyCallback(move)
+{
+    for (var j=move.count-1; j>=0; j--) {
+        aiMove.push(move.elem(j));
+    }
+    animFinished();
 }
 
 function isPlayerAI(p)
diff --git a/src/Morris/Board.hs b/src/Morris/Board.hs
--- a/src/Morris/Board.hs
+++ b/src/Morris/Board.hs
@@ -1,5 +1,6 @@
 module Morris.Board where
 
+import Control.DeepSeq
 import Data.Word
 import Data.Word.Odd
 import Data.Bits
@@ -13,6 +14,8 @@
 newtype Board = Board Word64 deriving (Eq, Ord, Show)
 
 newtype Position = Position Int deriving (Eq, Ord, Show)
+
+instance NFData Position
 
 data FirstAction
     = Place Position
diff --git a/src/Morris/Main.hs b/src/Morris/Main.hs
--- a/src/Morris/Main.hs
+++ b/src/Morris/Main.hs
@@ -4,8 +4,12 @@
 import Morris.Board
 
 import Graphics.QML
+import Control.Concurrent
+import Control.DeepSeq
+import Control.Exception
 import Data.Maybe
 import Data.List
+import Data.Tagged
 import Data.Typeable
 import Data.IntMap (IntMap)
 import qualified Data.IntMap as IntMap
@@ -85,9 +89,9 @@
         defMethod "elem" posListElem,
         defPropertyRO "count" posListCount]
 
-instance MarshalThis PosListObj where
-    type ThisObj PosListObj = PosListObj
-    mThis = objectThisMarshaller
+instance Marshal PosListObj where
+    type MarshalMode PosListObj = ValObjToOnly PosListObj
+    marshaller = objSimpleMarshaller
 
 data GameObj = GameObj {
     gameBoard :: Board,
@@ -114,10 +118,13 @@
 getActions gs =
     newObject $ PosListObj $ gameActions gs
 
-getAIMove :: GameObj -> Int -> IO (ObjRef PosListObj)
-getAIMove gs d =
-    newObject $ PosListObj $
-    maybe [] moveToPositions $ aiMove d (gameBias gs) $ gameBoard gs
+startAI :: ObjRef GameObj -> Int -> IO ()
+startAI gsRef d = fmap (const ()) $ forkIO $ do
+    let gs = fromObjRef gsRef
+        ps = maybe [] moveToPositions $ aiMove d (gameBias gs) $ gameBoard gs
+    evaluate $ force ps
+    posObj <- newObject $ PosListObj ps
+    fireSignal (Tagged gsRef :: Tagged AIReady (ObjRef GameObj)) posObj
 
 selectTarget :: GameObj -> Int -> IO (ObjRef GameObj)
 selectTarget gs i =
@@ -162,20 +169,26 @@
         Nothing -> -1
         Just (_,Position pos) -> pos
 
+data AIReady deriving Typeable
+
+instance SignalKey AIReady where
+    type SignalParams AIReady = ObjRef PosListObj -> IO ()
+
 instance Object GameObj where
     classDef = defClass [
         defPropertyRO "player" getPlayer,
         defPropertyRO "targets" getTargets,
         defPropertyRO "actions" getActions,
-        defMethod "getAIMove" getAIMove,
+        defMethod "startAI" startAI,
+        defSignal (Tagged "aiReady" :: Tagged AIReady String),
         defMethod "selectTarget" selectTarget,
         defPropertyRO "indexCount" getIndexCount,
         defMethod "idxPlayer" getPlayerAtIndex,
         defMethod "idxPosition" getPositionAtIndex]
 
-instance MarshalThis GameObj where
-    type ThisObj GameObj = GameObj
-    mThis = objectThisMarshaller
+instance Marshal GameObj where
+    type MarshalMode GameObj = ValObjToOnly GameObj
+    marshaller = objSimpleMarshaller
 
 createGame :: ObjRef MainObj -> IO (ObjRef GameObj)
 createGame _ =
@@ -191,9 +204,8 @@
 main = do
     ctx <- newObject $ MainObj
     qml <- getDataFileName "morris.qml"
-    createEngine defaultEngineConfig {
+    runEngineLoop defaultEngineConfig {
         initialURL = filePathToURI qml,
         initialWindowState = ShowWindowWithTitle "HsQML Morris",
-        contextObject = Just ctx}
-    runEngines
+        contextObject = Just $ anyObjRef ctx}
 
