diff --git a/CHANGELOG.md b/CHANGELOG.md
index f33bd2b12..566637823 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,18 +4,38 @@ All notable changes will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
-## [UNRELEASED]
-### Added
-- Cool waveform stuff for chart editor
-- Noises in chart editor lol!
-- 3 AWESOME PICO VS. DARNELL SONGS!!
-- Character offset editor / spritesheet viewer
-## Changed
-- Lerp'd the healthbar
-- Resetting from game over and "restart song" should be faster
-- Health gain is different depending on how accurate you hit notes!
-- slight less health gained on sustain notes
-- The wave-y effect on Thorns for the school is now a shader, instead of a pre-baked animation!
+## [0.3.0] - 2024-03-29
+# Added
+- New Story Level: Weekend 1, starting Pico, Darnell, and Nene.
+  - Beat the level in Story Mode to unlock the songs for Freeplay!
+- 12 new Erect remixes, featuring Kawai Sprite, Saruky, Kohta Takahashi, and Saster
+  - Unlocked instantly in Freeplay
+- New visually enhanced Freeplay menu.
+  - Sorting, favorites, and more.
+- New Results screen upon completing any song or story level.
+- New refactored Chart Editor prototype (accessible via `~` in the main menu or `7` in the Play State, rebindable). (VERY EARLY PROTOTYPE. EXPECT BUGS AND CRASHES)
+- Implemented a new scripting system using HScript (an interpreted language with Haxe-like syntax) for incredible flexibility.
+  - All character-specific, stage-specific, or song-specific behaviors have been moved to HScript.
+- New song events system allows for simple customization of camera behavior.
+  - Mods can implement custom song events via HScript, and new built-in song events will come in the future.
+- New credits menu to list all the dozens of people who contributed.
+# Changed
+- Completely refactored the game's input system for higher reliability and accuracy.
+- Reworked note rendering to massively reduce lag on larger charts.
+- Reworks to scoring and health gain.
+- Dedicated gamepad support with the ability to rebind buttons.
+- Improvements to video cutscenes and dialogue, allowing them to be easily skipped or restarted.
+- Updated Polymod by several major versions, allowing for fully dynamic asset replacement and support for scripted classes.
+- Completely refactored almost every part of the game's code for performance, stability, and extensibility.
+  - This is not the Ludem Dare game held together with sticks and glue you played three years ago.
+- Characters, stages, songs, story levels, and dialogue are now built from JSON data registries rather than being hardcoded.
+  - All of these also support attaching scripts for custom behavior, more documentation on this soon.
+  - You can forcibly reload the game's JSON data and scripts by pressing F5.
+- Fully refactored the game's chart file format for extensibility and readability.
+  - You can migrate old charts using the Import FNF Legacy option in the chart editor.
+- Various visual tweaks and improvements.
+# Fixed
+- 17 quadrillion bugs across hundreds of PRs.
 
 ## [0.2.8] - 2021-04-18 (note, this one is iffy cuz we slacked wit it lol!)
 ### Added
@@ -90,7 +110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - Clear section button to note editor
 - Swap button in note editor
 - a new boot text or two
-- automatic check for when you're on an old version of the game! 
+- automatic check for when you're on an old version of the game!
 ### Changed
 - Made Spookeez on Normal easier.
 - Mouse is now visible in note editor
diff --git a/assets b/assets
index 2b408f67f..11b551182 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 2b408f67fecfdb7f3a68e04f8de5f9b5bbff1d8b
+Subproject commit 11b551182dc4a45a6decd8d5efec592c808f8943
diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx
index 69acb36b5..56dd1e80f 100644
--- a/source/funkin/play/ResultState.hx
+++ b/source/funkin/play/ResultState.hx
@@ -324,7 +324,8 @@ class ResultState extends MusicBeatSubState
     FlxTween.tween(difficulty, {y: diffYTween}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.8});
 
     songName.y = -songName.height;
