diff --git a/source/flixel/tweens/misc/BackgroundColorTween.hx b/source/flixel/tweens/misc/BackgroundColorTween.hx
deleted file mode 100644
index b8b2d993f..000000000
--- a/source/flixel/tweens/misc/BackgroundColorTween.hx
+++ /dev/null
@@ -1,66 +0,0 @@
-package flixel.tweens.misc;
-
-/**
- * Tweens the background color of a state.
- * Tweens the red, green, blue, and/or alpha values of the color.
- *
- * @see `flixel.tweens.misc.ColorTween` for something that operates on sprites!
- */
-class BackgroundColorTween extends FlxTween
-{
-  public var color(default, null):FlxColor;
-
-  var startColor:FlxColor;
-  var endColor:FlxColor;
-
-  /**
-   * State object whose color to tween
-   */
-  public var targetState(default, null):FlxState;
-
-  /**
-   * Clean up references
-   */
-  override public function destroy()
-  {
-    super.destroy();
-    targetState = null;
-  }
-
-  /**
-   * Tweens the color to a new color and an alpha to a new alpha.
-   *
-   * @param	duration		  Duration of the tween.
-   * @param	fromColor		  Start color.
-   * @param	toColor			  End color.
-   * @param	targetState		Optional sprite object whose color to tween.
-   * @return  The tween for chaining.
-   */
-  public function tween(duration:Float, fromColor:FlxColor, toColor:FlxColor, ?targetState:FlxSprite):ColorTween
-  {
-    this.color = startColor = fromColor;
-    this.endColor = toColor;
-    this.duration = duration;
-    this.targetState = targetState;
-    this.start();
-    return this;
-  }
-
-  override function update(elapsed:Float):Void
-  {
-    super.update(elapsed);
-    color = FlxColor.interpolate(startColor, endColor, scale);
-
-    if (targetState != null)
-    {
-      targetState.bgColor = color;
-      // Alpha should apply inherently.
-      // targetState.alpha = color.alphaFloat;
-    }
-  }
-
-  override function isTweenOf(object:Dynamic, ?field:String):Bool
-  {
-    return targetState == object && (field == null || field == "color");
-  }
-}
diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx
index 0a59fb70b..b08710c33 100644
--- a/source/funkin/InitState.hx
+++ b/source/funkin/InitState.hx
@@ -203,6 +203,9 @@ class InitState extends FlxState
     // Plugins provide a useful interface for globally active Flixel objects,
     // that receive update events regardless of the current state.
     // TODO: Move scripted Module behavior to a Flixel plugin.
+    #if debug
+    funkin.util.plugins.MemoryGCPlugin.initialize();
+    #end
     funkin.util.plugins.EvacuateDebugPlugin.initialize();
     funkin.util.plugins.ForceCrashPlugin.initialize();
     funkin.util.plugins.ReloadAssetsDebugPlugin.initialize();
diff --git a/source/funkin/audio/FunkinSound.hx b/source/funkin/audio/FunkinSound.hx
index e7ce68d08..704407c14 100644
--- a/source/funkin/audio/FunkinSound.hx
+++ b/source/funkin/audio/FunkinSound.hx
@@ -25,6 +25,9 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
 {
   static final MAX_VOLUME:Float = 2.0;
 
+  /**
+   * Using `FunkinSound.load` will override a dead instance from here rather than creating a new one, if possible!
+   */
   static var cache(default, null):FlxTypedGroup<FunkinSound> = new FlxTypedGroup<FunkinSound>();
 
   public var muted(default, set):Bool = false;
@@ -264,6 +267,8 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
   {
     var sound:FunkinSound = cache.recycle(construct);
 
+    // Load the sound.
+    // Sets `exists = true` as a side effect.
     sound.loadEmbedded(embeddedSound, looped, autoDestroy, onComplete);
 
     if (embeddedSound is String)
diff --git a/source/funkin/audio/SoundGroup.hx b/source/funkin/audio/SoundGroup.hx
index 0e81a0901..a26537c2a 100644
--- a/source/funkin/audio/SoundGroup.hx
+++ b/source/funkin/audio/SoundGroup.hx
@@ -80,8 +80,9 @@ class SoundGroup extends FlxTypedGroup<FunkinSound>
 
     // We have to play, then pause the sound to set the time,
     // else the sound will restart immediately when played.
-    result.play(true, 0.0);
-    result.pause();
+    // TODO: Past me experienced that issue but present me didn't? Investigate.
+    // result.play(true, 0.0);
+    // result.pause();
     result.time = this.time;
 
     result.onComplete = function() {
diff --git a/source/funkin/graphics/video/FlxVideo.hx b/source/funkin/graphics/video/FlxVideo.hx
index e95d7caa6..66829af00 100644
--- a/source/funkin/graphics/video/FlxVideo.hx
+++ b/source/funkin/graphics/video/FlxVideo.hx
@@ -40,6 +40,15 @@ class FlxVideo extends FlxBasic
     netStream.play(videoPath);
   }
 
+  public function restartVideo():Void
+  {
+    // Seek to the beginning of the video.
+    if (netStream != null)
+    {
+      netStream.seek(0);
+    }
+  }
+
   public function finishVideo():Void
   {
     netStream.dispose();
diff --git a/source/funkin/import.hx b/source/funkin/import.hx
index 23b588044..02055d4ed 100644
--- a/source/funkin/import.hx
+++ b/source/funkin/import.hx
@@ -15,7 +15,6 @@ using funkin.util.tools.ArraySortTools;
 using funkin.util.tools.ArrayTools;
 using funkin.util.tools.DynamicTools;
 using funkin.util.tools.FloatTools;
-using funkin.util.tools.FlxTweenTools;
 using funkin.util.tools.Int64Tools;
 using funkin.util.tools.IntTools;
 using funkin.util.tools.IteratorTools;
diff --git a/source/funkin/input/Controls.hx b/source/funkin/input/Controls.hx
index c4760cf5f..0857678d0 100644
--- a/source/funkin/input/Controls.hx
+++ b/source/funkin/input/Controls.hx
@@ -58,12 +58,11 @@ class Controls extends FlxActionSet
   var _back = new FlxActionDigital(Action.BACK);
   var _pause = new FlxActionDigital(Action.PAUSE);
   var _reset = new FlxActionDigital(Action.RESET);
+  var _screenshot = new FlxActionDigital(Action.SCREENSHOT);
   var _cutscene_advance = new FlxActionDigital(Action.CUTSCENE_ADVANCE);
-  var _cutscene_skip = new FlxActionDigital(Action.CUTSCENE_SKIP);
   var _debug_menu = new FlxActionDigital(Action.DEBUG_MENU);
   var _debug_chart = new FlxActionDigital(Action.DEBUG_CHART);
   var _debug_stage = new FlxActionDigital(Action.DEBUG_STAGE);
-  var _screenshot = new FlxActionDigital(Action.SCREENSHOT);
   var _volume_up = new FlxActionDigital(Action.VOLUME_UP);
   var _volume_down = new FlxActionDigital(Action.VOLUME_DOWN);
   var _volume_mute = new FlxActionDigital(Action.VOLUME_MUTE);
@@ -208,16 +207,21 @@ class Controls extends FlxActionSet
   inline function get_PAUSE()
     return _pause.check();
 
+  public var RESET(get, never):Bool;
+
+  inline function get_RESET()
+    return _reset.check();
+
+  public var SCREENSHOT(get, never):Bool;
+
+  inline function get_SCREENSHOT()
+    return _screenshot.check();
+
   public var CUTSCENE_ADVANCE(get, never):Bool;
 
   inline function get_CUTSCENE_ADVANCE()
     return _cutscene_advance.check();
 
-  public var CUTSCENE_SKIP(get, never):Bool;
-
-  inline function get_CUTSCENE_SKIP()
-    return _cutscene_skip.check();
-
   public var DEBUG_MENU(get, never):Bool;
 
   inline function get_DEBUG_MENU()
@@ -233,11 +237,6 @@ class Controls extends FlxActionSet
   inline function get_DEBUG_STAGE()
     return _debug_stage.check();
 
-  public var SCREENSHOT(get, never):Bool;
-
-  inline function get_SCREENSHOT()
-    return _screenshot.check();
-
   public var VOLUME_UP(get, never):Bool;
 
   inline function get_VOLUME_UP()
@@ -253,11 +252,6 @@ class Controls extends FlxActionSet
   inline function get_VOLUME_MUTE()
     return _volume_mute.check();
 
-  public var RESET(get, never):Bool;
-
-  inline function get_RESET()
-    return _reset.check();
-
   public function new(name, scheme:KeyboardScheme = null)
   {
     super(name);
@@ -289,16 +283,15 @@ class Controls extends FlxActionSet
     add(_accept);
     add(_back);
     add(_pause);
+    add(_reset);
+    add(_screenshot);
     add(_cutscene_advance);
-    add(_cutscene_skip);
     add(_debug_menu);
     add(_debug_chart);
     add(_debug_stage);
-    add(_screenshot);
     add(_volume_up);
     add(_volume_down);
     add(_volume_mute);
-    add(_reset);
 
     for (action in digitalActions)
       byName[action.name] = action;
@@ -383,12 +376,11 @@ class Controls extends FlxActionSet
       case BACK: _back;
       case PAUSE: _pause;
       case RESET: _reset;
+      case SCREENSHOT: _screenshot;
       case CUTSCENE_ADVANCE: _cutscene_advance;
-      case CUTSCENE_SKIP: _cutscene_skip;
       case DEBUG_MENU: _debug_menu;
       case DEBUG_CHART: _debug_chart;
       case DEBUG_STAGE: _debug_stage;
-      case SCREENSHOT: _screenshot;
       case VOLUME_UP: _volume_up;
       case VOLUME_DOWN: _volume_down;
       case VOLUME_MUTE: _volume_mute;
@@ -449,26 +441,24 @@ class Controls extends FlxActionSet
         func(_back, JUST_PRESSED);
       case PAUSE:
         func(_pause, JUST_PRESSED);
+      case RESET:
+        func(_reset, JUST_PRESSED);
+      case SCREENSHOT:
+        func(_screenshot, JUST_PRESSED);
       case CUTSCENE_ADVANCE:
         func(_cutscene_advance, JUST_PRESSED);
-      case CUTSCENE_SKIP:
-        func(_cutscene_skip, PRESSED);
       case DEBUG_MENU:
         func(_debug_menu, JUST_PRESSED);
       case DEBUG_CHART:
         func(_debug_chart, JUST_PRESSED);
       case DEBUG_STAGE:
         func(_debug_stage, JUST_PRESSED);
-      case SCREENSHOT:
-        func(_screenshot, JUST_PRESSED);
       case VOLUME_UP:
         func(_volume_up, JUST_PRESSED);
       case VOLUME_DOWN:
         func(_volume_down, JUST_PRESSED);
       case VOLUME_MUTE:
         func(_volume_mute, JUST_PRESSED);
-      case RESET:
-        func(_reset, JUST_PRESSED);
     }
   }
 
@@ -654,13 +644,12 @@ class Controls extends FlxActionSet
     bindKeys(Control.ACCEPT, getDefaultKeybinds(scheme, Control.ACCEPT));
     bindKeys(Control.BACK, getDefaultKeybinds(scheme, Control.BACK));
     bindKeys(Control.PAUSE, getDefaultKeybinds(scheme, Control.PAUSE));
+    bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET));
+    bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT));
     bindKeys(Control.CUTSCENE_ADVANCE, getDefaultKeybinds(scheme, Control.CUTSCENE_ADVANCE));
