diff --git a/app/lib/surface/SpriteBoss.coffee b/app/lib/surface/SpriteBoss.coffee
index 319449141..0a5e64478 100644
--- a/app/lib/surface/SpriteBoss.coffee
+++ b/app/lib/surface/SpriteBoss.coffee
@@ -248,6 +248,8 @@ module.exports = class SpriteBoss extends CocoClass
   # Marks
 
   updateSelection: ->
+    if @selectedSprite and (not @selectedSprite.thang.exists or not @world.getThangByID @selectedSprite.thang.id)
+      @selectSprite null, null, null
     @updateTarget()
     return unless @selectionMark
     @selectionMark.toggle @selectedSprite?
diff --git a/app/styles/play/level/hud.sass b/app/styles/play/level/hud.sass
index 63f8b1a94..a775375ef 100644
--- a/app/styles/play/level/hud.sass
+++ b/app/styles/play/level/hud.sass
@@ -223,7 +223,10 @@
 
         .hud-hint
           font-weight: normal
-          color: #888888
+          color: #aaa
+          position: absolute
+          top: 0
+          right: 4px
 
         .enter
           position: absolute
diff --git a/app/views/play/level/hud_view.coffee b/app/views/play/level/hud_view.coffee
index e70714eda..41dba1118 100644
--- a/app/views/play/level/hud_view.coffee
+++ b/app/views/play/level/hud_view.coffee
@@ -163,7 +163,7 @@ module.exports = class HUDView extends View
     else
       s = $.i18n.t('play_level.hud_continue', defaultValue: "Continue (press shift-space)")
       if @shiftSpacePressed > 4 and not @escapePressed
-        group.append('<span class="hud-hint">Press esc to skip dialog</span>')
+        @bubble.append('<span class="hud-hint">skip: esc</span>')
       group.append($('<button class="btn btn-small banner with-dot">' + s + ' <div class="dot"></div></button>'))
       @lastResponses = null
     @bubble.append($("<h3>#{@speaker ? 'Captain Anya'}</h3>"))
diff --git a/app/views/play/level/tome/spell.coffee b/app/views/play/level/tome/spell.coffee
index 17cc4d748..6a3b409ac 100644
--- a/app/views/play/level/tome/spell.coffee
+++ b/app/views/play/level/tome/spell.coffee
@@ -30,6 +30,9 @@ module.exports = class Spell
   addThang: (thang) ->
     @thangs[thang.id] ?= {thang: thang, aether: @createAether(thang), castAether: null}
 
+  removeThangID: (thangID) ->
+    delete @thangs[thangID]
+
   canRead: (team) ->
     (team ? me.team) in @permissions.read or (team ? me.team) in @permissions.readwrite
 
diff --git a/app/views/play/level/tome/spell_list_view.coffee b/app/views/play/level/tome/spell_list_view.coffee
index 6b5862d38..2fabeffd6 100644
--- a/app/views/play/level/tome/spell_list_view.coffee
+++ b/app/views/play/level/tome/spell_list_view.coffee
@@ -79,3 +79,11 @@ module.exports = class SpellListView extends View
   addThang: (thang) ->
     @sortSpells()
     @addSpellListEntries()
+
+  adjustSpells: (spells) ->
+    for entry in @entries when _.isEmpty entry.spell.thangs
+      entry.$el.remove()
+      entry.destroy()
+    @spells = @options.spells = spells
+    @sortSpells()
+    @addSpellListEntries()
diff --git a/app/views/play/level/tome/spell_view.coffee b/app/views/play/level/tome/spell_view.coffee
index cd4235f34..ed3619c79 100644
--- a/app/views/play/level/tome/spell_view.coffee
+++ b/app/views/play/level/tome/spell_view.coffee
@@ -377,11 +377,12 @@ module.exports = class SpellView extends View
     @updateAether false, false
 
   onNewWorld: (e) ->
+    @spell.removeThangID thangID for thangID of @spell.thangs when not e.world.getThangByID thangID
     for thangID, spellThang of @spell.thangs
-      aether = e.world.userCodeMap[thangID][@spell.name]
-      #console.log thangID, "got new castAether with raw", aether.raw, "problems", aether.problems
+      thang = e.world.getThangByID(thangID)
+      aether = e.world.userCodeMap[thangID]?[@spell.name]  # Might not be there if this is a new Programmable Thang.
       spellThang.castAether = aether
-      spellThang.aether = @spell.createAether e.world.getThangByID(thangID)
+      spellThang.aether = @spell.createAether thang
       #console.log thangID, @spell.spellKey, "ran", aether.metrics.callsExecuted, "times over", aether.metrics.statementsExecuted, "statements, with max recursion depth", aether.metrics.maxDepth, "and full flow/metrics", aether.metrics, aether.flow
     @spell.transpile()
     @updateAether false, false