-    FlxTween.tween(songName, {y: diffYTween - 35}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9});
+    var fuckedupnumber = (10) * (songName.text.length / 15);
+    FlxTween.tween(songName, {y: diffYTween - 35 - fuckedupnumber}, 0.5, {ease: FlxEase.expoOut, startDelay: 0.9});
     songName.x = (difficulty.x + difficulty.width) + 20;
 
     new FlxTimer().start(3, _ -> {
diff --git a/source/funkin/ui/freeplay/FreeplayState.hx b/source/funkin/ui/freeplay/FreeplayState.hx
index 860b8f235..513d411f7 100644
--- a/source/funkin/ui/freeplay/FreeplayState.hx
+++ b/source/funkin/ui/freeplay/FreeplayState.hx
@@ -560,6 +560,12 @@ class FreeplayState extends MusicBeatSubState
   {
     var tempSongs:Array<FreeplaySongData> = songs;
 
+    // Remember just the difficulty because it's important for song sorting.
+    if (rememberedDifficulty != null)
+    {
+      currentDifficulty = rememberedDifficulty;
+    }
+
     if (filterStuff != null) tempSongs = sortSongs(tempSongs, filterStuff);
 
     // Filter further by current selected difficulty.
@@ -579,6 +585,7 @@ class FreeplayState extends MusicBeatSubState
 
     // Only now do we know that the filter is actually changing.
 
+    // If curSelected is 0, the result will be null and fall back to the rememberedSongId.
     rememberedSongId = grpCapsules.members[curSelected]?.songData?.songId ?? rememberedSongId;
 
     for (cap in grpCapsules.members)
@@ -635,7 +642,7 @@ class FreeplayState extends MusicBeatSubState
     rememberSelection();
 
     changeSelection();
-    changeDiff();
+    changeDiff(0, true);
   }
 
   /**
@@ -946,16 +953,16 @@ class FreeplayState extends MusicBeatSubState
         caps.doJumpOut = true;
       }
 
-      if (Type.getClass(FlxG.state) == MainMenuState)
+      if (Type.getClass(_parentState) == MainMenuState)
       {
-        FlxG.state.persistentUpdate = false;
-        FlxG.state.persistentDraw = true;
+        _parentState.persistentUpdate = false;
+        _parentState.persistentDraw = true;
       }
 
       new FlxTimer().start(longestTimer, (_) -> {
         FlxTransitionableState.skipNextTransIn = true;
         FlxTransitionableState.skipNextTransOut = true;
-        if (Type.getClass(FlxG.state) == MainMenuState)
+        if (Type.getClass(_parentState) == MainMenuState)
         {
           FunkinSound.playMusic('freakyMenu',
             {
@@ -987,7 +994,7 @@ class FreeplayState extends MusicBeatSubState
     }
   }
 
-  function changeDiff(change:Int = 0):Void
+  function changeDiff(change:Int = 0, force:Bool = false):Void
   {
     touchTimer = 0;
 
@@ -1047,7 +1054,7 @@ class FreeplayState extends MusicBeatSubState
       }
     }
 
-    if (change != 0)
+    if (change != 0 || force)
     {
       // Update the song capsules to reflect the new difficulty info.
       for (songCapsule in grpCapsules.members)
diff --git a/source/funkin/ui/mainmenu/MainMenuState.hx b/source/funkin/ui/mainmenu/MainMenuState.hx
index 11c7c6ebf..466dbbb90 100644
--- a/source/funkin/ui/mainmenu/MainMenuState.hx
+++ b/source/funkin/ui/mainmenu/MainMenuState.hx
@@ -54,6 +54,7 @@ class MainMenuState extends MusicBeatState
 
     playMenuMusic();
 
+    // We want the state to always be able to begin with being able to accept inputs and show the anims of the menu items.
     persistentUpdate = true;
     persistentDraw = true;
 
@@ -360,7 +361,7 @@ class MainMenuState extends MusicBeatState
     }
     #end
 
-    if (FlxG.sound.music.volume < 0.8)
+    if (FlxG.sound.music != null && FlxG.sound.music.volume < 0.8)
     {
       FlxG.sound.music.volume += 0.5 * elapsed;
     }