diff --git a/WriteSongInfoJSON/Example-OBSBrowserSource.html b/WriteSongInfoJSON/Example-OBSBrowserSource.html
new file mode 100644
index 0000000..5443a9d
--- /dev/null
+++ b/WriteSongInfoJSON/Example-OBSBrowserSource.html
@@ -0,0 +1,294 @@
+
+
+
+
+
+ SimplyLove Example JSON OBS Browser Source
+
+
+
+
+
+
![Song Banner]()
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/WriteSongInfoJSON/README.md b/WriteSongInfoJSON/README.md
new file mode 100644
index 0000000..52e16df
--- /dev/null
+++ b/WriteSongInfoJSON/README.md
@@ -0,0 +1,34 @@
+## WriteSongInfoJSON
+This module writes current song information to a json file: `Save/SongInfo.json`
+The JSON is updated any time `ScreenGameplay` is entered, and can be used by anything you want!
+Included is an example HTML file which can be used with OBS to create a clean on-screen display of the current song, a preview of this is below:
+
+![Preview of the Browser Source]()
+
+How to use this module, and the example browser source:
+- Place `WriteSongInfoJSON.lua` in the `/Themes/Simply Love/Modules` folder.
+- Place `Example-OBSBrowserSource.html` in the `/Save` folder.
+- Add a Browser Source in OBS:
+ - Check the Local File box.
+ - Browse to and select the Example-OBSBrowserSource.html file.
+ - Set the width to 760.
+ - Set the height to 170.
+- You can resize and move this source anywhere in the scene.
+
+The JSON object output looks like this currently:
+```
+{
+ "artist" : "Music Artist",
+ "banner" : "/Songs/Pack/Song/Banner.ext",
+ "blockRating" : 8,
+ "diffColor" : [ 1, 0.49019607901573181, 0, 1 ],
+ "difficulty" : "Expert",
+ "length" : "2:06",
+ "pack" : "Pack Name",
+ "stepArtist" : "Step Artist",
+ "stepCount" : 523,
+ "stepDesc" : "DT",
+ "style" : "single",
+ "title" : "Song Title"
+}
+```
\ No newline at end of file
diff --git a/WriteSongInfoJSON/Screenshot 2025-05-16 23-25-47.png b/WriteSongInfoJSON/Screenshot 2025-05-16 23-25-47.png
new file mode 100644
index 0000000..be00961
Binary files /dev/null and b/WriteSongInfoJSON/Screenshot 2025-05-16 23-25-47.png differ
diff --git a/WriteSongInfoJSON/WriteSongInfoJSON.lua b/WriteSongInfoJSON/WriteSongInfoJSON.lua
new file mode 100644
index 0000000..d9cd145
--- /dev/null
+++ b/WriteSongInfoJSON/WriteSongInfoJSON.lua
@@ -0,0 +1,89 @@
+-- Twitch chat module for Simply Love
+--
+-- Copyright (c) 2022 Vincent Nguyen
+--
+-- Permission to use, copy, modify, and/or distribute this software for any
+-- purpose with or without fee is hereby granted, provided that the above
+-- copyright notice and this permission notice appear in all copies.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+local t = {}
+
+t["ScreenGameplay"] = Def.Actor {
+ ModuleCommand = function(self)
+ --Game Data
+ local style = GAMESTATE:GetCurrentStyle():GetName():gsub("8", "")
+
+ --Song Data
+ local song = GAMESTATE:GetCurrentSong()
+ local name = song:GetTranslitFullTitle()
+ local artist = song:GetTranslitArtist()
+ local pack = song:GetGroupName()
+ local banner = song:GetBannerPath()
+ local time = (function(t) return string.format("%d:%02d", math.floor(t/60), math.floor(t%60)) end)(song:GetStepsSeconds())
+
+ -- Step Data
+ local stepData, diff, steps
+ if (GAMESTATE:IsCourseMode()) then
+ stepData = GAMESTATE:GetCurrentCourse():GetCourseEntry(GAMESTATE:GetCourseSongIndex()):GetSong():GetOneSteps(0, 4)
+ stepArtist = stepData:GetAuthorCredit()
+ else
+ stepData = GAMESTATE:GetCurrentSteps(0)
+ stepArtist = stepData:GetAuthorCredit()
+ end
+
+ if (stepData ~= nil) then
+ blockRating = stepData:GetMeter() or "?"
+ difficulty = stepData:GetDifficulty() or ""
+ stepDesc = stepData:GetDescription() or ""
+ stepCount = stepData:GetRadarValues(0):GetValue(5) or ""
+ if difficulty and difficulty ~= "" then
+ diffColor = DifficultyColor(difficulty)
+ else
+ diffColor = {0,0,0,0}
+ end
+ else
+ blockRating = "?"
+ difficulty = ""
+ stepCount = ""
+ stepDesc = ""
+ diffColor = {0,0,0,0}
+ end
+
+ -- Build lua table
+ local data = {
+ title = name,
+ artist = artist,
+ pack = pack,
+ stepArtist = stepArtist,
+ stepDesc = stepDesc,
+ banner = banner,
+ length = time,
+ style = style,
+ difficulty = THEME:GetString("Difficulty",ToEnumShortString(difficulty)),
+ blockRating = blockRating,
+ diffColor = diffColor,
+ stepCount = stepCount
+ }
+
+ -- Final
+ local f = RageFileUtil.CreateRageFile()
+ if f:Open("Save/SongInfo.json", 2) then
+ f:Write(JsonEncode(data))
+ else
+ local fError = f:GetError()
+ Trace( "[FileUtils] Error writing to file: ".. fError )
+ f:ClearError()
+ end
+ f:destroy()
+ end
+}
+
+return t
\ No newline at end of file