TableturfBattleApp/TableturfBattleClient/index.html
Andrio Celos 38fc94f4e4 Replace the loading spinner with the Splatoon one
The asset isn't included in this repository for copyright reasons, but will be available on the live site
2023-08-12 18:09:13 +10:00

568 lines
25 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<base href="https://tableturf.andriocelos.net/tableturf/"/>
<script>
baseUrl = window.location.toString().replace(/\/(?:index.html|deckeditor|game\/[^/]*|replay\/[^/]*)$/, '/');
document.getElementsByTagName('base')[0].href = baseUrl;
</script>
<title>Tableturf Battle</title>
<link rel="apple-touch-icon" sizes="180x180" href="assets/external/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="assets/external/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/external/favicon-16x16.png">
<link rel="manifest" href="assets/site.webmanifest">
<link rel="stylesheet" href="tableturf.css"/>
<script src="config/config.js"></script>
<script src="qrcodejs/qrcode.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:type" content="website"/>
<meta name="title" property="og:title" content="Tableturf Battle"/>
<meta name="description" property="og:description" content="(Beta) An unofficial simulator for Tableturf Battle from Splatoon 3. Play online with friends using any in-game cards!"/>
<meta property="og:url" content="https://tableturf.andriocelos.net/"/>
<meta name="theme-color" content="#0c92f2" data-react-helmet="true"/>
</head>
<body>
<div id="noJSPage">This application requires JavaScript.</div>
<div id="preGamePage" hidden>
<div id="logoBanner"><img title="Tableturf Battle" alt="Tableturf Battle logo" id="logo" src="assets/external/logo.png"></div>
<h1>Tableturf Battle</h1>
<form id="preGameForm">
<p><label for="nameBox">Choose a nickname: <input type="text" id="nameBox" required minlength="1" maxlength="20"/></label></p>
<div id="preGameDefaultSection">
<button type="submit" id="preGameImplicitSubmitButton" tabindex="-1"></button>
<p>
<button type="submit" id="newGameButton">Create a room</button>
<button type="button" id="newGameSetupButton">More options</button>
</p>
<p>
<label for="gameIDBox">Enter a game link or ID to join a game:<br/>
<input type="text" id="gameIDBox" placeholder="Game link or ID"/></label>
<button type="submit" id="joinGameButton">Join game</button>
<button type="submit" id="spectateGameButton">Spectate</button>
</p>
</div>
<div id="preGameJoinSection" hidden>
<p>
<button type="submit" id="joinGameButton2">Join game</button>
<button type="submit" id="spectateGameButton2">Spectate</button>
</p>
<a id="preGameBackButton" href="../..">Create or join a different room</a>
</div>
<p>
<a id="preGameDeckEditorButton" href="deckeditor">Edit decks</a> |
<a id="preGameReplayButton" href="replay">Replay</a> |
<a id="preGameHelpButton" href="help">Help</a>
</p>
<div id="preGameLoadingSection" class="loadingContainer" hidden>
<div class="loadingSpinner"><div></div><div></div></div> <span id="preGameLoadingLabel"></span>
</div>
</form>
<footer>
<p>This website is not affiliated with Nintendo. All product names, logos, and brands are property of their respective owners.</p>
<p><a href="https://github.com/AndrioCelos/TableturfBattleApp">GitHub</a><span id="discordSection"> | <a id="discordLink">Discord</a></span></p>
</footer>
</div>
<div id="lobbyPage" hidden>
<section id="lobbyPlayerListSection">
<p>Other players can join using a link to this page.<br/>
<button type="button" id="shareLinkButton">Share link</button><button type="button" id="showQrCodeButton">Show QR code</button></p>
<ul id="playerList"></ul>
<label for="lobbyTimeLimitBox">Turn time limit: <input type="text" id="lobbyTimeLimitBox" placeholder="None" readonly/><span id="lobbyTimeLimitUnit"> seconds</span></label>
<div id="lobbySelectedStageSection" hidden>
<h3>Stage</h3>
</div>
</section>
<section id="lobbyStageSection" hidden>
<h3>Vote for the stage.</h3>
<form id="stageSelectionForm">
<div class="submitButtonContainer">
<button type="submit" id="submitStageButton">Submit</button>
<div class="loadingContainer">
<div class="loadingSpinner"><div></div><div></div></div>
</div>
</div>
<div id="stageList">
<button type="button" id="stageRandomButton" class="stageRandom">Random</button>
</div>
<div id="stageListLoadingSection"><div class="loadingSpinner"><div></div><div></div></div> Loading stages...</div>
</form>
</section>
<div id="lobbyDeckSection" hidden>
<h3>Choose your deck.</h3>
<form id="deckSelectionForm">
<div class="submitButtonContainer">
<button type="submit" id="submitDeckButton" disabled>Submit</button>
<div class="loadingContainer">
<div class="loadingSpinner"><div></div><div></div></div>
</div>
</div>
<div id="lobbyDeckList" class="deckList"></div>
</form>
</div>
<dialog id="qrCodeDialog">
<form method="dialog">
<p>Scan this QR code to join the game.</p>
<div id="qrCode"></div>
<button type="submit">Close</button>
</form>
</dialog>
</div>
<div id="gamePage" hidden>
<div class="playerBar" data-index="1">
<div class="result"></div>
<div class="name">Player 2</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div class="playerBar" data-index="3">
<div class="result"></div>
<div class="name">Player 4</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div id="gameControls">
<div id="debugColour" style="display: none">
<table>
<tr>
<th>Colour</th>
<th>H</th>
<th>S</th>
<th>L</th>
<th>RGB</th>
</tr>
<tr>
<td>1i</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colH0I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colS0I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="0" id="colL0I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="0" id="colRGB0I" value="#ecf901"/></td>
</tr>
<tr>
<td>1s</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colH0S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colS0S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="1" id="colL0S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="1" id="colRGB0S" value="#fa9e00"/></td>
</tr>
<tr>
<td>1a</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colH0A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colS0A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="0" data-index="2" id="colL0A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="0" data-index="2" id="colRGB0A" value="#f9f91f"/></td>
</tr>
<tr>
<td>2i</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colH1I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colS1I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="0" id="colL1I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="0" id="colRGB1I" value="#4a5cfc"/></td>
</tr>
<tr>
<td>2s</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colH1S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colS1S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="1" id="colL1S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="1" id="colRGB1S" value="#01edfe"/></td>
</tr>
<tr>
<td>2a</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colH1A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colS1A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="1" data-index="2" id="colL1A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="1" data-index="2" id="colRGB1A" value="#d5e1e1"/></td>
</tr>
<tr>
<td>3i</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colH2I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colS2I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="0" id="colL2I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="0" id="colRGB2I" value="#f906e0"/></td>
</tr>
<tr>
<td>3s</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colH2S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colS2S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="1" id="colL2S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="1" id="colRGB2S" value="#8006f9"/></td>
</tr>
<tr>
<td>3a</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colH2A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colS2A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="2" data-index="2" id="colL2A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="2" data-index="2" id="colRGB2A" value="#ebb4fd"/></td>
</tr>
<tr>
<td>4i</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colH3I" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colS3I" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="0" id="colL3I" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="0" id="colRGB3I" value="#06f994"/></td>
</tr>
<tr>
<td>4s</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colH3S" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colS3S" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="1" id="colL3S" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="1" id="colRGB3S" value="#06f906"/></td>
</tr>
<tr>
<td>4a</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colH3A" min="0" max="359"/></td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colS3A" min="0" max="100"/>%</td>
<td><input type="number" autocomplete="off" data-player="3" data-index="2" id="colL3A" min="0" max="100"/>%</td>
<td><input type="text" autocomplete="off" data-player="3" data-index="2" id="colRGB3A" value="#b4fdc7"/></td>
</tr>
</table>
</div>
<div id="cardHint" hidden></div>
<div id="handContainer"></div>
<div id="playRow">
<button type="button" id="passButton">Pass</button>
<button type="button" id="specialButton">Special Attack</button>
</div>
<div id="spectatorRow">
<a id="leaveButton" href="#">Exit</a>
<button id="replayPreviousButton">Previous turn</button>
<button id="replayNextButton">Next turn</button>
<button id="shareReplayLinkButton">Copy replay link</button>
<button id="flipButton">Change view</button>
</div>
</div>
<div class="playerBar" data-index="2">
<div class="result"></div>
<div class="name">Player 3</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div class="playerBar" data-index="0">
<div class="result"></div>
<div class="name">Player 1</div>
<div class="specialPoints">&nbsp;</div>
<div class="playerStats">
<div class="statSpecialPoints">
<div class="statLabel">Special points</div>
<div class="statValue">0</div>
</div>
<div class="statPasses">
<div class="statLabel">Turns passed</div>
<div class="statValue">0</div>
</div>
</div>
</div>
<div id="showDeckContainer" hidden>
<div id="showDeck">
<ul id="showDeckList"></ul>
<div>
<button type="button" id="showDeckCloseButton">Close</button>
</div>
</div>
</div>
<div id="testControls">
<div id="testControlsHeader" class="testControls">
<button type="button" id="testDeckButton">Deck</button>
<button type="button" id="testAllCardsButton">All cards</button>
</div>
<div id="testDeckContainer" class="testControls">
<button id="testAllCardsMobileButton">All cards</button>
<div id="testDeckList"></div>
</div>
<div id="testAllCardsContainer" class="testControls" hidden>
<div id="testAllCardsHeader">
<label for="testAllCardsListSortBox">
Sort by
<select id="testAllCardsListSortBox" autocomplete="off"></select>
</label>
<input type="text" id="testAllCardsListFilterBox" placeholder="Filter"/>
</div>
<div id="testAllCardsList" class="cardListGrid"></div>
</div>
<div id="testControlsFooter" class="testControls">
<button type="button" id="testUndoButton">Undo</button>
<button type="button" id="testBackButton">End test</button>
</div>
</div>
<div id="testCardListBackdrop" hidden></div>
<div id="timeSection">
<div id="turnNumberContainer" hidden>
<p>Turns left</p>
<div id="turnNumberLabel">12</div>
</div>
<div id="timeContainer">
<div id="timeContainerContent">
<svg viewBox="0 0 100 100">
<path fill-rule="evenodd" d="M 50,0 a 50 50 360 1 1 0,100 a 50 50 360 1 1 0,-100 z M 40,10 h 20 v 30 h 30 v 20 h -50 z"/>
</svg>
<div id="timeLabel">69</div>
</div>
</div>
</div>
<div id="scoreSection">
<div class="pointsContainer" data-index="1"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="3"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="2"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
<div class="pointsContainer" data-index="0"><span class="points">69</span><span class="pointsToContainer">&rarrhk; <span class="pointsTo">60</span></span><span class="pointsDelta">+1</span></div>
</div>
<div id="boardSection">
<table id="gameBoard" tabindex="0"></table>
<div id="redrawModal" hidden>
<div id="redrawBox">
<p>Redraw your starting hand?</p>
<p><button type="button" id="redrawNoButton" data-redraw="false">Hold steady</button></p>
<p><button type="button" id="redrawYesButton" data-redraw="true">Redraw</button></p>
</div>
</div>
</div>
<div id="gameButtonsContainer">
<button id="rotateLeftButton" title="Rotate card anticlockwise (Shift+R)">&cularr;</button>
<button id="rotateRightButton" title="Rotate card clockwise (R)">&curarr;</button>
<button id="gameDeckButton" title="Show deck (D)">&#x1F0A0;</button>
</div>
<div class="playContainer" data-index="1"></div>
<div class="playContainer" data-index="3"></div>
<div class="playContainer" data-index="2"></div>
<div class="playContainer" data-index="0"></div>
<div id="playHint" hidden></div>
<div id="testPlacementList"></div>
</div>
<div id="deckListPage" hidden>
<section id="deckEditordeckListPage">
<a id="deckListBackButton" href=".">Back</a>
<h3>Deck list</h3>
<button id="deckExportAllButton">Export all</button>
<div id="deckList" class="deckList">
<div id="addDeckControls">
<button id="newDeckButton">New deck</button>
<button id="importDeckButton">Import deck</button>
</div>
</div>
</section>
<section id="deckEditorDeckViewSection" hidden>
<a id="deckViewBackButton" href="#">Back</a>
<h3 id="deckName">Deck</h3>
<div>
<button type="button" id="deckEditButton">Edit</button>
<button type="button" id="deckListTestButton">Test</button>
<button type="button" id="deckExportButton">Export</button>
<button type="button" id="deckRenameButton">Rename</button>
<button type="button" id="deckCopyButton">Copy</button>
<button type="button" id="deckDeleteButton" class="danger">Delete</button>
</div>
<div class="deckSizeContainer">Total: <div id="deckViewSize">0</div></div>
<div id="deckCardListView">
</div>
</section>
<dialog id="deckImportDialog">
<form id="deckImportForm" method="dialog">
<label for="deckImportTextButton">
<input type="radio" id="deckImportTextButton" name="deckImportMethod"/>
Import from a Tableturf Battle simulator
</label>
<section id="deckImportTextSection">
<textarea id="deckImportTextBox" rows="4" cols="45" autocomplete="off" placeholder="Paste the export string here."></textarea>
<button type="submit" id="deckImportOkButton">OK</button>
</section>
<label for="deckImportScreenshotButton">
<input type="radio" id="deckImportScreenshotButton" name="deckImportMethod"/>
Import from screenshots
</label>
<section id="deckImportScreenshotSection">
<input type="file" id="deckImportFileBox" accept="image/png,image/jpeg,image/webp,image/bmp" multiple autocomplete="off"/>
<div>
<button type="button" id="deckImportScreenshotInstructionsButton">Show instructions</button>
<div id="deckImportScreenshotInstructions" hidden>
<ol>
<li>In <em>Splatoon 3</em>, open the main menu with X, select the Status tab, the Tableturf Battle section, then Card List.</li>
<li>Enter the Edit Deck menu with Y.</li>
<li>Move the cursor to the deck you want to import.</li>
<li>Take a screenshot using the capture button on your controller.<br/>If you have an external capture device, you can alternatively take a screenshot that way.</li>
<li>Repeat steps 3 and 4 for each deck you want to import.</li>
</ol>
<label for="deckImportScreenshotInstructionsButtonPC">
<input type="radio" id="deckImportScreenshotInstructionsButtonPC" name="deckImportScreenshotMethod"/>
Download screenshots using a PC
</label>
<label for="deckImportScreenshotInstructionsButtonMobile">
<input type="radio" id="deckImportScreenshotInstructionsButtonMobile" name="deckImportScreenshotMethod"/>
Download screenshots using a mobile device
</label>
<ol id="deckImportScreenshotInstructionsPC" start="6" hidden>
<li>Go to System Settings, then select Data Management, then Manage Screenshots and Videos, then Copy to PC via USB Connection.</li>
<li>Connect a USB cable to your PC and the USB-C port on the bottom of your Nintendo Switch.</li>
<li>The Nintendo Switch Album is now accessible in This PC or Devices in your file manager. Click Browse below and select the screenshots you created.</li>
</ol>
<ol id="deckImportScreenshotInstructionsMobile" start="6" hidden>
<li>In the Album, select one of the screenshots you created.</li>
<li>Enter the Editing and Posting menu with A, then select Send to Smart Device.</li>
<li>Follow the prompts to download the screenshots on your mobile device.<br/>On Android devices, it may be necessary to turn off mobile data.</li>
</ol>
</div>
</div>
</section>
<div id="deckImportErrorBox" class="error" hidden></div>
<button type="submit" id="deckImportCancelButton">Cancel</button>
</form>
</dialog>
<dialog id="deckExportDialog">
<form method="dialog">
<textarea id="deckExportTextBox" readonly rows="24" cols="45"></textarea>
<div>
<button type="button" id="deckExportCopyButton">Copy</button>
<button type="submit">Close</button>
</div>
</form>
</dialog>
</div>
<div id="deckEditPage" hidden>
<section id="deckEditordeckEditPage">
<h3 id="deckName2">Deck</h3>
<div>
<button type="button" id="deckTestButton">Test</button>
<button type="button" id="deckSaveButton">Save</button>
<button type="button" id="deckCancelButton">Cancel</button>
</div>
<div class="deckSizeContainer">Total: <div id="deckEditSize">0</div></div>
<div id="deckCardListEdit">
</div>
</section>
<section id="deckEditorCardListSection">
<div id="cardListHeader">
<a id="deckCardListBackButton" href="#">Back</a>
<h3>All cards</h3>
<label for="cardListSortBox">
Sort by
<select id="cardListSortBox" autocomplete="off"></select>
</label>
<input type="text" id="cardListFilterBox" placeholder="Filter"/>
</div>
<div id="cardList" class="cardListGrid"></div>
</section>
<div id="deckEditorCardListBackdrop"></div>
</div>
<dialog id="testStageSelectionDialog">
<h3>Select a stage.</h3>
<form id="testStageSelectionForm" method="dialog">
<div id="testStageSelectionList"></div>
<button type="submit">Cancel</button>
</form>
</dialog>
<dialog id="gameSetupDialog">
<form id="gameSetupForm" method="dialog">
<div id="preGameDefaultSection">
<p>
<label for="maxPlayersBox">
Player limit:
<select id="maxPlayersBox">
<option value="2">2 players</option>
<option value="3">3 players</option>
<option value="4">4 players</option>
</select>
</label>
</p>
<p>
<label for="turnTimeLimitBox">
Turn time limit:
<input type="number" id="turnTimeLimitBox" min="10" max="120" step="10" placeholder="None"/>
<span id="turnTimeLimitUnit">seconds</span>
</label>
</p>
<p>
<button type="submit" id="gameSetupSubmitButton">Create room</button>
<button type="submit">Back</button>
</p>
</div>
</form>
</dialog>
<dialog id="errorDialog">
<div id="errorMessage"></div>
<form id="errorDialogForm" method="dialog">
<button type="submit">OK</button>
</form>
</dialog>
<dialog id="helpDialog">
<h2>Controls</h2>
<section id="helpControls">
<article>
<h3>Keyboard</h3>
<table>
<tr><th>Move card:</th><td>Arrow keys</td></tr>
<tr><th>Rotate clockwise:</th><td>R</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Shift+R</td></tr>
<tr><th>Confirm:</th><td>Enter</td></tr>
<tr><th>Deselect card:</th><td>Backspace</td></tr>
<tr><th>Pass:</th><td>P</td></tr>
<tr><th>Special attack:</th><td>S</td></tr>
<tr><th>Show deck:</th><td>D</td></tr>
</table>
</article>
<article>
<h3>Mouse</h3>
<table>
<tr><th>Move card:</th><td>Pointer</td></tr>
<tr><th>Rotate clockwise:</th><td>Right click or wheel down</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Wheel up</td></tr>
<tr><th>Confirm:</th><td>Left click</td></tr>
</table>
</article>
<article>
<h3>Touch</h3>
<table>
<tr><th>Move card:</th><td>Drag anywhere on the board</td></tr>
<tr><th>Rotate clockwise:</th><td>Tap &curarr;</td></tr>
<tr><th>Rotate anticlockwise:</th><td>Tap &cularr;</td></tr>
<tr><th>Confirm:</th><td>Tap anywhere on the board</td></tr>
</table>
</article>
</section>
<footer>
<form method="dialog">
<button type="submit">OK</button>
</form>
</footer>
</dialog>
<script src="build/tsbuild.js"></script>
</body>
</html>