diff --git a/appveyor.yml b/appveyor.yml
index cc6dfb9c88..b26a895788 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -20,4 +20,4 @@ build:
   verbosity: minimal
 after_build:
   - cmd: inspectcode /o="inspectcodereport.xml" /caches-home="inspectcode" osu.sln
-  - cmd: NVika parsereport "inspectcodereport.xml"
\ No newline at end of file
+  - cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
\ No newline at end of file
diff --git a/osu-framework b/osu-framework
index 00e48bcd31..3ad1dd52ae 160000
--- a/osu-framework
+++ b/osu-framework
@@ -1 +1 @@
-Subproject commit 00e48bcd31b7debda89bbcf62927706c43eba644
+Subproject commit 3ad1dd52ae511b816fb928f70ef811ec605c5c18
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs
new file mode 100644
index 0000000000..b2c211b7f0
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseReplaySettingsOverlay.cs
@@ -0,0 +1,55 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Testing;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Screens.Play;
+using osu.Game.Screens.Play.ReplaySettings;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+    internal class TestCaseReplaySettingsOverlay : TestCase
+    {
+        public override string Description => @"Settings visible in replay/auto";
+
+        private ExampleContainer container;
+
+        public override void Reset()
+        {
+            base.Reset();
+
+            Add(new ReplaySettingsOverlay()
+            {
+                Anchor = Anchor.TopRight,
+                Origin = Anchor.TopRight,
+            });
+
+            Add(container = new ExampleContainer());
+
+            AddStep(@"Add button", () => container.Add(new OsuButton
+            {
+                RelativeSizeAxes = Axes.X,
+                Text = @"Button",
+            }));
+
+            AddStep(@"Add checkbox", () => container.Add(new ReplayCheckbox
+            {
+                LabelText = "Checkbox",
+            }));
+
+            AddStep(@"Add textbox", () => container.Add(new FocusedTextBox
+            {
+                RelativeSizeAxes = Axes.X,
+                Height = 30,
+                PlaceholderText = "Textbox",
+                HoldFocus = false,
+            }));
+        }
+
+        private class ExampleContainer : ReplayGroup
+        {
+            protected override string Title => @"example";
+        }
+    }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
new file mode 100644
index 0000000000..fb5be719c1
--- /dev/null
+++ b/osu.Desktop.VisualTests/Tests/TestCaseSkipButton.cs
@@ -0,0 +1,19 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Testing;
+using osu.Game.Screens.Play;
+
+namespace osu.Desktop.VisualTests.Tests
+{
+    internal class TestCaseSkipButton : TestCase
+    {
+        public override string Description => @"Skip skip skippediskip";
+
+        public override void Reset()
+        {
+            base.Reset();
+            Add(new SkipButton(Clock.CurrentTime + 5000));
+        }
+    }
+}
diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
index ba17cfc3d8..2decb4c469 100644
--- a/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
+++ b/osu.Desktop.VisualTests/Tests/TestCaseTwoLayerButton.cs
@@ -3,20 +3,18 @@
 
 using osu.Framework.Testing;
 using osu.Game.Graphics.UserInterface;
-using osu.Game.Screens.Play;
 
 namespace osu.Desktop.VisualTests.Tests
 {
     internal class TestCaseTwoLayerButton : TestCase
     {
-        public override string Description => @"Back and skip and what not";
+        public override string Description => @"Mostly back button";
 
         public override void Reset()
         {
             base.Reset();
 
             Add(new BackButton());
-            Add(new SkipButton(Clock.CurrentTime + 5000));
         }
     }
 }
diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
index 850c38cc24..f72b08adde 100644
--- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
+++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj
@@ -196,6 +196,7 @@
     <Compile Include="Tests\TestCaseMusicController.cs" />
     <Compile Include="Tests\TestCaseNotificationManager.cs" />
     <Compile Include="Tests\TestCaseOnScreenDisplay.cs" />
+    <Compile Include="Tests\TestCaseReplaySettingsOverlay.cs" />
     <Compile Include="Tests\TestCasePlayer.cs" />
     <Compile Include="Tests\TestCaseHitObjects.cs" />
     <Compile Include="Tests\TestCaseKeyCounter.cs" />
@@ -203,6 +204,7 @@
     <Compile Include="Tests\TestCaseReplay.cs" />
     <Compile Include="Tests\TestCaseResults.cs" />
     <Compile Include="Tests\TestCaseScoreCounter.cs" />
+    <Compile Include="Tests\TestCaseSkipButton.cs" />
     <Compile Include="Tests\TestCaseTabControl.cs" />
     <Compile Include="Tests\TestCaseTaikoHitObjects.cs" />
     <Compile Include="Tests\TestCaseTaikoPlayfield.cs" />
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 8b2a06ad0b..3f56dc0b79 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -71,6 +71,9 @@ namespace osu.Game.Configuration
             Set(OsuSetting.ShowInterface, true);
             Set(OsuSetting.KeyOverlay, false);
 
+            Set(OsuSetting.FloatingComments, false);
+            Set(OsuSetting.PlaybackSpeed, 1.0, 0.5f, 2);
+
             // Update
 
             Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
@@ -90,6 +93,8 @@ namespace osu.Game.Configuration
         AutoCursorSize,
         DimLevel,
         KeyOverlay,
+        FloatingComments,
+        PlaybackSpeed,
         ShowInterface,
         MouseDisableButtons,
         MouseDisableWheel,
diff --git a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
index 46addf5ac2..815d820a47 100644
--- a/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
+++ b/osu.Game/Graphics/Cursor/OsuTooltipContainer.cs
@@ -1,6 +1,7 @@
 // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
 // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
 
+using OpenTK;
 using OpenTK.Graphics;
 using osu.Framework.Allocation;
 using osu.Framework.Extensions.Color4Extensions;
@@ -24,6 +25,7 @@ namespace osu.Game.Graphics.Cursor
         {
             private readonly Box background;
             private readonly OsuSpriteText text;
+            private bool instantMovement = true;
 
             public override string TooltipText
             {
@@ -32,7 +34,7 @@ namespace osu.Game.Graphics.Cursor
                     if (value == text.Text) return;
 
                     text.Text = value;
-                    if (Alpha > 0)
+                    if (IsPresent)
                     {
                         AutoSizeDuration = 250;
                         background.FlashColour(OsuColour.Gray(0.4f), 1000, EasingTypes.OutQuint);
@@ -80,6 +82,7 @@ namespace osu.Game.Graphics.Cursor
 
             protected override void PopIn()
             {
+                instantMovement |= !IsPresent;
                 FadeIn(500, EasingTypes.OutQuint);
             }
 
@@ -88,6 +91,19 @@ namespace osu.Game.Graphics.Cursor
                 using (BeginDelayedSequence(150))
                     FadeOut(500, EasingTypes.OutQuint);
             }
+
+            public override void Move(Vector2 pos)
+            {
+                if (instantMovement)
+                {
+                    Position = pos;
+                    instantMovement = false;
+                }
+                else
+                {
+                    MoveTo(pos, 200, EasingTypes.OutQuint);
+                }
+            }
         }
     }
 }
diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs
new file mode 100644
index 0000000000..d2a87d2dd0
--- /dev/null
+++ b/osu.Game/Graphics/UserInterface/IconButton.cs
@@ -0,0 +1,114 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Input;
+
+namespace osu.Game.Graphics.UserInterface
+{
+    public class IconButton : ClickableContainer
+    {
+        private readonly TextAwesome icon;
+        private readonly Box hover;
+        private readonly Container content;
+
+        public FontAwesome Icon
+        {
+            get { return icon.Icon; }
+            set { icon.Icon = value; }
+        }
+
+        private const float button_size = 30;
+        private Color4 flashColour;
+
+        public Vector2 IconScale
+        {
+            get { return icon.Scale; }
+            set { icon.Scale = value; }
+        }
+
+        public IconButton()
+        {
+            AutoSizeAxes = Axes.Both;
+
+            Origin = Anchor.Centre;
+            Anchor = Anchor.Centre;
+
+            Children = new Drawable[]
+            {
+                content = new Container
+                {
+                    Origin = Anchor.Centre,
+                    Anchor = Anchor.Centre,
+                    Size = new Vector2 (button_size),
+
+                    CornerRadius = 5,
+                    Masking = true,
+                    EdgeEffect = new EdgeEffect
+                    {
+                        Colour = Color4.Black.Opacity(0.04f),
+                        Type = EdgeEffectType.Shadow,
+                        Radius = 5,
+                    },
+                    Children = new Drawable[]
+                    {
+                        hover = new Box
+                        {
+                            RelativeSizeAxes = Axes.Both,
+                            Alpha = 0,
+                        },
+                        icon = new TextAwesome
+                        {
+                            Origin = Anchor.Centre,
+                            Anchor = Anchor.Centre,
+                            TextSize = 18,
+                        }
+                    }
+                }
+            };
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            hover.Colour = colours.Yellow.Opacity(0.6f);
+            flashColour = colours.Yellow;
+        }
+
+        protected override bool OnHover(InputState state)
+        {
+            hover.FadeIn(500, EasingTypes.OutQuint);
+            return base.OnHover(state);
+        }
+
+        protected override void OnHoverLost(InputState state)
+        {
+            hover.FadeOut(500, EasingTypes.OutQuint);
+            base.OnHoverLost(state);
+        }
+
+        protected override bool OnClick(InputState state)
+        {
+            hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
+            return base.OnClick(state);
+        }
+
+        protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
+        {
+            content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
+            return base.OnMouseDown(state, args);
+        }
+
+        protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
+        {
+            content.ScaleTo(1, 1000, EasingTypes.OutElastic);
+            return base.OnMouseUp(state, args);
+        }
+    }
+}
diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs
index 82ede8f079..a5cbc9f53f 100644
--- a/osu.Game/Graphics/UserInterface/Nub.cs
+++ b/osu.Game/Graphics/UserInterface/Nub.cs
@@ -12,13 +12,12 @@ using osu.Framework.Graphics.UserInterface;
 
 namespace osu.Game.Graphics.UserInterface
 {
-    public class Nub : CircularContainer, IHasCurrentValue<bool>
+    public class Nub : CircularContainer, IHasCurrentValue<bool>, IHasAccentColour
     {
         public const float COLLAPSED_SIZE = 20;
         public const float EXPANDED_SIZE = 40;
 
         private const float border_width = 3;
-        private Color4 glowingColour, idleColour;
 
         public Nub()
         {
@@ -53,33 +52,41 @@ namespace osu.Game.Graphics.UserInterface
         [BackgroundDependencyLoader]
         private void load(OsuColour colours)
         {
-            Colour = idleColour = colours.Pink;
-            glowingColour = colours.PinkLighter;
+            AccentColour = colours.Pink;
+            GlowingAccentColour = colours.PinkLighter;
+            GlowColour = colours.PinkDarker;
 
             EdgeEffect = new EdgeEffect
             {
-                Colour = colours.PinkDarker,
+                Colour = GlowColour,
                 Type = EdgeEffectType.Glow,
                 Radius = 10,
                 Roundness = 8,
             };
+        }
 
+        protected override void LoadComplete()
+        {
             FadeEdgeEffectTo(0);
         }
 
+        private bool glowing;
         public bool Glowing
         {
+            get { return glowing; }
             set
             {
+                glowing = value;
+
                 if (value)
                 {
-                    FadeColour(glowingColour, 500, EasingTypes.OutQuint);
+                    FadeColour(GlowingAccentColour, 500, EasingTypes.OutQuint);
                     FadeEdgeEffectTo(1, 500, EasingTypes.OutQuint);
                 }
                 else
                 {
                     FadeEdgeEffectTo(0, 500);
-                    FadeColour(idleColour, 500);
+                    FadeColour(AccentColour, 500);
                 }
             }
         }
@@ -93,5 +100,43 @@ namespace osu.Game.Graphics.UserInterface
         }
 
         public Bindable<bool> Current { get; } = new Bindable<bool>();
+
+        private Color4 accentColour;
+        public Color4 AccentColour
+        {
+            get { return accentColour; }
+            set
+            {
+                accentColour = value;
+                if (!Glowing)
+                    Colour = value;
+            }
+        }
+
+        private Color4 glowingAccentColour;
+        public Color4 GlowingAccentColour
+        {
+            get { return glowingAccentColour; }
+            set
+            {
+                glowingAccentColour = value;
+                if (Glowing)
+                    Colour = value;
+            }
+        }
+
+        private Color4 glowColour;
+        public Color4 GlowColour
+        {
+            get { return glowColour; }
+            set
+            {
+                glowColour = value;
+
+                var effect = EdgeEffect;
+                effect.Colour = value;
+                EdgeEffect = effect;
+            }
+        }
     }
 }
diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
index 85231ffab9..198a01b5a4 100644
--- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
+++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs
@@ -51,7 +51,8 @@ namespace osu.Game.Graphics.UserInterface
             }
         }
 
-        private readonly Nub nub;
+        protected readonly Nub Nub;
+
         private readonly SpriteText labelSpriteText;
         private SampleChannel sampleChecked;
         private SampleChannel sampleUnchecked;
@@ -64,7 +65,7 @@ namespace osu.Game.Graphics.UserInterface
             Children = new Drawable[]
             {
                 labelSpriteText = new OsuSpriteText(),
-                nub = new Nub
+                Nub = new Nub
                 {
                     Anchor = Anchor.CentreRight,
                     Origin = Anchor.CentreRight,
@@ -72,7 +73,7 @@ namespace osu.Game.Graphics.UserInterface
                 }
             };
 
-            nub.Current.BindTo(Current);
+            Nub.Current.BindTo(Current);
 
             Current.ValueChanged += newValue =>
             {
@@ -90,15 +91,15 @@ namespace osu.Game.Graphics.UserInterface
 
         protected override bool OnHover(InputState state)
         {
-            nub.Glowing = true;
-            nub.Expanded = true;
+            Nub.Glowing = true;
+            Nub.Expanded = true;
             return base.OnHover(state);
         }
 
         protected override void OnHoverLost(InputState state)
         {
-            nub.Glowing = false;
-            nub.Expanded = false;
+            Nub.Glowing = false;
+            Nub.Expanded = false;
             base.OnHoverLost(state);
         }
 
diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
index c8be085b51..2dab952204 100644
--- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
+++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs
@@ -3,6 +3,7 @@
 
 using System;
 using OpenTK;
+using OpenTK.Graphics;
 using osu.Framework.Allocation;
 using osu.Framework.Audio;
 using osu.Framework.Audio.Sample;
@@ -15,14 +16,14 @@ using osu.Framework.Graphics.Cursor;
 
 namespace osu.Game.Graphics.UserInterface
 {
-    public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip
+    public class OsuSliderBar<T> : SliderBar<T>, IHasTooltip, IHasAccentColour
         where T : struct, IEquatable<T>
     {
         private SampleChannel sample;
         private double lastSampleTime;
         private T lastSampleValue;
 
-        private readonly Nub nub;
+        protected readonly Nub Nub;
         private readonly Box leftBox;
         private readonly Box rightBox;
 
@@ -46,6 +47,18 @@ namespace osu.Game.Graphics.UserInterface
             }
         }
 
+        private Color4 accentColour;
+        public Color4 AccentColour
+        {
+            get { return accentColour; }
+            set
+            {
+                accentColour = value;
+                leftBox.Colour = value;
+                rightBox.Colour = value;
+            }
+        }
+
         public OsuSliderBar()
         {
             Height = 12;
@@ -71,7 +84,7 @@ namespace osu.Game.Graphics.UserInterface
                     Origin = Anchor.CentreRight,
                     Alpha = 0.5f,
                 },
-                nub = new Nub
+                Nub = new Nub
                 {
                     Origin = Anchor.TopCentre,
                     Expanded = true,
@@ -88,19 +101,18 @@ namespace osu.Game.Graphics.UserInterface
         private void load(AudioManager audio, OsuColour colours)
         {
             sample = audio.Sample.Get(@"Sliderbar/sliderbar");
-            leftBox.Colour = colours.Pink;
-            rightBox.Colour = colours.Pink;
+            AccentColour = colours.Pink;
         }
 
         protected override bool OnHover(InputState state)
         {
-            nub.Glowing = true;
+            Nub.Glowing = true;
             return base.OnHover(state);
         }
 
         protected override void OnHoverLost(InputState state)
         {
-            nub.Glowing = false;
+            Nub.Glowing = false;
             base.OnHoverLost(state);
         }
 
@@ -133,13 +145,13 @@ namespace osu.Game.Graphics.UserInterface
 
         protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
         {
-            nub.Current.Value = true;
+            Nub.Current.Value = true;
             return base.OnMouseDown(state, args);
         }
 
         protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
         {
-            nub.Current.Value = false;
+            Nub.Current.Value = false;
             return base.OnMouseUp(state, args);
         }
 
@@ -147,14 +159,14 @@ namespace osu.Game.Graphics.UserInterface
         {
             base.UpdateAfterChildren();
             leftBox.Scale = new Vector2(MathHelper.Clamp(
-                nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
+                Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
             rightBox.Scale = new Vector2(MathHelper.Clamp(
-                DrawWidth - nub.DrawPosition.X - nub.DrawWidth / 2, 0, DrawWidth), 1);
+                DrawWidth - Nub.DrawPosition.X - Nub.DrawWidth / 2, 0, DrawWidth), 1);
         }
 
         protected override void UpdateValue(float value)
         {
-            nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
+            Nub.MoveToX(RangePadding + UsableWidth * value, 250, EasingTypes.OutQuint);
         }
     }
 }
diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs
index 93fd0a8956..01685cc7dc 100644
--- a/osu.Game/Online/Chat/Channel.cs
+++ b/osu.Game/Online/Chat/Channel.cs
@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using Newtonsoft.Json;
+using osu.Framework.Configuration;
 using osu.Framework.Lists;
 
 namespace osu.Game.Online.Chat
@@ -25,7 +26,7 @@ namespace osu.Game.Online.Chat
 
         public readonly SortedList<Message> Messages = new SortedList<Message>(Comparer<Message>.Default);
 
-        //internal bool Joined;
+        public Bindable<bool> Joined = new Bindable<bool>();
 
         public bool ReadOnly => Name != "#lazer";
 
diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs
new file mode 100644
index 0000000000..9aa11cdd4f
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelListItem.cs
@@ -0,0 +1,188 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Configuration;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+    public class ChannelListItem : ClickableContainer, IFilterable
+    {
+        private const float width_padding = 5;
+        private const float channel_width = 150;
+        private const float text_size = 15;
+        private const float transition_duration = 100;
+
+        private readonly Channel channel;
+
+        private readonly Bindable<bool> joinedBind = new Bindable<bool>();
+        private readonly OsuSpriteText name;
+        private readonly OsuSpriteText topic;
+        private readonly TextAwesome joinedCheckmark;
+
+        private Color4 joinedColour;
+        private Color4 topicColour;
+        private Color4 hoverColour;
+
+        public string[] FilterTerms => new[] { channel.Name };
+        public bool MatchingFilter
+        {
+            set
+            {
+                FadeTo(value ? 1f : 0f, 100);
+            }
+        }
+
+        public Action<Channel> OnRequestJoin;
+        public Action<Channel> OnRequestLeave;
+
+        public ChannelListItem(Channel channel)
+        {
+            this.channel = channel;
+
+            RelativeSizeAxes = Axes.X;
+            AutoSizeAxes = Axes.Y;
+
+            Action = () => { (channel.Joined ? OnRequestLeave : OnRequestJoin)?.Invoke(channel); };
+
+            Children = new Drawable[]
+            {
+                new FillFlowContainer
+                {
+                    RelativeSizeAxes = Axes.X,
+                    AutoSizeAxes = Axes.Y,
+                    Direction = FillDirection.Horizontal,
+                    Children = new Drawable[]
+                    {
+                        new Container
+                        {
+                            Children = new[]
+                            {
+                                joinedCheckmark = new TextAwesome
+                                {
+                                    Anchor = Anchor.TopRight,
+                                    Origin = Anchor.TopRight,
+                                    Icon = FontAwesome.fa_check_circle,
+                                    TextSize = text_size,
+                                    Shadow = false,
+                                    Margin = new MarginPadding { Right = 10f },
+                                    Alpha = 0f,
+                                },
+                            },
+                        },
+                        new Container
+                        {
+                            Width = channel_width,
+                            AutoSizeAxes = Axes.Y,
+                            Children = new[]
+                            {
+                                name = new OsuSpriteText
+                                {
+                                    Text = channel.ToString(),
+                                    TextSize = text_size,
+                                    Font = @"Exo2.0-Bold",
+                                    Shadow = false,
+                                },
+                            },
+                        },
+                        new Container
+                        {
+                            RelativeSizeAxes = Axes.X,
+                            Width = 0.7f,
+                            AutoSizeAxes = Axes.Y,
+                            Margin = new MarginPadding { Left = width_padding },
+                            Children = new[]
+                            {
+                                topic = new OsuSpriteText
+                                {
+                                    Text = channel.Topic,
+                                    TextSize = text_size,
+                                    Font = @"Exo2.0-SemiBold",
+                                    Shadow = false,
+                                    Alpha = 0.8f,
+                                },
+                            },
+                        },
+                        new FillFlowContainer
+                        {
+                            AutoSizeAxes = Axes.Both,
+                            Direction = FillDirection.Horizontal,
+                            Margin = new MarginPadding { Left = width_padding },
+                            Spacing = new Vector2(3f, 0f),
+                            Children = new Drawable[]
+                            {
+                                new TextAwesome
+                                {
+                                    Icon = FontAwesome.fa_user,
+                                    TextSize = text_size - 2,
+                                    Shadow = false,
+                                    Margin = new MarginPadding { Top = 1 },
+                                },
+                                new OsuSpriteText
+                                {
+                                    Text = @"0",
+                                    TextSize = text_size,
+                                    Font = @"Exo2.0-SemiBold",
+                                    Shadow = false,
+                                },
+                            },
+                        },
+                    },
+                },
+            };
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            topicColour = colours.Gray9;
+            joinedColour = colours.Blue;
+            hoverColour = colours.Yellow;
+
+            joinedBind.ValueChanged += updateColour;
+            joinedBind.BindTo(channel.Joined);
+        }
+
+        protected override bool OnHover(InputState state)
+        {
+            if (!channel.Joined.Value)
+                name.FadeColour(hoverColour, 50, EasingTypes.OutQuint);
+
+            return base.OnHover(state);
+        }
+
+        protected override void OnHoverLost(InputState state)
+        {
+            if (!channel.Joined.Value)
+                name.FadeColour(Color4.White, transition_duration);
+        }
+
+        private void updateColour(bool joined)
+        {
+            if (joined)
+            {
+                name.FadeColour(Color4.White, transition_duration);
+                joinedCheckmark.FadeTo(1f, transition_duration);
+                topic.FadeTo(0.8f, transition_duration);
+                topic.FadeColour(Color4.White, transition_duration);
+                FadeColour(joinedColour, transition_duration);
+            }
+            else
+            {
+                joinedCheckmark.FadeTo(0f, transition_duration);
+                topic.FadeTo(1f, transition_duration);
+                topic.FadeColour(topicColour, transition_duration);
+                FadeColour(Color4.White, transition_duration);
+            }
+        }
+    }
+}
diff --git a/osu.Game/Overlays/Chat/ChannelSection.cs b/osu.Game/Overlays/Chat/ChannelSection.cs
new file mode 100644
index 0000000000..f12ec53605
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelSection.cs
@@ -0,0 +1,63 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System.Collections.Generic;
+using System.Linq;
+using OpenTK;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+    public class ChannelSection : Container, IHasFilterableChildren
+    {
+        private readonly OsuSpriteText header;
+
+        public readonly FillFlowContainer<ChannelListItem> ChannelFlow;
+
+        public IEnumerable<IFilterable> FilterableChildren => ChannelFlow.Children;
+        public string[] FilterTerms => new[] { Header };
+        public bool MatchingFilter
+        {
+            set
+            {
+                FadeTo(value ? 1f : 0f, 100);
+            }
+        }
+
+        public string Header
+        {
+            get { return header.Text; }
+            set { header.Text = value.ToUpper(); }
+        }
+
+        public IEnumerable<Channel> Channels
+        {
+            set { ChannelFlow.Children = value.Select(c => new ChannelListItem(c)); }
+        }
+
+        public ChannelSection()
+        {
+            RelativeSizeAxes = Axes.X;
+            AutoSizeAxes = Axes.Y;
+
+            Children = new Drawable[]
+            {
+                header = new OsuSpriteText
+                {
+                    TextSize = 15,
+                    Font = @"Exo2.0-Bold",
+                },
+                ChannelFlow = new FillFlowContainer<ChannelListItem>
+                {
+                    RelativeSizeAxes = Axes.X,
+                    AutoSizeAxes = Axes.Y,
+                    Margin = new MarginPadding { Top = 25 },
+                    Spacing = new Vector2(0f, 5f),
+                },
+            };
+        }
+    }
+}
diff --git a/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
new file mode 100644
index 0000000000..cd736a5fe9
--- /dev/null
+++ b/osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
@@ -0,0 +1,184 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using System;
+using System.Collections.Generic;
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Input;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Backgrounds;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Online.Chat;
+
+namespace osu.Game.Overlays.Chat
+{
+    public class ChannelSelectionOverlay : FocusedOverlayContainer
+    {
+        public static readonly float WIDTH_PADDING = 170;
+
+        private const float transition_duration = 500;
+
+        private readonly Box bg;
+        private readonly Triangles triangles;
+        private readonly Box headerBg;
+        private readonly SearchTextBox search;
+        private readonly SearchContainer<ChannelSection> sectionsFlow;
+
+        public Action<Channel> OnRequestJoin;
+        public Action<Channel> OnRequestLeave;
+
+        public IEnumerable<ChannelSection> Sections
+        {
+            set
+            {
+                sectionsFlow.Children = value;
+
+                foreach (ChannelSection s in sectionsFlow.Children)
+                {
+                    foreach (ChannelListItem c in s.ChannelFlow.Children)
+                    {
+                        c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); };
+                        c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); };
+                    }
+                }
+            }
+        }
+
+        public ChannelSelectionOverlay()
+        {
+            RelativeSizeAxes = Axes.X;
+
+            Children = new Drawable[]
+            {
+                new Container
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Masking = true,
+                    Children = new Drawable[]
+                    {
+                        bg = new Box
+                        {
+                            RelativeSizeAxes = Axes.Both,
+                        },
+                        triangles = new Triangles
+                        {
+                            RelativeSizeAxes = Axes.Both,
+                            TriangleScale = 5,
+                        },
+                    },
+                },
+                new Container
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Padding = new MarginPadding { Top = 85, Right = WIDTH_PADDING },
+                    Children = new[]
+                    {
+                        new ScrollContainer
+                        {
+                            RelativeSizeAxes = Axes.Both,
+                            Children = new[]
+                            {
+                                sectionsFlow = new SearchContainer<ChannelSection>
+                                {
+                                    RelativeSizeAxes = Axes.X,
+                                    AutoSizeAxes = Axes.Y,
+                                    Direction = FillDirection.Vertical,
+                                    LayoutDuration = 200,
+                                    LayoutEasing = EasingTypes.OutQuint,
+                                    Spacing = new Vector2(0f, 20f),
+                                    Padding = new MarginPadding { Vertical = 20, Left = WIDTH_PADDING },
+                                },
+                            },
+                        },
+                    },
+                },
+                new Container
+                {
+                    RelativeSizeAxes = Axes.X,
+                    AutoSizeAxes = Axes.Y,
+                    Children = new Drawable[]
+                    {
+                        headerBg = new Box
+                        {
+                            RelativeSizeAxes = Axes.Both,
+                        },
+                        new FillFlowContainer
+                        {
+                            RelativeSizeAxes = Axes.X,
+                            AutoSizeAxes = Axes.Y,
+                            Direction = FillDirection.Vertical,
+                            Spacing = new Vector2(0f, 10f),
+                            Padding = new MarginPadding { Top = 10f, Bottom = 10f, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
+                            Children = new Drawable[]
+                            {
+                                new OsuSpriteText
+                                {
+                                    Text = @"Chat Channels",
+                                    TextSize = 20,
+                                    Shadow = false,
+                                },
+                                search = new HeaderSearchTextBox
+                                {
+                                    RelativeSizeAxes = Axes.X,
+                                    PlaceholderText = @"Search",
+                                    Exit = Hide,
+                                },
+                            },
+                        },
+                    },
+                },
+            };
+
+            search.Current.ValueChanged += newValue => sectionsFlow.SearchTerm = newValue;
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            bg.Colour = colours.Gray3;
+            triangles.ColourDark = colours.Gray3;
+            triangles.ColourLight = OsuColour.FromHex(@"353535");
+
+            headerBg.Colour = colours.Gray2.Opacity(0.75f);
+        }
+
+        protected override void OnFocus(InputState state)
+        {
+            InputManager.ChangeFocus(search);
+            base.OnFocus(state);
+        }
+
+        protected override void PopIn()
+        {
+            if (Alpha == 0) MoveToY(DrawHeight);
+
+            FadeIn(transition_duration, EasingTypes.OutQuint);
+            MoveToY(0, transition_duration, EasingTypes.OutQuint);
+
+            search.HoldFocus = true;
+            base.PopIn();
+        }
+
+        protected override void PopOut()
+        {
+            FadeOut(transition_duration, EasingTypes.InSine);
+            MoveToY(DrawHeight, transition_duration, EasingTypes.InSine);
+
+            search.HoldFocus = false;
+            base.PopOut();
+        }
+
+        private class HeaderSearchTextBox : SearchTextBox
+        {
+            protected override Color4 BackgroundFocused => Color4.Black.Opacity(0.2f);
+            protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.2f);
+        }
+    }
+}
diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs
index a281cff7db..23ddff9381 100644
--- a/osu.Game/Overlays/Chat/ChatTabControl.cs
+++ b/osu.Game/Overlays/Chat/ChatTabControl.cs
@@ -207,11 +207,15 @@ namespace osu.Game.Overlays.Chat
             {
                 public override bool Active
                 {
-                    get { return base.Active; }
+                    get { return false; }
+                    // ReSharper disable once ValueParameterNotUsed
                     set
                     {
-                        activeBindable.Value = value;
-                        base.Active = value;
+                        // we basically never want this tab to become active.
+                        // this allows us to become a "toggle" tab.
+                        // is a bit hacky, to say the least.
+                        activeBindable.Value = !activeBindable.Value;
+                        base.Active = false;
                     }
                 }
 
@@ -220,6 +224,9 @@ namespace osu.Game.Overlays.Chat
                 public ChannelSelectorTabItem(Channel value, Bindable<bool> active) : base(value)
                 {
                     activeBindable = active;
+                    activeBindable.ValueChanged += v => selectorUpdateState();
+
+
                     Depth = float.MaxValue;
                     Width = 45;
 
@@ -235,6 +242,26 @@ namespace osu.Game.Overlays.Chat
                     backgroundInactive = colour.Gray2;
                     backgroundActive = colour.Gray3;
                 }
+
+                protected override void LoadComplete()
+                {
+                    base.LoadComplete();
+
+                    selectorUpdateState();
+                }
+
+                protected override void OnHoverLost(InputState state)
+                {
+                    selectorUpdateState();
+                }
+
+                private void selectorUpdateState()
+                {
+                    if (activeBindable.Value)
+                        fadeActive();
+                    else
+                        fadeInactive();
+                }
             }
         }
     }
diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs
index f81c0ea922..c32199f881 100644
--- a/osu.Game/Overlays/ChatOverlay.cs
+++ b/osu.Game/Overlays/ChatOverlay.cs
@@ -29,6 +29,7 @@ namespace osu.Game.Overlays
     public class ChatOverlay : FocusedOverlayContainer, IOnlineComponent
     {
         private const float textbox_height = 60;
+        private const float channel_selection_min_height = 0.3f;
 
         private ScheduledDelegate messageRequest;
 
@@ -48,16 +49,21 @@ namespace osu.Game.Overlays
 
         private readonly ChatTabControl channelTabs;
 
+        private readonly Container chatContainer;
         private readonly Box chatBackground;
         private readonly Box tabBackground;
 
         private Bindable<double> chatHeight;
 
+        private readonly Container channelSelectionContainer;
+        private readonly ChannelSelectionOverlay channelSelection;
+
+        protected override bool InternalContains(Vector2 screenSpacePos) => chatContainer.Contains(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.Contains(screenSpacePos);
+
         public ChatOverlay()
         {
             RelativeSizeAxes = Axes.Both;
             RelativePositionAxes = Axes.Both;
-            Size = new Vector2(1, DEFAULT_HEIGHT);
             Anchor = Anchor.BottomLeft;
             Origin = Anchor.BottomLeft;
 
@@ -65,74 +71,120 @@ namespace osu.Game.Overlays
 
             Children = new Drawable[]
             {
-                new Container
+                channelSelectionContainer = new Container
                 {
-                    Name = @"chat area",
                     RelativeSizeAxes = Axes.Both,
-                    Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
-                    Children = new Drawable[]
+                    Height = 1f - DEFAULT_HEIGHT,
+                    Masking = true,
+                    Children = new[]
                     {
-                        chatBackground = new Box
+                        channelSelection = new ChannelSelectionOverlay
                         {
                             RelativeSizeAxes = Axes.Both,
                         },
-                        currentChannelContainer = new Container
+                    },
+                },
+                chatContainer = new Container
+                {
+                    Name = @"chat container",
+                    Anchor = Anchor.BottomLeft,
+                    Origin = Anchor.BottomLeft,
+                    RelativeSizeAxes = Axes.Both,
+                    Height = DEFAULT_HEIGHT,
+                    Children = new[]
+                    {
+                        new Container
                         {
+                            Name = @"chat area",
                             RelativeSizeAxes = Axes.Both,
-                            Padding = new MarginPadding
+                            Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
+                            Children = new Drawable[]
                             {
-                                Bottom = textbox_height + padding
-                            },
+                                chatBackground = new Box
+                                {
+                                    RelativeSizeAxes = Axes.Both,
+                                },
+                                currentChannelContainer = new Container
+                                {
+                                    RelativeSizeAxes = Axes.Both,
+                                    Padding = new MarginPadding
+                                    {
+                                        Bottom = textbox_height + padding
+                                    },
+                                },
+                                new Container
+                                {
+                                    Anchor = Anchor.BottomLeft,
+                                    Origin = Anchor.BottomLeft,
+                                    RelativeSizeAxes = Axes.X,
+                                    Height = textbox_height,
+                                    Padding = new MarginPadding
+                                    {
+                                        Top = padding * 2,
+                                        Bottom = padding * 2,
+                                        Left = ChatLine.LEFT_PADDING + padding * 2,
+                                        Right = padding * 2,
+                                    },
+                                    Children = new Drawable[]
+                                    {
+                                        inputTextBox = new FocusedTextBox
+                                        {
+                                            RelativeSizeAxes = Axes.Both,
+                                            Height = 1,
+                                            PlaceholderText = "type your message",
+                                            Exit = () => State = Visibility.Hidden,
+                                            OnCommit = postMessage,
+                                            ReleaseFocusOnCommit = false,
+                                            HoldFocus = true,
+                                        }
+                                    }
+                                }
+                            }
                         },
                         new Container
                         {
-                            Anchor = Anchor.BottomLeft,
-                            Origin = Anchor.BottomLeft,
+                            Name = @"tabs area",
                             RelativeSizeAxes = Axes.X,
-                            Height = textbox_height,
-                            Padding = new MarginPadding
-                            {
-                                Top = padding * 2,
-                                Bottom = padding * 2,
-                                Left = ChatLine.LEFT_PADDING + padding * 2,
-                                Right = padding * 2,
-                            },
+                            Height = TAB_AREA_HEIGHT,
                             Children = new Drawable[]
                             {
-                                inputTextBox = new FocusedTextBox
+                                tabBackground = new Box
                                 {
                                     RelativeSizeAxes = Axes.Both,
-                                    Height = 1,
-                                    PlaceholderText = "type your message",
-                                    Exit = () => State = Visibility.Hidden,
-                                    OnCommit = postMessage,
-                                    HoldFocus = true,
-                                }
+                                    Colour = Color4.Black,
+                                },
+                                channelTabs = new ChatTabControl
+                                {
+                                    RelativeSizeAxes = Axes.Both,
+                                },
                             }
-                        }
-                    }
-                },
-                new Container
-                {
-                    Name = @"tabs area",
-                    RelativeSizeAxes = Axes.X,
-                    Height = TAB_AREA_HEIGHT,
-                    Children = new Drawable[]
-                    {
-                        tabBackground = new Box
-                        {
-                            RelativeSizeAxes = Axes.Both,
-                            Colour = Color4.Black,
                         },
-                        channelTabs = new ChatTabControl
-                        {
-                            RelativeSizeAxes = Axes.Both,
-                        },
-                    }
+                    },
                 },
             };
 
             channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
+            channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
+            channelSelection.StateChanged += (overlay, state) =>
+            {
+                channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible;
+
+                if (state == Visibility.Visible)
+                {
+                    inputTextBox.HoldFocus = false;
+                    if (1f - chatHeight.Value < channel_selection_min_height)
+                    {
+                        chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, EasingTypes.OutQuint);
+                        channelSelectionContainer.ResizeHeightTo(channel_selection_min_height, 800, EasingTypes.OutQuint);
+                        channelSelection.Show();
+                        chatHeight.Value = 1f - channel_selection_min_height;
+                    }
+                }
+                else
+                {
+                    inputTextBox.HoldFocus = true;
+                }
+            };
         }
 
         private double startDragChatHeight;