-    bindKeys(Control.CUTSCENE_SKIP, getDefaultKeybinds(scheme, Control.CUTSCENE_SKIP));
     bindKeys(Control.DEBUG_MENU, getDefaultKeybinds(scheme, Control.DEBUG_MENU));
     bindKeys(Control.DEBUG_CHART, getDefaultKeybinds(scheme, Control.DEBUG_CHART));
     bindKeys(Control.DEBUG_STAGE, getDefaultKeybinds(scheme, Control.DEBUG_STAGE));
-    bindKeys(Control.RESET, getDefaultKeybinds(scheme, Control.RESET));
-    bindKeys(Control.SCREENSHOT, getDefaultKeybinds(scheme, Control.SCREENSHOT));
     bindKeys(Control.VOLUME_UP, getDefaultKeybinds(scheme, Control.VOLUME_UP));
     bindKeys(Control.VOLUME_DOWN, getDefaultKeybinds(scheme, Control.VOLUME_DOWN));
     bindKeys(Control.VOLUME_MUTE, getDefaultKeybinds(scheme, Control.VOLUME_MUTE));
@@ -683,16 +672,15 @@ class Controls extends FlxActionSet
           case Control.ACCEPT: return [Z, SPACE, ENTER];
           case Control.BACK: return [X, BACKSPACE, ESCAPE];
           case Control.PAUSE: return [P, ENTER, ESCAPE];
+          case Control.RESET: return [R];
+          case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen
           case Control.CUTSCENE_ADVANCE: return [Z, ENTER];
-          case Control.CUTSCENE_SKIP: return [P, ESCAPE];
           case Control.DEBUG_MENU: return [GRAVEACCENT];
           case Control.DEBUG_CHART: return [];
           case Control.DEBUG_STAGE: return [];
-          case Control.SCREENSHOT: return [F3]; // TODO: Change this back to PrintScreen
           case Control.VOLUME_UP: return [PLUS, NUMPADPLUS];
           case Control.VOLUME_DOWN: return [MINUS, NUMPADMINUS];
           case Control.VOLUME_MUTE: return [ZERO, NUMPADZERO];
-          case Control.RESET: return [R];
         }
       case Duo(true):
         switch (control) {
@@ -707,16 +695,15 @@ class Controls extends FlxActionSet
           case Control.ACCEPT: return [G, Z];
           case Control.BACK: return [H, X];
           case Control.PAUSE: return [ONE];
+          case Control.RESET: return [R];
+          case Control.SCREENSHOT: return [PRINTSCREEN];
           case Control.CUTSCENE_ADVANCE: return [G, Z];
-          case Control.CUTSCENE_SKIP: return [ONE];
           case Control.DEBUG_MENU: return [GRAVEACCENT];
           case Control.DEBUG_CHART: return [];
           case Control.DEBUG_STAGE: return [];
-          case Control.SCREENSHOT: return [PRINTSCREEN];
           case Control.VOLUME_UP: return [PLUS];
           case Control.VOLUME_DOWN: return [MINUS];
           case Control.VOLUME_MUTE: return [ZERO];
-          case Control.RESET: return [R];
         }
       case Duo(false):
         switch (control) {
@@ -731,16 +718,15 @@ class Controls extends FlxActionSet
           case Control.ACCEPT: return [ENTER];
           case Control.BACK: return [ESCAPE];
           case Control.PAUSE: return [ONE];
+          case Control.RESET: return [R];
+          case Control.SCREENSHOT: return [PRINTSCREEN];
           case Control.CUTSCENE_ADVANCE: return [ENTER];
-          case Control.CUTSCENE_SKIP: return [ONE];
           case Control.DEBUG_MENU: return [GRAVEACCENT];
           case Control.DEBUG_CHART: return [];
           case Control.DEBUG_STAGE: return [];
-          case Control.SCREENSHOT: return [PRINTSCREEN];
           case Control.VOLUME_UP: return [NUMPADPLUS];
           case Control.VOLUME_DOWN: return [NUMPADMINUS];
           case Control.VOLUME_MUTE: return [NUMPADZERO];
-          case Control.RESET: return [R];
         }
       default:
         // Fallthrough.
