From a764112bd40b9458f4925f5b6a4998f760a9b3e1 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 5 Apr 2024 01:24:03 -0400
Subject: [PATCH 01/10] Removed many unused assets to optimize bandwidth usage.

---
 Project.xml                                   |   4 +
 assets                                        |   2 +-
 source/funkin/Paths.hx                        |   2 +-
 source/funkin/modding/PolymodHandler.hx       |   4 +-
 source/funkin/play/cutscene/VideoCutscene.hx  |   9 +-
 .../funkin/ui/credits/CreditsDataHandler.hx   |   7 ++
 .../components/ChartEditorNoteSprite.hx       |   6 -
 source/funkin/ui/freeplay/AlbumRoll.hx        |  35 ------
 source/funkin/ui/freeplay/DifficultyStars.hx  | 106 ------------------
 source/funkin/ui/freeplay/FreeplayState.hx    |  11 --
 source/funkin/ui/mainmenu/MainMenuState.hx    |   4 +-
 11 files changed, 25 insertions(+), 165 deletions(-)
 delete mode 100644 source/funkin/ui/freeplay/DifficultyStars.hx

diff --git a/Project.xml b/Project.xml
index 8ba14e7dc..db338d32a 100644
--- a/Project.xml
+++ b/Project.xml
@@ -45,6 +45,7 @@
 		<library name="week6" preload="true" />
 		<library name="week7" preload="true" />
 		<library name="weekend1" preload="true" />
+		<library name="videos" preload="true" />
 	</section>
 	<section if="NO_PRELOAD_ALL">
 		<library name="songs" preload="false" />
@@ -58,10 +59,13 @@
 		<library name="week6" preload="false" />
 		<library name="week7" preload="false" />
 		<library name="weekend1" preload="false" />
+		<library name="videos" preload="false" />
 	</section>
 	<library name="art" preload="false" />
 	<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg|*.wav" if="web" />
 	<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3|*.wav" unless="web" />
+	<!-- Videos go in their own library because web never needs to preload them, they can just be streamed. -->
+	<assets path="assets/videos" library="videos" />
 	<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg|*.wav" if="web" />
 	<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3|*.wav" unless="web" />
 	<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg|*.wav" if="web" />
diff --git a/assets b/assets
index 5027bc656..a11c558e4 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 5027bc656c9df5ec208ab256f9494bd7da425111
+Subproject commit a11c558e4c0ed796c34246b43abc9c2d024d0a42
diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx
index fd4ef76fa..54a4b7acf 100644
--- a/source/funkin/Paths.hx
+++ b/source/funkin/Paths.hx
@@ -113,7 +113,7 @@ class Paths
 
   public static function videos(key:String, ?library:String):String
   {
-    return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library);
+    return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library ?? 'videos');
   }
 
   public static function voices(song:String, ?suffix:String = ''):String
diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx
index 78f660d3f..62860ee0f 100644
--- a/source/funkin/modding/PolymodHandler.hx
+++ b/source/funkin/modding/PolymodHandler.hx
@@ -240,8 +240,8 @@ class PolymodHandler
   {
     return {
       assetLibraryPaths: [
-        'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'tutorial' => 'tutorial', 'week1' => 'week1',      'week2' => 'week2',
-            'week3' => 'week3',   'week4' => 'week4', 'week5' => 'week5',       'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1',
+        'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'videos' => 'videos', 'tutorial' => 'tutorial', 'week1' => 'week1',
+        'week2' => 'week2', 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1',
       ],
       coreAssetRedirect: CORE_FOLDER,
     }
diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx
index 3da51185f..6983fbcad 100644
--- a/source/funkin/play/cutscene/VideoCutscene.hx
+++ b/source/funkin/play/cutscene/VideoCutscene.hx
@@ -67,8 +67,13 @@ class VideoCutscene
     if (!openfl.Assets.exists(filePath))
     {
       // Display a popup.
-      lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video');
-      return;
+      // lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video');
+      // return;
+
+      // TODO: After moving videos to their own library,
+      // this function ALWAYS FAILS on web, but the video still plays.
+      // I think that's due to a weird quirk with how OpenFL libraries work.
+      trace('Video file does not exist: ${filePath}');
     }
 
     var rawFilePath = Paths.stripLibrary(filePath);
diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx
index 86afdafd1..628a9f893 100644
--- a/source/funkin/ui/credits/CreditsDataHandler.hx
+++ b/source/funkin/ui/credits/CreditsDataHandler.hx
@@ -99,12 +99,19 @@ class CreditsDataHandler
 
   static function fetchCreditsData():funkin.data.JsonFile
   {
+    #if !macro
     var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim();
 
     return {
       fileName: CREDITS_DATA_PATH,
       contents: rawJson
     };
+    #else
+    return {
+      fileName: CREDITS_DATA_PATH,
+      contents: null
+    };
+    #end
   }
 
   static function parseCreditsData(file:JsonFile):Null<CreditsData>
diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
index cd403c6f8..98f5a47aa 100644
--- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
+++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
@@ -117,12 +117,6 @@ class ChartEditorNoteSprite extends FlxSprite
     {
       noteFrameCollection.pushFrame(frame);
     }
-    var frameCollectionNormal2:FlxAtlasFrames = Paths.getSparrowAtlas('NoteHoldNormal');
-
-    for (frame in frameCollectionNormal2.frames)
-    {
-      noteFrameCollection.pushFrame(frame);
-    }
 
     // Pixel notes
     var graphicPixel = FlxG.bitmap.add(Paths.image('weeb/pixelUI/arrows-pixels', 'week6'), false, null);
diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx
index bde946e79..c1263fed6 100644
--- a/source/funkin/ui/freeplay/AlbumRoll.hx
+++ b/source/funkin/ui/freeplay/AlbumRoll.hx
@@ -37,7 +37,6 @@ class AlbumRoll extends FlxSpriteGroup
 
   var albumArt:FunkinSprite;
   var albumTitle:FunkinSprite;
-  var difficultyStars:DifficultyStars;
 
   var _exitMovers:Null<FreeplayState.ExitMoverData>;
 
@@ -52,9 +51,6 @@ class AlbumRoll extends FlxSpriteGroup
     albumTitle.zIndex = 200;
     add(albumTitle);
 
-    difficultyStars = new DifficultyStars(140, 39);
-
-    difficultyStars.stars.visible = true;
     albumTitle.visible = false;
     // albumArtist.visible = false;
 
@@ -158,21 +154,6 @@ class AlbumRoll extends FlxSpriteGroup
         speed: 0.2,
         wait: 0.1
       });
-
-    /*
-      exitMovers.set([albumArtist],
-        {
-          x: FlxG.width * 1.1,
-          speed: 0.2,
-          wait: 0.2
-        });
-     */
-    exitMovers.set([difficultyStars],
-      {
-        x: FlxG.width * 1.2,
-        speed: 0.2,
-        wait: 0.3
-      });
   }
 
   var titleTimer:Null<FlxTimer> = null;
@@ -198,26 +179,10 @@ class AlbumRoll extends FlxSpriteGroup
     });
   }
 
-  public function setDifficultyStars(?difficulty:Int):Void
-  {
-    if (difficulty == null) return;
-
-    difficultyStars.difficulty = difficulty;
-  }
-
   public function showTitle():Void
   {
     albumTitle.visible = true;
     albumTitle.animation.play('active');
     albumTitle.animation.finishCallback = (_) -> albumTitle.animation.play('idle');
   }
-
-  /**
-   * Make the album stars visible.
-   */
-  public function showStars():Void
-  {
-    // albumArtist.visible = false;
-    difficultyStars.stars.visible = false;
-  }
 }
diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx
deleted file mode 100644
index 51526bcbe..000000000
--- a/source/funkin/ui/freeplay/DifficultyStars.hx
+++ /dev/null
@@ -1,106 +0,0 @@
-package funkin.ui.freeplay;
-
-import flixel.group.FlxSpriteGroup;
-import funkin.graphics.adobeanimate.FlxAtlasSprite;
-import funkin.graphics.shaders.HSVShader;
-
-class DifficultyStars extends FlxSpriteGroup
-{
-  /**
-   * Internal handler var for difficulty... ranges from 0... to 15
-   * 0 is 1 star... 15 is 0 stars!
-   */
-  var curDifficulty(default, set):Int = 0;
-
-  /**
-   * Range between 0 and 15
-   */
-  public var difficulty(default, set):Int = 1;
-
-  public var stars:FlxAtlasSprite;
-
-  var flames:FreeplayFlames;
-
-  var hsvShader:HSVShader;
-
-  public function new(x:Float, y:Float)
-  {
-    super(x, y);
-
-    hsvShader = new HSVShader();
-
-    flames = new FreeplayFlames(0, 0);
-    add(flames);
-
-    stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars"));
-    stars.anim.play("diff stars");
-    add(stars);
-
-    stars.shader = hsvShader;
-
-    for (memb in flames.members)
-      memb.shader = hsvShader;
-  }
-
-  override function update(elapsed:Float):Void
-  {
-    super.update(elapsed);
-
-    // "loops" the current animation
-    // for clarity, the animation file looks like
-    // frame : stars
-    // 0-99: 1 star
-    // 100-199: 2 stars
-    // ......
-    // 1300-1499: 15 stars
-    // 1500 : 0 stars
-    if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100)
-    {
-      stars.anim.play("diff stars", true, false, curDifficulty * 100);
-    }
-  }
-
-  function set_difficulty(value:Int):Int
-  {
-    difficulty = value;
-
-    if (difficulty <= 0)
-    {
-      difficulty = 0;
-      curDifficulty = 15;
-    }
-    else if (difficulty <= 15)
-    {
-      difficulty = value;
-      curDifficulty = difficulty - 1;
-    }
-    else
-    {
-      difficulty = 15;
-      curDifficulty = difficulty - 1;
-    }
-
-    if (difficulty > 10) flames.flameCount = difficulty - 10;
-    else
-      flames.flameCount = 0;
-
-    return difficulty;
-  }
-
-  function set_curDifficulty(value:Int):Int
-  {
-    curDifficulty = value;
-    if (curDifficulty == 15)
-    {
-      stars.anim.play("diff stars", true, false, 1500);
-      stars.anim.pause();
-    }
-    else
-    {
-      stars.anim.curFrame = Std.int(curDifficulty * 100);
-      stars.anim.play("diff stars", true, false, curDifficulty * 100);
-    }
-
-    return curDifficulty;
-  }
-}
diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx
index 0724ad022..af76a42ce 100644
--- a/source/funkin/ui/freeplay/FreeplayState.hx
+++ b/source/funkin/ui/freeplay/FreeplayState.hx
@@ -473,10 +473,6 @@ class FreeplayState extends MusicBeatSubState
         albumRoll.showTitle();
       });
 
