atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
d1cbd183925db8a39c0632ba9c4cda7718c95e71
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/ui.html

99524cf9f17catagen2026-10-10 10:53 UTC1
<!DOCTYPE html>
99524cf9f17catagen2026-10-10 10:53 UTC2
<html>
99524cf9f17catagen2026-10-10 10:53 UTC3
<head>
99524cf9f17catagen2026-10-10 10:53 UTC4
<meta charset="utf-8">
99524cf9f17catagen2026-10-10 10:53 UTC5
<title>jelqd</title>
99524cf9f17catagen2026-10-10 10:53 UTC6
</head>
99524cf9f17catagen2026-10-10 10:53 UTC7
<body>
99524cf9f17catagen2026-10-10 10:53 UTC8
99524cf9f17catagen2026-10-10 10:53 UTC9
<h1 id="status">jelqd</h1>
99524cf9f17catagen2026-10-10 10:53 UTC10
<p id="detail">A roguelike played over HTTP. Press POST /runs to begin.</p>
99524cf9f17catagen2026-10-10 10:53 UTC11
<ul id="links"></ul>
99524cf9f17catagen2026-10-10 10:53 UTC12
<ul id="headers"></ul>
99524cf9f17catagen2026-10-10 10:53 UTC13
<pre id="body"></pre>
99524cf9f17catagen2026-10-10 10:53 UTC14
99524cf9f17catagen2026-10-10 10:53 UTC15
<hr>
99524cf9f17catagen2026-10-10 10:53 UTC16
99524cf9f17catagen2026-10-10 10:53 UTC17
<h2>Run</h2>
99524cf9f17catagen2026-10-10 10:53 UTC18
<p>
99524cf9f17catagen2026-10-10 10:53 UTC19
Run <input id="run" size="20" placeholder="/runs/...">
99524cf9f17catagen2026-10-10 10:53 UTC20
seed <input id="seed" size="12" placeholder="(unranked)">
99524cf9f17catagen2026-10-10 10:53 UTC21
<button onclick="start()">POST /runs</button>
99524cf9f17catagen2026-10-10 10:53 UTC22
</p>
99524cf9f17catagen2026-10-10 10:53 UTC23
99524cf9f17catagen2026-10-10 10:53 UTC24
<h2>JELQ</h2>
99524cf9f17catagen2026-10-10 10:53 UTC25
<p>
99524cf9f17catagen2026-10-10 10:53 UTC26
technique
99524cf9f17catagen2026-10-10 10:53 UTC27
<select id="technique">
99524cf9f17catagen2026-10-10 10:53 UTC28
<option>warmup</option>
99524cf9f17catagen2026-10-10 10:53 UTC29
<option>wet</option>
99524cf9f17catagen2026-10-10 10:53 UTC30
<option>dry</option>
99524cf9f17catagen2026-10-10 10:53 UTC31
<option>stretch</option>
99524cf9f17catagen2026-10-10 10:53 UTC32
<option>uli</option>
99524cf9f17catagen2026-10-10 10:53 UTC33
<option>edge</option>
99524cf9f17catagen2026-10-10 10:53 UTC34
<option>pump</option>
99524cf9f17catagen2026-10-10 10:53 UTC35
<option>ice</option>
99524cf9f17catagen2026-10-10 10:53 UTC36
<option>supplement</option>
99524cf9f17catagen2026-10-10 10:53 UTC37
</select>
99524cf9f17catagen2026-10-10 10:53 UTC38
or combo <input id="combo" size="14" placeholder="wet,stretch">
99524cf9f17catagen2026-10-10 10:53 UTC39
intensity <input id="intensity" type="number" min="1" max="10" value="5" size="3">
99524cf9f17catagen2026-10-10 10:53 UTC40
Content-Type
99524cf9f17catagen2026-10-10 10:53 UTC41
<select id="lube">
99524cf9f17catagen2026-10-10 10:53 UTC42
<option value="">(none)</option>
99524cf9f17catagen2026-10-10 10:53 UTC43
<option>application/baby-oil</option>
99524cf9f17catagen2026-10-10 10:53 UTC44
<option>application/coconut-oil</option>
99524cf9f17catagen2026-10-10 10:53 UTC45
<option>application/lotion</option>
99524cf9f17catagen2026-10-10 10:53 UTC46
<option>application/vaseline</option>
99524cf9f17catagen2026-10-10 10:53 UTC47
<option>text/plain; charset=spit</option>
99524cf9f17catagen2026-10-10 10:53 UTC48
<option>image/jpeg</option>
99524cf9f17catagen2026-10-10 10:53 UTC49
</select>
99524cf9f17catagen2026-10-10 10:53 UTC50
<button onclick="jelq()">JELQ</button>
99524cf9f17catagen2026-10-10 10:53 UTC51
</p>
99524cf9f17catagen2026-10-10 10:53 UTC52
99524cf9f17catagen2026-10-10 10:53 UTC53
<h2>Methods</h2>
99524cf9f17catagen2026-10-10 10:53 UTC54
<ul>
99524cf9f17catagen2026-10-10 10:53 UTC55
<li>the run: <button onclick="go('GET', '')">GET</button> <button onclick="go('HEAD', '')">HEAD</button> <button onclick="go('PUT', '')">PUT</button> <button onclick="go('OPTIONS', '')">OPTIONS</button> <button onclick="go('TRACE', '')">TRACE</button> <button onclick="go('DELETE', '')">DELETE</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC56
<li>/floor: <button onclick="go('GET', '/floor')">GET</button> <button onclick="go('POST', '/floor')">POST</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC57
<li>/drawer: <button onclick="go('POST', '/drawer')">POST</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC58
<li>/inventory: <button onclick="go('GET', '/inventory')">GET</button> item <input id="item" size="16"> <button onclick="go('GET', '/inventory/' + val('item'))">GET</button> <button onclick="go('DELETE', '/inventory/' + val('item'))">DELETE</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC59
<li>/techniques: <button onclick="go('GET', '/techniques')">GET</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC60
<li>/length: <button onclick="go('GET', '/length')">GET</button> <button onclick="go('HEAD', '/length')">HEAD</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC61
<li>/foreskin: <button onclick="go('GET', '/foreskin')">GET</button> <button onclick="go('DELETE', '/foreskin')">DELETE</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC62
<li>/branches: <button onclick="go('POST', '/branches/forum')">POST forum</button> <button onclick="go('POST', '/branches/close-tab')">POST close-tab</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC63
<li>/shop: <button onclick="go('GET', '/shop')">GET</button> item <input id="buy" size="16"> <button onclick="go('POST', '/shop/' + val('buy'))">POST</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC64
<li>/portal: <button onclick="go('GET', '/portal')">GET</button> <button onclick="go('POST', '/portal')">POST</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC65
<li>/elder: <button onclick="go('GET', '/elder')">GET</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC66
<li>/grip: <button onclick="go('GET', '/grip')">GET</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC67
<li>/diagnosis: <button onclick="go('GET', '/diagnosis')">GET</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC68
<li>PATCH the run, as application/json-patch+json:<br>
99524cf9f17catagen2026-10-10 10:53 UTC69
<textarea id="patch" rows="2" cols="60">[{"op": "test", "path": "/length", "value": 6}]</textarea>
99524cf9f17catagen2026-10-10 10:53 UTC70
<button onclick="go('PATCH', '', [['Content-Type', 'application/json-patch+json']], val('patch'))">PATCH</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC71
<li>anything: method <input id="method" size="8" value="GET"> path <input id="path" size="30" value="/leaderboard"> <button onclick="send(val('method'), val('path'))">Send</button></li>
99524cf9f17catagen2026-10-10 10:53 UTC72
</ul>
99524cf9f17catagen2026-10-10 10:53 UTC73
99524cf9f17catagen2026-10-10 10:53 UTC74
<h2>Headers</h2>
99524cf9f17catagen2026-10-10 10:53 UTC75
<p>Sent with every request when filled in.</p>
99524cf9f17catagen2026-10-10 10:53 UTC76
<ul>
99524cf9f17catagen2026-10-10 10:53 UTC77
<li>Authorization <input id="authorization" size="50" placeholder='Excuse "homework"'></li>
99524cf9f17catagen2026-10-10 10:53 UTC78
<li>Proxy-Authorization <input id="proxy-authorization" size="30" placeholder="Ruler 5.4"></li>
99524cf9f17catagen2026-10-10 10:53 UTC79
<li>If-Match <input id="if-match" size="24"></li>
99524cf9f17catagen2026-10-10 10:53 UTC80
<li>If-None-Match <input id="if-none-match" size="24"></li>
99524cf9f17catagen2026-10-10 10:53 UTC81
<li>If-Modified-Since <input id="if-modified-since" size="32"></li>
99524cf9f17catagen2026-10-10 10:53 UTC82
<li>Range <input id="range" size="16" placeholder="inches=0-2"></li>
99524cf9f17catagen2026-10-10 10:53 UTC83
<li>Accept <input id="accept" size="30"></li>
99524cf9f17catagen2026-10-10 10:53 UTC84
<li>Accept-Encoding <input id="accept-encoding" size="10"></li>
99524cf9f17catagen2026-10-10 10:53 UTC85
<li>Expect <input id="expect" size="16"></li>
99524cf9f17catagen2026-10-10 10:53 UTC86
<li>Upgrade <input id="upgrade" size="16" placeholder="underhand"></li>
99524cf9f17catagen2026-10-10 10:53 UTC87
</ul>
99524cf9f17catagen2026-10-10 10:53 UTC88
99524cf9f17catagen2026-10-10 10:53 UTC89
<hr>
99524cf9f17catagen2026-10-10 10:53 UTC90
<p><a href="/leaderboard">/leaderboard</a> <a href="/graveyard">/graveyard</a> <a href="/forum/threads/2009">/forum/threads/2009</a></p>
99524cf9f17catagen2026-10-10 10:53 UTC91
99524cf9f17catagen2026-10-10 10:53 UTC92
<script>
99524cf9f17catagen2026-10-10 10:53 UTC93
const HEADERS = ["Authorization", "Proxy-Authorization", "If-Match", "If-None-Match", "If-Modified-Since", "Range", "Accept", "Accept-Encoding", "Expect", "Upgrade"];
99524cf9f17catagen2026-10-10 10:53 UTC94
99524cf9f17catagen2026-10-10 10:53 UTC95
function val(id) {
99524cf9f17catagen2026-10-10 10:53 UTC96
  return document.getElementById(id).value.trim();
99524cf9f17catagen2026-10-10 10:53 UTC97
}
99524cf9f17catagen2026-10-10 10:53 UTC98
99524cf9f17catagen2026-10-10 10:53 UTC99
function put(id, text) {
99524cf9f17catagen2026-10-10 10:53 UTC100
  document.getElementById(id).textContent = text;
99524cf9f17catagen2026-10-10 10:53 UTC101
}
99524cf9f17catagen2026-10-10 10:53 UTC102
99524cf9f17catagen2026-10-10 10:53 UTC103
function item(list, text, onclick) {
99524cf9f17catagen2026-10-10 10:53 UTC104
  const li = document.createElement("li");
99524cf9f17catagen2026-10-10 10:53 UTC105
  if (onclick) {
99524cf9f17catagen2026-10-10 10:53 UTC106
    const button = document.createElement("button");
99524cf9f17catagen2026-10-10 10:53 UTC107
    button.textContent = text;
99524cf9f17catagen2026-10-10 10:53 UTC108
    button.onclick = onclick;
99524cf9f17catagen2026-10-10 10:53 UTC109
    li.appendChild(button);
99524cf9f17catagen2026-10-10 10:53 UTC110
  } else {
99524cf9f17catagen2026-10-10 10:53 UTC111
    li.textContent = text;
99524cf9f17catagen2026-10-10 10:53 UTC112
  }
99524cf9f17catagen2026-10-10 10:53 UTC113
  document.getElementById(list).appendChild(li);
99524cf9f17catagen2026-10-10 10:53 UTC114
}
99524cf9f17catagen2026-10-10 10:53 UTC115
99524cf9f17catagen2026-10-10 10:53 UTC116
function hrefs(value, found) {
99524cf9f17catagen2026-10-10 10:53 UTC117
  if (value && typeof value === "object") {
99524cf9f17catagen2026-10-10 10:53 UTC118
    if (typeof value.href === "string") found.push([value.method || "GET", value.href]);
99524cf9f17catagen2026-10-10 10:53 UTC119
    for (const key in value) hrefs(value[key], found);
99524cf9f17catagen2026-10-10 10:53 UTC120
  }
99524cf9f17catagen2026-10-10 10:53 UTC121
  return found;
99524cf9f17catagen2026-10-10 10:53 UTC122
}
99524cf9f17catagen2026-10-10 10:53 UTC123
99524cf9f17catagen2026-10-10 10:53 UTC124
async function send(method, path, extra, body) {
99524cf9f17catagen2026-10-10 10:53 UTC125
  const headers = HEADERS.map(name => [name, val(name.toLowerCase())]).filter(h => h[1]);
99524cf9f17catagen2026-10-10 10:53 UTC126
  if (val("upgrade")) headers.push(["Connection", "upgrade"]);
99524cf9f17catagen2026-10-10 10:53 UTC127
  const response = await fetch("/ui/send", {
99524cf9f17catagen2026-10-10 10:53 UTC128
    method: "POST",
99524cf9f17catagen2026-10-10 10:53 UTC129
    headers: {"Content-Type": "application/json"},
99524cf9f17catagen2026-10-10 10:53 UTC130
    body: JSON.stringify({method, path, headers: headers.concat(extra || []), body: body || ""}),
99524cf9f17catagen2026-10-10 10:53 UTC131
  });
99524cf9f17catagen2026-10-10 10:53 UTC132
  show(await response.json(), path);
99524cf9f17catagen2026-10-10 10:53 UTC133
}
99524cf9f17catagen2026-10-10 10:53 UTC134
99524cf9f17catagen2026-10-10 10:53 UTC135
function show(r, path) {
99524cf9f17catagen2026-10-10 10:53 UTC136
  put("status", r.status + " " + (r.reason || ""));
99524cf9f17catagen2026-10-10 10:53 UTC137
  let parsed = null;
99524cf9f17catagen2026-10-10 10:53 UTC138
  try { parsed = JSON.parse(r.body); } catch (e) {}
99524cf9f17catagen2026-10-10 10:53 UTC139
  put("detail", parsed && parsed.detail ? parsed.detail : "");
99524cf9f17catagen2026-10-10 10:53 UTC140
  put("body", r.body);
99524cf9f17catagen2026-10-10 10:53 UTC141
  document.getElementById("headers").replaceChildren();
99524cf9f17catagen2026-10-10 10:53 UTC142
  document.getElementById("links").replaceChildren();
99524cf9f17catagen2026-10-10 10:53 UTC143
  for (const [name, value] of r.headers) item("headers", name + ": " + value);
99524cf9f17catagen2026-10-10 10:53 UTC144
  const location = r.headers.find(h => h[0] === "location");
99524cf9f17catagen2026-10-10 10:53 UTC145
  if (location && path === "/runs" && r.status === 201) document.getElementById("run").value = location[1];
99524cf9f17catagen2026-10-10 10:53 UTC146
  if (location) item("links", "GET " + location[1], () => send("GET", location[1]));
99524cf9f17catagen2026-10-10 10:53 UTC147
  for (const [method, href] of hrefs(parsed, [])) item("links", method + " " + href, () => send(method, href));
99524cf9f17catagen2026-10-10 10:53 UTC148
}
99524cf9f17catagen2026-10-10 10:53 UTC149
99524cf9f17catagen2026-10-10 10:53 UTC150
function go(method, sub, extra, body) {
99524cf9f17catagen2026-10-10 10:53 UTC151
  if (!val("run")) {
99524cf9f17catagen2026-10-10 10:53 UTC152
    put("status", "No run");
99524cf9f17catagen2026-10-10 10:53 UTC153
    put("detail", "Press POST /runs first.");
99524cf9f17catagen2026-10-10 10:53 UTC154
    return;
99524cf9f17catagen2026-10-10 10:53 UTC155
  }
99524cf9f17catagen2026-10-10 10:53 UTC156
  send(method, val("run") + sub, extra, body);
99524cf9f17catagen2026-10-10 10:53 UTC157
}
99524cf9f17catagen2026-10-10 10:53 UTC158
99524cf9f17catagen2026-10-10 10:53 UTC159
function start() {
99524cf9f17catagen2026-10-10 10:53 UTC160
  send("POST", val("seed") ? "/runs?seed=" + encodeURIComponent(val("seed")) : "/runs");
99524cf9f17catagen2026-10-10 10:53 UTC161
}
99524cf9f17catagen2026-10-10 10:53 UTC162
99524cf9f17catagen2026-10-10 10:53 UTC163
function jelq() {
99524cf9f17catagen2026-10-10 10:53 UTC164
  const technique = val("combo") || val("technique");
99524cf9f17catagen2026-10-10 10:53 UTC165
  const query = "?technique=" + encodeURIComponent(technique) + "&intensity=" + encodeURIComponent(val("intensity"));
99524cf9f17catagen2026-10-10 10:53 UTC166
  const lube = val("lube");
99524cf9f17catagen2026-10-10 10:53 UTC167
  go("JELQ", query, lube ? [["Content-Type", lube]] : []);
99524cf9f17catagen2026-10-10 10:53 UTC168
}
99524cf9f17catagen2026-10-10 10:53 UTC169
</script>
99524cf9f17catagen2026-10-10 10:53 UTC170
</body>
99524cf9f17catagen2026-10-10 10:53 UTC171
</html>