Files
EldenRingDeathCounter/mobile.html
s0wlz (Matthias Puchstein) 45f94b1bdf init: Elden Ring death counter with multi-client server
Deno HTTP + WebSocket server serving three pages:
- / desktop with YOU DIED overlay and keyboard controls
- /mobile touch-optimized control page
- /obs transparent browser source for OBS

Count persisted to counter.json, synced in real time across all
connected clients. Compiles to a self-contained Windows .exe via
deno compile.
2026-03-18 02:37:01 +01:00

262 lines
6.9 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<title>Elden Counter Mobile</title>
<style>
:root{
--bg0:#06060a;
--bg1:#0b0b12;
--panel: rgba(12, 12, 18, .85);
--border: rgba(212, 175, 55, .30);
--border2: rgba(212, 175, 55, .15);
--text: rgba(245, 238, 210, .92);
--muted: rgba(245, 238, 210, .62);
--gold: rgba(212, 175, 55, .95);
--shadow: 0 26px 80px rgba(0,0,0,.55);
--radius: 18px;
}
*{ box-sizing:border-box; -webkit-tap-highlight-color: transparent; }
html, body{
margin:0;
height:100%;
}
body{
min-height:100svh;
display:flex;
flex-direction:column;
align-items:center;
justify-content:center;
gap:20px;
padding:24px 16px;
color:var(--text);
font-family: ui-serif, Georgia, "Times New Roman", Times, serif;
background:
radial-gradient(1200px 650px at 50% 18%, rgba(212,175,55,.10), transparent 55%),
radial-gradient(900px 500px at 20% 70%, rgba(180,120,40,.08), transparent 60%),
linear-gradient(180deg, var(--bg1), var(--bg0));
overflow:hidden;
}
body::before{
content:"";
position:fixed;
inset:0;
pointer-events:none;
background-image: radial-gradient(rgba(255,255,255,.06) 1px, transparent 1px);
background-size: 3px 3px;
opacity:.08;
mix-blend-mode: overlay;
filter: blur(.2px);
}
h1{
margin:0;
font-size: 15px;
letter-spacing: 1.4px;
font-weight: 800;
color: rgba(245,238,210,.70);
text-transform: uppercase;
font-variant: small-caps;
position:relative;
z-index:1;
}
.bigBox{
position:relative;
z-index:1;
width:min(360px, 90vw);
border:1px solid var(--border);
border-radius: 20px;
padding: 28px 16px 22px;
display:grid;
place-items:center;
background:
radial-gradient(500px 220px at 50% 30%, rgba(212,175,55,.12), transparent 70%),
linear-gradient(180deg, rgba(255,255,255,.04), rgba(0,0,0,.12));
box-shadow: inset 0 0 0 1px rgba(0,0,0,.35), var(--shadow);
backdrop-filter: blur(10px);
}
.roman{
font-size: clamp(52px, 14vw, 80px);
font-weight: 900;
letter-spacing: 4px;
color: rgba(245,238,210,.94);
text-shadow:
0 0 16px rgba(212,175,55,.12),
0 0 34px rgba(212,175,55,.08);
text-align:center;
font-variant: small-caps;
}
.arabic{
margin-top:8px;
font-family: ui-sans-serif, system-ui, sans-serif;
font-size: 14px;
color: var(--muted);
letter-spacing:.2px;
}
.controls{
position:relative;
z-index:1;
display:flex;
flex-direction:column;
gap:14px;
width:min(360px, 90vw);
}
.row{
display:flex;
gap:14px;
}
button{
appearance:none;
flex:1;
border:1px solid var(--border);
color: var(--text);
background: linear-gradient(180deg, rgba(212,175,55,.16), rgba(0,0,0,.18));
border-radius: 16px;
font-size: 26px;
font-weight: 900;
letter-spacing:.4px;
cursor:pointer;
box-shadow: 0 10px 22px rgba(0,0,0,.35);
transition: transform .08s ease, filter .12s ease, border-color .12s ease;
font-variant: small-caps;
font-family: ui-serif, Georgia, "Times New Roman", Times, serif;
padding: 22px 10px;
/* Prevent double-tap zoom */
touch-action: manipulation;
}
button:active{
transform: scale(0.97);
filter: brightness(1.12);
border-color: rgba(212,175,55,.55);
}
.btnGhost{
border-color: rgba(245,238,210,.18);
background: linear-gradient(180deg, rgba(255,255,255,.05), rgba(0,0,0,.18));
font-size: 18px;
}
.status{
position:relative;
z-index:1;
font-family: ui-sans-serif, system-ui, sans-serif;
font-size: 12px;
color: var(--muted);
border:1px solid rgba(245,238,210,.14);
border-radius:999px;
padding:6px 14px;
background: rgba(255,255,255,.03);
transition: border-color .3s ease;
}
</style>
</head>
<body>
<h1>Deathcounter</h1>
<section class="bigBox" aria-live="polite">
<div class="roman" id="roman"></div>
<div class="arabic" id="arabic">Tode: 0</div>
</section>
<div class="controls">
<div class="row">
<button id="minus">1</button>
<button id="plus">+1</button>
</div>
<button class="btnGhost" id="reset">Reset</button>
</div>
<span class="status" id="status">Verbinde…</span>
<script>
function toRoman(n) {
const map = [
{ val: 1000, sym: "M" },
{ val: 900, sym: "CM" },
{ val: 500, sym: "D" },
{ val: 400, sym: "CD" },
{ val: 100, sym: "C" },
{ val: 90, sym: "XC" },
{ val: 50, sym: "L" },
{ val: 40, sym: "XL" },
{ val: 10, sym: "X" },
{ val: 9, sym: "IX" },
{ val: 5, sym: "V" },
{ val: 4, sym: "IV" },
{ val: 1, sym: "I" }
];
let res = "";
for (const { val, sym } of map) {
while (n >= val) { res += sym; n -= val; }
}
return res;
}
const romanEl = document.getElementById("roman");
const arabicEl = document.getElementById("arabic");
const statusEl = document.getElementById("status");
let currentCount = 0;
function clamp(n, min, max){ return Math.max(min, Math.min(max, n)); }
function render(count) {
currentCount = clamp(count, 0, 3999);
romanEl.textContent = currentCount === 0 ? "—" : toRoman(currentCount);
arabicEl.textContent = `Tode: ${currentCount}`;
}
let ws;
function connect() {
ws = new WebSocket(`ws://${location.host}/ws`);
ws.onopen = () => {
statusEl.textContent = "Verbunden ✓";
statusEl.style.borderColor = "rgba(212,175,55,.35)";
setTimeout(() => (statusEl.style.borderColor = "rgba(245,238,210,.14)"), 1500);
};
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (typeof msg.count === "number") render(msg.count);
};
ws.onclose = () => {
statusEl.textContent = "Getrennt — verbinde neu…";
statusEl.style.borderColor = "rgba(170,30,25,.5)";
setTimeout(connect, 2000);
};
ws.onerror = () => ws.close();
}
function send(action) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ action }));
}
}
document.getElementById("plus").addEventListener("click", () => send("increment"));
document.getElementById("minus").addEventListener("click", () => send("decrement"));
document.getElementById("reset").addEventListener("click", () => send("reset"));
connect();
</script>
</body>
</html>