-      new FlxTimer().start(35 / 24, function(_) {
-        albumRoll.showStars();
-      });
-
       FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut});
 
       var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls);
@@ -1047,9 +1043,6 @@ class FreeplayState extends MusicBeatSubState
       }
     }
 
-    // Set the difficulty star count on the right.
-    albumRoll.setDifficultyStars(daSong?.songRating);
-
     // Set the album graphic and play the animation if relevant.
     var newAlbumId:String = daSong?.albumId;
     if (albumRoll.albumId != newAlbumId)
@@ -1169,10 +1162,6 @@ class FreeplayState extends MusicBeatSubState
     {
       currentDifficulty = rememberedDifficulty;
     }
-
-    // Set the difficulty star count on the right.
-    var daSong:Null<FreeplaySongData> = grpCapsules.members[curSelected]?.songData;
-    albumRoll.setDifficultyStars(daSong?.songRating ?? 0);
   }
 
   function changeSelection(change:Int = 0):Void
diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx
index f38db1ccd..c1dc54ffe 100644
--- a/source/funkin/ui/mainmenu/MainMenuState.hx
+++ b/source/funkin/ui/mainmenu/MainMenuState.hx
@@ -1,5 +1,6 @@
 package funkin.ui.mainmenu;
 
+import funkin.graphics.FunkinSprite;
 import flixel.addons.transition.FlxTransitionableState;
 import funkin.ui.debug.DebugMenuSubState;
 import flixel.FlxObject;
@@ -56,7 +57,8 @@ class MainMenuState extends MusicBeatState
     persistentUpdate = false;
     persistentDraw = true;
 
-    var bg:FlxSprite = new FlxSprite(Paths.image('menuBG'));
+    var bg = FunkinSprite.create('menuDesat');
+    bg.color = 0xFFFDE871;
     bg.scrollFactor.x = 0;
     bg.scrollFactor.y = 0.17;
     bg.setGraphicSize(Std.int(bg.width * 1.2));

From af8a37d299aa6ea015dd7476ec4dfa8fbf4c9264 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Fri, 5 Apr 2024 19:33:24 -0400
Subject: [PATCH 02/10] assets submod

---
 assets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets b/assets
index a11c558e4..2eb07acf1 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit a11c558e4c0ed796c34246b43abc9c2d024d0a42
+Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88

From a6d44b1f1552e747f45028659bf5887fc7da9f08 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 5 Apr 2024 01:24:03 -0400
Subject: [PATCH 03/10] Removed many unused assets to optimize bandwidth usage.

---
 Project.xml                                   |   4 +
 assets                                        |   2 +-
 source/funkin/Paths.hx                        |   2 +-
 source/funkin/modding/PolymodHandler.hx       |   4 +-
 source/funkin/play/cutscene/VideoCutscene.hx  |   9 +-
 .../funkin/ui/credits/CreditsDataHandler.hx   |   7 ++
 .../components/ChartEditorNoteSprite.hx       |   6 -
 source/funkin/ui/freeplay/DifficultyStars.hx  | 106 ------------------
 source/funkin/ui/freeplay/FreeplayState.hx    |  11 +-
 source/funkin/ui/mainmenu/MainMenuState.hx    |   4 +-
 10 files changed, 29 insertions(+), 126 deletions(-)
 delete mode 100644 source/funkin/ui/freeplay/DifficultyStars.hx

