<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0">
<title>Controller</title>
<style>
html, body {
touch-action: none;
margin: 0;
font-family: sans-serif;
background: #f0f0f0;
}
button {
font-size: 2em;
margin: 10px;
padding: 20px 50px;
border-radius: 16px;
border: none;
background: #222;
color: #fff;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
outline: none;
}
button:active {
background: #444;
}
#joystickArea {
width: 200px;
height: 200px;
background: #ddd;
border-radius: 50%;
position: relative;
margin: 20px auto;
touch-action: none;
}
#stick {
width: 60px;
height: 60px;
background: #666;
border-radius: 50%;
position: absolute;
left: 70px;
top: 70px;
touch-action: none;
}
#inputArea {
display: flex;
justify-content: center;
margin: 10px;
}
#typed {
font-size: 1.5em;
padding: 8px;
width: 60%;
border-radius: 8px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<h1>Controller</h1>
<div id="inputArea">
<input type="text" id="typed" placeholder="Type message…" />
<button onclick="sendTyped()">Send</button>
</div>
<div style="text-align: center;">
<button ontouchstart="sendButton('A', 1)" ontouchend="sendButton('A', 0)">A</button>
<button ontouchstart="sendButton('B', 1)" ontouchend="sendButton('B', 0)">B</button>
</div>
<div id="joystickArea">
<div id="stick"></div>
</div>
<div id="status" style="text-align:center">Connecting…</div>
<script>
let ws = new WebSocket('wss://' + location.hostname + (location.port ? ':' + location.port : '') + '/');
const status = document.getElementById('status');
const typed = document.getElementById('typed');
ws.onopen = () => status.textContent = "Connected!";
ws.onclose = () => status.textContent = "Connection closed.";
ws.onerror = (e) => status.textContent = "Error: " + e;
function sendMessage(obj) {
if (ws.readyState === 1) {
ws.send(JSON.stringify(obj));
}
}
function sendButton(button, pressed) {
sendMessage({ type: "button", button, pressed });
}
function sendTyped() {
const value = typed.value.trim();
if (value) {
sendMessage({ type: "text", value });
typed.value = "";
}
}
const joystick = document.getElementById('joystickArea');
const stick = document.getElementById('stick');
let dragging = false;
let joyX = 0;
let joyY = 0;
function updateStick(x, y) {
const radius = 100;
const dx = x - radius;
const dy = y - radius;
const len = Math.min(Math.sqrt(dx * dx + dy * dy), radius);
const angle = Math.atan2(dy, dx);
const lx = Math.cos(angle) * len;
const ly = Math.sin(angle) * len;
joyX = +(lx / radius).toFixed(2);
joyY = +(ly / radius).toFixed(2);
stick.style.left = (lx + radius - 30) + 'px';
stick.style.top = (ly + radius - 30) + 'px';
}
joystick.addEventListener('touchstart', e => {
dragging = true;
updateStick(e.touches[0].clientX - joystick.offsetLeft, e.touches[0].clientY - joystick.offsetTop);
e.preventDefault();
});
joystick.addEventListener('touchmove', e => {
if (!dragging) return;
updateStick(e.touches[0].clientX - joystick.offsetLeft, e.touches[0].clientY - joystick.offsetTop);
e.preventDefault();
});
joystick.addEventListener('touchend', () => {
dragging = false;
joyX = 0;
joyY = 0;
stick.style.left = '70px';
stick.style.top = '70px';
});
setInterval(() => {
sendMessage({ type: "joystick", x: joyX, y: joyY });
}, 20);
</script>
</body>
</html>