@@ -205,8 +257,9 @@ namespace osu.Game.Overlays
             chatHeight = config.GetBindable<double>(OsuSetting.ChatDisplayHeight);
             chatHeight.ValueChanged += h =>
             {
-                Height = (float)h;
-                tabBackground.FadeTo(Height == 1 ? 1 : 0.8f, 200);
+                chatContainer.Height = (float)h;
+                channelSelectionContainer.Height = 1f - (float)h;
+                tabBackground.FadeTo(h == 1 ? 1 : 0.8f, 200);
             };
             chatHeight.TriggerChange();
 
@@ -243,6 +296,16 @@ namespace osu.Game.Overlays
                     addChannel(channels.Find(c => c.Name == @"#lazer"));
                     addChannel(channels.Find(c => c.Name == @"#osu"));
                     addChannel(channels.Find(c => c.Name == @"#lobby"));
+
+                    channelSelection.OnRequestJoin = addChannel;
+                    channelSelection.Sections = new[]
+                    {
+                        new ChannelSection
+                        {
+                            Header = "All Channels",
+                            Channels = channels,
+                        },
+                    };
                 });
 
                 messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
@@ -262,9 +325,7 @@ namespace osu.Game.Overlays
 
             set
             {
-                if (currentChannel == value) return;
-
-                if (channelTabs.ChannelSelectorActive) return;
+                if (currentChannel == value || value == null) return;
 
                 currentChannel = value;
 
@@ -316,6 +377,8 @@ namespace osu.Game.Overlays
 
             if (CurrentChannel == null)
                 CurrentChannel = channel;
+
+            channel.Joined.Value = true;
         }
 
         private void fetchInitialMessages(Channel channel)
diff --git a/osu.Game/Overlays/Music/CollectionsDropdown.cs b/osu.Game/Overlays/Music/CollectionsDropdown.cs
new file mode 100644
index 0000000000..fd2ef23b9c
--- /dev/null
+++ b/osu.Game/Overlays/Music/CollectionsDropdown.cs
@@ -0,0 +1,73 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.UserInterface;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Overlays.Music
+{
+    public class CollectionsDropdown<T> : OsuDropdown<T>
+    {
+        protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
+        protected override Menu CreateMenu() => new CollectionsMenu();
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            AccentColour = colours.Gray6;
+        }
+
+        private class CollectionsHeader : OsuDropdownHeader
+        {
+            [BackgroundDependencyLoader]
+            private void load(OsuColour colours)
+            {
+                BackgroundColour = colours.Gray4;
+            }
+
+            public CollectionsHeader()
+            {
+                CornerRadius = 5;
+                Height = 30;
+                Icon.TextSize = 14;
+                Icon.Margin = new MarginPadding(0);
+                Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
+                EdgeEffect = new EdgeEffect
+                {
+                    Type = EdgeEffectType.Shadow,
+                    Colour = Color4.Black.Opacity(0.3f),
+                    Radius = 3,
+                    Offset = new Vector2(0f, 1f),
+                };
+            }
+        }
+
+        private class CollectionsMenu : OsuMenu
+        {
+            [BackgroundDependencyLoader]
+            private void load(OsuColour colours)
+            {
+                Background.Colour = colours.Gray4;
+            }
+
+            public CollectionsMenu()
+            {
+                CornerRadius = 5;
+                EdgeEffect = new EdgeEffect
+                {
+                    Type = EdgeEffectType.Shadow,
+                    Colour = Color4.Black.Opacity(0.3f),
+                    Radius = 3,
+                    Offset = new Vector2(0f, 1f),
+                };
+            }
+        }
+    }
+}
diff --git a/osu.Game/Overlays/Music/FilterControl.cs b/osu.Game/Overlays/Music/FilterControl.cs
index 6d8790a9e8..56cd6e864b 100644
--- a/osu.Game/Overlays/Music/FilterControl.cs
+++ b/osu.Game/Overlays/Music/FilterControl.cs
@@ -3,10 +3,8 @@
 
 using System.Collections.Generic;
 using osu.Framework.Allocation;
-using osu.Framework.Extensions.Color4Extensions;
 using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.UserInterface;
 using osu.Game.Graphics;
 using osu.Game.Graphics.UserInterface;
 using OpenTK;
@@ -74,63 +72,5 @@ namespace osu.Game.Overlays.Music
                 backgroundColour = colours.Gray2;
             }
         }
-
-        private class CollectionsDropdown<T> : OsuDropdown<T>
-        {
-            protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
-            protected override Menu CreateMenu() => new CollectionsMenu();
-
-            [BackgroundDependencyLoader]
-            private void load(OsuColour colours)
-            {
-                AccentColour = colours.Gray6;
-            }
-
-            private class CollectionsHeader : OsuDropdownHeader
-            {
-                [BackgroundDependencyLoader]
-                private void load(OsuColour colours)
-                {
-                    BackgroundColour = colours.Gray4;
-                }
-
-                public CollectionsHeader()
-                {
-                    CornerRadius = 5;
-                    Height = 30;
-                    Icon.TextSize = 14;
-                    Icon.Margin = new MarginPadding(0);
-                    Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
-                    EdgeEffect = new EdgeEffect
-                    {
-                        Type = EdgeEffectType.Shadow,
-                        Colour = Color4.Black.Opacity(0.3f),
-                        Radius = 3,
-                        Offset = new Vector2(0f, 1f),
-                    };
-                }
-            }
-
-            private class CollectionsMenu : OsuMenu
-            {
-                [BackgroundDependencyLoader]
-                private void load(OsuColour colours)
-                {
-                    Background.Colour = colours.Gray4;
-                }
-
-                public CollectionsMenu()
-                {
-                    CornerRadius = 5;
-                    EdgeEffect = new EdgeEffect
-                    {
-                        Type = EdgeEffectType.Shadow,
-                        Colour = Color4.Black.Opacity(0.3f),
-                        Radius = 3,
-                        Offset = new Vector2(0f, 1f),
-                    };
-                }
-            }
-        }
     }
 }
diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs
index 0618f96cac..789e45adfc 100644
--- a/osu.Game/Overlays/Music/PlaylistItem.cs
+++ b/osu.Game/Overlays/Music/PlaylistItem.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
         private Color4 artistColour;
 
         private TextAwesome handle;
-        private Paragraph text;
+        private TextFlowContainer text;
         private IEnumerable<SpriteText> titleSprites;
         private UnicodeBindableString titleBind;
         private UnicodeBindableString artistBind;
@@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Music
                     Margin = new MarginPadding { Left = 5 },
                     Padding = new MarginPadding { Top = 2 },
                 },
-                text = new Paragraph
+                text = new TextFlowContainer
                 {
                     RelativeSizeAxes = Axes.X,
                     AutoSizeAxes = Axes.Y,
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index f1be55801f..bfe10e845e 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -22,6 +22,7 @@ using osu.Game.Graphics;
 using osu.Game.Graphics.Sprites;
 using osu.Framework.Threading;
 using osu.Game.Overlays.Music;
+using osu.Game.Graphics.UserInterface;
 
 namespace osu.Game.Overlays
 {
@@ -38,8 +39,8 @@ namespace osu.Game.Overlays
         private Drawable currentBackground;
         private DragBar progressBar;
 
-        private Button playButton;
-        private Button playlistButton;
+        private IconButton playButton;
+        private IconButton playlistButton;
 
         private SpriteText title, artist;
 
@@ -143,7 +144,7 @@ namespace osu.Game.Overlays
                                     Anchor = Anchor.BottomCentre,
                                     Children = new Drawable[]
                                     {
-                                        new FillFlowContainer<Button>
+                                        new FillFlowContainer<IconButton>
                                         {
                                             AutoSizeAxes = Axes.Both,
                                             Direction = FillDirection.Horizontal,
@@ -152,26 +153,26 @@ namespace osu.Game.Overlays
                                             Anchor = Anchor.Centre,
                                             Children = new[]
                                             {
-                                                new Button
+                                                new IconButton
                                                 {
                                                     Action = prev,
                                                     Icon = FontAwesome.fa_step_backward,
                                                 },
-                                                playButton = new Button
+                                                playButton = new IconButton
                                                 {
                                                     Scale = new Vector2(1.4f),
                                                     IconScale = new Vector2(1.4f),
                                                     Action = play,
                                                     Icon = FontAwesome.fa_play_circle_o,
                                                 },
-                                                new Button
+                                                new IconButton
                                                 {
                                                     Action = next,
                                                     Icon = FontAwesome.fa_step_forward,
                                                 },
                                             }
                                         },
-                                        playlistButton = new Button
+                                        playlistButton = new IconButton
                                         {
                                             Origin = Anchor.Centre,
                                             Anchor = Anchor.CentreRight,
@@ -415,105 +416,5 @@ namespace osu.Game.Overlays
                 sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
             }
         }
-
-        private class Button : ClickableContainer
-        {
-            private readonly TextAwesome icon;
-            private readonly Box hover;
-            private readonly Container content;
-
-            public FontAwesome Icon
-            {
-                get { return icon.Icon; }
-                set { icon.Icon = value; }
-            }
-
-            private const float button_size = 30;
-            private Color4 flashColour;
-
-            public Vector2 IconScale
-            {
-                get { return icon.Scale; }
-                set { icon.Scale = value; }
-            }
-
-            public Button()
-            {
-                AutoSizeAxes = Axes.Both;
-
-                Origin = Anchor.Centre;
-                Anchor = Anchor.Centre;
-
-                Children = new Drawable[]
-                {
-                    content = new Container
-                    {
-                        Size = new Vector2(button_size),
-                        CornerRadius = 5,
-                        Masking = true,
-
-                        Origin = Anchor.Centre,
-                        Anchor = Anchor.Centre,
-                        EdgeEffect = new EdgeEffect
-                        {
-                            Colour = Color4.Black.Opacity(0.04f),
-                            Type = EdgeEffectType.Shadow,
-                            Radius = 5,
-                        },
-                        Children = new Drawable[]
-                        {
-                            hover = new Box
-                            {
-                                RelativeSizeAxes = Axes.Both,
-                                Alpha = 0,
-                            },
-                            icon = new TextAwesome
-                            {
-                                TextSize = 18,
-                                Origin = Anchor.Centre,
-                                Anchor = Anchor.Centre
-                            }
-                        }
-                    }
-                };
-            }
-
-            [BackgroundDependencyLoader]
-            private void load(OsuColour colours)
-            {
-                hover.Colour = colours.Yellow.Opacity(0.6f);
-                flashColour = colours.Yellow;
-            }
-
-            protected override bool OnHover(InputState state)
-            {
-                hover.FadeIn(500, EasingTypes.OutQuint);
-                return base.OnHover(state);
-            }
-
-            protected override void OnHoverLost(InputState state)
-            {
-                hover.FadeOut(500, EasingTypes.OutQuint);
-                base.OnHoverLost(state);
-            }
-
-            protected override bool OnClick(InputState state)
-            {
-                hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
-                return base.OnClick(state);
-            }
-
-            protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
-            {
-                content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
-                return base.OnMouseDown(state, args);
-            }
-
-            protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
-            {
-                content.ScaleTo(1, 1000, EasingTypes.OutElastic);
-                return base.OnMouseUp(state, args);
-            }
-        }
     }
 }
