diff --git a/README.md b/README.md
index b1e46c8..5c12354 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ To change size, set root font size (default 10px)
```
To right align
```css
-body { flex-direction: row-reverse; } .row { justify-content: flex-end; }
+body > .row { flex-direction: row-reverse; } .row { justify-content: flex-end; }
```
To change fade duration (default 300ms)
```css
diff --git a/index.html b/index.html
index 63c1c6d..51bc108 100644
--- a/index.html
+++ b/index.html
@@ -6,24 +6,24 @@
-
-
-
- Title
- Subtitle
-
-
-
- Artist
- Mapper
-
-
-
-
Easy
-

-
Diff Label
-
-
25f
+
+

+
+
+ Title
+ Subtitle
+
+
+ Artist
+ Mapper
+
+
+
Easy
+

+
Diff Label
+
+
25f
+
diff --git a/main.js b/main.js
index 4476e30..64af5c8 100644
--- a/main.js
+++ b/main.js
@@ -1,15 +1,46 @@
"use strict";
-// https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay
-const bspUrl = "ws://localhost:2947/socket";
+// Data providers
+
+const beatSaberPlus = {
+ // https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay
+ url: "ws://localhost:2947/socket",
+
+ /** @param {MessageEvent
} e */
+ onMessage: function(e) {
+ /** @type {BeatSaberPlusEvent} */
+ const data = JSON.parse(e.data);
+ switch (data._type) {
+ case "event":
+ switch (data._event) {
+ case "gameState":
+ document.body.dataset.gameState = data.gameStateChanged;
+ break;
+
+ case "mapInfo":
+ updateMapInfo(data.mapInfoChanged);
+ break;
+ }
+ break;
+
+ default:
+ console.log("message", e.data);
+ break;
+ }
+ },
+};
+
+// WebSocket connection
+
+const provider = beatSaberPlus;
const retryMs = 10000;
let retries = 0;
function connect() {
- console.log(`Connecting to ${bspUrl} (attempt ${retries++})`);
- const ws = new WebSocket(bspUrl);
+ console.log(`Connecting to ${provider.url} (attempt ${retries++})`);
+ const ws = new WebSocket(provider.url);
ws.onopen = onOpen;
- ws.onmessage = onMessage;
+ ws.onmessage = provider.onMessage;
ws.onclose = onClose;
}
@@ -18,42 +49,21 @@ function onOpen() {
retries = 0;
}
-/** @param {MessageEvent} e */
-function onMessage(e) {
- /** @type {BeatSaberPlusEvent} */
- const data = JSON.parse(e.data);
- switch (data._type) {
- case "event":
- switch (data._event) {
- case "gameState":
- document.body.dataset.gameState = data.gameStateChanged;
- break;
-
- case "mapInfo":
- updateMapInfo(data.mapInfoChanged);
- break;
- }
- break;
-
- default:
- console.log("message", e.data);
- break;
- }
-}
-
/** @param {CloseEvent} e */
function onClose(e) {
console.log(`Connection closed. code: ${e.code}, reason: ${e.reason}, clean: ${e.wasClean}`);
setTimeout(connect, retryMs);
}
-const cover = document.getElementById("cover");
+// Map info
+
+const cover = document.getElementById("coverImg");
const title = document.getElementById("title");
const subTitle = document.getElementById("subTitle");
const artist = document.getElementById("artist");
const mapper = document.getElementById("mapper");
const difficulty = document.getElementById("difficulty");
-const characteristicIcon = document.getElementById("characteristicIcon");
+const characteristic = document.getElementById("characteristicImg");
const difficultyLabel = document.getElementById("difficultyLabel");
const type = document.getElementById("type");
const bsrKey = document.getElementById("bsrKey");
@@ -62,13 +72,13 @@ const bsrKey = document.getElementById("bsrKey");
async function updateMapInfo(data) {
const custom = data.level_id.startsWith("custom_level_");
const wip = custom && data.level_id.endsWith("WIP");
- cover.style.backgroundImage = data.coverRaw ? `url("data:image/jpeg;base64,${data.coverRaw}")` : "";
+ cover.src = data.coverRaw ? `data:image/jpeg;base64,${data.coverRaw}` : "images/unknown.svg";
title.textContent = data.name || "";
subTitle.textContent = data.sub_name || "";
artist.textContent = data.artist || "";
mapper.textContent = data.mapper || "";
difficulty.textContent = data.difficulty.replace("Plus", " +") || "";
- characteristicIcon.src = `images/characteristic/${data.characteristic}.svg`;
+ characteristic.src = `images/characteristic/${data.characteristic}.svg`;
difficultyLabel.textContent = ""; // BS+ does not provide label
type.textContent = !custom ? "OST" : wip ? "WIP" : "";
bsrKey.textContent = data.BSRKey || "???"; // Always empty?
@@ -95,6 +105,4 @@ async function updateMapInfo(data) {
connect();
-document.documentElement.onclick = function() {
- document.body.dataset.gameState = document.body.dataset.gameState === "Playing" ? "Menu" : "Playing";
-};
+document.documentElement.onclick = () => document.body.classList.toggle("preview");
diff --git a/style.css b/style.css
index e4f6130..eadc0c7 100644
--- a/style.css
+++ b/style.css
@@ -10,12 +10,13 @@ html {
}
body {
- display: flex;
margin: 0;
padding: 1.4rem 1.6rem;
- gap: 1.6rem;
overflow: hidden;
font-family: "Montserrat", sans-serif;
+ font-size: 1.5rem;
+ font-weight: 600;
+ line-height: 1.2;
white-space: nowrap;
background: rgba(0, 0, 0, 0);
color: white;
@@ -24,47 +25,45 @@ body {
}
body.loading,
-body:not([data-game-state="Playing"]) {
+body:not([data-game-state="Playing"], .preview) {
opacity: 0;
}
-#cover {
- width: 6.8rem;
- height: 6.8rem;
- border-radius: 0.6rem;
- background-image: url("images/unknown.svg");
- background-repeat: no-repeat;
- background-size: contain;
- flex-shrink: 0;
+.row {
+ display: flex;
+ gap: 1.6rem;
}
-#songData {
+.column {
display: flex;
flex-direction: column;
flex-grow: 1;
- justify-content: space-between;
- margin: -0.4rem 0 -0.2rem;
+ gap: 0.35rem;
+ margin-top: -0.4rem;
overflow: hidden;
- line-height: 1.2;
- font-size: 1.5rem;
- font-weight: 600;
}
-#songData * {
+.column * {
overflow: hidden;
text-overflow: ellipsis;
}
-#songData .row {
- display: flex;
+.column .row {
align-items: baseline;
- column-gap: 0.6em;
+ gap: 0.9rem;
}
-#songData span:empty {
+.column span:empty {
display: none;
}
+#coverImg {
+ width: 6.8rem;
+ height: 6.8rem;
+ border-radius: 0.6rem;
+ flex-shrink: 0;
+}
+
#title {
font-size: 2.4rem;
font-weight: 700;
@@ -91,7 +90,7 @@ body:not([data-game-state="Playing"]) {
flex-shrink: 99999;
}
-#characteristicIcon {
+#characteristicImg {
width: 1.1em;
height: 1.1em;
flex-shrink: 0;
diff --git a/types.d.ts b/types.d.ts
index 8e17f1e..ecf57d4 100644
--- a/types.d.ts
+++ b/types.d.ts
@@ -65,6 +65,7 @@ type MapInfoChanged = MapInfoChangedEvent["mapInfoChanged"];
interface Document {
// Assume non-null
- getElementById(elementId: `${string}Icon`): HTMLImageElement;
+ getElementById(elementId: `${string}Img`): HTMLImageElement;
+ getElementById(elementId: `${string}Input`): HTMLInputElement;
getElementById(elementId: string): HTMLElement;
}