@@ -843,15 +829,14 @@ class Controls extends FlxActionSet
       Control.NOTE_LEFT => getDefaultGamepadBinds(Control.NOTE_LEFT),
       Control.NOTE_RIGHT => getDefaultGamepadBinds(Control.NOTE_RIGHT),
       Control.PAUSE => getDefaultGamepadBinds(Control.PAUSE),
+      Control.RESET => getDefaultGamepadBinds(Control.RESET),
       // Control.SCREENSHOT => [],
       // Control.VOLUME_UP => [RIGHT_SHOULDER],
       // Control.VOLUME_DOWN => [LEFT_SHOULDER],
       // Control.VOLUME_MUTE => [RIGHT_TRIGGER],
       Control.CUTSCENE_ADVANCE => getDefaultGamepadBinds(Control.CUTSCENE_ADVANCE),
-      Control.CUTSCENE_SKIP => getDefaultGamepadBinds(Control.CUTSCENE_SKIP),
       // Control.DEBUG_MENU
       // Control.DEBUG_CHART
-      Control.RESET => getDefaultGamepadBinds(Control.RESET)
     ]);
   }
 
@@ -868,15 +853,14 @@ class Controls extends FlxActionSet
       case Control.NOTE_LEFT: return [DPAD_LEFT, X, LEFT_STICK_DIGITAL_LEFT, RIGHT_STICK_DIGITAL_LEFT];
       case Control.NOTE_RIGHT: return [DPAD_RIGHT, B, LEFT_STICK_DIGITAL_RIGHT, RIGHT_STICK_DIGITAL_RIGHT];
       case Control.PAUSE: return [START];
+      case Control.RESET: return [RIGHT_SHOULDER];
       case Control.SCREENSHOT: return [];
       case Control.VOLUME_UP: return [];
       case Control.VOLUME_DOWN: return [];
       case Control.VOLUME_MUTE: return [];
       case Control.CUTSCENE_ADVANCE: return [A];
-      case Control.CUTSCENE_SKIP: return [START];
       case Control.DEBUG_MENU: return [];
       case Control.DEBUG_CHART: return [];
-      case Control.RESET: return [RIGHT_SHOULDER];
       default:
         // Fallthrough.
     }
@@ -1228,14 +1212,13 @@ enum Control
   UI_RIGHT;
   UI_DOWN;
   RESET;
+  SCREENSHOT;
   ACCEPT;
   BACK;
   PAUSE;
   // CUTSCENE
   CUTSCENE_ADVANCE;
-  CUTSCENE_SKIP;
   // SCREENSHOT
-  SCREENSHOT;
   // VOLUME
   VOLUME_UP;
   VOLUME_DOWN;
@@ -1279,15 +1262,14 @@ abstract Action(String) to String from String
   var BACK = "back";
   var PAUSE = "pause";
   var RESET = "reset";
+  // SCREENSHOT
+  var SCREENSHOT = "screenshot";
   // CUTSCENE
   var CUTSCENE_ADVANCE = "cutscene_advance";
-  var CUTSCENE_SKIP = "cutscene_skip";
   // VOLUME
   var VOLUME_UP = "volume_up";
   var VOLUME_DOWN = "volume_down";
   var VOLUME_MUTE = "volume_mute";
-  // SCREENSHOT
-  var SCREENSHOT = "screenshot";
   // DEBUG
   var DEBUG_MENU = "debug_menu";
   var DEBUG_CHART = "debug_chart";
diff --git a/source/funkin/play/PauseSubState.hx b/source/funkin/play/PauseSubState.hx
index 8300ac936..4f2a76e19 100644
--- a/source/funkin/play/PauseSubState.hx
+++ b/source/funkin/play/PauseSubState.hx
@@ -1,5 +1,24 @@
 package funkin.play;
 
