Files
ClimbingBoardGPT/webapp/static/index.html
2026-05-22 13:57:56 -04:00

176 lines
6.9 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ClimbingBoardGPT</title>
<link rel="stylesheet" href="/static/app.css?v=16" />
</head>
<body>
<header class="site-header">
<div>
<p class="eyebrow">ClimbingBoardGPT</p>
<h1>Board-climbing route generation and grade prediction</h1>
<p>Transformer demo for Tension Board 2 12x12 and Kilter Board Original 16x12 routes.</p>
</div>
<div id="health" class="health">Loading…</div>
</header>
<main class="layout">
<section class="controls">
<div class="card">
<h2>Generate a climb</h2>
<label>Board
<select id="gen-board">
<option value="tb2">Tension Board 2 (12x12)</option>
<option value="kilter">Kilter Board Original (16x12)</option>
</select>
</label>
<label>Angle
<select id="gen-angle"></select>
</label>
<label>Target V-grade
<select id="gen-grade"></select>
</label>
<label>Temperature
<input id="gen-temperature" type="number" value="0.9" min="0.1" max="2.0" step="0.1" />
<span class="field-help">Lower = safer/common; higher = more creative/weird. Use temperature ≤ 2.</span>
</label>
<button id="generate-btn">Generate</button>
</div>
<div class="card">
<h2>Predict grade</h2>
<label>Board
<select id="pred-board">
<option value="tb2">Tension Board 2 (12x12)</option>
<option value="kilter">Kilter Board Original (16x12)</option>
</select>
</label>
<label>Angle
<select id="pred-angle"></select>
</label>
<label>Frames string
<textarea id="pred-frames" rows="5" placeholder="Click holds below, or paste p652r5p631r6p322r6p326r7"></textarea>
</label>
<button id="predict-btn" disabled>Predict pasted / clicked climb</button>
</div>
<div class="card">
<h2>Click holds to build a climb</h2>
<label>Role for next clicked hold
<select id="click-role">
<option value="start">start</option>
<option value="middle" selected>middle</option>
<option value="finish">finish</option>
<option value="foot">foot</option>
</select>
</label>
<div class="button-row">
<button id="undo-hold-btn" class="secondary">Undo</button>
<button id="clear-holds-btn" class="secondary">Clear board</button>
</div>
<p class="small">
Click a hold on the board image. The app appends the corresponding
BoardLib frame token using the selected semantic role.
</p>
<ul id="builder-list" class="builder-list"></ul>
</div>
<div class="card explain" id="explain-card">
<h2>What the controls mean</h2>
<dl>
<dt>Temperature</dt>
<dd>Sampling randomness. Lower values are more conservative; higher values are more exploratory.</dd>
<dt>Target V-grade</dt>
<dd>The grade token given to the generator. The generated route is also checked by the grade predictor.</dd>
<dt>Known climb</dt>
<dd>An exact match against the tokenized dataset: same board, same angle, and same hold-role set.</dd>
<dt>Validity</dt>
<dd>A structural check: enough holds, no duplicate placements, at least one start, and at least one finish.</dd>
</dl>
</div>
<div class="card explain">
<h2>How this works</h2>
<p>
Routes are converted into tokens such as
<code>&lt;BOARD_TB2&gt;</code>, <code>&lt;ANGLE_40&gt;</code>,
and <code>&lt;TB2_p652_start&gt;</code>.
</p>
<p>
The generator samples a token sequence. The grade predictor removes the grade token and estimates difficulty from the board, angle, and hold-role tokens.
</p>
</div>
<div class="card note">
<h2>Links</h2>
<ul class="link-list">
<li><a href="https://github.com/psark007/ClimbingBoardGPT" target="_blank" rel="noreferrer">ClimbingBoardGPT repo</a></li>
<li><a href="https://github.com/psark007/Tension-Board-2-Analysis" target="_blank" rel="noreferrer">Tension Board 2 Analysis repo</a></li>
<li><a href="https://github.com/psark007/Kilter-Board-Analysis" target="_blank" rel="noreferrer">Kilter Board Analysis repo</a></li>
<li><a href="https://pawelsarkowicz.xyz" target="_blank" rel="noreferrer">pawelsarkowicz.xyz</a></li>
</ul>
</div>
<div class="card note" id="data-acknowledgement-card">
<h2>Data acknowledgement</h2>
<p>
Tension Board 2 route data is from Tension Climbing. Kilter Board route data is from Kilter.
</p>
</div>
<div class="card note" id="angle-scope-card">
<h2>Angle scope</h2>
<p>
The physical boards can be used at steeper angles than this demo exposes. This model snapshot is intentionally restricted to the angle range used in training/evaluation: TB2 up to 50° and Kilter up to 55°.
</p>
<p>
The restriction avoids asking the models to extrapolate into sparse, noisier high-angle data where grades and route distributions are less reliable.
</p>
</div>
<div class="card note" id="edge-grade-caveat-card">
<h2>High-grade caveat</h2>
<p>
Generation and prediction are both less reliable at edge-case grades, especially around V10 and above. Those grades are rarer in the data, so the generator has weaker grade control and the predictor has less signal for accurate scoring.
</p>
</div>
<div class="card note">
<h2>To-do</h2>
<p>
This demo currently focuses on the full-board layouts: Tension Board 2 Mirror 12x12 and Kilter Board Original 16x12. Other board sizes are future work.
</p>
</div>
</section>
<section class="viewer">
<div class="result-card">
<div class="result-header">
<h2 id="result-title">Choose a board and run a request</h2>
<p id="result-subtitle">The climb overlay will appear below. You can also click holds to build a route for prediction.</p>
<div id="warning-box" class="warning-box" hidden></div>
<button id="clear-board-btn" class="secondary clear-board">Clear board</button>
</div>
<div id="board-stage" class="board-stage">
<img id="board-bg" alt="Board background" />
<svg id="overlay" xmlns="http://www.w3.org/2000/svg"></svg>
</div>
<details class="json-block">
<summary>Raw result JSON</summary>
<pre id="raw-json">{}</pre>
</details>
</div>
</section>
</main>
<script src="/static/app.js?v=16"></script>
</body>
</html>