diff --git a/assets b/assets
index 361f696ce..005c96f85 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit 361f696cec5c4027ebcfa6f7cec5ba718eaab0d2
+Subproject commit 005c96f85f4304865acb196e7cc4d6d83f9d76d8
diff --git a/source/funkin/play/character/BaseCharacter.hx b/source/funkin/play/character/BaseCharacter.hx
index c228d803a..0dab2101a 100644
--- a/source/funkin/play/character/BaseCharacter.hx
+++ b/source/funkin/play/character/BaseCharacter.hx
@@ -461,7 +461,6 @@ class BaseCharacter extends Bopper
       if (!currentAnimation.startsWith('dance') && !currentAnimation.startsWith('idle') && !isAnimationFinished()) return;
     }
 
-    trace('${characterId}: Actually dancing');
     // Otherwise, fallback to the super dance() method, which handles playing the idle animation.
     super.dance();
   }
diff --git a/source/funkin/play/stage/Bopper.hx b/source/funkin/play/stage/Bopper.hx
index 0061e85fb..87151de21 100644
--- a/source/funkin/play/stage/Bopper.hx
+++ b/source/funkin/play/stage/Bopper.hx
@@ -177,10 +177,8 @@ class Bopper extends StageProp implements IPlayStateScriptedClass
    */
   public function onStepHit(event:SongTimeScriptEvent)
   {
-    if (danceEvery > 0) trace('step hit(${danceEvery}): ${event.step % (danceEvery * Constants.STEPS_PER_BEAT)} == 0?');
     if (danceEvery > 0 && (event.step % (danceEvery * Constants.STEPS_PER_BEAT)) == 0)
     {
-      trace('dance onStepHit!');
       dance(shouldBop);
     }
   }
diff --git a/source/funkin/play/stage/Stage.hx b/source/funkin/play/stage/Stage.hx
index f4e22e380..85b0056ca 100644
--- a/source/funkin/play/stage/Stage.hx
+++ b/source/funkin/play/stage/Stage.hx
@@ -769,7 +769,16 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
    * A function that gets called once per step in the song.
    * @param curStep The current step number.
    */
-  public function onStepHit(event:SongTimeScriptEvent):Void {}
+  public function onStepHit(event:SongTimeScriptEvent):Void
+  {
+    // Override me in your scripted stage to perform custom behavior!
+    // Make sure to call super.onStepHit(event) if you want to keep the boppers dancing.
+
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
   /**
    * A function that gets called once per beat in the song (once every four steps).
@@ -786,7 +795,13 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
     }
   }
 
-  public function onUpdate(event:UpdateScriptEvent) {}
+  public function onUpdate(event:UpdateScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
   public override function kill()
   {
@@ -866,35 +881,131 @@ class Stage extends FlxSpriteGroup implements IPlayStateScriptedClass implements
     return StageRegistry.instance.parseEntryDataWithMigration(id, StageRegistry.instance.fetchEntryVersion(id));
   }
 
-  public function onScriptEvent(event:ScriptEvent) {}
+  public function onScriptEvent(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onPause(event:PauseScriptEvent) {}
+  public function onPause(event:PauseScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onResume(event:ScriptEvent) {}
+  public function onResume(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onSongStart(event:ScriptEvent) {}
+  public function onSongStart(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onSongEnd(event:ScriptEvent) {}
+  public function onSongEnd(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onGameOver(event:ScriptEvent) {}
+  public function onGameOver(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onCountdownStart(event:CountdownScriptEvent) {}
+  public function onCountdownStart(event:CountdownScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onCountdownStep(event:CountdownScriptEvent) {}
+  public function onCountdownStep(event:CountdownScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onCountdownEnd(event:CountdownScriptEvent) {}
+  public function onCountdownEnd(event:CountdownScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onNoteIncoming(event:NoteScriptEvent) {}
+  public function onNoteIncoming(event:NoteScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onNoteHit(event:HitNoteScriptEvent) {}
+  public function onNoteHit(event:HitNoteScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onNoteMiss(event:NoteScriptEvent) {}
+  public function onNoteMiss(event:NoteScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onSongEvent(event:SongEventScriptEvent) {}
+  public function onSongEvent(event:SongEventScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onNoteGhostMiss(event:GhostMissNoteScriptEvent) {}
+  public function onNoteGhostMiss(event:GhostMissNoteScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onSongLoaded(event:SongLoadScriptEvent) {}
+  public function onSongLoaded(event:SongLoadScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 
-  public function onSongRetry(event:ScriptEvent) {}
+  public function onSongRetry(event:ScriptEvent)
+  {
+    for (bopper in boppers)
+    {
+      ScriptEventDispatcher.callEvent(bopper, event);
+    }
+  }
 }