+import flixel.addons.transition.FlxTransitionableState;
+import flixel.FlxG;
+import flixel.util.FlxTimer;
+import flixel.FlxSprite;
+import flixel.group.FlxSpriteGroup;
+import flixel.math.FlxMath;
+import flixel.text.FlxText;
+import flixel.tweens.FlxEase;
+import flixel.tweens.FlxTween;
+import flixel.util.FlxColor;
+import funkin.audio.FunkinSound;
+import funkin.data.song.SongRegistry;
+import funkin.graphics.FunkinSprite;
+import funkin.play.cutscene.VideoCutscene;
+import funkin.play.PlayState;
+import funkin.ui.AtlasText;
+import funkin.ui.MusicBeatSubState;
+import funkin.ui.transition.StickerSubState;
+
 typedef PauseSubStateParams =
 {
   ?mode:PauseMode,
@@ -10,29 +29,36 @@ typedef PauseSubStateParams =
  */
 class PauseSubState extends MusicBeatSubState
 {
-  static final PAUSE_MENU_ENTRIES_STANDARD = [
+  static final PAUSE_MENU_ENTRIES_STANDARD:Array<PauseMenuEntry> = [
     {text: 'Resume', callback: resume},
     {text: 'Restart Song', callback: restartPlayState},
     {text: 'Change Difficulty', callback: switchMode.bind(_, Difficulty)},
-    {text: 'Enable Practice Mode', callback: enablePracticeMode, filter: () -> (PlayState.instance?.isPracticeMode ?? true)},
+    {text: 'Enable Practice Mode', callback: enablePracticeMode, filter: () -> !(PlayState.instance?.isPracticeMode ?? false)},
     {text: 'Exit to Menu', callback: quitToMenu},
   ];
 
-  static final PAUSE_MENU_ENTRIES_CHARTING = [
+  static final PAUSE_MENU_ENTRIES_CHARTING:Array<PauseMenuEntry> = [
     {text: 'Resume', callback: resume},
     {text: 'Restart Song', callback: restartPlayState},
     {text: 'Return to Chart Editor', callback: quitToChartEditor},
   ];
 
-  static final PAUSE_MENU_ENTRIES_DIFFICULTY = [
+  static final PAUSE_MENU_ENTRIES_DIFFICULTY:Array<PauseMenuEntry> = [
     {text: 'Back', callback: switchMode.bind(_, Standard)}
     // Other entries are added dynamically.
   ];
 
-  static final PAUSE_MENU_ENTRIES_CUTSCENE = [
+  static final PAUSE_MENU_ENTRIES_VIDEO_CUTSCENE:Array<PauseMenuEntry> = [
     {text: 'Resume', callback: resume},
-    {text: 'Restart Cutscene', callback: restartCutscene},
-    {text: 'Skip Cutscene', callback: skipCutscene},
+    {text: 'Restart Cutscene', callback: restartVideoCutscene},
+    {text: 'Skip Cutscene', callback: skipVideoCutscene},
+    {text: 'Exit to Menu', callback: quitToMenu},
+  ];
+
+  static final PAUSE_MENU_ENTRIES_CONVERSATION:Array<PauseMenuEntry> = [
+    {text: 'Resume', callback: resume},
+    {text: 'Restart Dialogue', callback: restartConversation},
+    {text: 'Skip Dialogue', callback: skipConversation},
     {text: 'Exit to Menu', callback: quitToMenu},
   ];
 
@@ -42,15 +68,21 @@ class PauseSubState extends MusicBeatSubState
   public static var musicSuffix:String = '';
 
   // Status
-  var menuEntries:Array<PauseMenuEntry>;
+  var currentMenuEntries:Array<PauseMenuEntry>;
   var currentEntry:Int = 0;
   var currentMode:PauseMode;
-  var allowInput:Bool = true;
+
+  /**
+   * Disallow input until the transition in is complete!
+   * This prevents the pause menu from immediately closing.
+   */
+  public var allowInput:Bool = false;
 
   // Graphics
-  var metadata:FlxTypedGroup<FlxText>;
+  var background:FunkinSprite;
+  var metadata:FlxTypedSpriteGroup<FlxText>;
   var metadataPractice:FlxText;
-  var menuEntryText:FlxTypedGroup<AtlasText>;
+  var menuEntryText:FlxTypedSpriteGroup<AtlasText>;
 
   // Audio
   var pauseMusic:FunkinSound;
@@ -58,9 +90,7 @@ class PauseSubState extends MusicBeatSubState
   public function new(?params:PauseSubStateParams)
   {
     super();
-    this.currentMode = params?.mode ?? PauseMode.Standard;
-
-    this.bgColor = FlxColor.TRANSPARENT; // Transparent, fades into black later.
+    this.currentMode = params?.mode ?? Standard;
   }
 
   public override function create():Void
@@ -69,8 +99,16 @@ class PauseSubState extends MusicBeatSubState
 
     startPauseMusic();
 
+    buildBackground();
+
     buildMetadata();
 
+    menuEntryText = new FlxTypedSpriteGroup<AtlasText>();
+    menuEntryText.scrollFactor.set(0, 0);
+    add(menuEntryText);
+
+    regenerateMenu();
+
     transitionIn();
   }
 
@@ -81,47 +119,69 @@ class PauseSubState extends MusicBeatSubState
     handleInputs();
   }
 
+  public override function destroy():Void
+  {
+    super.destroy();
+    pauseMusic.stop();
+  }
+
   function startPauseMusic():Void
   {
-    pauseMusic = FunkinSound.load(Paths.music('breakfast-pixel'), true, true);
+    pauseMusic = FunkinSound.load(Paths.music('breakfast$musicSuffix'), true, true);
 
     // Start playing at a random point in the song.
     pauseMusic.play(false, FlxG.random.int(0, Std.int(pauseMusic.length / 2)));
     pauseMusic.fadeIn(MUSIC_FADE_IN_TIME, 0, MUSIC_FINAL_VOLUME);
   }
 
+  function buildBackground():Void
+  {
+    // Using state.bgColor causes bugs!
+    background = new FunkinSprite(0, 0);
+    background.makeSolidColor(FlxG.width, FlxG.height, FlxColor.BLACK);
+    background.alpha = 0.0;
+    background.scrollFactor.set(0, 0);
+    background.updateHitbox();
+    add(background);
+  }
+
   /**
    * Render the metadata in the top right.
    */
   function buildMetadata():Void
   {
-    metadata = new FlxTypedGroup<FlxSprite>();
+    metadata = new FlxTypedSpriteGroup<FlxText>();
+    metadata.scrollFactor.set(0, 0);
     add(metadata);
 
-    var metadataSong:FlxText = new FlxText(20, 15, 0, 'Song Name - Artist');
+    var metadataSong:FlxText = new FlxText(20, 15, FlxG.width - 40, 'Song Name - Artist');
     metadataSong.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
     if (PlayState.instance?.currentChart != null)
     {
-      metadataSong.text += '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
+      metadataSong.text = '${PlayState.instance.currentChart.songName} - ${PlayState.instance.currentChart.songArtist}';
     }
+    metadataSong.scrollFactor.set(0, 0);
     metadata.add(metadataSong);
 
-    var metadataDifficulty:FlxText = new FlxText(20, 15 + 32, 0, 'Difficulty');
+    var metadataDifficulty:FlxText = new FlxText(20, 15 + 32, FlxG.width - 40, 'Difficulty: ');
     metadataDifficulty.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
     if (PlayState.instance?.currentDifficulty != null)
     {
       metadataDifficulty.text += PlayState.instance.currentDifficulty.toTitleCase();
     }
+    metadataDifficulty.scrollFactor.set(0, 0);
     metadata.add(metadataDifficulty);
 
-    var metadataDeaths:FlxText = new FlxText(20, 15 + 64, 0, '0 Blue Balls');
+    var metadataDeaths:FlxText = new FlxText(20, 15 + 64, FlxG.width - 40, '0 Blue Balls');
     metadataDeaths.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
     metadataDeaths.text = '${PlayState.instance?.deathCounter} Blue Balls';
+    metadataDeaths.scrollFactor.set(0, 0);
     metadata.add(metadataDeaths);
 
-    metadataPractice = new FlxText(20, 15 + 96, 0, 'PRACTICE MODE');
+    metadataPractice = new FlxText(20, 15 + 96, FlxG.width - 40, 'PRACTICE MODE');
     metadataPractice.setFormat(Paths.font('vcr.ttf'), 32, FlxColor.WHITE, FlxTextAlign.RIGHT);
     metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
+    metadataPractice.scrollFactor.set(0, 0);
     metadata.add(metadataPractice);
   }
 
@@ -149,30 +209,45 @@ class PauseSubState extends MusicBeatSubState
           trace('DIFFICULTIES: ${difficultiesInVariation}');
           for (difficulty in difficultiesInVariation)
           {
-            difficulties.push({text: difficulty.toTitleCase(), callback: () -> changeDifficulty(this, difficulty)});
+            entries.push({text: difficulty.toTitleCase(), callback: (state) -> changeDifficulty(state, difficulty)});
           }
         }
 
         // Add the back button.
         currentMenuEntries = entries.concat(PAUSE_MENU_ENTRIES_DIFFICULTY.clone());
+      case PauseMode.Conversation:
+        currentMenuEntries = PAUSE_MENU_ENTRIES_CONVERSATION.clone();
       case PauseMode.Cutscene:
-        currentMenuEntries = PAUSE_MENU_ENTRIES_CUTSCENE.clone();
+        currentMenuEntries = PAUSE_MENU_ENTRIES_VIDEO_CUTSCENE.clone();
     }
 
     // Render out the entries depending on the mode.
-    for (entryIndex in 0...entries)
+    var entryIndex:Int = 0;
+    var toRemove = [];
+    for (entry in currentMenuEntries)
     {
-      var entry:PauseMenuEntry = entries[entryIndex];
+      if (entry == null || (entry.filter != null && !entry.filter()))
+      {
+        // Remove entries that should be hidden.
+        toRemove.push(entry);
+      }
+      else
+      {
+        // Handle visible entries.
+        var yPos:Float = 70 * entryIndex + 30;
+        var text:AtlasText = new AtlasText(0, yPos, entry.text, AtlasFont.BOLD);
+        text.scrollFactor.set(0, 0);
+        text.alpha = 0;
+        menuEntryText.add(text);
 
-      // Remove entries that should be hidden.
-      if (entry.filter != null && !entry.filter()) currentMenuEntries.remove(entry);
+        entry.sprite = text;
 
-      var yPos:Float = 70 * entryIndex + 30;
-      var text:AtlasText = new AtlasText(0, yPos, entry.text, AtlasFont.BOLD);
-      text.alpha = 0;
-      menuEntryText.add(text);
-
-      entry.sprite = text;
+        entryIndex++;
+      }
+    }
+    for (entry in toRemove)
+    {
+      currentMenuEntries.remove(entry);
     }
 
     metadataPractice.visible = PlayState.instance?.isPracticeMode ?? false;
@@ -182,15 +257,19 @@ class PauseSubState extends MusicBeatSubState
 
   function transitionIn():Void
   {
-    FlxTween.globalManager.bgColor(this, 0.4, FlxColor.fromRGB(0, 0, 0, 0.0), FlxColor.fromRGB(0, 0, 0, 0.6), {ease: FlxEase.quartInOut});
+    FlxTween.tween(background, {alpha: 0.6}, 0.4, {ease: FlxEase.quartInOut});
 
     // Animate each element a little bit downwards.
-    var delay:Float = 0.3;
+    var delay:Float = 0.1;
     for (child in metadata.members)
     {
       FlxTween.tween(child, {alpha: 1, y: child.y + 5}, 0.4, {ease: FlxEase.quartInOut, startDelay: delay});
-      delay += 0.2;
+      delay += 0.05;
     }
+
+    new FlxTimer().start(0.2, (_) -> {
+      allowInput = true;
+    });
   }
 
   function handleInputs():Void
@@ -205,22 +284,24 @@ class PauseSubState extends MusicBeatSubState
     {
       changeSelection(1);
     }
-    if (controls.PAUSE)
-    {
-      resume(this);
-    }
+
     if (controls.ACCEPT)
     {
-      menuEntries[currentEntry].callback(this);
+      currentMenuEntries[currentEntry].callback(this);
+    }
+    else if (controls.PAUSE)
+    {
+      resume(this);
     }
 
     #if (debug || FORCE_DEBUG_VERSION)
     // to pause the game and get screenshots easy, press H on pause menu!
     if (FlxG.keys.justPressed.H)
     {
-      var visible = !metaDataGrp.visible;
-      metadata = visible;
-      menuEntryText = visible;
+      var visible = !metadata.visible;
+
+      metadata.visible = visible;
+      menuEntryText.visible = visible;
       this.bgColor = visible ? 0x99000000 : 0x00000000; // 60% or fully transparent black
     }
     #end
@@ -232,14 +313,14 @@ class PauseSubState extends MusicBeatSubState
 
     currentEntry += change;
 
-    if (currentEntry < 0) currentEntry = menuEntries.length - 1;
-    if (currentEntry >= menuEntries.length) currentEntry = 0;
+    if (currentEntry < 0) currentEntry = currentMenuEntries.length - 1;
+    if (currentEntry >= currentMenuEntries.length) currentEntry = 0;
 
-    for (entryIndex in 0...menuEntries.length)
+    for (entryIndex in 0...currentMenuEntries.length)
     {
       var isCurrent:Bool = entryIndex == currentEntry;
 
-      var entry:PauseMenuEntry = menuEntries[entryIndex];
+      var entry:PauseMenuEntry = currentMenuEntries[entryIndex];
       var text:AtlasText = entry.sprite;
 
       // Set the transparency.
@@ -248,6 +329,7 @@ class PauseSubState extends MusicBeatSubState
       // Set the position.
       var targetX = FlxMath.remapToRange((entryIndex - currentEntry), 0, 1, 0, 1.3) * 20 + 90;
       var targetY = FlxMath.remapToRange((entryIndex - currentEntry), 0, 1, 0, 1.3) * 120 + (FlxG.height * 0.48);
+      trace(targetY);
       FlxTween.tween(text, {x: targetX, y: targetY}, 0.16, {ease: FlxEase.linear});
     }
   }
@@ -291,7 +373,35 @@ class PauseSubState extends MusicBeatSubState
     if (PlayState.instance == null) return;
 
     PlayState.instance.isPracticeMode = true;
-    regenerateMenu();
+    state.regenerateMenu();
+  }
+
+  static function restartVideoCutscene(state:PauseSubState):Void
+  {
+    VideoCutscene.restartVideo();
+    state.close();
+  }
+
+  static function skipVideoCutscene(state:PauseSubState):Void
+  {
+    VideoCutscene.finishVideo();
+    state.close();
+  }
+
+  static function restartConversation(state:PauseSubState):Void
+  {
+    if (PlayState.instance?.currentConversation == null) return;
+
+    PlayState.instance.currentConversation.resetConversation();
+    state.close();
+  }
+
+  static function skipConversation(state:PauseSubState):Void
+  {
+    if (PlayState.instance?.currentConversation == null) return;
+
+    PlayState.instance.currentConversation.skipConversation();
+    state.close();
   }
 
   static function quitToMenu(state:PauseSubState):Void