diff --git a/app/views/play/level/tome/thang_list_entry_view.coffee b/app/views/play/level/tome/thang_list_entry_view.coffee
index fb143ddaa..1db0f3741 100644
--- a/app/views/play/level/tome/thang_list_entry_view.coffee
+++ b/app/views/play/level/tome/thang_list_entry_view.coffee
@@ -46,6 +46,7 @@ module.exports = class ThangListEntryView extends View
     @$el.append @avatar.el  # Before rendering, so render can use parent for popover
     @avatar.render()
     @avatar.setSharedThangs @spells.length  # A bit weird to call it sharedThangs; could refactor if we like this
+    @$el.toggle Boolean(@thang.exists)
     @$el.popover(
       animation: false
       html: true
diff --git a/app/views/play/level/tome/thang_list_view.coffee b/app/views/play/level/tome/thang_list_view.coffee
index 405acde5b..a2f5f8939 100644
--- a/app/views/play/level/tome/thang_list_view.coffee
+++ b/app/views/play/level/tome/thang_list_view.coffee
@@ -72,7 +72,11 @@ module.exports = class ThangListView extends View
       return entry.spells[0]
     null
 
-  addThang: (thang) ->
-    @thangs.push thang
+  adjustThangs: (spells, thangs, toRemove, toAdd) ->
+    for entry in @entries when _.find toRemove, {id: entry.thang.id}
+      entry.$el.remove()
+      entry.destroy()
+    @spells = @options.spells = spells
+    @thangs = @options.thangs = _.filter thangs, 'isSelectable'
     @sortThangs()
-    @addThangListEntries [thang]
+    @addThangListEntries toAdd
diff --git a/app/views/play/level/tome/tome_view.coffee b/app/views/play/level/tome/tome_view.coffee
index 3e5b85d3d..a030b70d7 100644
--- a/app/views/play/level/tome/tome_view.coffee
+++ b/app/views/play/level/tome/tome_view.coffee
@@ -47,7 +47,7 @@ module.exports = class TomeView extends View
     'tome:cast-spell': "onCastSpell"
     'tome:toggle-spell-list': 'onToggleSpellList'
     'surface:sprite-selected': 'onSpriteSelected'
-    'surface:new-thang-added': 'onNewThangAdded'
+    'god:new-world-created': 'onNewWorld'
 
   events:
     'click #spell-view': 'onSpellViewClick'
@@ -58,7 +58,7 @@ module.exports = class TomeView extends View
     programmableThangs = _.filter @options.thangs, 'isProgrammable'
 
     if programmableThangs.length
-      @createSpells programmableThangs  # Do before spellList, thangList, and castButton
+      @createSpells programmableThangs, programmableThangs[0].world  # Do before spellList, thangList, and castButton
       @spellList = @insertSubView new SpellListView spells: @spells, supermodel: @supermodel
       @thangList = @insertSubView new ThangListView spells: @spells, thangs: @options.thangs, supermodel: @supermodel
       @castButton = @insertSubView new CastButtonView spells: @spells
@@ -66,20 +66,20 @@ module.exports = class TomeView extends View
       @cast()
       console.log "Warning: There are no Programmable Thangs in this level, which makes it unplayable."
 
-  onNewThangAdded: (e) ->
-    return unless e.thang.isProgrammable and not _.find @thangList.thangs, id: e.thang.id
-    @createSpells [e.thang]
-    @spellList.addThang e.thang
-    @thangList.addThang e.thang
+  onNewWorld: (e) ->
+    oldThangs = @thangList.thangs
+    newThangs = e.world.thangs
+    toRemove = (thang for thang in oldThangs when not e.world.getThangByID thang.id)
+    toAdd = (thang for thang in newThangs when not _.find oldThangs, id: thang.id)
+    @createSpells toAdd, e.world
+    @thangList.adjustThangs @spells, newThangs, toRemove, toAdd
+    @spellList.adjustSpells @spells
 
-  createSpells: (programmableThangs) ->
-    # If needed, we could make this able to update when programmableThangs changes.
-    # We haven't done that yet, so call it just once on init.
+  createSpells: (programmableThangs, world) ->
     pathPrefixComponents = ['play', 'level', @options.levelID, @options.session.id, 'code']
     @spells ?= {}
     @thangSpells ?= {}
     for thang in programmableThangs
-      world = thang.world
       continue if @thangSpells[thang.id]?
       @thangSpells[thang.id] = []
       for methodName, method of thang.programmableMethods
@@ -92,8 +92,12 @@ module.exports = class TomeView extends View
         unless method.cloneOf
           spell = @spells[spellKey] = new Spell programmableMethod: method, spellKey: spellKey, pathComponents: pathPrefixComponents.concat(pathComponents), session: @options.session, supermodel: @supermodel, skipFlow: @getQueryVariable("skip_flow") is "true", skipProtectAPI: @getQueryVariable("skip_protect_api") is "true"
     for thangID, spellKeys of @thangSpells
-      thang = world.getThangByID(thangID)
-      @spells[spellKey].addThang thang for spellKey in spellKeys
+      thang = world.getThangByID thangID
+      if thang
+        @spells[spellKey].addThang thang for spellKey in spellKeys
+      else
+        delete @thangSpells[thangID]
+        @spells[spellKey].removeThangID thangID for spellKey in spellKeys
     null
 
   onSpellLoaded: (e) ->