diff --git a/app/styles/play/world-map-view.sass b/app/styles/play/world-map-view.sass
index 471a7ee52..9da4c8e1e 100644
--- a/app/styles/play/world-map-view.sass
+++ b/app/styles/play/world-map-view.sass
@@ -261,3 +261,29 @@ $gameControlMargin: 30px
 
     button
       margin-left: 10px
+
+  #volume-button
+    position: absolute
+    left: 1%
+    top: 1%
+    padding: 3px 8px
+    @include opacity(0.75)
+
+    &:hover
+      @include opacity(1.0)
+
+    .glyphicon
+      display: none
+      font-size: 32px
+
+    &.vol-up .glyphicon.glyphicon-volume-up
+      display: inline-block
+
+    &.vol-off .glyphicon.glyphicon-volume-off
+      display: inline-block
+      @include opacity(0.50)
+      &:hover
+        @include opacity(0.75)
+
+    &.vol-down .glyphicon.glyphicon-volume-down
+      display: inline-block
diff --git a/app/templates/play/world-map-view.jade b/app/templates/play/world-map-view.jade
index c7c88f85f..47b65a10b 100644
--- a/app/templates/play/world-map-view.jade
+++ b/app/templates/play/world-map-view.jade
@@ -58,3 +58,8 @@
   else
     span.spr= me.get('name')
     button#logout-button.btn.btn-default.btn-flat.btn-sm(data-i18n="login.log_out") Log Out
+
+button.btn.btn-lg.btn-inverse#volume-button(title="Adjust volume")
+  .glyphicon.glyphicon-volume-off
+  .glyphicon.glyphicon-volume-down
+  .glyphicon.glyphicon-volume-up
diff --git a/app/views/play/WorldMapView.coffee b/app/views/play/WorldMapView.coffee
index d1ccbb13a..101c178e3 100644
--- a/app/views/play/WorldMapView.coffee
+++ b/app/views/play/WorldMapView.coffee
@@ -26,6 +26,7 @@ module.exports = class WorldMapView extends RootView
     'mouseenter .level a': 'onMouseEnterLevel'
     'mouseleave .level a': 'onMouseLeaveLevel'
     'mousemove .map': 'onMouseMoveMap'
+    'click #volume-button': 'onToggleVolume'
 
   constructor: (options) ->
     super options
@@ -87,6 +88,7 @@ module.exports = class WorldMapView extends RootView
       _.defer => @$el.find('.game-controls .btn').tooltip()  # Have to defer or i18n doesn't take effect.
       @$el.find('.level').tooltip()
     @$el.addClass _.string.slugify @terrain
+    @updateVolume()
 
   onSessionsLoaded: (e) ->
     for session in @sessions.models
@@ -206,6 +208,30 @@ module.exports = class WorldMapView extends RootView
       fullHero.setURL url
       @supermodel.loadModel fullHero, 'thang'
 
+  updateVolume: (volume) ->
+    volume ?= me.get('volume') ? 1.0
+    classes = ['vol-off', 'vol-down', 'vol-up']
+    button = $('#volume-button', @$el)
+    button.toggleClass 'vol-off', volume <= 0.0
+    button.toggleClass 'vol-down', 0.0 < volume < 1.0
+    button.toggleClass 'vol-up', volume >= 1.0
+    createjs.Sound.setVolume(if volume is 1 then 0.6 else volume)  # Quieter for now until individual sound FX controls work again.
+    if volume isnt me.get 'volume'
+      me.set 'volume', volume
+      me.patch()
+
+  onToggleVolume: (e) ->
+    button = $(e.target).closest('#volume-button')
+    classes = ['vol-off', 'vol-down', 'vol-up']
+    volumes = [0, 0.4, 1.0]
+    for oldClass, i in classes
+      if button.hasClass oldClass
+        newI = (i + 1) % classes.length
+        break
+      else if i is classes.length - 1  # no oldClass
+        newI = 2
+    @updateVolume volumes[newI]
+
 
 tutorials = [
   {