@@ -306,11 +416,11 @@ class PauseSubState extends MusicBeatSubState
     if (PlayStatePlaylist.isStoryMode)
     {
       PlayStatePlaylist.reset();
-      openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.story.StoryMenuState(sticker)));
+      state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.story.StoryMenuState(sticker)));
     }
     else
     {
-      openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(null, sticker)));
+      state.openSubState(new funkin.ui.transition.StickerSubState(null, (sticker) -> new funkin.ui.freeplay.FreeplayState(null, sticker)));
     }
   }
 
@@ -351,7 +461,12 @@ enum PauseMode
   Difficulty;
 
   /**
-   * The menu displayed when the player pauses the game during a cutscene.
+   * The menu displayed when the player pauses the game during a conversation.
+   */
+  Conversation;
+
+  /**
+   * The menu displayed when the player pauses the game during a video cutscene.
    */
   Cutscene;
 }
diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx
index 1dbba5b54..ca2344b0a 100644
--- a/source/funkin/play/PlayState.hx
+++ b/source/funkin/play/PlayState.hx
@@ -314,6 +314,11 @@ class PlayState extends MusicBeatSubState
   **/
   var inputReleaseQueue:Array<PreciseInputEvent> = [];
 
+  /**
+   * If we just unpaused the game, we shouldn't be able to pause again for one frame.
+   */
+  var justUnpaused:Bool = false;
+
   /**
    * PRIVATE INSTANCE VARIABLES
    * Private instance variables should be used for information that must be reset or dereferenced
@@ -442,11 +447,6 @@ class PlayState extends MusicBeatSubState
    */
   var comboPopUps:PopUpStuff;
 
-  /**
-   * The circular sprite that appears while the user is holding down the Skip Cutscene button.
-   */
-  var skipTimer:FlxPieDial;
-
   /**
    * PROPERTIES
    */
@@ -474,7 +474,7 @@ class PlayState extends MusicBeatSubState
     if (!Std.isOfType(this.subState, PauseSubState)) return false;
 
     var pauseSubState:PauseSubState = cast this.subState;