diff --git a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
index 9cf5c42319..311fa072c6 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/MouseSettings.cs
@@ -14,14 +14,31 @@ namespace osu.Game.Overlays.Settings.Sections.Input
     {
         protected override string Header => "Mouse";
 
+        private readonly BindableBool rawInputToggle = new BindableBool();
+        private Bindable<string> activeInputHandlers;
+        private SensitivitySetting sensitivity;
+
         [BackgroundDependencyLoader]
         private void load(OsuConfigManager osuConfig, FrameworkConfigManager config)
         {
+            activeInputHandlers = config.GetBindable<string>(FrameworkSetting.ActiveInputHandlers);
+            rawInputToggle.Value = activeInputHandlers.Value.Contains("Raw");
+
             Children = new Drawable[]
             {
+                new SettingsCheckbox
+                {
+                    LabelText = "Raw Input",
+                    Bindable = rawInputToggle
+                },
+                sensitivity = new SensitivitySetting
+                {
+                    LabelText = "Cursor Sensitivity",
+                    Bindable = config.GetBindable<double>(FrameworkSetting.CursorSensitivity)
+                },
                 new SettingsEnumDropdown<ConfineMouseMode>
                 {
-                    LabelText = "Confine mouse cursor",
+                    LabelText = "Confine mouse cursor to window",
                     Bindable = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
                 },
                 new SettingsCheckbox
@@ -35,11 +52,82 @@ namespace osu.Game.Overlays.Settings.Sections.Input
                     Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
                 },
             };
+
+            rawInputToggle.ValueChanged += enabled =>
+            {
+                // this is temporary until we support per-handler settings.
+                const string raw_mouse_handler = @"OpenTKRawMouseHandler";
+                const string standard_mouse_handler = @"OpenTKMouseHandler";
+
+                activeInputHandlers.Value = enabled ?
+                    activeInputHandlers.Value.Replace(standard_mouse_handler, raw_mouse_handler) :
+                    activeInputHandlers.Value.Replace(raw_mouse_handler, standard_mouse_handler);
+
+                sensitivity.Bindable.Disabled = !enabled;
+            };
+
+            rawInputToggle.TriggerChange();
+        }
+
+        private class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
+        {
+            public override Bindable<double> Bindable
+            {
+                get { return ((SensitivitySlider)Control).Sensitivity; }
+
+                set
+                {
+                    BindableDouble doubleValue = (BindableDouble)value;
+
+                    // create a second layer of bindable so we can only handle state changes when not being dragged.
+                    ((SensitivitySlider)Control).Sensitivity = doubleValue;
+
+                    // this bindable will still act as the "interactive" bindable displayed during a drag.
+                    base.Bindable = new BindableDouble(doubleValue.Value)
+                    {
+                        MinValue = doubleValue.MinValue,
+                        MaxValue = doubleValue.MaxValue
+                    };
+
+                    // one-way binding to update the sliderbar with changes from external actions.
+                    doubleValue.DisabledChanged += disabled => base.Bindable.Disabled = disabled;
+                    doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue;
+                }
+            }
         }
 
         private class SensitivitySlider : OsuSliderBar<double>
         {
-            public override string TooltipText => Current.Value.ToString(@"0.##x");
+            public Bindable<double> Sensitivity;
+
+            public SensitivitySlider()
+            {
+                KeyboardStep = 0.01f;
+
+                Current.ValueChanged += newValue =>
+                {
+                    if (!isDragging && Sensitivity != null)
+                        Sensitivity.Value = newValue;
+                };
+            }
+
+            private bool isDragging;
+
+            protected override bool OnDragStart(InputState state)
+            {
+                isDragging = true;
+                return base.OnDragStart(state);
+            }
+
+            protected override bool OnDragEnd(InputState state)
+            {
+                isDragging = false;
+                Current.TriggerChange();
+
+                return base.OnDragEnd(state);
+            }
+
+            public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x");
         }
     }
-}
+}
\ No newline at end of file
diff --git a/osu.Game/Overlays/Settings/SettingsItem.cs b/osu.Game/Overlays/Settings/SettingsItem.cs
index 7cddefb755..14b67dd6df 100644
--- a/osu.Game/Overlays/Settings/SettingsItem.cs
+++ b/osu.Game/Overlays/Settings/SettingsItem.cs
@@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings
         // hold a reference to the provided bindable so we don't have to in every settings section.
         private Bindable<T> bindable;
 
-        public Bindable<T> Bindable
+        public virtual Bindable<T> Bindable
         {
             get
             {
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 115611c244..3248495b61 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -7,21 +7,24 @@ using osu.Framework.Graphics;
 using osu.Framework.Graphics.Containers;
 using osu.Framework.Input;
 using osu.Game.Configuration;
+using osu.Game.Graphics;
 using osu.Game.Graphics.UserInterface;
 using osu.Game.Overlays;
 using osu.Game.Overlays.Notifications;
 using osu.Game.Rulesets.Scoring;
 using osu.Game.Rulesets.UI;
 using osu.Game.Screens.Play.HUD;
+using OpenTK;
 using OpenTK.Input;
 
 namespace osu.Game.Screens.Play
 {
-    public abstract class HUDOverlay : Container
+    public class HUDOverlay : Container
     {
         private const int duration = 100;
 
         private readonly Container content;
+
         public readonly KeyCounterCollection KeyCounter;
         public readonly RollingCounter<int> ComboCounter;
         public readonly ScoreCounter ScoreCounter;
@@ -31,18 +34,11 @@ namespace osu.Game.Screens.Play
         public readonly ModDisplay ModDisplay;
 
         private Bindable<bool> showHud;
+        private bool replayLoaded;
 
         private static bool hasShownNotificationOnce;
 
-        protected abstract KeyCounterCollection CreateKeyCounter();
-        protected abstract RollingCounter<int> CreateComboCounter();
-        protected abstract RollingCounter<double> CreateAccuracyCounter();
-        protected abstract ScoreCounter CreateScoreCounter();
-        protected abstract HealthDisplay CreateHealthDisplay();
-        protected abstract SongProgress CreateProgress();
-        protected abstract ModDisplay CreateModsContainer();
-
-        protected HUDOverlay()
+        public HUDOverlay()
         {
             RelativeSizeAxes = Axes.Both;
 
@@ -59,12 +55,13 @@ namespace osu.Game.Screens.Play
                     HealthDisplay = CreateHealthDisplay(),
                     Progress = CreateProgress(),
                     ModDisplay = CreateModsContainer(),
+                    //ReplaySettingsOverlay = CreateReplaySettingsOverlay(),
                 }
             });
         }
 
         [BackgroundDependencyLoader(true)]
-        private void load(OsuConfigManager config, NotificationManager notificationManager)
+        private void load(OsuConfigManager config, NotificationManager notificationManager, OsuColour colours)
         {
             showHud = config.GetBindable<bool>(OsuSetting.ShowInterface);
             showHud.ValueChanged += hudVisibility => content.FadeTo(hudVisibility ? 1 : 0, duration);
@@ -79,24 +76,32 @@ namespace osu.Game.Screens.Play
                     Text = @"The score overlay is currently disabled. You can toggle this by pressing Shift+Tab."
                 });
             }
-        }
 
-        public virtual void BindProcessor(ScoreProcessor processor)
-        {
-            ScoreCounter?.Current.BindTo(processor.TotalScore);
-            AccuracyCounter?.Current.BindTo(processor.Accuracy);
-            ComboCounter?.Current.BindTo(processor.Combo);
-            HealthDisplay?.Current.BindTo(processor.Health);
+            // todo: the stuff below should probably not be in this base implementation, but in each individual class.
+            ComboCounter.AccentColour = colours.BlueLighter;
+            AccuracyCounter.AccentColour = colours.BlueLighter;
+            ScoreCounter.AccentColour = colours.BlueLighter;
+
+            var shd = HealthDisplay as StandardHealthDisplay;
+            if (shd != null)
+            {
+                shd.AccentColour = colours.BlueLighter;
+                shd.GlowColour = colours.BlueDarker;
+            }
         }
 
         public virtual void BindHitRenderer(HitRenderer hitRenderer)
         {
             hitRenderer.InputManager.Add(KeyCounter.GetReceptor());
 
+            replayLoaded = hitRenderer.HasReplayLoaded;
+
             // in the case a replay isn't loaded, we want some elements to only appear briefly.
-            if (!hitRenderer.HasReplayLoaded)
+            if (!replayLoaded)
+            {
                 using (ModDisplay.BeginDelayedSequence(2000))
                     ModDisplay.FadeOut(200);
+            }
         }
 
         protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