diff --git a/Project.xml b/Project.xml
index 8ba14e7dc..db338d32a 100644
--- a/Project.xml
+++ b/Project.xml
@@ -45,6 +45,7 @@
 		<library name="week6" preload="true" />
 		<library name="week7" preload="true" />
 		<library name="weekend1" preload="true" />
+		<library name="videos" preload="true" />
 	</section>
 	<section if="NO_PRELOAD_ALL">
 		<library name="songs" preload="false" />
@@ -58,10 +59,13 @@
 		<library name="week6" preload="false" />
 		<library name="week7" preload="false" />
 		<library name="weekend1" preload="false" />
+		<library name="videos" preload="false" />
 	</section>
 	<library name="art" preload="false" />
 	<assets path="assets/songs" library="songs" exclude="*.fla|*.ogg|*.wav" if="web" />
 	<assets path="assets/songs" library="songs" exclude="*.fla|*.mp3|*.wav" unless="web" />
+	<!-- Videos go in their own library because web never needs to preload them, they can just be streamed. -->
+	<assets path="assets/videos" library="videos" />
 	<assets path="assets/shared" library="shared" exclude="*.fla|*.ogg|*.wav" if="web" />
 	<assets path="assets/shared" library="shared" exclude="*.fla|*.mp3|*.wav" unless="web" />
 	<assets path="assets/tutorial" library="tutorial" exclude="*.fla|*.ogg|*.wav" if="web" />
diff --git a/assets b/assets
index e8f4d2d91..2eb07acf1 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6
+Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88
diff --git a/source/funkin/Paths.hx b/source/funkin/Paths.hx
index fd4ef76fa..54a4b7acf 100644
--- a/source/funkin/Paths.hx
+++ b/source/funkin/Paths.hx
@@ -113,7 +113,7 @@ class Paths
 
   public static function videos(key:String, ?library:String):String
   {
-    return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library);
+    return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library ?? 'videos');
   }
 
   public static function voices(song:String, ?suffix:String = ''):String