-    return pauseSubState.exitingToMenu;
+    return !pauseSubState.allowInput;
   }
 
   /**
@@ -629,14 +629,6 @@ class PlayState extends MusicBeatSubState
     comboPopUps.cameras = [camHUD];
     add(comboPopUps);
 
-    // The little dial that shows up when you hold the Skip Cutscene key.
-    skipTimer = new FlxPieDial(16, 16, 32, FlxColor.WHITE, 36, CIRCLE, true, 24);
-    skipTimer.amount = 0;
-    skipTimer.zIndex = 1000;
-    add(skipTimer);
-    // Renders only in video cutscene mode.
-    skipTimer.cameras = [camCutscene];
-
     #if discord_rpc
     // Initialize Discord Rich Presence.
     initDiscord();
@@ -752,6 +744,8 @@ class PlayState extends MusicBeatSubState
 
   public override function update(elapsed:Float):Void
   {
+    // TOTAL: 9.42% CPU Time when profiled in VS 2019.
+
     if (criticalFailure) return;
 
     super.update(elapsed);
@@ -853,7 +847,7 @@ class PlayState extends MusicBeatSubState
     #end
 
     // Attempt to pause the game.
-    if ((controls.PAUSE || androidPause) && isInCountdown && mayPauseGame)
+    if ((controls.PAUSE || androidPause) && isInCountdown && mayPauseGame && !justUnpaused)
     {
       var event = new PauseScriptEvent(FlxG.random.bool(1 / 1000));
 
@@ -888,12 +882,12 @@ class PlayState extends MusicBeatSubState
             boyfriendPos = currentStage.getBoyfriend().getScreenPosition();
           }
 
-          var pauseSubState:FlxSubState = new PauseSubState(isChartingMode);
+          var pauseSubState:FlxSubState = new PauseSubState({mode: isChartingMode ? Charting : Standard});
 
           FlxTransitionableSubState.skipNextTransIn = true;
           FlxTransitionableSubState.skipNextTransOut = true;
-          openSubState(pauseSubState);
           pauseSubState.camera = camHUD;
+          openSubState(pauseSubState);
           // boyfriendPos.put(); // TODO: Why is this here?
         }
 
@@ -1017,6 +1011,8 @@ class PlayState extends MusicBeatSubState
 
     // Moving notes into position is now done by Strumline.update().
     processNotes(elapsed);
+
+    justUnpaused = false;
   }
 
   public override function dispatchEvent(event:ScriptEvent):Void
@@ -1105,6 +1101,8 @@ class PlayState extends MusicBeatSubState
         DiscordClient.changePresence(detailsText, '${currentChart.songName} ($storyDifficultyText)', iconRPC);
       }
       #end
+
+      justUnpaused = true;
     }
     else if (Std.isOfType(subState, Transition))
     {
@@ -2444,58 +2442,39 @@ class PlayState extends MusicBeatSubState
    */
   function handleCutsceneKeys(elapsed:Float):Void
   {
+    if (isGamePaused) return;
+
     if (currentConversation != null)
     {
-      if (controls.CUTSCENE_ADVANCE) currentConversation?.advanceConversation();
-
-      if (controls.CUTSCENE_SKIP)
+      // Pause/unpause may conflict with advancing the conversation!
+      if (controls.CUTSCENE_ADVANCE && !justUnpaused)
       {
-        currentConversation?.trySkipConversation(elapsed);
+        currentConversation?.advanceConversation();
       }
-      else
+      else if (controls.PAUSE && !justUnpaused)
       {
-        currentConversation?.trySkipConversation(-1);
+        var pauseSubState:FlxSubState = new PauseSubState({mode: Conversation});
+
+        persistentUpdate = false;
+        FlxTransitionableSubState.skipNextTransIn = true;
+        FlxTransitionableSubState.skipNextTransOut = true;
+        pauseSubState.camera = camCutscene;
+        openSubState(pauseSubState);
       }
     }
     else if (VideoCutscene.isPlaying())
     {
       // This is a video cutscene.
-
-      if (controls.CUTSCENE_SKIP)
+      if (controls.PAUSE && !justUnpaused)
       {
-        trySkipVideoCutscene(elapsed);
+        var pauseSubState:FlxSubState = new PauseSubState({mode: Cutscene});
+
+        persistentUpdate = false;
+        FlxTransitionableSubState.skipNextTransIn = true;
+        FlxTransitionableSubState.skipNextTransOut = true;
+        pauseSubState.camera = camCutscene;
+        openSubState(pauseSubState);
       }
-      else
-      {
-        trySkipVideoCutscene(-1);
-      }
-    }
-  }
-
-  /**
-   * Handle logic for the skip timer.
-   * If the skip button is being held, pass the amount of time elapsed since last game update.
-   * If the skip button has been released, pass a negative number.
-   */
-  function trySkipVideoCutscene(elapsed:Float):Void
-  {
-    if (skipTimer == null || skipTimer.animation == null) return;
-
-    if (elapsed < 0)
-    {
-      skipHeldTimer = 0.0;
-    }
-    else
-    {
-      skipHeldTimer += elapsed;
-    }
-
-    skipTimer.visible = skipHeldTimer >= 0.05;
-    skipTimer.amount = Math.min(skipHeldTimer / 1.5, 1.0);
-
-    if (skipHeldTimer >= 1.5)
-    {
-      VideoCutscene.finishVideo();
     }
   }
 
@@ -2694,7 +2673,7 @@ class PlayState extends MusicBeatSubState
       FlxG.sound.music.pause();
       if (vocals != null)
       {
-        vocals.pause();
+        vocals.destroy();
         remove(vocals);
       }
     }
diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx
index 934919b65..a883a528a 100644
--- a/source/funkin/play/cutscene/VideoCutscene.hx
+++ b/source/funkin/play/cutscene/VideoCutscene.hx
@@ -118,6 +118,24 @@ class VideoCutscene
   }
   #end
 