@@ -115,5 +120,82 @@ namespace osu.Game.Screens.Play
 
             return base.OnKeyDown(state, args);
         }
+
+        protected virtual RollingCounter<double> CreateAccuracyCounter() => new PercentageCounter
+        {
+            Anchor = Anchor.TopCentre,
+            Origin = Anchor.TopRight,
+            Position = new Vector2(0, 35),
+            TextSize = 20,
+            Margin = new MarginPadding { Right = 140 },
+        };
+
+        protected virtual RollingCounter<int> CreateComboCounter() => new SimpleComboCounter
+        {
+            Anchor = Anchor.TopCentre,
+            Origin = Anchor.TopLeft,
+            Position = new Vector2(0, 35),
+            Margin = new MarginPadding { Left = 140 },
+            TextSize = 20,
+        };
+
+        protected virtual HealthDisplay CreateHealthDisplay() => new StandardHealthDisplay
+        {
+            Size = new Vector2(1, 5),
+            RelativeSizeAxes = Axes.X,
+            Margin = new MarginPadding { Top = 20 }
+        };
+
+        protected virtual KeyCounterCollection CreateKeyCounter() => new KeyCounterCollection
+        {
+            IsCounting = true,
+            FadeTime = 50,
+            Anchor = Anchor.BottomRight,
+            Origin = Anchor.BottomRight,
+            Margin = new MarginPadding(10),
+            Y = -TwoLayerButton.SIZE_RETRACTED.Y,
+        };
+
+        protected virtual ScoreCounter CreateScoreCounter() => new ScoreCounter(6)
+        {
+            Anchor = Anchor.TopCentre,
+            Origin = Anchor.TopCentre,
+            TextSize = 40,
+            Position = new Vector2(0, 30),
+        };
+
+        protected virtual SongProgress CreateProgress() => new SongProgress
+        {
+            Anchor = Anchor.BottomLeft,
+            Origin = Anchor.BottomLeft,
+            RelativeSizeAxes = Axes.X,
+        };
+
+        protected virtual ModDisplay CreateModsContainer() => new ModDisplay
+        {
+            Anchor = Anchor.TopRight,
+            Origin = Anchor.TopRight,
+            AutoSizeAxes = Axes.Both,
+            Margin = new MarginPadding { Top = 20, Right = 10 },
+        };
+
+        //protected virtual ReplaySettingsOverlay CreateReplaySettingsOverlay() => new ReplaySettingsOverlay
+        //{
+        //    Anchor = Anchor.TopRight,
+        //    Origin = Anchor.TopRight,
+        //    Margin = new MarginPadding { Top = 100, Right = 10 },
+        //};
+
+        public virtual void BindProcessor(ScoreProcessor processor)
+        {
+            ScoreCounter?.Current.BindTo(processor.TotalScore);
+            AccuracyCounter?.Current.BindTo(processor.Accuracy);
+            ComboCounter?.Current.BindTo(processor.Combo);
+            HealthDisplay?.Current.BindTo(processor.Health);
+
+            var shd = HealthDisplay as StandardHealthDisplay;
+            if (shd != null)
+                processor.NewJudgement += shd.Flash;
+        }
     }
 }
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 707d026e2b..d4b8445ed9 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -170,7 +170,7 @@ namespace osu.Game.Screens.Play
                                 HitRenderer,
                             }
                         },