diff --git a/source/funkin/modding/PolymodHandler.hx b/source/funkin/modding/PolymodHandler.hx
index 78f660d3f..62860ee0f 100644
--- a/source/funkin/modding/PolymodHandler.hx
+++ b/source/funkin/modding/PolymodHandler.hx
@@ -240,8 +240,8 @@ class PolymodHandler
   {
     return {
       assetLibraryPaths: [
-        'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'tutorial' => 'tutorial', 'week1' => 'week1',      'week2' => 'week2',
-            'week3' => 'week3',   'week4' => 'week4', 'week5' => 'week5',       'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1',
+        'default' => 'preload', 'shared' => 'shared', 'songs' => 'songs', 'videos' => 'videos', 'tutorial' => 'tutorial', 'week1' => 'week1',
+        'week2' => 'week2', 'week3' => 'week3', 'week4' => 'week4', 'week5' => 'week5', 'week6' => 'week6', 'week7' => 'week7', 'weekend1' => 'weekend1',
       ],
       coreAssetRedirect: CORE_FOLDER,
     }
diff --git a/source/funkin/play/cutscene/VideoCutscene.hx b/source/funkin/play/cutscene/VideoCutscene.hx
index 0c05bc876..0939dae38 100644
--- a/source/funkin/play/cutscene/VideoCutscene.hx
+++ b/source/funkin/play/cutscene/VideoCutscene.hx
@@ -67,8 +67,13 @@ class VideoCutscene
     if (!openfl.Assets.exists(filePath))
     {
       // Display a popup.
-      lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video');
-      return;
+      // lime.app.Application.current.window.alert('Video file does not exist: ${filePath}', 'Error playing video');
+      // return;
+
+      // TODO: After moving videos to their own library,
+      // this function ALWAYS FAILS on web, but the video still plays.
+      // I think that's due to a weird quirk with how OpenFL libraries work.
+      trace('Video file does not exist: ${filePath}');
     }
 
     var rawFilePath = Paths.stripLibrary(filePath);
diff --git a/source/funkin/ui/credits/CreditsDataHandler.hx b/source/funkin/ui/credits/CreditsDataHandler.hx
index 86afdafd1..628a9f893 100644
--- a/source/funkin/ui/credits/CreditsDataHandler.hx
+++ b/source/funkin/ui/credits/CreditsDataHandler.hx
@@ -99,12 +99,19 @@ class CreditsDataHandler
 
   static function fetchCreditsData():funkin.data.JsonFile
   {
+    #if !macro
     var rawJson:String = openfl.Assets.getText(CREDITS_DATA_PATH).trim();
 
     return {
       fileName: CREDITS_DATA_PATH,
       contents: rawJson
     };
+    #else
+    return {
+      fileName: CREDITS_DATA_PATH,
+      contents: null
+    };
+    #end
   }
 
   static function parseCreditsData(file:JsonFile):Null<CreditsData>
diff --git a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
index cd403c6f8..98f5a47aa 100644
--- a/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
+++ b/source/funkin/ui/debug/charting/components/ChartEditorNoteSprite.hx
@@ -117,12 +117,6 @@ class ChartEditorNoteSprite extends FlxSprite
     {
       noteFrameCollection.pushFrame(frame);
     }
-    var frameCollectionNormal2:FlxAtlasFrames = Paths.getSparrowAtlas('NoteHoldNormal');
-
-    for (frame in frameCollectionNormal2.frames)
-    {
-      noteFrameCollection.pushFrame(frame);
-    }
 
     // Pixel notes
     var graphicPixel = FlxG.bitmap.add(Paths.image('weeb/pixelUI/arrows-pixels', 'week6'), false, null);
diff --git a/source/funkin/ui/freeplay/DifficultyStars.hx b/source/funkin/ui/freeplay/DifficultyStars.hx
deleted file mode 100644
index 51526bcbe..000000000
--- a/source/funkin/ui/freeplay/DifficultyStars.hx
+++ /dev/null
@@ -1,106 +0,0 @@
-package funkin.ui.freeplay;
-
-import flixel.group.FlxSpriteGroup;
-import funkin.graphics.adobeanimate.FlxAtlasSprite;
-import funkin.graphics.shaders.HSVShader;
-
-class DifficultyStars extends FlxSpriteGroup
-{
-  /**
-   * Internal handler var for difficulty... ranges from 0... to 15
-   * 0 is 1 star... 15 is 0 stars!
-   */
-  var curDifficulty(default, set):Int = 0;
-
-  /**
-   * Range between 0 and 15
-   */
-  public var difficulty(default, set):Int = 1;
-
-  public var stars:FlxAtlasSprite;
-
-  var flames:FreeplayFlames;
-
-  var hsvShader:HSVShader;
-
-  public function new(x:Float, y:Float)
-  {
-    super(x, y);
-
-    hsvShader = new HSVShader();
-
-    flames = new FreeplayFlames(0, 0);
-    add(flames);
-
-    stars = new FlxAtlasSprite(0, 0, Paths.animateAtlas("freeplay/freeplayStars"));
-    stars.anim.play("diff stars");
-    add(stars);
-
-    stars.shader = hsvShader;
-
-    for (memb in flames.members)
-      memb.shader = hsvShader;
-  }
-
-  override function update(elapsed:Float):Void
-  {
-    super.update(elapsed);
-
-    // "loops" the current animation
-    // for clarity, the animation file looks like
-    // frame : stars
-    // 0-99: 1 star
-    // 100-199: 2 stars
-    // ......
-    // 1300-1499: 15 stars
-    // 1500 : 0 stars
-    if (curDifficulty < 15 && stars.anim.curFrame >= (curDifficulty + 1) * 100)
-    {
-      stars.anim.play("diff stars", true, false, curDifficulty * 100);
-    }
-  }
-
-  function set_difficulty(value:Int):Int
-  {
-    difficulty = value;
-
-    if (difficulty <= 0)
-    {
-      difficulty = 0;
-      curDifficulty = 15;
-    }
-    else if (difficulty <= 15)
-    {
-      difficulty = value;
-      curDifficulty = difficulty - 1;
-    }
-    else
-    {
-      difficulty = 15;
-      curDifficulty = difficulty - 1;
-    }
-
-    if (difficulty > 10) flames.flameCount = difficulty - 10;
-    else
-      flames.flameCount = 0;
-
-    return difficulty;
-  }
-
-  function set_curDifficulty(value:Int):Int
-  {
-    curDifficulty = value;
-    if (curDifficulty == 15)
-    {
-      stars.anim.play("diff stars", true, false, 1500);
-      stars.anim.pause();
-    }
-    else
-    {
-      stars.anim.curFrame = Std.int(curDifficulty * 100);
-      stars.anim.play("diff stars", true, false, curDifficulty * 100);
-    }
-
-    return curDifficulty;
-  }
-}
diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx
index dc1f164ea..150f5a0b1 100644
--- a/source/funkin/ui/freeplay/FreeplayState.hx
+++ b/source/funkin/ui/freeplay/FreeplayState.hx
@@ -469,6 +469,10 @@ class FreeplayState extends MusicBeatSubState
 
       albumRoll.playIntro();
 
+      new FlxTimer().start(0.75, function(_) {
+        albumRoll.showTitle();
+      });
+
       FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut});
 
       var diffSelLeft:DifficultySelector = new DifficultySelector(20, grpDifficulties.y - 10, false, controls);