+  public static function restartVideo():Void
+  {
+    #if html5
+    if (vid != null)
+    {
+      vid.restartVideo();
+    }
+    #end
+
+    #if hxCodec
+    if (vid != null)
+    {
+      // Seek to the start of the video.
+      vid.bitmap.time = 0;
+    }
+    #end
+  }
+
   public static function finishVideo(?transitionTime:Float = 0.5):Void
   {
     trace('ALERT: Finish video cutscene called!');
diff --git a/source/funkin/play/cutscene/dialogue/Conversation.hx b/source/funkin/play/cutscene/dialogue/Conversation.hx
index dc3fd8c8a..150f6bf6f 100644
--- a/source/funkin/play/cutscene/dialogue/Conversation.hx
+++ b/source/funkin/play/cutscene/dialogue/Conversation.hx
@@ -31,10 +31,6 @@ import funkin.data.dialogue.DialogueBoxRegistry;
  */
 class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass implements IRegistryEntry<ConversationData>
 {
-  static final CONVERSATION_SKIP_TIMER:Float = 1.5;
-
-  var skipHeldTimer:Float = 0.0;
-
   /**
    * The ID of the conversation.
    */
@@ -105,8 +101,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
 
   var currentDialogueBox:DialogueBox;
 
-  var skipTimer:FlxPieDial;
-
   public function new(id:String)
   {
     super();
@@ -124,8 +118,8 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
   {
     // Reset the progress in the dialogue.
     currentDialogueEntry = 0;
+    currentDialogueLine = 0;
     this.state = ConversationState.Start;
-    this.alpha = 1.0;
 
     // Start the dialogue.
     dispatchEvent(new DialogueScriptEvent(DIALOGUE_START, this, false));
@@ -153,6 +147,12 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
 
   function setupBackdrop():Void
   {
+    if (backdrop != null)
+    {
+      backdrop.destroy();
+      backdrop = null;
+    }
+
     backdrop = new FunkinSprite(0, 0);
 
     if (_data.backdrop == null) return;
@@ -181,12 +181,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
     refresh();
   }
 
-  function setupSkipTimer():Void
-  {
-    add(skipTimer = new FlxPieDial(16, 16, 32, FlxColor.WHITE, 36, CIRCLE, true, 24));
-    skipTimer.amount = 0;
-  }
-
   public override function update(elapsed:Float):Void
   {
     super.update(elapsed);
@@ -201,8 +195,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
     // Skip the next steps if the current speaker is already displayed.
     if (currentSpeaker != null && nextSpeakerId == currentSpeaker.id) return;
 
-    var nextSpeaker:Speaker = SpeakerRegistry.instance.fetchEntry(nextSpeakerId);
-
     if (currentSpeaker != null)
     {
       remove(currentSpeaker);
@@ -210,6 +202,8 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
       currentSpeaker = null;
     }
 
+    var nextSpeaker:Speaker = SpeakerRegistry.instance.fetchEntry(nextSpeakerId);
+
     if (nextSpeaker == null)
     {
       if (nextSpeakerId == null)
@@ -222,6 +216,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
       }
       return;
     }
+    if (!nextSpeaker.alive) nextSpeaker.revive();
 
     ScriptEventDispatcher.callEvent(nextSpeaker, new ScriptEvent(CREATE, true));
 
@@ -266,6 +261,7 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
       trace('Dialogue box could not be retrieved.');
       return;
     }
+    if (!nextDialogueBox.alive) nextDialogueBox.revive();
 
     ScriptEventDispatcher.callEvent(nextDialogueBox, new ScriptEvent(CREATE, true));
 
@@ -347,29 +343,21 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
     currentDialogueEntry = 0;
     this.state = ConversationState.Start;
 
-    advanceConversation();
-  }
+    if (outroTween != null) outroTween.cancel(); // Canc
+    outroTween = null;
 
-  public function trySkipConversation(elapsed:Float):Void
-  {
-    if (skipTimer == null || skipTimer.animation == null) return;
+    this.alpha = 0.0;
+    if (this.music != null) this.music.stop();
+    this.music = null;
 
-    if (elapsed < 0)
-    {
-      skipHeldTimer = 0.0;
-    }
-    else
-    {
-      skipHeldTimer += elapsed;
-    }
+    if (currentSpeaker != null) currentSpeaker.kill();
+    currentSpeaker = null;
+    if (currentDialogueBox != null) currentDialogueBox.kill();
+    currentDialogueBox = null;
+    if (backdrop != null) backdrop.kill();
+    backdrop = null;
 
-    skipTimer.visible = skipHeldTimer >= 0.05;
-    skipTimer.amount = Math.min(skipHeldTimer / CONVERSATION_SKIP_TIMER, 1.0);
-
-    if (skipHeldTimer >= CONVERSATION_SKIP_TIMER)
-    {
-      skipConversation();
-    }
+    startConversation();
   }
 
   /**
@@ -425,7 +413,6 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
     // Fade in the music and backdrop.
     setupMusic();
     setupBackdrop();
-    setupSkipTimer();
 
     // Advance the conversation.
     state = ConversationState.Opening;
@@ -554,12 +541,16 @@ class Conversation extends FlxSpriteGroup implements IDialogueScriptedClass impl
     if (this.music != null) this.music.stop();
     this.music = null;
 
-    this.skipTimer = null;
     if (currentSpeaker != null) currentSpeaker.kill();
+    remove(currentSpeaker);
     currentSpeaker = null;
+
     if (currentDialogueBox != null) currentDialogueBox.kill();
+    remove(currentDialogueBox);
     currentDialogueBox = null;
+
     if (backdrop != null) backdrop.kill();
+    remove(backdrop);
     backdrop = null;
 
     this.clear();
diff --git a/source/funkin/play/cutscene/dialogue/DialogueBox.hx b/source/funkin/play/cutscene/dialogue/DialogueBox.hx
index 6f8a0086a..eb603a352 100644
--- a/source/funkin/play/cutscene/dialogue/DialogueBox.hx
+++ b/source/funkin/play/cutscene/dialogue/DialogueBox.hx
@@ -8,6 +8,7 @@ import flixel.text.FlxText;
 import flixel.addons.text.FlxTypeText;
 import funkin.util.assets.FlxAnimationUtil;
 import funkin.modding.events.ScriptEvent;
+import funkin.audio.FunkinSound;
 import funkin.modding.IScriptedClass.IDialogueScriptedClass;
 import flixel.util.FlxColor;
 import funkin.data.dialogue.DialogueBoxData;
@@ -111,9 +112,6 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
     this.y = 0;
     this.alpha = 1;
 
-    this.boxSprite = new FlxSprite(0, 0);
-    add(this.boxSprite);
-
     loadSpritesheet();
     loadAnimations();
 
@@ -122,6 +120,15 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
 
   function loadSpritesheet():Void
   {
+    if (this.boxSprite != null)
+    {
+      remove(this.boxSprite);
+      this.boxSprite = null;
+    }
+
+    this.boxSprite = new FlxSprite(0, 0);
+    add(this.boxSprite);
+
     trace('[DIALOGUE BOX] Loading spritesheet ${_data.assetPath} for ${id}');
 
     var tex:FlxFramesCollection = Paths.getSparrowAtlas(_data.assetPath);
@@ -190,6 +197,31 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
     this.boxSprite.updateHitbox();
   }
 
+  /**
+   * Calls `kill()` on the group's members and then on the group itself.
+   * You can revive this group later via `revive()` after this.
+   */
+  public override function kill():Void
+  {
+    super.kill();
+    if (this.boxSprite != null)
+    {
+      this.boxSprite.kill();
+      this.boxSprite = null;
+    }
+    if (this.textDisplay != null)
+    {
+      this.textDisplay.kill();
+      this.textDisplay = null;
+    }
+    this.clear();
+  }
+
+  public override function revive():Void
+  {
+    super.revive();
+  }
+
   function loadAnimations():Void
   {
     trace('[DIALOGUE BOX] Loading ${_data.animations.length} animations for ${id}');
@@ -246,7 +278,8 @@ class DialogueBox extends FlxSpriteGroup implements IDialogueScriptedClass imple
     textDisplay.setFormat(_data.text.fontFamily, _data.text.size, FlxColor.fromString(_data.text.color), LEFT, SHADOW,
       FlxColor.fromString(_data.text.shadowColor ?? '#00000000'), false);
     textDisplay.borderSize = _data.text.shadowWidth ?? 2;
-    textDisplay.sounds = [FlxG.sound.load(Paths.sound('pixelText'), 0.6)];
+    // TODO: Add an option to configure this.
+    textDisplay.sounds = [FunkinSound.load(Paths.sound('pixelText'), 0.6)];
 
     textDisplay.completeCallback = onTypingComplete;
 
diff --git a/source/funkin/play/cutscene/dialogue/Speaker.hx b/source/funkin/play/cutscene/dialogue/Speaker.hx
index d5bffd7b0..0d59854a7 100644
--- a/source/funkin/play/cutscene/dialogue/Speaker.hx
+++ b/source/funkin/play/cutscene/dialogue/Speaker.hx
@@ -106,6 +106,23 @@ class Speaker extends FlxSprite implements IDialogueScriptedClass implements IRe
     loadAnimations();
   }
 
+  /**
+   * Calls `kill()` on the group's members and then on the group itself.
+   * You can revive this group later via `revive()` after this.
+   */
+  public override function kill():Void
+  {
+    super.kill();
+  }
+
+  public override function revive():Void
+  {
+    super.revive();
+
+    loadSpritesheet();
+    loadAnimations();
+  }
+
   function loadSpritesheet():Void
   {
     trace('[SPEAKER] Loading spritesheet ${_data.assetPath} for ${id}');
diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx
index 970aebc57..105e6db43 100644
--- a/source/funkin/play/song/Song.hx
+++ b/source/funkin/play/song/Song.hx
@@ -614,9 +614,9 @@ class SongDifficulty
     }
 
     // Add player vocals.
-    if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(Assets.getSound(voiceList[0])));
+    if (voiceList[0] != null) result.addPlayerVoice(FunkinSound.load(voiceList[0]));
     // Add opponent vocals.
-    if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(Assets.getSound(voiceList[1])));
+    if (voiceList[1] != null) result.addOpponentVoice(FunkinSound.load(voiceList[1]));
 
     // Add additional vocals.
     if (voiceList.length > 2)
diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx
index ff5e5bfb8..6246dcb58 100644
--- a/source/funkin/save/Save.hx
+++ b/source/funkin/save/Save.hx
@@ -893,12 +893,6 @@ typedef SaveControlsData =
    */
   var ?CUTSCENE_ADVANCE:Array<Int>;
 