-                        hudOverlay = new StandardHUDOverlay
+                        hudOverlay = new HUDOverlay
                         {
                             Anchor = Anchor.Centre,
                             Origin = Anchor.Centre
diff --git a/osu.Game/Screens/Play/ReplaySettings/CollectionSettings.cs b/osu.Game/Screens/Play/ReplaySettings/CollectionSettings.cs
new file mode 100644
index 0000000000..482581abca
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/CollectionSettings.cs
@@ -0,0 +1,33 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Overlays.Music;
+using System.Collections.Generic;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public class CollectionSettings : ReplayGroup
+    {
+        protected override string Title => @"collections";
+
+        [BackgroundDependencyLoader]
+        private void load()
+        {
+            Children = new Drawable[]
+            {
+                new OsuSpriteText
+                {
+                    Text = @"Add current song to",
+                },
+                new CollectionsDropdown<PlaylistCollection>
+                {
+                    RelativeSizeAxes = Axes.X,
+                    Items = new[] { new KeyValuePair<string, PlaylistCollection>(@"All", PlaylistCollection.All) },
+                },
+            };
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettings/DiscussionSettings.cs b/osu.Game/Screens/Play/ReplaySettings/DiscussionSettings.cs
new file mode 100644
index 0000000000..9c4fb03517
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/DiscussionSettings.cs
@@ -0,0 +1,35 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Game.Configuration;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public class DiscussionSettings : ReplayGroup
+    {
+        protected override string Title => @"discussions";
+
+        [BackgroundDependencyLoader]
+        private void load(OsuConfigManager config)
+        {
+            Children = new Drawable[]
+            {
+                new ReplayCheckbox
+                {
+                    LabelText = "Show floating comments",
+                    Bindable = config.GetBindable<bool>(OsuSetting.FloatingComments)
+                },
+                new FocusedTextBox
+                {
+                    RelativeSizeAxes = Axes.X,
+                    Height = 30,
+                    PlaceholderText = "Add Comment",
+                    HoldFocus = false,
+                },
+            };
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs
new file mode 100644
index 0000000000..7f69d3109c
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/PlaybackSettings.cs
@@ -0,0 +1,27 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Game.Configuration;
+using osu.Framework.Graphics;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public class PlaybackSettings : ReplayGroup
+    {
+        protected override string Title => @"playback";
+
+        [BackgroundDependencyLoader]
+        private void load(OsuConfigManager config)
+        {
+            Children = new Drawable[]
+            {
+                new ReplaySliderBar<double>()
+                {
+                    LabelText = "Playback speed",
+                    Bindable = config.GetBindable<double>(OsuSetting.PlaybackSpeed)
+                }
+            };
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettings/ReplayCheckbox.cs b/osu.Game/Screens/Play/ReplaySettings/ReplayCheckbox.cs
new file mode 100644
index 0000000000..7ad1e4f527
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/ReplayCheckbox.cs
@@ -0,0 +1,20 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Game.Graphics;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public class ReplayCheckbox : OsuCheckbox
+    {
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            Nub.AccentColour = colours.Yellow;
+            Nub.GlowingAccentColour = colours.YellowLighter;
+            Nub.GlowColour = colours.YellowDarker;
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettings/ReplayGroup.cs b/osu.Game/Screens/Play/ReplaySettings/ReplayGroup.cs
new file mode 100644
index 0000000000..3e4c0dca5c
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/ReplayGroup.cs
@@ -0,0 +1,132 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using OpenTK;
+using OpenTK.Graphics;
+using osu.Framework.Allocation;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics.UserInterface;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public abstract class ReplayGroup : Container
+    {
+        /// <summary>
+        /// The title to be displayed in the header of this group.
+        /// </summary>
+        protected abstract string Title { get; }
+
+        private const float transition_duration = 250;
+        private const int container_width = 270;
+        private const int border_thickness = 2;
+        private const int header_height = 30;
+        private const int corner_radius = 5;
+
+        private readonly FillFlowContainer content;
+        private readonly IconButton button;
+
+        private bool expanded = true;
+
+        private Color4 buttonActiveColour;
+
+        protected ReplayGroup()
+        {
+            AutoSizeAxes = Axes.Y;
+            Width = container_width;
+            Masking = true;
+            CornerRadius = corner_radius;
+            BorderColour = Color4.Black;
+            BorderThickness = border_thickness;
+
+            InternalChildren = new Drawable[]
+            {
+                new Box
+                {
+                    RelativeSizeAxes = Axes.Both,
+                    Colour = Color4.Black,
+                    Alpha = 0.5f,
+                },
+                new FillFlowContainer
+                {
+                    Direction = FillDirection.Vertical,
+                    RelativeSizeAxes = Axes.X,
+                    AutoSizeAxes = Axes.Y,
+                    Children = new Drawable[]
+                    {
+                        new Container
+                        {
+                            Name = @"Header",
+                            Origin = Anchor.TopCentre,
+                            Anchor = Anchor.TopCentre,
+                            RelativeSizeAxes = Axes.X,
+                            Height = header_height,
+                            Children = new Drawable[]
+                            {
+                                new OsuSpriteText
+                                {
+                                    Origin = Anchor.CentreLeft,
+                                    Anchor = Anchor.CentreLeft,
+                                    Text = Title.ToUpper(),
+                                    TextSize = 17,
+                                    Font = @"Exo2.0-Bold",
+                                    Margin = new MarginPadding { Left = 10 },
+                                },
+                                button = new IconButton
+                                {
+                                    Origin = Anchor.Centre,
+                                    Anchor = Anchor.CentreRight,
+                                    Position = new Vector2(-15,0),
+                                    Icon = FontAwesome.fa_bars,
+                                    Scale = new Vector2(0.75f),
+                                    Action = toggleContentVisibility,
+                                },
+                            }
+                        },
+                        content = new FillFlowContainer
+                        {
+                            Name = @"Content",
+                            Origin = Anchor.TopCentre,
+                            Anchor = Anchor.TopCentre,
+                            Direction = FillDirection.Vertical,
+                            RelativeSizeAxes = Axes.X,
+                            AutoSizeDuration = transition_duration,
+                            AutoSizeEasing = EasingTypes.OutQuint,
+                            AutoSizeAxes = Axes.Y,
+                            Padding = new MarginPadding(15),
+                            Spacing = new Vector2(0, 15),
+                        }
+                    }
+                },
+            };
+        }
+
+        [BackgroundDependencyLoader]
+        private void load(OsuColour colours)
+        {
+            button.Colour = buttonActiveColour = colours.Yellow;
+        }
+
+        protected override Container<Drawable> Content => content;
+
+        private void toggleContentVisibility()
+        {
+            content.ClearTransforms();
+
+            expanded = !expanded;
+
+            if (expanded)
+                content.AutoSizeAxes = Axes.Y;
+            else
+            {
+                content.AutoSizeAxes = Axes.None;
+                content.ResizeHeightTo(0, transition_duration, EasingTypes.OutQuint);
+            }
+
+            button.FadeColour(expanded ? buttonActiveColour : Color4.White, 200, EasingTypes.OutQuint);
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettings/ReplaySliderBar.cs b/osu.Game/Screens/Play/ReplaySettings/ReplaySliderBar.cs
new file mode 100644
index 0000000000..4992c3a1e7
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettings/ReplaySliderBar.cs
@@ -0,0 +1,34 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Allocation;
+using osu.Game.Graphics.UserInterface;
+using System;
+using osu.Game.Graphics;
+using osu.Framework.Graphics;
+using osu.Game.Overlays.Settings;
+
+namespace osu.Game.Screens.Play.ReplaySettings
+{
+    public class ReplaySliderBar<T> : SettingsSlider<T>
+        where T : struct, IEquatable<T>
+    {
+        protected override Drawable CreateControl() => new Sliderbar()
+        {
+            Margin = new MarginPadding { Top = 5, Bottom = 5 },
+            RelativeSizeAxes = Axes.X
+        };
+
+        private class Sliderbar : OsuSliderBar<T>
+        {
+            [BackgroundDependencyLoader]
+            private void load(OsuColour colours)
+            {
+                AccentColour = colours.Yellow;
+                Nub.AccentColour = colours.Yellow;
+                Nub.GlowingAccentColour = colours.YellowLighter;
+                Nub.GlowColour = colours.YellowDarker;
+            }
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/ReplaySettingsOverlay.cs b/osu.Game/Screens/Play/ReplaySettingsOverlay.cs
new file mode 100644
index 0000000000..415f70005d
--- /dev/null
+++ b/osu.Game/Screens/Play/ReplaySettingsOverlay.cs
@@ -0,0 +1,24 @@
+// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
+// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
+
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Screens.Play.ReplaySettings;
+using OpenTK;
+
+namespace osu.Game.Screens.Play
+{
+    public class ReplaySettingsOverlay : FillFlowContainer
+    {
+        public ReplaySettingsOverlay()
+        {
+            Direction = FillDirection.Vertical;
+            AutoSizeAxes = Axes.Both;
+            Spacing = new Vector2(0, 20);
+
+            Add(new CollectionSettings());
+            Add(new DiscussionSettings());
+            Add(new PlaybackSettings());
+        }
+    }
+}
diff --git a/osu.Game/Screens/Play/StandardHUDOverlay.cs b/osu.Game/Screens/Play/StandardHUDOverlay.cs
deleted file mode 100644
index 87fbea6810..0000000000
--- a/osu.Game/Screens/Play/StandardHUDOverlay.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
-// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
-
-using osu.Framework.Allocation;
-using osu.Framework.Graphics;
-using osu.Game.Graphics;
-using osu.Game.Graphics.UserInterface;
-using osu.Game.Rulesets.Scoring;
-using osu.Game.Screens.Play.HUD;
-using OpenTK;
-
-namespace osu.Game.Screens.Play
-{
-    public class StandardHUDOverlay : HUDOverlay
-    {
-        protected override RollingCounter<double> CreateAccuracyCounter() => new PercentageCounter
-        {
-            Anchor = Anchor.TopCentre,
-            Origin = Anchor.TopRight,
-            Position = new Vector2(0, 35),
-            TextSize = 20,
-            Margin = new MarginPadding { Right = 140 },
-        };
-
-        protected override RollingCounter<int> CreateComboCounter() => new SimpleComboCounter
-        {
-            Anchor = Anchor.TopCentre,
-            Origin = Anchor.TopLeft,
-            Position = new Vector2(0, 35),
-            Margin = new MarginPadding { Left = 140 },
-            TextSize = 20,
-        };
-
-        protected override HealthDisplay CreateHealthDisplay() => new StandardHealthDisplay
-        {
-            Size = new Vector2(1, 5),
-            RelativeSizeAxes = Axes.X,
-            Margin = new MarginPadding { Top = 20 }
-        };
-
-        protected override KeyCounterCollection CreateKeyCounter() => new KeyCounterCollection
-        {
-            IsCounting = true,
-            FadeTime = 50,
-            Anchor = Anchor.BottomRight,
-            Origin = Anchor.BottomRight,
-            Margin = new MarginPadding(10),
-            Y = - TwoLayerButton.SIZE_RETRACTED.Y,
-        };
-
-        protected override ScoreCounter CreateScoreCounter() => new ScoreCounter(6)
-        {
-            Anchor = Anchor.TopCentre,
-            Origin = Anchor.TopCentre,
-            TextSize = 40,
-            Position = new Vector2(0, 30),
-        };
-
-        protected override SongProgress CreateProgress() => new SongProgress
-        {
-            Anchor = Anchor.BottomLeft,
-            Origin = Anchor.BottomLeft,
-            RelativeSizeAxes = Axes.X,
-        };
-
-        protected override ModDisplay CreateModsContainer() => new ModDisplay
-        {
-            Anchor = Anchor.TopRight,
-            Origin = Anchor.TopRight,
-            AutoSizeAxes = Axes.Both,
-            Margin = new MarginPadding { Top = 20, Right = 10 },
-        };
-
-        [BackgroundDependencyLoader]
-        private void load(OsuColour colours)
-        {
-            ComboCounter.AccentColour = colours.BlueLighter;
-            AccuracyCounter.AccentColour = colours.BlueLighter;
-            ScoreCounter.AccentColour = colours.BlueLighter;
-
-            var shd = HealthDisplay as StandardHealthDisplay;
-            if (shd != null)
-            {
-                shd.AccentColour = colours.BlueLighter;
-                shd.GlowColour = colours.BlueDarker;
-            }
-        }
-
-        public override void BindProcessor(ScoreProcessor processor)
-        {
-            base.BindProcessor(processor);
-
-            var shd = HealthDisplay as StandardHealthDisplay;
-            if (shd != null)
-                processor.NewJudgement += shd.Flash;
-        }
-    }
-}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index e90a462db6..98b87608da 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -74,10 +74,12 @@
     <Compile Include="Audio\SampleInfoList.cs" />
     <Compile Include="Beatmaps\Drawables\BeatmapBackgroundSprite.cs" />
     <Compile Include="Beatmaps\DifficultyCalculator.cs" />
+    <Compile Include="Graphics\UserInterface\IconButton.cs" />
     <Compile Include="Configuration\SelectionRandomType.cs" />
     <Compile Include="Online\API\Requests\PostMessageRequest.cs" />
     <Compile Include="Online\Chat\ErrorMessage.cs" />
     <Compile Include="Overlays\Chat\ChatTabControl.cs" />
+    <Compile Include="Overlays\Music\CollectionsDropdown.cs" />
     <Compile Include="Overlays\Music\FilterControl.cs" />
     <Compile Include="Overlays\Music\PlaylistItem.cs" />
     <Compile Include="Overlays\Music\PlaylistList.cs" />
@@ -244,11 +246,17 @@
     <Compile Include="Screens\Charts\ChartInfo.cs" />
     <Compile Include="Screens\Edit\Editor.cs" />
     <Compile Include="Screens\Play\HotkeyRetryOverlay.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\CollectionSettings.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\DiscussionSettings.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\ReplayGroup.cs" />
+    <Compile Include="Screens\Play\ReplaySettingsOverlay.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\ReplaySliderBar.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\PlaybackSettings.cs" />
+    <Compile Include="Screens\Play\ReplaySettings\ReplayCheckbox.cs" />
     <Compile Include="Screens\Play\PauseContainer.cs" />
     <Compile Include="Screens\Play\SongProgressInfo.cs" />
     <Compile Include="Screens\Play\HUD\ModDisplay.cs" />
     <Compile Include="Screens\Play\SquareGraph.cs" />
-    <Compile Include="Screens\Play\StandardHUDOverlay.cs" />
     <Compile Include="Screens\Ranking\ResultsPage.cs" />
     <Compile Include="Screens\Ranking\ResultsPageRanking.cs" />
     <Compile Include="Screens\Ranking\ResultsPageScore.cs" />
@@ -438,6 +446,9 @@
     <Compile Include="Overlays\Music\PlaylistOverlay.cs" />
     <Compile Include="Rulesets\Replays\IAutoGenerator.cs" />
     <Compile Include="Rulesets\Replays\AutoGenerator.cs" />
+    <Compile Include="Overlays\Chat\ChannelSelectionOverlay.cs" />
+    <Compile Include="Overlays\Chat\ChannelListItem.cs" />
+    <Compile Include="Overlays\Chat\ChannelSection.cs" />
     <Compile Include="Screens\Multiplayer\DrawableRoom.cs" />
     <Compile Include="Online\Multiplayer\Room.cs" />
     <Compile Include="Online\Multiplayer\RoomStatus.cs" />