@@ -1039,9 +1043,6 @@ class FreeplayState extends MusicBeatSubState
       }
     }
 
-    // Set the difficulty star count on the right.
-    albumRoll.setDifficultyStars(daSong?.songRating);
-
     // Set the album graphic and play the animation if relevant.
     var newAlbumId:String = daSong?.albumId;
     if (albumRoll.albumId != newAlbumId)
@@ -1161,10 +1162,6 @@ class FreeplayState extends MusicBeatSubState
     {
       currentDifficulty = rememberedDifficulty;
     }
-
-    // Set the difficulty star count on the right.
-    var daSong:Null<FreeplaySongData> = grpCapsules.members[curSelected]?.songData;
-    albumRoll.setDifficultyStars(daSong?.songRating ?? 0);
   }
 
   function changeSelection(change:Int = 0):Void
diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx
index f38db1ccd..c1dc54ffe 100644
--- a/source/funkin/ui/mainmenu/MainMenuState.hx
+++ b/source/funkin/ui/mainmenu/MainMenuState.hx
@@ -1,5 +1,6 @@
 package funkin.ui.mainmenu;
 
+import funkin.graphics.FunkinSprite;
 import flixel.addons.transition.FlxTransitionableState;
 import funkin.ui.debug.DebugMenuSubState;
 import flixel.FlxObject;
@@ -56,7 +57,8 @@ class MainMenuState extends MusicBeatState
     persistentUpdate = false;
     persistentDraw = true;
 
-    var bg:FlxSprite = new FlxSprite(Paths.image('menuBG'));
+    var bg = FunkinSprite.create('menuDesat');
+    bg.color = 0xFFFDE871;
     bg.scrollFactor.x = 0;
     bg.scrollFactor.y = 0.17;
     bg.setGraphicSize(Std.int(bg.width * 1.2));

From da4f1fb424564b1be658fd0d32b7b53e743299a0 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Fri, 5 Apr 2024 19:47:33 -0400
Subject: [PATCH 04/10] remove difficulty stars

---
 source/funkin/ui/freeplay/AlbumRoll.hx     | 52 +++++++++++-----------
 source/funkin/ui/freeplay/FreeplayState.hx |  2 +-
 2 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/source/funkin/ui/freeplay/AlbumRoll.hx b/source/funkin/ui/freeplay/AlbumRoll.hx
index 189e04973..89c6c73a6 100644
--- a/source/funkin/ui/freeplay/AlbumRoll.hx
+++ b/source/funkin/ui/freeplay/AlbumRoll.hx
@@ -37,8 +37,8 @@ class AlbumRoll extends FlxSpriteGroup
   }
 
   var newAlbumArt:FlxAtlasSprite;
-  var difficultyStars:DifficultyStars;
 
+  // var difficultyStars:DifficultyStars;
   var _exitMovers:Null<FreeplayState.ExitMoverData>;
 
   var albumData:Album;
@@ -65,9 +65,9 @@ class AlbumRoll extends FlxSpriteGroup
 
     add(newAlbumArt);
 
-    difficultyStars = new DifficultyStars(140, 39);
-    difficultyStars.stars.visible = false;
-    add(difficultyStars);
+    // difficultyStars = new DifficultyStars(140, 39);
+    // difficultyStars.stars.visible = false;
+    // add(difficultyStars);
   }
 
   function onAlbumFinish(animName:String):Void
@@ -86,7 +86,7 @@ class AlbumRoll extends FlxSpriteGroup
   {
     if (albumId == null)
     {
-      difficultyStars.stars.visible = false;
+      // difficultyStars.stars.visible = false;
       return;
     }
 
@@ -133,12 +133,12 @@ class AlbumRoll extends FlxSpriteGroup
         wait: 0
       });
 
-    exitMovers.set([difficultyStars],
-      {
-        x: FlxG.width * 1.2,
-        speed: 0.2,
-        wait: 0.3
-      });
+    // exitMovers.set([difficultyStars],
+    //   {
+    //     x: FlxG.width * 1.2,
+    //     speed: 0.2,
+    //     wait: 0.3
+    //   });
   }
 
   var titleTimer:Null<FlxTimer> = null;
@@ -151,10 +151,10 @@ class AlbumRoll extends FlxSpriteGroup
     newAlbumArt.visible = true;
     newAlbumArt.playAnimation(animNames.get('$albumId-active'), false, false, false);
 
