Complete rewrite from scratch
- Plain JS - BS+ only - Simple song info only - No configuration
9
.editorconfig
Normal file
@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
max_line_length = 120
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
12
LICENSE.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Copyright (c) 2025 iza
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted.
|
||||
|
||||
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.
|
||||
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# Beat Saber Overlay
|
||||
|
||||
Simple Beat Saber stream overlay for https://www.twitch.tv/iza_k
|
||||
|
||||
Requires BeatSaberPlus
|
||||
|
||||
<img width="533" height="95" alt="image" src="https://github.com/user-attachments/assets/7c334ac5-8ed1-4dfd-b2a6-3da682da4357" />
|
||||
18
dprint.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"lineWidth": 120,
|
||||
"newLineKind": "lf",
|
||||
"useTabs": true,
|
||||
"typescript": { "useBraces": "maintain" },
|
||||
"json": {},
|
||||
"markdown": {},
|
||||
"malva": {},
|
||||
"markup": {},
|
||||
"excludes": ["**/node_modules", "**/build", "**/dist", "**/*-lock.json", "**/*.svg"],
|
||||
"plugins": [
|
||||
"https://plugins.dprint.dev/typescript-0.95.15.wasm",
|
||||
"https://plugins.dprint.dev/json-0.21.1.wasm",
|
||||
"https://plugins.dprint.dev/markdown-0.21.1.wasm",
|
||||
"https://plugins.dprint.dev/g-plane/malva-v0.15.2.wasm",
|
||||
"https://plugins.dprint.dev/g-plane/markup_fmt-v0.26.0.wasm"
|
||||
]
|
||||
}
|
||||
BIN
fonts/montserrat.woff2
Normal file
48
images/characteristic/360Degree.svg
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 28.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1280 1280"
|
||||
style="enable-background: new 0 0 1280 1280"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<style type="text/css">.st0{fill:#FFFFFF;}</style>
|
||||
<g>
|
||||
<path
|
||||
class="st0"
|
||||
d="M197.39,338.14v127.8H83V314.09c0-99.23,36.13-148.87,108.43-148.87h100.46
|
||||
c72.28,0,108.43,49.63,108.43,148.87v202.98c0,62.16-13.93,100.25-41.77,114.28c27.84,14.03,41.77,50.12,41.77,108.26v225.55
|
||||
c0,99.23-36.15,148.85-108.43,148.85H191.43C119.13,1114,83,1064.38,83,965.15V814.78h114.39v126.3c0,16.06,1.99,26.83,5.96,32.34
|
||||
s11.27,8.27,21.89,8.27h33.82c10.6,0,17.9-2.76,21.88-8.27c3.97-5.51,5.98-16.28,5.98-32.34V738.1c0-16.03-1.83-27.05-5.48-33.07
|
||||
s-11.1-9.03-22.37-9.03h-76.6V569.69h76.6c10.6,0,17.9-2.76,21.88-8.27c3.97-5.51,5.98-16.28,5.98-32.32V338.14
|
||||
c0-16.03-2-26.81-5.98-32.32c-3.97-5.51-11.27-8.28-21.88-8.28h-33.82c-10.62,0-17.92,2.77-21.89,8.28S197.39,322.12,197.39,338.14
|
||||
z"
|
||||
/>
|
||||
<path
|
||||
class="st0"
|
||||
d="M584.33,562.18h108.43c72.28,0,108.43,49.62,108.43,148.85v254.12c0,99.23-36.15,148.85-108.43,148.85h-113.4
|
||||
c-72.29,0-108.43-49.62-108.43-148.85V314.09c0-99.23,36.13-148.87,108.43-148.87h108.43c72.28,0,108.43,49.63,108.43,148.87
|
||||
v145.84h-112.4V338.14c0-16.03-2-26.81-5.98-32.32s-11.27-8.28-21.88-8.28h-43.77c-10.62,0-17.92,2.77-21.89,8.28
|
||||
c-3.97,5.51-5.96,16.3-5.96,32.32L584.33,562.18L584.33,562.18z M688.78,941.08v-209c0-16.03-2-26.81-5.98-32.32
|
||||
c-3.97-5.51-11.6-8.27-22.87-8.27h-75.6v249.59c0,16.06,1.99,26.83,5.96,32.34c3.97,5.51,11.27,8.27,21.89,8.27h47.75
|
||||
c11.27,0,18.9-2.76,22.87-8.27S688.78,957.14,688.78,941.08z"
|
||||
/>
|
||||
<path
|
||||
class="st0"
|
||||
d="M1199.04,314.09v651.07c0,99.23-36.15,148.85-108.43,148.85H975.24c-72.29,0-108.43-49.62-108.43-148.85
|
||||
V314.09c0-99.23,36.13-148.87,108.43-148.87h115.38C1162.9,165.22,1199.04,214.85,1199.04,314.09z M1084.66,941.08V338.14
|
||||
c0-16.03-2-26.81-5.98-32.32s-11.6-8.28-22.87-8.28h-45.76c-10.62,0-17.92,2.77-21.89,8.28c-3.97,5.51-5.96,16.3-5.96,32.32v602.94
|
||||
c0,16.06,1.99,26.83,5.96,32.34c3.97,5.51,11.27,8.27,21.89,8.27h45.76c11.27,0,18.9-2.76,22.87-8.27
|
||||
S1084.66,957.14,1084.66,941.08z"
|
||||
/>
|
||||
</g>
|
||||
<text
|
||||
transform="matrix(1 0 0 1 -381.2729 778.7275)"
|
||||
style='font-family: "MyriadPro-Regular"; font-size: 12px'
|
||||
>Lorem ipsum</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
22
images/characteristic/90Degree.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 1280">
|
||||
<g>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M386.25,168.31h112.6c72.4,0,108.61,49.2,108.61,147.59v645.51c0,98.39-36.21,147.59-108.61,147.59H390.23
|
||||
c-72.41,0-108.61-49.2-108.61-147.59V819.79h112.6v117.77c0,15.91,1.99,26.6,5.98,32.05c3.99,5.47,11.29,8.2,21.92,8.2h44.84
|
||||
c10.62,0,17.94-2.73,21.92-8.2c3.99-5.45,5.98-16.14,5.98-32.05V730.34H386.25c-72.41,0-108.61-49.2-108.61-147.59V315.9
|
||||
C277.64,217.51,313.84,168.31,386.25,168.31z M418.14,606.6h76.73V339.75c0-15.89-1.99-26.58-5.98-32.05
|
||||
c-3.99-5.45-11.3-8.2-21.92-8.2h-48.83c-10.63,0-17.94,2.75-21.92,8.2c-3.99,5.47-5.98,16.17-5.98,32.05v226.6
|
||||
c0,15.91,1.99,26.6,5.98,32.05C400.2,603.88,407.5,606.6,418.14,606.6z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1013,315.9v645.51c0,98.39-36.21,147.59-108.61,147.59H788.8c-72.41,0-108.61-49.2-108.61-147.59V315.9
|
||||
c0-98.39,36.2-147.59,108.61-147.59h115.59C976.79,168.31,1013,217.51,1013,315.9z M898.41,937.56V339.75
|
||||
c0-15.89-1.99-26.58-5.98-32.05c-3.98-5.45-11.63-8.2-22.92-8.2h-45.84c-10.63,0-17.94,2.75-21.92,8.2
|
||||
c-3.98,5.47-5.98,16.17-5.98,32.05v597.81c0,15.91,1.99,26.6,5.98,32.05c3.99,5.47,11.29,8.2,21.92,8.2h45.84
|
||||
c11.29,0,18.93-2.73,22.92-8.2C896.42,964.16,898.41,953.47,898.41,937.56z"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
27
images/characteristic/Lawless.svg
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 1280">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M639.63,931.84c-32.42,0-64.85,0.01-97.27,0c-49.35-0.02-91.47-40.08-94.1-89.41
|
||||
c-0.23-4.24-0.68-8.49-1.24-12.7c-2.09-15.62-8.63-23.1-24.53-24.41c-22.41-1.84-43.94-5.51-62.46-19.39
|
||||
c-25.42-19.04-40.52-43.98-39.39-76.17c0.66-18.65-4.31-34.83-11.99-51.32c-26.74-57.41-47.22-117.1-51.51-180.6
|
||||
c-6.77-100.1,19.79-189.66,91.12-263.06c67.86-69.83,152.88-103.69,247.85-113.16c97.36-9.71,189.34,9.89,272.44,62.65
|
||||
c101.84,64.65,154.46,157.75,155.77,279.06c0.74,69.03-18.74,133.48-44.27,196.55c-5.26,13-12.77,25.23-16.73,38.57
|
||||
c-3.05,10.29-2.68,21.75-2.92,32.7c-0.47,22.04-6.94,41.84-20.71,59.07c-17.3,21.65-40.59,31.48-67.65,33.62
|
||||
c-0.85,0.07-1.71-0.01-2.56,0.02c-27.51,1.05-35.9,8.81-37.05,36.03c-0.87,20.78-7.73,39.17-20.44,55.24
|
||||
c-18.74,23.7-43.11,36.72-73.81,36.72C705.33,931.84,672.48,931.84,639.63,931.84z M480.05,675.84c54.01,0,96.15-41.51,96.22-94.81
|
||||
c0.08-54.41-41.23-95.84-93.84-97.55c-53.66-1.74-99.41,45.06-98.41,95.82C385.11,633.95,425.78,675.84,480.05,675.84z
|
||||
M800.21,483.84c-53.87,0-95.87,41.64-95.93,95.11c-0.06,54.3,41.34,95.6,94.14,97.25c53.21,1.66,99.2-44.9,98.12-96.11
|
||||
C895.39,525.54,854.69,483.84,800.21,483.84z M640.62,775.21c3.39,5.64,6,11.05,9.59,15.72c9.19,11.96,24.81,16.36,37.63,11.13
|
||||
c11.95-4.87,18.72-15.54,16.14-31.29c-6.07-37-23.41-67.85-53.77-90.78c-6.73-5.08-12.97-5.26-19.7-0.1
|
||||
c-30.87,23.65-49.06,54.84-53.97,93.24c-1.86,14.55,4.56,24.54,16.05,28.77c12.63,4.65,24.61,2.59,34.06-7.2
|
||||
C631.85,789.29,635.55,782.41,640.62,775.21z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1236.1,788.03L1236.1,788.03c-10.85-23.21-38.46-33.24-61.67-22.39l-533.92,249.47L106.75,766.76
|
||||
c-23.23-10.81-50.82-0.74-61.63,22.49l0,0c-10.81,23.23-0.74,50.82,22.49,61.63l463.17,215.5l-12.54,5.86l-2.58-5.53L290.31,1172
|
||||
l43.52,93.13l225.34-105.29l-1.66-3.55l83.09-38.82l82.58,38.42l-1.96,4.21l225.51,104.93l43.37-93.2l-225.51-104.93l-2.27,4.87
|
||||
l-11.98-5.57l463.37-216.51C1236.92,838.85,1246.95,811.24,1236.1,788.03z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
29
images/characteristic/Legacy.svg
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 26.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg
|
||||
version="1.2"
|
||||
baseProfile="tiny"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1280 1280"
|
||||
overflow="visible"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M589,559V243c0,0-1-13,11-13c9,0,67.64,0,82,0c14,0,11,15,11,15v415.45c0,0,2,6.55-20,20.55s-26,16-40,10
|
||||
S356,574,356,574s-12-10-8-22s21-54,26-66s25-6,25-6L589,559z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1219.5,640c0-322.26-261.24-583.5-583.5-583.5S52.5,317.74,52.5,640s261.24,583.5,583.5,583.5
|
||||
c73.98,0,144.73-13.78,209.85-38.89C877.96,1198.99,913.54,1207,951,1207c142.21,0,257.5-115.29,257.5-257.5
|
||||
c0-39.06-8.71-76.08-24.27-109.24C1207.05,777.8,1219.5,710.36,1219.5,640z M739.36,1096.19c-32.16,7.08-65.57,10.81-99.86,10.81
|
||||
C384.07,1107,177,899.93,177,644.5S384.07,182,639.5,182S1102,389.07,1102,644.5c0,30.9-3.04,61.09-8.82,90.3
|
||||
C1052.44,707.76,1003.56,692,951,692c-142.21,0-257.5,115.29-257.5,257.5C693.5,1004.01,710.46,1054.56,739.36,1096.19z M1032,1099
|
||||
H872v-61h160c0,0,37-26,37-69s-37-58-37-58H879v57l-101-98l101-98v68h151c0,0,102,21,102,130S1032,1099,1032,1099z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
25
images/characteristic/Lightshow.svg
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 1280">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1214.77,1060.46L345.4,323.04c-10.53-8.93-26.3-7.63-35.23,2.89l0,0c-8.93,10.53-7.63,26.3,2.89,35.23
|
||||
l760.31,644.9C1001.05,989.8,914.14,981,823,981c-112.48,0-218.54,13.4-298.65,37.72c-46.18,14.02-81.2,30.97-104.39,50.3
|
||||
L231.57,407.7c-3.78-13.28-17.61-20.97-30.89-17.19c-13.28,3.78-20.97,17.61-17.19,30.89l200.62,704.3c0.58,2.03,1.39,3.92,2.4,5.67
|
||||
c0.77,45.1,48.38,83.26,137.83,110.42c80.11,24.32,186.17,37.72,298.65,37.72s218.54-13.4,298.65-37.72
|
||||
c90.18-27.38,137.85-65.95,137.85-111.53C1259.5,1104.5,1244.28,1080.98,1214.77,1060.46z M1107.71,1195.85
|
||||
C1032,1218.84,930.88,1231.5,823,1231.5s-209-12.66-284.71-35.65c-71.7-21.77-103.79-48.63-103.79-65.6s32.09-43.83,103.79-65.6
|
||||
C614,1041.66,715.12,1029,823,1029s209,12.66,284.71,35.65c28.28,8.59,50.4,17.97,66.82,27.22l16.4,13.91
|
||||
c3,2.55,6.43,4.26,10.01,5.16c7.13,7.14,10.57,13.75,10.57,19.3C1211.5,1147.22,1179.41,1174.08,1107.71,1195.85z"
|
||||
/>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M314.38,157.41l-68.74-4.95l-63.09-91.22c-10.96-15.12-28.15-24.07-46.59-27.02
|
||||
c-18.44-2.95-36.92,1.47-52.04,12.42l-41.81,30.3C10.9,99.56,3.9,143.36,26.52,174.58l58.98,83.44l-22.94,71
|
||||
c-4.11,12.71,2.87,26.35,15.58,30.46h0c12.71,4.11,26.35-2.87,30.46-15.58l19.07-59.03l17.54,38.17c3.17,6.88,9.46,12.2,16.83,14.24
|
||||
c2.25,0.62,4.53,0.93,6.8,0.93c5,0,9.91-1.48,14.12-4.36l85.76-58.73c8.29-6.13,12.84-7.92,15.24-13.3l0.98-2.22
|
||||
c3.7-8.37,1.51-18.17-5.4-24.17l-1.31-1.13l-34.56-33.48l67.24,4.84c13.32,0.96,24.9-9.07,25.86-22.39v0
|
||||
C337.73,169.95,327.71,158.37,314.38,157.41z M70.24,115.78l41.81-30.3c3.79-2.75,8.25-4.18,12.84-4.18c1.16,0,2.34,0.09,3.51,0.28
|
||||
c5.79,0.92,10.88,4.05,14.32,8.8l50.4,73.24l-74.59,56.23l-53.19-73.4C58.24,136.64,60.44,122.88,70.24,115.78z M177.86,279.16
|
||||
l-13.44-29.26l35.11-25l23.84,23.09L177.86,279.16z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
21
images/characteristic/NoArrows.svg
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg
|
||||
version="1.2"
|
||||
baseProfile="tiny"
|
||||
id="Layer_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 1280 1280"
|
||||
overflow="visible"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M926.33,200H353.67C268.8,200,200,268.8,200,353.67v572.67c0,84.87,68.8,153.67,153.67,153.67h572.67
|
||||
c84.87,0,153.67-68.8,153.67-153.67V353.67C1080,268.8,1011.2,200,926.33,200z M640,824c-100.52,0-182-81.48-182-182
|
||||
s81.48-182,182-182s182,81.48,182,182S740.52,824,640,824z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 648 B |
14
images/characteristic/OneSaber.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 1280">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1219.85,1045.85l-224.8-83.69L854,850V645.44l317.06,43.14c33.1,4.5,63.58-18.68,68.08-51.77v0
|
||||
c4.5-33.1-18.68-63.58-51.77-68.08l-434.95-59.19C792.87,491.12,821,450.35,821,403c0-64.62-52.38-117-117-117s-117,52.38-117,117
|
||||
c0,51.94,33.85,95.97,80.69,111.25l-378.02-43.52c-2.67-0.31-5.31-0.42-7.92-0.38c4.76-10.41,4.8-22.84-0.97-33.74L80.93,59.64
|
||||
c-9.87-18.61-32.95-25.7-51.56-15.83v0c-18.61,9.87-25.7,32.95-15.83,51.56l199.84,376.98c5.13,9.68,13.83,16.23,23.62,18.91
|
||||
c-7.69,8.88-12.89,20.09-14.34,32.64v0c-3.82,33.18,19.98,63.18,53.17,67l323.91,37.29l0,0L598,810c0,0-128,2-189,5
|
||||
c-53,3-75,65-46.05,106.24c0.05-0.24,136.94,189.62,136.94,189.62c19.6,26.61,57.05,32.29,83.66,12.69l0,0
|
||||
c26.61-19.6,32.29-57.05,12.69-83.66L542,941l201-6l205.66,137.35l4.64,1.96l224.8,83.69c30.97,11.53,65.42-4.23,76.95-35.2v0
|
||||
C1266.57,1091.83,1250.82,1057.38,1219.85,1045.85z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
14
images/characteristic/Standard.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1280 1280">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M1014,1160c39,5,63-3,75.87-31.69l0,0c13.53-32.46-1.82-69.75-34.28-83.27L708.07,900.22l71.48-37.92
|
||||
l321.62,145.05c32.72,14.76,71.2,0.2,85.96-32.52v0c7.38-16.36,8.52-35.88,3.74-53.15c-0.68-2.47-1.5-4.8-2.41-7.02l8.48-529.63
|
||||
c0.33-20.64-16.13-37.64-36.77-37.97l0,0c-20.64-0.33-37.64,16.13-37.97,36.77l-7.66,478.4C974.56,800.83,832.1,745.34,692.3,683.52
|
||||
c5.01,0.61,10.11,0.93,15.28,0.93c69.05,0,125.03-55.98,125.03-125.03S776.63,434.4,707.58,434.4s-125.03,55.98-125.03,125.03
|
||||
c0,37.23,16.28,70.65,42.1,93.56c-142.4-65.53-282.26-137.13-424.6-202.8L409.6,121.57c11.1-17.41,5.99-40.51-11.42-51.61l0,0
|
||||
c-17.41-11.1-40.51-5.99-51.61,11.42L126.42,426.63c-25.08,3.05-49.73,19.87-60.04,42.73l0,0c-14.76,32.72-0.2,71.2,32.52,85.96
|
||||
l313.11,141.22l-68.3,175.18l-88.76,86.09c-20.92,20.29-25.68,50.93-14.09,75.96c3.82,8.45,9.46,16.24,16.9,22.74l115.03,100.42
|
||||
c27.77,24.24,69.93,21.38,94.17-6.38h0c24.24-27.77,21.38-69.93-6.38-94.17l-60.8-53.08l19.39-18.81h130.07l0.02-0.01L1014,1160z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
9
images/unknown.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="48" height="48" version="1.1" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m21.225 29.383c-0.09826-0.28968-0.22135-0.65379-0.3125-1.1086-0.09115-0.45481-0.13672-0.90394-0.13672-1.3474 0-0.69359 0.15625-1.319 0.46875-1.8761 0.32552-0.56852 0.72266-1.0972 1.1914-1.5862 0.48177-0.48892 0.99609-0.96079 1.543-1.4156 0.5599-0.45481 1.0742-0.89826 1.543-1.3303 0.48177-0.43207 0.87891-0.88688 1.1914-1.3644 0.32552-0.47755 0.48828-1.1434 0.48828-1.7944 0-0.58594-0.11719-1.0937-0.35156-1.5234-0.23438-0.44271-0.5599-0.80729-0.97656-1.0937-0.40364-0.29948-0.8724-0.52083-1.4062-0.66406-0.52083-0.14323-1.0807-0.21484-1.6797-0.21484-1.9401 0-3.7484 0.9081-5.5469 2.5977-0.56753 0.53317-1.5583-3.5623 0-4.5117 2.113-1.2875 4.349-1.875 6.6406-1.875 1.0547 0 2.0508 0.13672 2.9883 0.41016 0.9375 0.27344 1.7578 0.67708 2.4609 1.2109 0.70312 0.53386 1.2565 1.1979 1.6602 1.9922s0.60547 1.7187 0.60547 2.7734c0 1.0026-0.16927 1.9936-0.50781 2.6758-0.33854 0.68222-0.76823 1.3133-1.2891 1.8932-0.50781 0.56852-1.0612 1.0745-1.6602 1.5179-0.58594 0.44344-1.1393 0.88688-1.6602 1.3303-0.50781 0.44344-0.93099 0.90394-1.2695 1.3815-0.33854 0.47755-0.50781 1.0063-0.50781 1.5862 0 0.48892 0.07162 0.93236 0.21484 1.3303 0.14323 0.39796 0.29303 0.73083 0.42969 1.0063 0.31581 0.63652-3.8048 0.93258-4.1211-2e-6zm2.2266 8.3427c-0.74219 0-1.3997-0.25391-1.9727-0.76172-0.54688-0.49479-0.82031-1.1068-0.82031-1.8359 0-0.74219 0.27344-1.3542 0.82031-1.8359 0.5599-0.52083 1.2174-0.78125 1.9727-0.78125 0.74219 0 1.3932 0.26042 1.9531 0.78125 0.54688 0.48177 0.82031 1.0938 0.82031 1.8359 0 0.72917-0.27344 1.3411-0.82031 1.8359-0.57292 0.50781-1.224 0.76172-1.9531 0.76172z"
|
||||
fill="#f9f9f9"
|
||||
aria-label="?"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
31
index.html
Normal file
@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>BS Overlay</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="cover"></div>
|
||||
<div id="songData">
|
||||
<div class="row">
|
||||
<span id="title">Title</span>
|
||||
<span id="subTitle">Subtitle</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span id="artist">Artist</span>
|
||||
<span id="mapper">Mapper</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<span id="difficulty">Easy</span>
|
||||
<img id="characteristicIcon" src="images/characteristic/Standard.svg">
|
||||
<span id="difficultyLabel">Diff Label</span>
|
||||
<span id="bsrKey">25f</span>
|
||||
<span id="type">WIP</span>
|
||||
</div>
|
||||
</div>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
6
jsconfig.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"target": "es2021"
|
||||
}
|
||||
}
|
||||
81
main.js
Normal file
@ -0,0 +1,81 @@
|
||||
"use strict";
|
||||
// https://github.com/hardcpp/BeatSaberPlus/wiki/%5BEN%5D-Song-Overlay
|
||||
|
||||
const bspUrl = "ws://localhost:2947/socket";
|
||||
const retryMs = 5000;
|
||||
let retries = 0;
|
||||
|
||||
function connect() {
|
||||
console.log(`Connecting to ${bspUrl} (attempt ${retries++})`);
|
||||
const ws = new WebSocket(bspUrl);
|
||||
ws.onopen = () => console.log("Connection open.");
|
||||
ws.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
switch (data._type) {
|
||||
case "event":
|
||||
switch (data._event) {
|
||||
case "gameState":
|
||||
document.body.className = data.gameStateChanged;
|
||||
break;
|
||||
|
||||
case "mapInfo":
|
||||
updateMapInfo(data.mapInfoChanged);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log("message", e.data);
|
||||
break;
|
||||
}
|
||||
};
|
||||
ws.onclose = (e) => {
|
||||
console.log(`Connection closed. code: ${e.code}, reason: ${e.reason}, clean: ${e.wasClean}`);
|
||||
setTimeout(connect, retryMs);
|
||||
};
|
||||
}
|
||||
|
||||
const cover = document.getElementById("cover");
|
||||
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 difficultyLabel = document.getElementById("difficultyLabel");
|
||||
const bsrKey = document.getElementById("bsrKey");
|
||||
const type = document.getElementById("type");
|
||||
|
||||
/** @param {MapInfoChanged} data */
|
||||
function updateMapInfo(data) {
|
||||
const custom = data.level_id.startsWith("custom_level_");
|
||||
cover.style.backgroundImage = data.coverRaw ? `url("data:image/jpeg;base64,${data.coverRaw}")` : "";
|
||||
title.textContent = data.name || "";
|
||||
subTitle.textContent = data.sub_name || "";
|
||||
artist.textContent = data.artist || "";
|
||||
mapper.textContent = data.mapper || "";
|
||||
difficulty.textContent = data.difficulty.replace("Plus", " +") || "";
|
||||
characteristicIcon.setAttribute("src", `images/characteristic/${data.characteristic}.svg`);
|
||||
difficultyLabel.textContent = "";
|
||||
bsrKey.textContent = data.BSRKey || "";
|
||||
type.textContent = !custom ? "OST" : data.level_id.endsWith(" WIP") ? "WIP" : "";
|
||||
|
||||
if (custom) {
|
||||
fetch(`https://api.beatsaver.com/maps/hash/${data.level_id.substring(13, 53)}`)
|
||||
.then(response => response.json())
|
||||
.then(map => {
|
||||
if (!map.id) return;
|
||||
bsrKey.textContent = map.id;
|
||||
mapper.textContent = map.metadata.levelAuthorName; // Replace mapper name with full authors list
|
||||
// Find difficulty label
|
||||
const diff = map.versions[0].diffs.find(d =>
|
||||
d.characteristic === data.characteristic && d.difficulty === data.difficulty
|
||||
);
|
||||
if (diff.label) difficultyLabel.textContent = diff.label;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
document.documentElement.onclick = () => document.body.classList.toggle("Playing");
|
||||
113
style.css
Normal file
@ -0,0 +1,113 @@
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
font-display: swap;
|
||||
font-weight: 600 700;
|
||||
src: url("fonts/montserrat.woff2") format("woff2");
|
||||
}
|
||||
|
||||
:root {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
margin: 0;
|
||||
padding: 1.4rem 1.6rem;
|
||||
font-family: "Montserrat", sans-serif;
|
||||
white-space: nowrap;
|
||||
background: #0000;
|
||||
color: white;
|
||||
filter: drop-shadow(0 0 0.1rem black) drop-shadow(0 0 0.1rem black);
|
||||
transition: opacity 300ms ease-out;
|
||||
transition-delay: 200ms;
|
||||
}
|
||||
|
||||
body:not(.Playing) {
|
||||
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;
|
||||
}
|
||||
|
||||
#songData {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
justify-content: space-between;
|
||||
margin: -0.4rem 1.6rem -0.2rem;
|
||||
overflow: hidden;
|
||||
line-height: 1.2;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#songData * {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
#songData .row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
column-gap: 0.6em;
|
||||
}
|
||||
|
||||
#songData span:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#title {
|
||||
font-size: 2.4rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#subTitle,
|
||||
#artist,
|
||||
#mapper {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
#mapper:before,
|
||||
#difficultyLabel:before {
|
||||
content: "‹";
|
||||
}
|
||||
|
||||
#mapper:after,
|
||||
#difficultyLabel:after {
|
||||
content: "›";
|
||||
}
|
||||
|
||||
#difficultyLabel,
|
||||
#subTitle {
|
||||
flex-shrink: 99999;
|
||||
}
|
||||
|
||||
#characteristicIcon {
|
||||
width: 1.1em;
|
||||
height: 1.1em;
|
||||
flex-shrink: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
#type,
|
||||
#bsrKey {
|
||||
font-size: 1.6rem;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#bsrKey {
|
||||
letter-spacing: 0.2rem;
|
||||
}
|
||||
|
||||
#bsrKey:before {
|
||||
content: "!bsr ";
|
||||
letter-spacing: normal;
|
||||
}
|
||||
20
types.d.ts
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
interface Document {
|
||||
getElementById(elementId: string): HTMLElement;
|
||||
}
|
||||
|
||||
interface MapInfoChanged {
|
||||
"level_id": string;
|
||||
"name": string;
|
||||
"sub_name": string;
|
||||
"artist": string;
|
||||
"mapper": string;
|
||||
"characteristic": string;
|
||||
"difficulty": string;
|
||||
"duration": number;
|
||||
"BPM": number;
|
||||
"PP": number;
|
||||
"BSRKey": string;
|
||||
"coverRaw": string;
|
||||
"time": number;
|
||||
"timeMultiplier": number;
|
||||
}
|
||||