diff --git a/app/assets/javascripts/workers/worker_world.coffee b/app/assets/javascripts/workers/worker_world.coffee
new file mode 100644
index 000000000..1503051a7
--- /dev/null
+++ b/app/assets/javascripts/workers/worker_world.coffee
@@ -0,0 +1,140 @@
+
+throw "Attempt to load worker_world into main window instead of web worker." if not self.importScripts or not window?
+
+self.window = self
+self.workerID = "Worker"
+
+self.logLimit = 200
+self.logsLogged = 0
+console =
+  log: ->
+    self.logsLogged += 1
+    if self.logsLogged is self.logLimit
+      self.postMessage
+        type: 'console-log'
+        args: ["Log limit " + self.logLimit + " reached; shutting up."]
+        id: self.workerID
+    else if self.logsLogged < self.logLimit
+      args = [].slice.call arguments
+      for arg in args
+        if arg and arg.constructor and (arg.constructor.className is "Thang" or arg.isComponent)
+          arg = arg.toString()
+
+      try
+        self.postMessage
+          type: 'console-log'
+          args: args
+          id: self.workerID
+
+      catch error
+        self.postMessage
+          type: 'console-log'
+          args: ["Could not post log: " + args, error.toString(), error.stack, error.stackTrace]
+          id: self.workerID
+
+
+console.error = console.info = console.log
+self.console = console
+
+importScripts '/javascripts/world.js'
+
+
+self.transferableSupported = transferableSupported = ->
+  try
+    ab = new ArrayBuffer 1
+    worker.postMessage ab, [ab]
+    return ab.byteLength is 0
+  catch error
+    return false
+  return false
+
+
+  World = self.require 'lib/world/world'
+  GoalManager = self.require 'lib/world/GoalManager'
+
+  self.runWorld = runWorld = (args) ->
+    self.postedErrors = {}
+    self.t0 = new Date()
+    self.firstWorld = args.firstWorld
+    self.postedErrors = false
+    self.logsLogged = 0
+
+    try
+      self.world = new World args.worldName, args.userCodeMap
+      if args.level
+        self.world.loadFromLevel args.level, true
+      self.goalManager = new GoalManager self.world
+      self.goalManager.setGoals args.goals
+      self.goalManager.setCode args.userCodeMap
+      self.goalManager.worldGenerationWillBegin()
+      self.world.setGoalManager self.goalManager
+    catch error
+      self.onWorldError error
+      return
+    Math.random = self.world.rand.randf
+    self.world.loadFrames self.onWorldLoaded, self.onWorldError, self.onWorldLoadProgress
+
+self.onWorldLoaded = onWorldLoaded = () ->
+  self.goalManager.worldGenerationEnded()
+  t1 = new Date()
+  diff = t1 - self.t0
+  transferableSupported = self.transferableSupported()
+  try
+    serialized = self.world.serialize()
+  catch error
+    console.log "World serialization error:", error.toString() + "\n" + error.stack or error.stackTrace
+
+
+  t2 = new Date()
+
+  try
+    if transferableSupported
+      self.postMessage(
+        type: 'new-world'
+        serialized: serialized.serializedWorld
+        goalStates: self.goalManager.getGoalStates()
+      , serialized.transferableObjects)
+    else
+      self.postMessage
+        type: 'new-world'
+        serialized: serialized.serializedWorld
+        goalStates: self.goalManager.getGoalStates()
+  catch error
+    console.log "World delivery error:", error.toString + "\n" + error.stack or error.stackTrace
+  t3 = new Date()
+  console.log "And it was so: (" + (diff / self.world.totalFrames).toFixed(3) + "ms per frame,", self.world.totalFrames, "frames)\nSimulation :"
+  self.world = null
+
+self.onWorldError = onWorldError = (error) ->
+  if error instanceof Aether.problems.UserCodeProblem
+    unless self.postedErrors[error.key]
+      problem = error.serialize()
+      self.postMessage
+        type: 'user-code-problem'
+        problem: problem
+      self.postedErrors[error.key] = problem
+
+  else
+    console.log "Non-UserCodeError:", error.toString() + "\n" + error.stack or error.stackTrace
+  return true
+
+self.onWorldLoadProgress = onWorldLoadProgress = (progress) ->
+  self.postMessage
+    type: 'world-load-progress-changed'
+    progress: progress
+
+self.abort = abort = ->
+  if self.world and self.world.name
+    console.log "About to abort:", self.world.name, typeof self.world.abort
+    self.world?.abort()
+    self.world = null
+
+  self.postMessage
+    type: 'abort'
+
+self.reportIn = reportIn = ->
+  self.postMessage
+    type: 'reportIn'
+
+self.addEventListener 'message', (event) ->
+  self[event.data.func](event.data.args)