-    difficultyStars.stars.visible = false;
+    // difficultyStars.stars.visible = false;
     new FlxTimer().start(0.75, function(_) {
       // showTitle();
-      showStars();
+      // showStars();
     });
   }
 
@@ -163,18 +163,16 @@ class AlbumRoll extends FlxSpriteGroup
     newAlbumArt.playAnimation(animNames.get('$albumId-trans'), false, false, false);
   }
 
-  public function setDifficultyStars(?difficulty:Int):Void
-  {
-    if (difficulty == null) return;
-
-    difficultyStars.difficulty = difficulty;
-  }
-
-  /**
-   * Make the album stars visible.
-   */
-  public function showStars():Void
-  {
-    difficultyStars.stars.visible = false; // true;
-  }
+  // public function setDifficultyStars(?difficulty:Int):Void
+  // {
+  //   if (difficulty == null) return;
+  //   difficultyStars.difficulty = difficulty;
+  // }
+  // /**
+  //  * Make the album stars visible.
+  //  */
+  // public function showStars():Void
+  // {
+  //   difficultyStars.stars.visible = false; // true;
+  // }
 }
diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx
index 150f5a0b1..ae51ba82a 100644
--- a/source/funkin/ui/freeplay/FreeplayState.hx
+++ b/source/funkin/ui/freeplay/FreeplayState.hx
@@ -470,7 +470,7 @@ class FreeplayState extends MusicBeatSubState
       albumRoll.playIntro();
 
       new FlxTimer().start(0.75, function(_) {
-        albumRoll.showTitle();
+        // albumRoll.showTitle();
       });
 
       FlxTween.tween(grpDifficulties, {x: 90}, 0.6, {ease: FlxEase.quartOut});

From 2462bd2d9943fe7839335d080db74c0b3f3e5059 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Fri, 5 Apr 2024 22:05:34 -0400
Subject: [PATCH 05/10] Update assets submodule

---
 assets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets b/assets
index 2eb07acf1..84c3c7fef 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 2eb07acf1fbee70229b913f87cfc1bfddf22ab88
+Subproject commit 84c3c7fef411c616e558b5b497f70c106adc11d1

From 6d374c7af9e0e784bedd1c949b59c5c468b04c3d Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Mon, 8 Apr 2024 18:39:51 -0400
Subject: [PATCH 06/10] Fix loading issue tied to -DSONG compile define.

---
 .vscode/settings.json                       |  5 ++++
 source/funkin/InitState.hx                  | 33 +++++++++++++++++++++
 source/funkin/ui/transition/LoadingState.hx |  1 -
 3 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/.vscode/settings.json b/.vscode/settings.json
index 13a1862d2..0cca68aab 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -130,6 +130,11 @@
         "-DFORCE_DEBUG_VERSION"
       ]
     },
+    {
+      "label": "Windows / Debug (Straight to Play - 2hot)",
+      "target": "windows",
+      "args": ["-debug", "-DSONG=2hot", "-DFORCE_DEBUG_VERSION"]
+    },
     {
       "label": "HashLink / Debug (Straight to Play - Bopeebo Normal)",
       "target": "hl",
diff --git a/source/funkin/InitState.hx b/source/funkin/InitState.hx
index 6ea77ec18..9b842bc13 100644
--- a/source/funkin/InitState.hx
+++ b/source/funkin/InitState.hx
@@ -261,6 +261,35 @@ class InitState extends FlxState
       return;
     }
 
