diff --git a/app/assets/javascripts/workers/worker_world.js b/app/assets/javascripts/workers/worker_world.js
index d45a91e2e..03a100fd3 100644
--- a/app/assets/javascripts/workers/worker_world.js
+++ b/app/assets/javascripts/workers/worker_world.js
@@ -459,9 +459,9 @@ self.finalizePreload = function finalizePreload() {
   self.world.finalizePreload(self.onWorldLoaded);
 };
 
-self.updateFlags = function updateFlags(flags) {
+self.addFlagEvent = function addFlagEvent(flagEvent) {
   if(!self.world || self.world.framesSerializedSoFar == self.world.frames.length) return;
-  self.world.updateFlags(flags);
+  self.world.addFlagEvent(flagEvent);
 };
 
 self.addEventListener('message', function(event) {
diff --git a/app/lib/Angel.coffee b/app/lib/Angel.coffee
index fa9fb75cf..59547ca16 100644
--- a/app/lib/Angel.coffee
+++ b/app/lib/Angel.coffee
@@ -13,7 +13,7 @@ module.exports = class Angel extends CocoClass
   abortTimeoutDuration: 500  # give in-process or dying workers this long to give up
 
   subscriptions:
-    'self-wizard:target-changed': 'onSelfWizardTargetChanged'
+    'level:flag-updated': 'onFlagEvent'
 
   constructor: (@shared) ->
     super()
@@ -208,10 +208,9 @@ module.exports = class Angel extends CocoClass
     @worker.addEventListener 'message', @onWorkerMessage
     @worker.creationTime = new Date()
 
-  onSelfWizardTargetChanged: (e) ->
+  onFlagEvent: (e) ->
     return unless @running and @work.realTime
-    targetPos = e.sender.targetPos
-    @worker.postMessage func: 'updateFlags', args: [{type: 'wizard', targetPos: targetPos}]
+    @worker.postMessage func: 'addFlagEvent', args: e
 
 
   #### Synchronous code for running worlds on main thread (profiling / IE9) ####
diff --git a/app/lib/surface/CoordinateDisplay.coffee b/app/lib/surface/CoordinateDisplay.coffee
index f650e09b1..155f7e7ac 100644
--- a/app/lib/surface/CoordinateDisplay.coffee
+++ b/app/lib/surface/CoordinateDisplay.coffee
@@ -35,10 +35,6 @@ module.exports = class CoordinateDisplay extends createjs.Container
   onMouseOut: (e) -> @mouseInBounds = false
 
   onMouseMove: (e) ->
-    if @mouseInBounds and key.shift
-      $('#surface').addClass('flag-cursor') unless $('#surface').hasClass('flag-cursor')
-    else if @mouseInBounds
-      $('#surface').removeClass('flag-cursor') if $('#surface').hasClass('flag-cursor')
     wop = @camera.screenToWorld x: e.x, y: e.y
     wop.x = Math.round(wop.x)
     wop.y = Math.round(wop.y)
diff --git a/app/lib/surface/Label.coffee b/app/lib/surface/Label.coffee
index 959c92c13..30829d372 100644
--- a/app/lib/surface/Label.coffee
+++ b/app/lib/surface/Label.coffee
@@ -37,6 +37,8 @@ module.exports = class Label extends CocoClass
   build: ->
     @layer.removeChild @background if @background
     @layer.removeChild @label if @label
+    @label = null
+    @background = null
     return unless @text  # null or '' should both be skipped
     o = @buildLabelOptions()
     @layer.addChild @label = @buildLabel o
@@ -53,6 +55,17 @@ module.exports = class Label extends CocoClass
     @label.y = @background.y = @sprite.imageObject.y + offset.y
     null
 
+  show: ->
+    return unless @label
+    @layer.addChild @label
+    @layer.addChild @background
+    @layer.updateLayerOrder()
+
+  hide: ->
+    return unless @label
+    @layer.removeChild @background
+    @layer.removeChild @label
+
   buildLabelOptions: ->
     o = {}
     st = {dialogue: 'D', say: 'S', name: 'N'}[@style]
diff --git a/app/lib/surface/Surface.coffee b/app/lib/surface/Surface.coffee
index 91e243f0c..72604c0a0 100644
--- a/app/lib/surface/Surface.coffee
+++ b/app/lib/surface/Surface.coffee
@@ -69,6 +69,7 @@ module.exports = Surface = class Surface extends CocoClass
     'camera:zoom-updated': 'onZoomUpdated'
     'playback:real-time-playback-started': 'onRealTimePlaybackStarted'
     'playback:real-time-playback-ended': 'onRealTimePlaybackEnded'
+    'level:flag-selected': 'onFlagSelected'
 
   shortcuts:
     'ctrl+\\, ⌘+\\': 'onToggleDebug'
@@ -526,7 +527,9 @@ module.exports = Surface = class Surface extends CocoClass
   onMouseDown: (e) =>
     return if @disabled
     onBackground = not @stage.hitTest e.stageX, e.stageY
-    Backbone.Mediator.publish 'surface:stage-mouse-down', onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
+    event = onBackground: onBackground, x: e.stageX, y: e.stageY, originalEvent: e
+    Backbone.Mediator.publish 'surface:stage-mouse-down', event
+    @placeFlag event if @realTime
 
   onMouseUp: (e) =>
     return if @disabled
@@ -616,10 +619,35 @@ module.exports = Surface = class Surface extends CocoClass
   onRealTimePlaybackStarted: (e) ->
     @realTime = true
     @onResize()
+    @spriteBoss.selfWizardSprite?.imageObject.visible = false
+    @flags = {}
+    @flagHistory = []
 
   onRealTimePlaybackEnded: (e) ->
     @realTime = false
     @onResize()
+    @spriteBoss.selfWizardSprite?.imageObject.visible = true
+
+  onFlagSelected: (e) ->
+    @canvas.addClass("flag-selected")
+    @flagColor = e.color
+
+  placeFlag: (e) ->
+    return unless @flagColor
+    wop = @camera.screenToWorld x: e.x, y: e.y
+    targetPos = x: wop.x, y: wop.y
+    flag = player: me.id, team: me.team, color: @flagColor, targetPos: targetPos, time: @world.dt * @world.frames.length + 1, active: true
+    @flags[@flagColor] = flag
+    @flagHistory.push flag
+    Backbone.Mediator.publish 'level:flag-updated', flag
+    console.log 'trying to place flag at', @world.dt * @currentFrame, 'and think it will happen by', flag.time
+
+  removeFlag: (e) ->
+    delete @flags[e.color]
+    console.log e.color, 'deleted'
+    flag = player: me.id, team: me.team, color: e.color, time: @world.dt * @world.frames.length + 1, active: false
+    @flagHistory.push flag
+    Backbone.Mediator.publish 'level:flag-updated', flag
 
   # paths - TODO: move to SpriteBoss? but only update on frame drawing instead of on every frame update?
 
diff --git a/app/lib/surface/WizardSprite.coffee b/app/lib/surface/WizardSprite.coffee
index 5d929147c..3ba5f68af 100644
--- a/app/lib/surface/WizardSprite.coffee
+++ b/app/lib/surface/WizardSprite.coffee
@@ -35,7 +35,6 @@ module.exports = class WizardSprite extends IndieSprite
     @targetPos = @thang.pos
     if @isSelf
       @setNameLabel me.displayName()
-      @setColorHue me.get('wizardColor1')
     else if options.name
       @setNameLabel options.name
 
@@ -66,7 +65,6 @@ module.exports = class WizardSprite extends IndieSprite
       continue if playerID is me.id  # ignore changes for self wizard sprite
       @setNameLabel state.name
       continue unless state.wizard?
-      @setColorHue state.wizard.wizardColor1
       if targetID = state.wizard.targetSprite
         return console.warn 'Wizard Sprite couldn\'t find target sprite', targetID unless targetID of @options.sprites
         @setTarget @options.sprites[targetID]
@@ -91,17 +89,13 @@ module.exports = class WizardSprite extends IndieSprite
     @imageObject.scaleX = @imageObject.scaleY = @imageObject.alpha = 0
     createjs.Tween.get(@imageObject)
       .to({scaleX: 1, scaleY: 1, alpha: 1}, 1000, createjs.Ease.getPowInOut(2.2))
+    @labels.name?.show()
 
   animateOut: (callback) ->
     tween = createjs.Tween.get(@imageObject)
       .to({scaleX: 0, scaleY: 0, alpha: 0}, 1000, createjs.Ease.getPowInOut(2.2))
     tween.call(callback) if callback
-
-  setColorHue: (newColorHue) ->
-    # TODO: is this needed any more?
-    return if @colorHue is newColorHue
-    @colorHue = newColorHue
-    #@updateColorFilters()
+    @labels.name?.hide()
 
   setEditing: (@editing) ->
     if @editing
diff --git a/app/lib/world/world.coffee b/app/lib/world/world.coffee
index 9e20be655..ecaa78043 100644
--- a/app/lib/world/world.coffee
+++ b/app/lib/world/world.coffee
@@ -36,6 +36,7 @@ module.exports = class World
     @systems = []
     @systemMap = {}
     @scriptNotes = []
+    @flagHistory = []
     @rand = new Rand 0  # Existence System may change this seed
     @frames = [new WorldFrame(@, 0)]
 
@@ -169,8 +170,8 @@ module.exports = class World
   abort: ->
     @aborted = true
 
-  updateFlags: (@flags) ->
-    console.log "updated flags", @flags
+  addFlagEvent: (flagEvent) ->
+    @flagHistory.push flagEvent
 
   loadFromLevel: (level, willSimulate=true) ->
     @levelComponents = level.levelComponents
diff --git a/app/schemas/subscriptions/play.coffee b/app/schemas/subscriptions/play.coffee
index 51f81f992..e91420204 100644
--- a/app/schemas/subscriptions/play.coffee
+++ b/app/schemas/subscriptions/play.coffee
@@ -57,6 +57,39 @@ module.exports =
   'level:victory-hidden':
     {} # TODO schema
 
+  'level:flag-selected':
+    type: 'object'
+    additionalProperties: false
+    properties:
+      color:
+        type: 'string'
+        enum: ['red', 'green', 'blue']
+
+  'level:flag-updated':
+    type: 'object'
+    additionalProperties: false
+    required: ['player', 'color', 'time', 'active']
+    properties:
+      player:
+        type: 'string'
+      team:
+        type: 'string'
+      color:
+        type: 'string'
+        enum: ['red', 'green', 'blue']
+      time:
+        type: 'number'
+        minimum: 0
+      active:
+        type: 'boolean'
+      targetPos:
+        type: 'object'
+        additionalProperties: false
+        required: ['x', 'y']
+        properties:
+          x: {type: 'number'}
+          y: {type: 'number'}
+
   'next-game-pressed':
     {} # TODO schema
 
diff --git a/app/styles/base.sass b/app/styles/base.sass
index 332aaa624..a00d037ee 100644
--- a/app/styles/base.sass
+++ b/app/styles/base.sass
@@ -225,10 +225,6 @@ table.table
 .ui-slider-handle
   border: 1px solid black !important
 
-.flag-cursor
-  cursor: crosshair
-
-
 // Fonts
 
 .header-font
diff --git a/app/styles/play/level.sass b/app/styles/play/level.sass
index ea3fc3e5a..6105e6424 100644
--- a/app/styles/play/level.sass
+++ b/app/styles/play/level.sass
@@ -46,7 +46,10 @@ body.is-playing
     display: block
     z-index: 1
     @include transition(0.5s ease-out)
-    
+
+    &.flag-selected
+      cursor: crosshair
+
   min-width: 1024px
   position: relative
 
diff --git a/app/views/play/level/PlayLevelView.coffee b/app/views/play/level/PlayLevelView.coffee
index 1a5225d97..2eb1ddb38 100644
--- a/app/views/play/level/PlayLevelView.coffee
+++ b/app/views/play/level/PlayLevelView.coffee
@@ -72,6 +72,9 @@ module.exports = class PlayLevelView extends RootView
 
   shortcuts:
     'ctrl+s': 'onCtrlS'
+    'r': -> Backbone.Mediator.publish 'level:flag-selected', color: 'red'
+    'g': -> Backbone.Mediator.publish 'level:flag-selected', color: 'green'
+    'b': -> Backbone.Mediator.publish 'level:flag-selected', color: 'blue'
 
   # Initial Setup #############################################################
 
@@ -517,7 +520,7 @@ module.exports = class PlayLevelView extends RootView
 
   # Real-time playback
   onRealTimePlaybackStarted: (e) ->
-    @$el.addClass 'real-time'
+    @$el.addClass('real-time').focus()
     @onWindowResize()
 
   onRealTimePlaybackEnded: (e) ->
diff --git a/app/views/play/level/tome/CastButtonView.coffee b/app/views/play/level/tome/CastButtonView.coffee
index 5a426f92d..3b310f2f4 100644
--- a/app/views/play/level/tome/CastButtonView.coffee
+++ b/app/views/play/level/tome/CastButtonView.coffee
@@ -43,11 +43,9 @@ module.exports = class CastButtonView extends CocoView
     @$el.detach().prependTo(spellView.toolbarView.$el).show()
 
   onCastButtonClick: (e) ->
-    console.log "cas fast yo"
     Backbone.Mediator.publish 'tome:manual-cast', {}
 
   onCastRealTimeButtonClick: (e) ->
-    console.log "cas real time yo"
     Backbone.Mediator.publish 'tome:manual-cast', {realTime: true}
 
   onCastOptionsClick: (e) =>