-  /**
-   * Keybind for skipping a cutscene.
-   * @default `Escape`
-   */
-  var ?CUTSCENE_SKIP:Array<Int>;
-
   /**
    * Keybind for increasing volume.
    * @default `Plus`
diff --git a/source/funkin/save/migrator/RawSaveData_v1_0_0.hx b/source/funkin/save/migrator/RawSaveData_v1_0_0.hx
index b71102cce..a516f944a 100644
--- a/source/funkin/save/migrator/RawSaveData_v1_0_0.hx
+++ b/source/funkin/save/migrator/RawSaveData_v1_0_0.hx
@@ -35,7 +35,6 @@ typedef SaveControlsData_v1_0_0 =
   var ?ACCEPT:Array<Int>;
   var ?BACK:Array<Int>;
   var ?CUTSCENE_ADVANCE:Array<Int>;
-  var ?CUTSCENE_SKIP:Array<Int>;
   var ?NOTE_DOWN:Array<Int>;
   var ?NOTE_LEFT:Array<Int>;
   var ?NOTE_RIGHT:Array<Int>;
diff --git a/source/funkin/save/migrator/SaveDataMigrator.hx b/source/funkin/save/migrator/SaveDataMigrator.hx
index 92bee4ceb..f995660f7 100644
--- a/source/funkin/save/migrator/SaveDataMigrator.hx
+++ b/source/funkin/save/migrator/SaveDataMigrator.hx
@@ -272,7 +272,6 @@ class SaveDataMigrator
         ACCEPT: controlsData?.keys?.ACCEPT ?? null,
         BACK: controlsData?.keys?.BACK ?? null,
         CUTSCENE_ADVANCE: controlsData?.keys?.CUTSCENE_ADVANCE ?? null,
-        CUTSCENE_SKIP: controlsData?.keys?.CUTSCENE_SKIP ?? null,
         NOTE_DOWN: controlsData?.keys?.NOTE_DOWN ?? null,
         NOTE_LEFT: controlsData?.keys?.NOTE_LEFT ?? null,
         NOTE_RIGHT: controlsData?.keys?.NOTE_RIGHT ?? null,
@@ -293,7 +292,6 @@ class SaveDataMigrator
         ACCEPT: controlsData?.pad?.ACCEPT ?? null,
         BACK: controlsData?.pad?.BACK ?? null,
         CUTSCENE_ADVANCE: controlsData?.pad?.CUTSCENE_ADVANCE ?? null,
-        CUTSCENE_SKIP: controlsData?.pad?.CUTSCENE_SKIP ?? null,
         NOTE_DOWN: controlsData?.pad?.NOTE_DOWN ?? null,
         NOTE_LEFT: controlsData?.pad?.NOTE_LEFT ?? null,
         NOTE_RIGHT: controlsData?.pad?.NOTE_RIGHT ?? null,
diff --git a/source/funkin/ui/MusicBeatSubState.hx b/source/funkin/ui/MusicBeatSubState.hx
index 2c8970357..dc742874f 100644
--- a/source/funkin/ui/MusicBeatSubState.hx
+++ b/source/funkin/ui/MusicBeatSubState.hx
@@ -51,6 +51,7 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
 
   override function update(elapsed:Float):Void
   {
+    // 3.59% CPU Usage (100% is FlxTypedGroup#update() and most of that is updating each member.)
     super.update(elapsed);
 
     // Emergency exit button.
@@ -61,8 +62,11 @@ class MusicBeatSubState extends FlxSubState implements IEventHandler
 
     // Display Conductor info in the watch window.
     FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
+
+    // 0.09% CPU Usage?
     Conductor.watchQuick();
 
+    // 4.31% CPU Usage
     dispatchEvent(new UpdateScriptEvent(elapsed));
   }
 
diff --git a/source/funkin/ui/debug/dialogue/ConversationDebugState.hx b/source/funkin/ui/debug/dialogue/ConversationDebugState.hx
index 33a6f365a..abda3d3b1 100644
--- a/source/funkin/ui/debug/dialogue/ConversationDebugState.hx
+++ b/source/funkin/ui/debug/dialogue/ConversationDebugState.hx
@@ -62,15 +62,6 @@ class ConversationDebugState extends MusicBeatState
     if (conversation != null)
     {
       if (controls.CUTSCENE_ADVANCE) conversation.advanceConversation();
-
-      if (controls.CUTSCENE_SKIP)
-      {
-        conversation.trySkipConversation(elapsed);
-      }
-      else
-      {
-        conversation.trySkipConversation(-1);
-      }
     }
   }
 }
diff --git a/source/funkin/ui/options/ControlsMenu.hx b/source/funkin/ui/options/ControlsMenu.hx
index bda071846..62ae4b1a9 100644
--- a/source/funkin/ui/options/ControlsMenu.hx
+++ b/source/funkin/ui/options/ControlsMenu.hx
@@ -27,7 +27,7 @@ class ControlsMenu extends funkin.ui.options.OptionsState.Page
   static var controlGroups:Array<Array<Control>> = [
     [NOTE_UP, NOTE_DOWN, NOTE_LEFT, NOTE_RIGHT],
     [UI_UP, UI_DOWN, UI_LEFT, UI_RIGHT, ACCEPT, BACK],
-    [CUTSCENE_ADVANCE, CUTSCENE_SKIP],
+    [CUTSCENE_ADVANCE],
     [VOLUME_UP, VOLUME_DOWN, VOLUME_MUTE],
     [DEBUG_MENU, DEBUG_CHART]
   ];
diff --git a/source/funkin/util/plugins/MemoryGCPlugin.hx b/source/funkin/util/plugins/MemoryGCPlugin.hx
new file mode 100644
index 000000000..3df861eb5
--- /dev/null
+++ b/source/funkin/util/plugins/MemoryGCPlugin.hx
@@ -0,0 +1,37 @@
+package funkin.util.plugins;
+
+import flixel.FlxBasic;
+
+/**
+ * A plugin which adds functionality to press `Ins` to immediately perform memory garbage collection.
+ */
+class MemoryGCPlugin extends FlxBasic
+{
+  public function new()
+  {
+    super();
+  }
+
+  public static function initialize():Void
+  {
+    FlxG.plugins.addPlugin(new MemoryGCPlugin());
+  }
+
+  public override function update(elapsed:Float):Void
+  {
+    super.update(elapsed);
+
+    if (FlxG.keys.justPressed.INSERT)
+    {
+      var perfStart:Float = Sys.time();
+      funkin.util.MemoryUtil.collect(true);
+      var perfEnd:Float = Sys.time();
+      trace("Memory GC took " + (perfEnd - perfStart) + " seconds");
+    }
+  }
+
+  public override function destroy():Void
+  {
+    super.destroy();
+  }
+}
diff --git a/source/funkin/util/tools/FlxTweenTools.hx b/source/funkin/util/tools/FlxTweenTools.hx
deleted file mode 100644
index 0860af64b..000000000
--- a/source/funkin/util/tools/FlxTweenTools.hx
+++ /dev/null
@@ -1,25 +0,0 @@
-package funkin.util.tools;
-
-import flixel.tweens.FlxTween;
-import flixel.tweens.FlxTween.FlxTweenManager;
-
-class FlxTweenTools
-{
-  /**
-   * Tween the background color of a FlxState.
-   * @param globalManager `flixel.tweens.FlxTween.globalManager`
-   * @param targetState The FlxState to tween the background color of.
-   * @param duration The duration of the tween.
-   * @param fromColor The starting color.
-   * @param toColor The ending color.
-   * @param options The options for the tween.
-   * @return The tween.
-   */
-  public static function bgColor(globalManager:FlxTweenManager, targetState:FlxState, duration:Float = 1.0, fromColor:FlxColor, toColor:FlxColor,
-      ?options:TweenOptions):BackgroundColorTween
-  {
-    var tween = new BackgroundColorTween(options, this);
-    tween.tween(duration, fromColor, toColor, targetState);
-    globalManager.add(tween);
-  }
-}