+    // TODO: Rework loading behavior so we don't have to do this.
+    switch (songId)
+    {
+      case 'tutorial' | 'bopeebo' | 'fresh' | 'dadbattle':
+        Paths.setCurrentLevel('week1');
+        PlayStatePlaylist.campaignId = 'week1';
+      case 'spookeez' | 'south' | 'monster':
+        Paths.setCurrentLevel('week2');
+        PlayStatePlaylist.campaignId = 'week2';
+      case 'pico' | 'philly-nice' | 'blammed':
+        Paths.setCurrentLevel('week3');
+        PlayStatePlaylist.campaignId = 'week3';
+      case 'high' | 'satin-panties' | 'milf':
+        Paths.setCurrentLevel('week4');
+        PlayStatePlaylist.campaignId = 'week4';
+      case 'cocoa' | 'eggnog' | 'winter-horrorland':
+        Paths.setCurrentLevel('week5');
+        PlayStatePlaylist.campaignId = 'week5';
+      case 'senpai' | 'roses' | 'thorns':
+        Paths.setCurrentLevel('week6');
+        PlayStatePlaylist.campaignId = 'week6';
+      case 'ugh' | 'guns' | 'stress':
+        Paths.setCurrentLevel('week7');
+        PlayStatePlaylist.campaignId = 'week7';
+      case 'darnell' | 'lit-up' | '2hot' | 'blazin':
+        Paths.setCurrentLevel('weekend1');
+        PlayStatePlaylist.campaignId = 'weekend1';
+    }
+
     LoadingState.loadPlayState(
       {
         targetSong: songData,
@@ -283,6 +312,10 @@ class InitState extends FlxState
       return;
     }
 
+    // TODO: Rework loading behavior so we don't have to do this.
+    Paths.setCurrentLevel(levelId);
+    PlayStatePlaylist.campaignId = levelId;
+
     PlayStatePlaylist.playlistSongIds = currentLevel.getSongs();
     PlayStatePlaylist.isStoryMode = true;
     PlayStatePlaylist.campaignScore = 0;
diff --git a/source/funkin/ui/transition/LoadingState.hx b/source/funkin/ui/transition/LoadingState.hx
index af8798ae2..347190993 100644
--- a/source/funkin/ui/transition/LoadingState.hx
+++ b/source/funkin/ui/transition/LoadingState.hx
@@ -281,7 +281,6 @@ class LoadingState extends MusicBeatSubState
   {
     // TODO: This section is a hack! Redo this later when we have a proper asset caching system.
     FunkinSprite.preparePurgeCache();
-    FunkinSprite.cacheTexture(Paths.image('combo'));
     FunkinSprite.cacheTexture(Paths.image('healthBar'));
     FunkinSprite.cacheTexture(Paths.image('menuDesat'));
     FunkinSprite.cacheTexture(Paths.image('combo'));

From 97884021c0ad7fab887611d7971cd189e63df597 Mon Sep 17 00:00:00 2001
From: Mike Welsh <mwelsh@gmail.com>
Date: Mon, 8 Apr 2024 22:08:24 -0700
Subject: [PATCH 07/10] Fix bad initial save data when no save data present

If no save data was present, the game would check for legacy save
data in the ninjamuffin99 path to migrate over. This code was
incorrectly checking `FlxSave.data == null` to determine if
legacy data was present.

This caused an empty legacy save being migrated over, resulting
in a `volume` of 0 for any new player of the game.
---
 source/funkin/save/Save.hx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source/funkin/save/Save.hx b/source/funkin/save/Save.hx
index af2730ddd..bfbda2a02 100644
--- a/source/funkin/save/Save.hx
+++ b/source/funkin/save/Save.hx
@@ -693,7 +693,7 @@ class Save
     trace("[SAVE] Checking for legacy save data...");
     var legacySave:FlxSave = new FlxSave();
     legacySave.bind(SAVE_NAME_LEGACY, SAVE_PATH_LEGACY);
-    if (legacySave?.data == null)
+    if (legacySave.isEmpty())
     {
       trace("[SAVE] No legacy save data found.");
       return null;

From dbcbb73338db3dcb3ad758a8d2a1d8f4153db51e Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Tue, 9 Apr 2024 15:10:58 -0400
Subject: [PATCH 08/10] Main menu fix and Week 3 train fix

---
 assets                                     | 2 +-
 source/funkin/ui/mainmenu/MainMenuState.hx | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/assets b/assets
index e8f4d2d91..1a7a0b6cc 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit e8f4d2d91c7bd5a922465e7d67a0efb7d7574bd6
+Subproject commit 1a7a0b6cc60dc8131f1651caa7abef0c1944a10c
diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx
index f38db1ccd..ecd67b4da 100644
--- a/source/funkin/ui/mainmenu/MainMenuState.hx
+++ b/source/funkin/ui/mainmenu/MainMenuState.hx
@@ -174,6 +174,7 @@ class MainMenuState extends MusicBeatState
   {
     FlxG.cameras.reset(new FunkinCamera());
     FlxG.camera.follow(camFollow, null, 0.06);
+    FlxG.camera.snapToTarget();
   }
 
   function createMenuItem(name:String, atlas:String, callback:Void->Void, fireInstantly:Bool = false):Void

From eb752c242f3c59d275640bacc875e99b80c5d5e5 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Tue, 9 Apr 2024 20:13:59 -0400
Subject: [PATCH 09/10] assets submod

---
 assets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets b/assets
index 1a7a0b6cc..bef67ec4b 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 1a7a0b6cc60dc8131f1651caa7abef0c1944a10c
+Subproject commit bef67ec4b3c834416e73ce4e7c3e7128c5d7de63

From 1058181cc93a609363de5faf8ae5bcc69c5478cf Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Tue, 9 Apr 2024 20:25:33 -0400
Subject: [PATCH 10/10] assets submod

---
 assets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets b/assets
index 84c3c7fef..0782d868b 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 84c3c7fef411c616e558b5b497f70c106adc11d1
+Subproject commit 0782d868ba8379d699ef9ab9547c3507580628e2